3 * Copyright (c) 1998 New Generation Software (NGS) Oy
5 * Author: Markku Rossi <mtr@ngs.fi>
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.
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.
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,
26 * $Source: /cygdrive/c/RCVS/CVS/ReactOS/reactos/lib/kjs/jsc/gram.js,v $
30 /* General helpers. */
32 function JSC
$gram_reset ()
35 JSC
$cont_break
= new JSC
$ContBreak ();
39 function JSC
$alloc_label (num_labels
)
41 JSC
$label_count
+= num_labels
;
43 return JSC
$label_count
- num_labels
;
47 function JSC
$format_label (num
)
49 return ".L" + num
.toString ();
53 function JSC
$count_locals_from_stmt_list (list
)
57 /* First, count how many variables we need at the toplevel. */
59 for (i
= 0; i
< list
.length
; i
++)
60 lcount
+= list
[i
].count_locals (false);
62 /* Second, count the maximum amount needed by the nested blocks. */
64 for (i
= 0; i
< list
.length
; i
++)
66 var rc
= list
[i
].count_locals (true);
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
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
89 function JSC
$ContBreakFrame (loop_break
, loop_continue
, inswitch
, label
, next
)
91 this.loop_break
= loop_break
;
92 this.loop_continue
= loop_continue
;
93 this.inswitch
= inswitch
;
97 this.with_nesting
= 0;
102 function JSC
$ContBreak ()
104 this.top
= new JSC
$ContBreakFrame (null, null, false, null);
107 new JSC
$ContBreak ();
109 function JSC
$ContBreak
$push (loop_break
, loop_continue
, inswitch
, label
)
111 this.top
= new JSC
$ContBreakFrame (loop_break
, loop_continue
, inswitch
,
114 JSC
$ContBreak
.prototype.push
= JSC
$ContBreak
$push
;
116 function JSC
$ContBreak
$pop ()
118 if (this.top
== null)
119 error ("jsc: internal error: continue-break stack underflow");
121 this.top
= this.top
.next
;
123 JSC
$ContBreak
.prototype.pop
= JSC
$ContBreak
$pop
;
126 * Count the currently active `try' nesting that should be removed on
127 * `return' statement.
129 function JSC
$ContBreak
$try_return_nesting ()
134 for (f
= this.top
; f
; f
= f
.next
)
135 count
+= f
.try_nesting
;
139 JSC
$ContBreak
.prototype.try_return_nesting
= JSC
$ContBreak
$try_return_nesting
;
142 * Count currently active `with' nesting that should be removed on
143 * `continue' or `break' statement.
145 function JSC
$ContBreak
$count_with_nesting (label
)
150 for (f
= this.top
; f
; f
= f
.next
)
152 count
+= f
.with_nesting
;
155 if (f
.label
== label
)
164 JSC
$ContBreak
.prototype.count_with_nesting
= JSC
$ContBreak
$count_with_nesting
;
167 * Count the currently active `try' nesting that should be removed on
168 * `continue' or `break' statement.
170 function JSC
$ContBreak
$count_try_nesting (label
)
175 for (f
= this.top
; f
; f
= f
.next
)
177 count
+= f
.try_nesting
;
180 if (f
.label
== label
)
189 JSC
$ContBreak
.prototype.count_try_nesting
= JSC
$ContBreak
$count_try_nesting
;
191 function JSC
$ContBreak
$count_switch_nesting (label
)
196 for (f
= this.top
; f
; f
= f
.next
)
202 if (f
.label
== label
)
211 JSC
$ContBreak
.prototype.count_switch_nesting
212 = JSC
$ContBreak
$count_switch_nesting
;
214 function JSC
$ContBreak
$get_continue (label
)
218 for (f
= this.top
; f
; f
= f
.next
)
221 if (f
.label
== label
)
222 return f
.loop_continue
;
226 return f
.loop_continue
;
230 JSC
$ContBreak
.prototype.get_continue
= JSC
$ContBreak
$get_continue
;
232 function JSC
$ContBreak
$get_break (label
)
236 for (f
= this.top
; f
; f
= f
.next
)
239 if (f
.label
== label
)
248 JSC
$ContBreak
.prototype.get_break
= JSC
$ContBreak
$get_break
;
250 function JSC
$ContBreak
$is_unique_label (label
)
254 for (f
= this.top
; f
; f
= f
.next
)
255 if (f
.label
== label
)
260 JSC
$ContBreak
.prototype.is_unique_label
= JSC
$ContBreak
$is_unique_label
;
262 JSC
$cont_break
= null;
265 /* Function declaration. */
267 function JSC
$function_declaration (ln
, lbrace_ln
, name
, name_given
, args
,
268 block
, use_arguments_prop
)
271 this.lbrace_linenum
= lbrace_ln
;
273 this.name_given
= name_given
;
276 this.use_arguments_prop
= use_arguments_prop
;
277 this.asm
= JSC
$function_declaration_asm
;
280 function JSC
$function_declaration_asm ()
284 /* Define arguments. */
285 JSC
$ns
.push_frame ();
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
);
290 /* Define the function name to be a global symbol. */
291 new JSC
$ASM_symbol (this.linenum
, this.name
).link ();
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 ();
298 /* Count how many local variables we need. */
299 var num_locals
= JSC
$count_locals_from_stmt_list (this.block
);
301 /* Is the `arguments' property of function instance used? */
302 if (this.use_arguments_prop
)
307 new JSC
$ASM_locals (this.lbrace_linenum
, num_locals
).link ();
308 if (this.use_arguments_prop
)
311 * Create an array for the arguments array and store it to
312 * the first local variable.
314 var ln
= this.lbrace_linenum
;
315 var locn
= JSC
$ns
.alloc_local ();
316 JSC
$ns
.define_symbol ("arguments", JSC
$SCOPE_LOCAL
, locn
, ln
);
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 ();
325 /* Push individual argumens to the array. */
327 /* Init the loop counter. */
328 new JSC
$ASM_const_i0 (ln
).link ();
330 var l_loop
= new JSC
$ASM_label ();
331 var l_out
= new JSC
$ASM_label ();
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 ();
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 ();
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 ();
352 /* Increment loop counter and continue. */
353 new JSC
$ASM_add_1_i (ln
).link ();
354 new JSC
$ASM_jmp (ln
, l_loop
).link ();
359 /* Pop the loop counter. */
360 new JSC
$ASM_pop (ln
).link ();
364 /* Assembler for our body. */
365 for (i
= 0; i
< this.block
.length
; i
++)
366 this.block
[i
].asm ();
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.
375 if (this.block
.length
> 0)
376 ln
= this.block
[this.block
.length
- 1].linenum
;
380 new JSC
$ASM_const_undefined (ln
).link ();
381 new JSC
$ASM_return (ln
).link ();
383 /* Pop our namespace. */
388 function JSC
$zero_function ()
400 function JSC
$stmt_block (ln
, list
)
402 this.stype
= JSC
$STMT_BLOCK
;
405 this.asm
= JSC
$stmt_block_asm
;
406 this.count_locals
= JSC
$stmt_block_count_locals
;
409 function JSC
$stmt_block_asm ()
411 JSC
$ns
.push_frame ();
413 /* Assembler for our stmts. */
415 for (i
= 0; i
< this.stmts
.length
; i
++)
416 this.stmts
[i
].asm ();
422 function JSC
$stmt_block_count_locals (recursive
)
427 return JSC
$count_locals_from_stmt_list (this.stmts
);
430 /* Function declaration. */
432 function JSC
$stmt_function_declaration (ln
, container_id
, function_id
,
435 this.stype
= JSC
$STMT_FUNCTION_DECLARATION
;
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
;
444 function JSC
$stmt_function_declaration_asm ()
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 ();
453 function JSC
$stmt_empty (ln
)
455 this.stype
= JSC
$STMT_EMPTY
;
457 this.asm
= JSC
$stmt_empty_asm
;
458 this.count_locals
= JSC
$zero_function
;
461 function JSC
$stmt_empty_asm ()
469 function JSC
$stmt_continue (ln
, label
)
471 this.stype
= JSC
$STMT_CONTINUE
;
474 this.asm
= JSC
$stmt_continue_asm
;
475 this.count_locals
= JSC
$zero_function
;
478 function JSC
$stmt_continue_asm ()
480 var l_cont
= JSC
$cont_break
.get_continue (this.label
);
485 error (JSC
$filename
+ ":" + this.linenum
.toString ()
486 + ": label `" + this.label
487 + "' not found for continue statement");
489 error (JSC
$filename
+ ":" + this.linenum
.toString ()
490 + ": continue statement not within a loop");
493 var nesting
= JSC
$cont_break
.count_with_nesting (this.label
);
495 new JSC
$ASM_with_pop (this.linenum
, nesting
).link ();
497 nesting
= JSC
$cont_break
.count_try_nesting (this.label
);
499 new JSC
$ASM_try_pop (this.linenum
, nesting
).link ();
501 nesting
= JSC
$cont_break
.count_switch_nesting (this.label
);
504 /* Pop the value of the switch expression. */
506 new JSC
$ASM_pop (this.linenum
).link ();
508 new JSC
$ASM_pop_n (this.linenum
, nesting
).link ();
511 new JSC
$ASM_jmp (this.linenum
, l_cont
).link ();
517 function JSC
$stmt_break (ln
, label
)
519 this.stype
= JSC
$STMT_BREAK
;
522 this.asm
= JSC
$stmt_break_asm
;
523 this.count_locals
= JSC
$zero_function
;
526 function JSC
$stmt_break_asm ()
528 var l_break
= JSC
$cont_break
.get_break (this.label
);
533 error (JSC
$filename
+ ":" + this.linenum
.toString ()
534 + ": label `" + this.label
535 + "' not found for break statement");
537 error (JSC
$filename
+ ":" + this.linenum
.toString()
538 + ": break statement not within a loop or switch");
541 var nesting
= JSC
$cont_break
.count_with_nesting (this.label
);
543 new JSC
$ASM_with_pop (this.linenum
, nesting
).link ();
545 nesting
= JSC
$cont_break
.count_try_nesting (this.label
);
547 new JSC
$ASM_try_pop (this.linenum
, nesting
).link ();
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.
557 nesting
= JSC
$cont_break
.count_switch_nesting (this.label
);
561 new JSC
$ASM_pop (this.linenum
).link ();
563 new JSC
$ASM_pop_n (this.linenum
, nesting
).link ();
567 new JSC
$ASM_jmp (this.linenum
, l_break
).link ();
573 function JSC
$stmt_return (ln
, expr
)
575 this.stype
= JSC
$STMT_RETURN
;
578 this.asm
= JSC
$stmt_return_asm
;
579 this.count_locals
= JSC
$zero_function
;
582 function JSC
$stmt_return_asm ()
584 var nesting
= JSC
$cont_break
.try_return_nesting ();
586 new JSC
$ASM_try_pop (this.linenum
, nesting
).link ();
588 if (this.expr
!= null)
591 new JSC
$ASM_const_undefined (this.linenum
).link ();
593 new JSC
$ASM_return (this.linenum
).link ();
599 function JSC
$stmt_switch (ln
, last_ln
, expr
, clauses
)
601 this.stype
= JSC
$STMT_SWITCH
;
603 this.last_linenum
= last_ln
;
605 this.clauses
= clauses
;
606 this.asm
= JSC
$stmt_switch_asm
;
607 this.count_locals
= JSC
$stmt_switch_count_locals
;
610 function JSC
$stmt_switch_asm ()
612 /* Evaluate the switch expression to the top of the stack. */
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);
619 /* For each clause (except the first), insert check and body labels. */
621 for (i
= 1; i
< this.clauses
.length
; i
++)
623 this.clauses
[i
].l_check
= new JSC
$ASM_label ();
624 this.clauses
[i
].l_body
= new JSC
$ASM_label ();
627 /* Generate code for each clause. */
628 for (i
= 0; i
< this.clauses
.length
; i
++)
630 /* Is this the last clause? */
631 var last
= i
+ 1 >= this.clauses
.length
;
632 var c
= this.clauses
[i
];
634 var next_check
, next_body
;
636 next_check
= next_body
= l_break
;
639 next_check
= this.clauses
[i
+ 1].l_check
;
640 next_body
= this.clauses
[i
+ 1].l_body
;
646 * Must check if this clause matches the expression. If c.expr
647 * is null, this is the default clause that matches always.
653 new JSC
$ASM_dup (c
.linenum
).link ();
655 new JSC
$ASM_cmp_eq (c
.linenum
).link ();
656 new JSC
$ASM_iffalse_b (c
.linenum
, next_check
).link ();
661 /* The check label for the default case. */
665 /* Generate assembler for the body. */
670 for (j
= 0; j
< c
.length
; j
++)
673 /* And finally, jump to the next body. (this is the fallthrough case). */
674 new JSC
$ASM_jmp (c
.last_linenum
, next_body
).link ();
677 JSC
$cont_break
.pop ();
679 /* The break label. */
682 /* Pop the value of the switch expression. */
683 new JSC
$ASM_pop (this.last_linenum
).link ();
686 function JSC
$stmt_switch_count_locals (recursive
)
693 /* For the recursive cases, we need the maximum of our clause stmts. */
694 for (i
= 0; i
< this.clauses
.length
; i
++)
696 var c
= this.clauses
[i
];
697 for (j
= 0; j
< c
.length
; j
++)
699 var l
= c
[j
].count_locals (true);
708 * The case clauses are not blocks. Therefore, we need the amount,
709 * needed by the clauses at the top-level.
712 for (i
= 0; i
< this.clauses
.length
; i
++)
714 var c
= this.clauses
[i
];
715 for (j
= 0; j
< c
.length
; j
++)
716 locals
+= c
[j
].count_locals (false);
726 function JSC
$stmt_with (ln
, expr
, stmt
)
728 this.stype
= JSC
$STMT_WITH
;
732 this.asm
= JSC
$stmt_with_asm
;
733 this.count_locals
= JSC
$stmt_with_count_locals
;
736 function JSC
$stmt_with_asm ()
740 new JSC
$ASM_with_push (this.linenum
).link ();
741 JSC
$cont_break
.top
.with_nesting
++;
745 JSC
$cont_break
.top
.with_nesting
--;
746 new JSC
$ASM_with_pop (this.linenum
, 1).link ();
749 function JSC
$stmt_with_count_locals (recursive
)
753 if (this.stmt
.stype
== JSC
$STMT_VARIABLE
)
754 return this.stmt
.list
.length
;
759 return this.stmt
.count_locals (true);
765 function JSC
$stmt_try (ln
, try_block_last_ln
, try_last_ln
, block
, catch_list
,
768 this.stype
= JSC
$STMT_TRY
;
770 this.try_block_last_linenum
= try_block_last_ln
;
771 this.try_last_linenum
= try_last_ln
;
773 this.catch_list
= catch_list
;
775 this.asm
= JSC
$stmt_try_asm
;
776 this.count_locals
= JSC
$stmt_try_count_locals
;
779 function JSC
$stmt_try_asm ()
781 var l_finally
= new JSC
$ASM_label ();
783 /* Protect and execute the try-block. */
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
++;
791 JSC
$cont_break
.top
.try_nesting
--;
792 new JSC
$ASM_try_pop (this.try_block_last_linenum
, 1).link ();
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).
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 ();
802 * Handle try block failures. The thrown value is on the top of the
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
816 new JSC
$ASM_const_false (this.catch_list
.linenum
).link ();
817 new JSC
$ASM_swap (this.catch_list
.linenum
).link ();
819 /* Protect and execute the catch list. */
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
++;
826 /* Insert start and body labels for each catch list item. */
828 for (i
= 0; i
< this.catch_list
.length
; i
++)
830 this.catch_list
[i
].l_start
= new JSC
$ASM_label ();
831 this.catch_list
[i
].l_body
= new JSC
$ASM_label ();
834 /* A label for the catch list end. */
835 var l_catch_list_end
= new JSC
$ASM_label ();
837 /* Process the individual catches. */
838 for (i
= 0; i
< this.catch_list
.length
; i
++)
840 var c
= this.catch_list
[i
];
842 /* This is the starting point of this catch frame. */
846 * Create a new namespace frame and bind the catch's
847 * identifier to the thrown exception.
850 JSC
$ns
.push_frame ();
851 JSC
$ns
.define_symbol (c
.id
, JSC
$SCOPE_LOCAL
, JSC
$ns
.alloc_local (),
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 ();
858 /* Check the possible guard. We must protect its calculation. */
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
++;
865 /* Calculate the guard. */
868 JSC
$cont_break
.top
.try_nesting
--;
869 new JSC
$ASM_try_pop (c
.linenum
, 1).link ();
872 * Wow! We managed to do it. Now, let's check if we
873 * accept this catch case.
877 if (i
+ 1 >= this.catch_list
.length
)
878 next
= l_catch_list_end
;
880 next
= this.catch_list
[i
+ 1].l_start
;
882 if (c
.guard
.lang_type
== JSC
$JS_BOOLEAN
)
883 new JSC
$ASM_iffalse_b (c
.linenum
, next
).link ();
885 new JSC
$ASM_iffalse (c
.linenum
, next
).link ();
887 /* Yes, we do accept it. Just jump to do the stuffs. */
888 new JSC
$ASM_jmp (c
.linenum
, c
.l_body
).link ();
891 * The evaluation of the guard failed. Do the cleanup
892 * and jump to the next case.
895 l_guard_error
.link ();
897 /* Pop the exception. */
898 new JSC
$ASM_pop (c
.linenum
).link ();
900 /* Check the next case. */
901 new JSC
$ASM_jmp (c
.linenum
, next
).link ();
905 * We did enter the catch body. Let's update our boolean
906 * status variable to reflect this fact.
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 ();
915 /* Code for the catch body. */
918 /* We'r done with the namespace frame. */
922 * The next catch tag, or the l_catch_list_end follows us,
923 * so we don't need a jumps here.
928 * The catch list was evaluated without errors.
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 ();
935 /* Did we enter any of our catch lists? */
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 ();
945 * Push `true' to indicate an exception and jump to the finally
946 * block. The exception is now on the top of the stack.
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 ();
951 /* Yes, we did enter one (or many) of our catch lists. */
953 l_we_did_enter
.link ();
955 /* Pop the try-block's exception */
956 new JSC
$ASM_pop (this.catch_list
.last_linenum
).link ();
959 * Push a `false' to indicate "no errors" and jump to the
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 ();
967 * Handle catch list failures. The thrown value is on the top of the
971 l_catch_list_error
.link ();
974 * Pop the try-block's exception and our boolean `did we enter a
975 * catch block' variable. They are below our new exception.
977 new JSC
$ASM_apop (this.catch_list
.last_linenum
, 2).link ();
980 * Push `true' to indicate an exception. We will fallthrough to
981 * the finally part, so no jump is needed here.
983 new JSC
$ASM_const_true (this.catch_list
.last_linenum
).link ();
988 new JSC
$ASM_const_true (this.try_block_last_linenum
).link ();
991 /* The possible finally block. */
996 /* Execute it without protection. */
999 /* We'r almost there. Let's see if we have to raise a new exception. */
1001 var l_out
= new JSC
$ASM_label ();
1002 new JSC
$ASM_iffalse_b (this.try_last_linenum
, l_out
).link ();
1005 new JSC
$ASM_throw (this.try_last_linenum
).link ();
1007 /* The possible exception is handled. Please, continue. */
1011 function JSC
$stmt_try_count_locals (recursive
)
1018 c
= this.block
.count_locals (true);
1022 if (this.catch_list
)
1025 for (i
= 0; i
< this.catch_list
.length
; i
++)
1027 c
= this.catch_list
[i
].stmt
.count_locals (true);
1034 c
= this.fin
.count_locals (true);
1041 if (this.block
.stype
== JSC
$STMT_VARIABLE
)
1042 count
+= this.block
.list
.length
;
1044 if (this.catch_list
)
1046 /* One for the call variable. */
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
;
1056 if (this.fin
.stype
== JSC
$STMT_VARIABLE
)
1057 count
+= this.fin
.list
.length
;
1066 function JSC
$stmt_throw (ln
, expr
)
1068 this.stype
= JSC
$STMT_THROW
;
1071 this.asm
= JSC
$stmt_throw_asm
;
1072 this.count_locals
= JSC
$zero_function
;
1075 function JSC
$stmt_throw_asm ()
1078 new JSC
$ASM_throw (this.linenum
).link ();
1082 /* Labeled statement. */
1083 function JSC
$stmt_labeled_stmt (ln
, id
, stmt
)
1085 this.stype
= JSC
$STMT_LABELED_STMT
;
1089 this.asm
= JSC
$stmt_labeled_stmt_asm
;
1090 this.count_locals
= JSC
$stmt_labeled_stmt_count_locals
;
1093 function JSC
$stmt_labeled_stmt_asm ()
1095 var l_continue
= new JSC
$ASM_label ();
1096 var l_break
= new JSC
$ASM_label ();
1099 * It is an error if we already have a labeled statement with the
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");
1107 /* Push the break and continue labels. */
1108 JSC
$cont_break
.push (l_break
, l_continue
, false, this.id
);
1110 /* Dump the assembler. */
1115 /* And we'r done with out label scope. */
1116 JSC
$cont_break
.pop ();
1119 function JSC
$stmt_labeled_stmt_count_locals (recursive
)
1121 return this.stmt
.count_locals (recursive
);
1127 function JSC
$stmt_expr (expr
)
1129 this.stype
= JSC
$STMT_EXPR
;
1130 this.linenum
= expr
.linenum
;
1132 this.asm
= JSC
$stmt_expr_asm
;
1133 this.count_locals
= JSC
$zero_function
;
1136 function JSC
$stmt_expr_asm ()
1139 new JSC
$ASM_pop (this.linenum
).link ();
1145 function JSC
$stmt_if (ln
, expr
, stmt1
, stmt2
)
1147 this.stype
= JSC
$STMT_IF
;
1152 this.asm
= JSC
$stmt_if_asm
;
1153 this.count_locals
= JSC
$stmt_if_count_locals
;
1156 function JSC
$stmt_if_asm ()
1160 var l1
= new JSC
$ASM_label ();
1161 var l2
= new JSC
$ASM_label ();
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 ();
1167 new JSC
$ASM_iffalse (this.linenum
, l1
).link ();
1169 /* Code for the then branch. */
1171 new JSC
$ASM_jmp (this.linenum
, l2
).link ();
1173 /* Code for the else branch. */
1175 if (this.stmt2
!= null)
1183 function JSC
$stmt_if_count_locals (recursive
)
1190 if (this.stmt1
.stype
== JSC
$STMT_VARIABLE
)
1191 lcount
+= this.stmt1
.list
.length
;
1193 if (this.stmt2
!= null && this.stmt2
.stype
== JSC
$STMT_VARIABLE
)
1194 lcount
+= this.stmt2
.list
.length
;
1198 lcount
= this.stmt1
.count_locals (true);
1202 var c
= this.stmt2
.count_locals (true);
1214 function JSC
$stmt_do_while (ln
, expr
, stmt
)
1216 this.stype
= JSC
$STMT_DO_WHILE
;
1220 this.asm
= JSC
$stmt_do_while_asm
;
1221 this.count_locals
= JSC
$stmt_do_while_count_locals
;
1224 function JSC
$stmt_do_while_asm ()
1226 var l1
= new JSC
$ASM_label ();
1227 var l2
= new JSC
$ASM_label ();
1228 var l3
= new JSC
$ASM_label ();
1234 JSC
$cont_break
.push (l3
, l2
, false, null);
1236 JSC
$cont_break
.pop ();
1238 /* Condition & continue. */
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 ();
1245 new JSC
$ASM_iftrue (this.linenum
, l1
).link ();
1251 function JSC
$stmt_do_while_count_locals (recursive
)
1255 if (this.stmt
.stype
== JSC
$STMT_VARIABLE
)
1256 return this.stmt
.list
.length
;
1261 return this.stmt
.count_locals (true);
1266 function JSC
$stmt_while (ln
, expr
, stmt
)
1268 this.stype
= JSC
$STMT_WHILE
;
1272 this.asm
= JSC
$stmt_while_asm
;
1273 this.count_locals
= JSC
$stmt_while_count_locals
;
1276 function JSC
$stmt_while_asm ()
1278 var l1
= new JSC
$ASM_label ();
1279 var l2
= new JSC
$ASM_label ();
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 ();
1290 new JSC
$ASM_iffalse (this.linenum
, l2
).link ();
1293 JSC
$cont_break
.push (l2
, l1
, false, null);
1295 JSC
$cont_break
.pop ();
1298 new JSC
$ASM_jmp (this.linenum
, l1
).link ();
1305 function JSC
$stmt_while_count_locals (recursive
)
1309 if (this.stmt
.stype
== JSC
$STMT_VARIABLE
)
1310 return this.stmt
.list
.length
;
1315 return this.stmt
.count_locals (true);
1321 function JSC
$stmt_for (ln
, vars
, e1
, e2
, e3
, stmt
)
1323 this.stype
= JSC
$STMT_FOR
;
1330 this.asm
= JSC
$stmt_for_asm
;
1331 this.count_locals
= JSC
$stmt_for_count_locals
;
1334 function JSC
$stmt_for_asm ()
1336 /* Code for the init. */
1339 /* We have our own variable scope. */
1340 JSC
$ns
.push_frame ();
1343 for (i
= 0; i
< this.vars
.length
; i
++)
1345 var decl
= this.vars
[i
];
1347 JSC
$ns
.define_symbol (decl
.id
, JSC
$SCOPE_LOCAL
,
1348 JSC
$ns
.alloc_local (), this.linenum
);
1350 /* Possible init. */
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");
1361 new JSC
$ASM_store_local (this.linenum
, r
.value
).link ();
1365 else if (this.expr1
!= null)
1368 new JSC
$ASM_pop (this.linenum
).link ();
1371 var l1
= new JSC
$ASM_label ();
1372 var l2
= new JSC
$ASM_label ();
1373 var l3
= new JSC
$ASM_label ();
1379 var type_op
= false;
1380 if (this.expr2
!= null)
1383 if (JSC
$optimize_type
&& this.expr2
.lang_type
1384 && this.expr2
.lang_type
== JSC
$JS_BOOLEAN
)
1389 new JSC
$ASM_const_true (this.linenum
).link ();
1390 type_op
= JSC
$optimize_type
;
1393 new JSC
$ASM_iffalse_b (this.linenum
, l3
).link ();
1395 new JSC
$ASM_iffalse (this.linenum
, l3
).link ();
1397 JSC
$cont_break
.push (l3
, l2
, false, null);
1400 JSC
$cont_break
.pop ();
1402 /* Continue label. */
1406 if (this.expr3
!= null)
1409 new JSC
$ASM_pop (this.linenum
).link ();
1413 new JSC
$ASM_jmp (this.linenum
, l1
).link ();
1419 /* Pop the local variable scope. */
1420 JSC
$ns
.pop_frame ();
1424 function JSC
$stmt_for_count_locals (recursive
)
1431 count
+= this.vars
.length
;
1433 count
+= this.stmt
.count_locals (true);
1437 if (this.stmt
.stype
== JSC
$STMT_VARIABLE
)
1438 count
+= this.stmt
.list
.length
;
1447 function JSC
$stmt_for_in (ln
, vars
, e1
, e2
, stmt
)
1449 this.stype
= JSC
$STMT_FOR_IN
;
1455 this.asm
= JSC
$stmt_for_in_asm
;
1456 this.count_locals
= JSC
$stmt_for_in_count_locals
;
1459 function JSC
$stmt_for_in_asm ()
1465 /* We need our own variable scope here. */
1466 JSC
$ns
.push_frame ();
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
);
1472 /* Possible init. */
1476 new JSC
$ASM_store_local (this.linenum
, local_id
).link ();
1480 /* Init the world. */
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 ();
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 ();
1496 new JSC
$ASM_nth (this.linenum
).link ();
1497 new JSC
$ASM_iffalse_b (this.linenum
, l_iffalse_b
).link ();
1499 /* Store value to variable. */
1501 new JSC
$ASM_store_local (this.linenum
, local_id
).link ();
1503 JSC
$asm_expr_lvalue_store_asm (this.expr1
);
1506 JSC
$cont_break
.push (l_break
, l_cont
, false, null);
1508 JSC
$cont_break
.pop ();
1510 /* Continue label. */
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 ();
1523 new JSC
$ASM_jmp (this.linenum
, l_loop
).link ();
1526 l_iffalse_b
.link ();
1528 new JSC
$ASM_pop (this.linenum
).link ();
1532 new JSC
$ASM_pop_n (this.linenum
, 2).link ();
1535 /* Pop the variable scope. */
1536 JSC
$ns
.pop_frame ();
1539 function JSC
$stmt_for_in_count_locals (recursive
)
1548 count
+= this.stmt
.count_locals (true);
1552 if (this.stmt
.stype
== JSC
$STMT_VARIABLE
)
1553 count
+= this.stmt
.list
.length
;
1563 function JSC
$stmt_variable (ln
, list
)
1565 this.stype
= JSC
$STMT_VARIABLE
;
1567 this.global_level
= false;
1569 this.asm
= JSC
$stmt_variable_asm
;
1570 this.count_locals
= JSC
$stmt_variable_count_locals
;
1573 function JSC
$stmt_variable_asm ()
1577 /* Define all local variables to our namespace. */
1578 for (j
= 0; j
< this.list
.length
; j
++)
1580 var i
= this.list
[j
];
1582 if (!this.global_level
)
1583 JSC
$ns
.define_symbol (i
.id
, JSC
$SCOPE_LOCAL
,
1584 JSC
$ns
.alloc_local (), this.linenum
);
1589 if (this.global_level
)
1590 new JSC
$ASM_store_global (this.linenum
, i
.id
).link ();
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");
1598 new JSC
$ASM_store_local (this.linenum
, r
.value
).link ();
1604 function JSC
$stmt_variable_count_locals (recursive
)
1608 if (this.global_level
)
1609 /* We define these as global variables. */
1612 return this.list
.length
;
1618 function JSC
$var_declaration (id
, expr
)
1631 function JSC
$expr_this (ln
)
1633 this.etype
= JSC
$EXPR_THIS
;
1635 this.asm
= JSC
$expr_this_asm
;
1638 function JSC
$expr_this_asm ()
1640 new JSC
$ASM_load_arg (this.linenum
, 0).link ();
1645 function JSC
$expr_identifier (ln
, value
)
1647 this.etype
= JSC
$EXPR_IDENTIFIER
;
1650 this.asm
= JSC
$expr_identifier_asm
;
1653 function JSC
$expr_identifier_asm ()
1655 JSC
$asm_expr_lvalue_load_asm (this);
1660 function JSC
$expr_float (ln
, value
)
1662 this.etype
= JSC
$EXPR_FLOAT
;
1663 this.lang_type
= JSC
$JS_FLOAT
;
1666 this.asm
= JSC
$expr_float_asm
;
1669 function JSC
$expr_float_asm ()
1671 new JSC
$ASM_const (this.linenum
, this.value
).link ();
1676 function JSC
$expr_integer (ln
, value
)
1678 this.etype
= JSC
$EXPR_INTEGER
;
1679 this.lang_type
= JSC
$JS_INTEGER
;
1682 this.asm
= JSC
$expr_integer_asm
;
1685 function JSC
$expr_integer_asm ()
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 ();
1696 new JSC
$ASM_const_i (this.linenum
, this.value
).link ();
1701 function JSC
$expr_string (ln
, value
)
1703 this.etype
= JSC
$EXPR_STRING
;
1704 this.lang_type
= JSC
$JS_STRING
;
1707 this.asm
= JSC
$expr_string_asm
;
1710 function JSC
$expr_string_asm ()
1712 new JSC
$ASM_const (this.linenum
, this.value
).link ();
1717 function JSC
$expr_regexp (ln
, value
)
1719 this.etype
= JSC
$EXPR_REGEXP
;
1720 this.lang_type
= JSC
$JS_BUILTIN
;
1723 this.asm
= JSC
$expr_regexp_asm
;
1726 function JSC
$expr_regexp_asm ()
1728 new JSC
$ASM_const (this.linenum
, this.value
).link ();
1731 /* Array initializer. */
1733 function JSC
$expr_array_initializer (ln
, items
)
1735 this.etype
= JSC
$EXPR_ARRAY_INITIALIZER
;
1736 this.lang_type
= JSC
$JS_ARRAY
;
1739 this.asm
= JSC
$expr_array_initializer_asm
;
1742 function JSC
$expr_array_initializer_asm ()
1744 /* Generate assembler for the individual items. */
1747 for (i
= this.items
.length
- 1; i
>= 0; i
--)
1750 this.items
[i
].asm ();
1752 new JSC
$ASM_const_undefined (this.linenum
).link ();
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:
1762 * creates an array of length of 5, but code:
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.
1770 new JSC
$ASM_const (this.linenum
, -this.items
.length
).link ();
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 ();
1779 /* Object initializer. */
1781 function JSC
$expr_object_initializer (ln
, items
)
1783 this.etype
= JSC
$EXPR_OBJECT_INITIALIZER
;
1784 this.lang_type
= JSC
$JS_OBJECT
;
1787 this.asm
= JSC
$expr_object_initializer_asm
;
1790 function JSC
$expr_object_initializer_asm ()
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 ();
1799 /* Insert the items. */
1800 for (var i
= 0; i
< this.items
.length
; i
++)
1802 var item
= this.items
[i
];
1804 new JSC
$ASM_dup (item
.linenum
).link ();
1806 new JSC
$ASM_swap (item
.linenum
).link ();
1808 switch (item
.id_type
)
1810 case JSC
$tIDENTIFIER
:
1811 new JSC
$ASM_store_property (item
.linenum
, item
.id
).link ();
1815 new JSC
$ASM_const (item
.linenum
, item
.id
).link ();
1816 new JSC
$ASM_store_array (item
.linenum
).link ();
1823 new JSC
$ASM_const_i0 (item
.linenum
).link ();
1827 new JSC
$ASM_const_i1 (item
.linenum
).link ();
1831 new JSC
$ASM_const_i2 (item
.linenum
).link ();
1835 new JSC
$ASM_const_i3 (item
.linenum
).link ();
1839 new JSC
$ASM_const_i (item
.linenum
, item
.id
).link ();
1842 new JSC
$ASM_store_array (item
.linenum
).link ();
1851 function JSC
$expr_null (ln
)
1853 this.etype
= JSC
$EXPR_NULL
;
1854 this.lang_type
= JSC
$JS_NULL
;
1856 this.asm
= JSC
$expr_null_asm
;
1859 function JSC
$expr_null_asm ()
1861 new JSC
$ASM_const_null (this.linenum
).link ();
1866 function JSC
$expr_true (ln
)
1868 this.etype
= JSC
$EXPR_TRUE
;
1869 this.lang_type
= JSC
$JS_BOOLEAN
;
1871 this.asm
= JSC
$expr_true_asm
;
1874 function JSC
$expr_true_asm ()
1876 new JSC
$ASM_const_true (this.linenum
).link ();
1881 function JSC
$expr_false (ln
)
1883 this.etype
= JSC
$EXPR_FALSE
;
1884 this.lang_type
= JSC
$JS_BOOLEAN
;
1886 this.asm
= JSC
$expr_false_asm
;
1889 function JSC
$expr_false_asm ()
1891 new JSC
$ASM_const_false (this.linenum
).link ();
1895 /* Multiplicative expr. */
1897 function JSC
$expr_multiplicative (ln
, type
, e1
, e2
)
1899 this.etype
= JSC
$EXPR_MULTIPLICATIVE
;
1904 this.asm
= JSC
$expr_multiplicative_asm
;
1907 function JSC
$expr_multiplicative_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 ();
1916 new JSC
$ASM_mod (this.linenum
).link ();
1920 /* Additive expr. */
1922 function JSC
$expr_additive (ln
, type
, e1
, e2
)
1924 this.etype
= JSC
$EXPR_ADDITIVE
;
1929 this.asm
= JSC
$expr_additive_asm
;
1930 this.constant_folding
= JSC
$expr_additive_constant_folding
;
1933 function JSC
$expr_additive_asm ()
1937 if (this.type
== #'+')
1938 new JSC
$ASM_add (this.linenum
).link ();
1940 new JSC
$ASM_sub (this.linenum
).link ();
1943 function JSC
$expr_additive_constant_folding ()
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 ();
1950 /* This could be smarter. */
1951 if (this.e1
.lang_type
&& this.e2
.lang_type
1952 && this.e1
.lang_type
== this.e2
.lang_type
)
1954 switch (this.e1
.lang_type
)
1956 case JSC
$JS_INTEGER
:
1957 return new JSC
$expr_integer (this.linenum
,
1959 ? this.e1
.value
+ this.e2
.value
1960 : this.e1
.value
- this.e2
.value
);
1964 return new JSC
$expr_float (this.linenum
,
1966 ? this.e1
.value
+ this.e2
.value
1967 : this.e1
.value
- this.e2
.value
);
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
);
1988 function JSC
$expr_shift (ln
, type
, e1
, e2
)
1990 this.etype
= JSC
$EXPR_SHIFT
;
1995 this.asm
= JSC
$expr_shift_asm
;
1998 function JSC
$expr_shift_asm ()
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 ();
2008 new JSC
$ASM_shift_rright (this.linenum
).link ();
2012 /* Relational expr. */
2014 function JSC
$expr_relational (ln
, type
, e1
, e2
)
2016 this.etype
= JSC
$EXPR_RELATIONAL
;
2017 this.lang_type
= JSC
$JS_BOOLEAN
;
2022 this.asm
= JSC
$expr_relational_asm
;
2025 function JSC
$expr_relational_asm ()
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 ();
2037 new JSC
$ASM_cmp_ge (this.linenum
).link ();
2041 /* Equality expr. */
2043 function JSC
$expr_equality (ln
, type
, e1
, e2
)
2045 this.etype
= JSC
$EXPR_EQUALITY
;
2046 this.lang_type
= JSC
$JS_BOOLEAN
;
2051 this.asm
= JSC
$expr_equality_asm
;
2054 function JSC
$expr_equality_asm ()
2062 new JSC
$ASM_cmp_eq (this.linenum
).link ();
2066 new JSC
$ASM_cmp_ne (this.linenum
).link ();
2070 new JSC
$ASM_cmp_seq (this.linenum
).link ();
2074 new JSC
$ASM_cmp_sne (this.linenum
).link ();
2078 error ("jsc: expr_equality: internal compiler error");
2084 /* Bitwise and expr. */
2086 function JSC
$expr_bitwise_and (ln
, e1
, e2
)
2088 this.etype
= JSC
$EXPR_BITWISE
;
2092 this.asm
= JSC
$expr_bitwise_and_asm
;
2095 function JSC
$expr_bitwise_and_asm ()
2100 new JSC
$ASM_and (this.linenum
).link ();
2104 /* Bitwise or expr. */
2106 function JSC
$expr_bitwise_or (ln
, e1
, e2
)
2108 this.etype
= JSC
$EXPR_BITWISE
;
2112 this.asm
= JSC
$expr_bitwise_or_asm
;
2115 function JSC
$expr_bitwise_or_asm ()
2120 new JSC
$ASM_or (this.linenum
).link ();
2124 /* Bitwise xor expr. */
2126 function JSC
$expr_bitwise_xor (ln
, e1
, e2
)
2128 this.etype
= JSC
$EXPR_BITWISE
;
2132 this.asm
= JSC
$expr_bitwise_xor_asm
;
2135 function JSC
$expr_bitwise_xor_asm ()
2140 new JSC
$ASM_xor (this.linenum
).link ();
2144 /* Logical and expr. */
2146 function JSC
$expr_logical_and (ln
, e1
, e2
)
2148 this.etype
= JSC
$EXPR_LOGICAL
;
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
;
2157 this.asm
= JSC
$expr_logical_and_asm
;
2160 function JSC
$expr_logical_and_asm ()
2164 var l
= new JSC
$ASM_label ();
2165 new JSC
$ASM_dup (this.linenum
).link ();
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 ();
2171 new JSC
$ASM_iffalse (this.linenum
, l
).link ();
2173 new JSC
$ASM_pop (this.linenum
).link ();
2182 /* Logical or expr. */
2184 function JSC
$expr_logical_or (ln
, e1
, e2
)
2186 this.etype
= JSC
$EXPR_LOGICAL
;
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
;
2195 this.asm
= JSC
$expr_logical_or_asm
;
2198 function JSC
$expr_logical_or_asm ()
2202 var l
= new JSC
$ASM_label ();
2203 new JSC
$ASM_dup (this.linenum
).link ();
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 ();
2209 new JSC
$ASM_iftrue (this.linenum
, l
).link ();
2211 new JSC
$ASM_pop (this.linenum
).link ();
2222 function JSC
$expr_new (ln
, expr
, args
)
2224 this.etype
= JSC
$EXPR_NEW
;
2228 this.asm
= JSC
$expr_new_asm
;
2231 function JSC
$expr_new_asm ()
2237 /* Code for the arguments. */
2238 for (i
= this.args
.length
- 1; i
>= 0; i
--)
2239 this.args
[i
].asm ();
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 ();
2250 new JSC
$ASM_const (this.linenum
, this.args
.length
).link ();
2254 /* A `new Foo' call. This is identical to `new Foo ()'. */
2255 new JSC
$ASM_const_i0 (this.linenum
).link ();
2262 new JSC
$ASM_new (this.linenum
).link ();
2264 /* Replace the constructor's return value with the object. */
2265 new JSC
$ASM_swap (this.linenum
).link ();
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 ();
2273 /* Object property expr. */
2275 function JSC
$expr_object_property (ln
, expr
, id
)
2277 this.etype
= JSC
$EXPR_OBJECT_PROPERTY
;
2281 this.asm
= JSC
$expr_object_property_asm
;
2284 function JSC
$expr_object_property_asm ()
2286 JSC
$asm_expr_lvalue_load_asm (this);
2290 /* Object array expr. */
2292 function JSC
$expr_object_array (ln
, expr1
, expr2
)
2294 this.etype
= JSC
$EXPR_OBJECT_ARRAY
;
2298 this.asm
= JSC
$expr_object_array_asm
;
2301 function JSC
$expr_object_array_asm ()
2303 JSC
$asm_expr_lvalue_load_asm (this);
2309 function JSC
$expr_call (ln
, expr
, args
)
2311 this.etype
= JSC
$EXPR_CALL
;
2315 this.asm
= JSC
$expr_call_asm
;
2318 function JSC
$expr_call_asm ()
2322 /* Code for the arguments. */
2323 for (i
= this.args
.length
- 1; i
>= 0; i
--)
2324 this.args
[i
].asm ();
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 ();
2335 new JSC
$ASM_const (this.linenum
, this.args
.length
).link ();
2337 /* Check the function type. */
2338 if (this.expr
.etype
== JSC
$EXPR_IDENTIFIER
)
2340 /* The simple subroutine or global object method invocation. */
2342 var saved_with_nesting
= JSC
$cont_break
.top
.with_nesting
;
2343 JSC
$cont_break
.top
.with_nesting
= 0;
2345 JSC
$asm_expr_lvalue_load_asm (this.expr
);
2347 JSC
$cont_break
.top
.with_nesting
= saved_with_nesting
;
2349 if (JSC
$cont_break
.top
.with_nesting
> 0)
2350 new JSC
$ASM_jsr_w (this.linenum
, this.expr
.value
).link ();
2352 new JSC
$ASM_jsr (this.linenum
).link ();
2354 new JSC
$ASM_apop (this.linenum
, this.args
.length
+ 2).link ();
2356 else if (this.expr
.etype
== JSC
$EXPR_OBJECT_PROPERTY
)
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 ();
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 ();
2375 function JSC
$expr_assignment (ln
, type
, expr1
, expr2
)
2377 this.etype
= JSC
$EXPR_ASSIGNMENT
;
2382 this.asm
= JSC
$expr_assignment_asm
;
2385 function JSC
$expr_assignment_asm ()
2387 if (this.type
!= #'=')
2388 JSC
$asm_expr_lvalue_load_asm (this.expr1
);
2390 /* Count the rvalue. */
2393 if (this.type
== #'=')
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 ();
2419 error (JSC
$filename
+ ":" + this.linenum
.toString ()
2420 + ": internal compiler error in assignment expression");
2422 /* Duplicate the value. */
2423 new JSC
$ASM_dup (this.linenum
).link ();
2425 /* Store it to the lvalue. */
2426 JSC
$asm_expr_lvalue_store_asm (this.expr1
);
2429 function JSC
$asm_expr_lvalue_load_asm (expr
)
2433 if (expr
.etype
== JSC
$EXPR_IDENTIFIER
)
2435 /* Must check global / local / argument. */
2436 i
= JSC
$ns
.lookup_symbol (expr
.value
);
2439 if (JSC
$cont_break
.top
.with_nesting
> 0)
2440 new JSC
$ASM_load_global_w (expr
.linenum
, expr
.value
).link ();
2442 new JSC
$ASM_load_global (expr
.linenum
, expr
.value
).link ();
2444 else if (i
.scope
== JSC
$SCOPE_ARG
)
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");
2451 new JSC
$ASM_load_arg (expr
.linenum
, i
.value
).link ();
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");
2460 new JSC
$ASM_load_local (expr
.linenum
, i
.value
).link ();
2463 else if (expr
.etype
== JSC
$EXPR_OBJECT_PROPERTY
)
2466 new JSC
$ASM_load_property (expr
.linenum
, expr
.id
).link ();
2468 else if (expr
.etype
== JSC
$EXPR_OBJECT_ARRAY
)
2472 new JSC
$ASM_load_array (expr
.linenum
).link ();
2475 error (JSC
$filename
+ ":" + expr
.linenum
.toString () + ": syntax error");
2478 function JSC
$asm_expr_lvalue_store_asm (expr
)
2482 if (expr
.etype
== JSC
$EXPR_IDENTIFIER
)
2484 i
= JSC
$ns
.lookup_symbol (expr
.value
);
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 ();
2490 new JSC
$ASM_store_local (expr
.linenum
, i
.value
).link ();
2492 else if (expr
.etype
== JSC
$EXPR_OBJECT_PROPERTY
)
2495 new JSC
$ASM_store_property (expr
.linenum
, expr
.id
).link ();
2497 else if (expr
.etype
== JSC
$EXPR_OBJECT_ARRAY
)
2501 new JSC
$ASM_store_array (expr
.linenum
).link ();
2504 error (JSC
$filename
+ ":" + expr
.linenum
.toString () + ": syntax error");
2510 function JSC
$expr_quest_colon (ln
, e1
, e2
, e3
)
2512 this.etype
= JSC
$EXPR_QUEST_COLON
;
2517 this.asm
= JSC
$expr_quest_colon_asm
;
2520 function JSC
$expr_quest_colon_asm()
2522 /* Code for the condition. */
2525 var l1
= new JSC
$ASM_label ();
2526 var l2
= new JSC
$ASM_label ();
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 ();
2532 new JSC
$ASM_iffalse (this.linenum
, l1
).link ();
2534 /* Code for the true branch. */
2536 new JSC
$ASM_jmp (this.linenum
, l2
).link ();
2538 /* Code for the false branch. */
2549 function JSC
$expr_unary (ln
, type
, expr
)
2551 this.etype
= JSC
$EXPR_UNARY
;
2555 this.asm
= JSC
$expr_unary_asm
;
2558 function JSC
$expr_unary_asm ()
2560 if (this.type
== #'!')
2563 new JSC
$ASM_not (this.linenum
).link ();
2565 else if (this.type
== #'+')
2570 else if (this.type
== #'~')
2573 new JSC
$ASM_const (this.linenum
, -1).link ();
2574 new JSC
$ASM_xor (this.linenum
).link ();
2576 else if (this.type
== #'-')
2579 new JSC
$ASM_neg (this.linenum
).link ();
2581 else if (this.type
== JSC
$tDELETE
)
2583 if (this.expr
.etype
== JSC
$EXPR_OBJECT_PROPERTY
)
2585 this.expr
.expr
.asm ();
2586 new JSC
$ASM_delete_property (this.linenum
, this.expr
.id
).link ();
2588 else if (this.expr
.etype
== JSC
$EXPR_OBJECT_ARRAY
)
2590 this.expr
.expr1
.asm ();
2591 this.expr
.expr2
.asm ();
2592 new JSC
$ASM_delete_array (this.linenum
).link ();
2594 else if (this.expr
.etype
== JSC
$EXPR_IDENTIFIER
)
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");
2600 new JSC
$ASM_const_null (this.linenum
).link ();
2601 new JSC
$ASM_delete_property (this.linenum
, this.expr
.value
).link ();
2604 error (JSC
$filename
+ ":" + this.linenum
.toString ()
2605 + ": illegal target for the delete operand");
2607 else if (this.type
== JSC
$tVOID
)
2610 new JSC
$ASM_pop (this.linenum
).link ();
2611 new JSC
$ASM_const_undefined (this.linenum
).link ();
2613 else if (this.type
== JSC
$tTYPEOF
)
2616 new JSC
$ASM_typeof (this.linenum
).link ();
2618 else if (this.type
== JSC
$tPLUSPLUS
2619 || this.type
== JSC
$tMINUSMINUS
)
2621 /* Fetch the old value. */
2622 JSC
$asm_expr_lvalue_load_asm (this.expr
);
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 ();
2629 new JSC
$ASM_sub (this.linenum
).link ();
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
);
2637 error ("jsc: internal error: unary expr's type is "
2638 + this.type
.toString ());
2645 function JSC
$expr_postfix (ln
, type
, expr
)
2647 this.etype
= JSC
$EXPR_POSTFIX
;
2651 this.asm
= JSC
$expr_postfix_asm
;
2654 function JSC
$expr_postfix_asm ()
2656 /* Fetch the old value. */
2657 JSC
$asm_expr_lvalue_load_asm (this.expr
);
2659 /* Duplicate the value since it is the expression's value. */
2660 new JSC
$ASM_dup (this.linenum
).link ();
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 ();
2667 new JSC
$ASM_sub (this.linenum
).link ();
2669 /* And finally, store it back. */
2670 JSC
$asm_expr_lvalue_store_asm (this.expr
);
2676 function JSC
$expr_comma (ln
, expr1
, expr2
)
2678 this.etype
= JSC
$EXPR_COMMA
;
2682 this.asm
= JSC
$expr_comma_asm
;
2685 function JSC
$expr_comma_asm ()
2688 new JSC
$ASM_pop (this.linenum
).link ();