5 // Cesar Octavio Lopez Nataren
7 // (C) 2003, 2004 Cesar Octavio Lopez Nataren, <cesar@ciencias.unam.mx>
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 using System
.Reflection
;
34 using System
.Reflection
.Emit
;
35 using System
.Collections
;
37 namespace Microsoft
.JScript
{
39 internal class If
: AST
{
41 internal AST cond
, true_stm
, false_stm
;
43 internal If (AST parent
, AST condition
, AST true_stm
, AST false_stm
, int line_number
)
45 this.cond
= condition
;
46 this.true_stm
= true_stm
;
47 this.false_stm
= false_stm
;
48 this.line_number
= line_number
;
51 public override string ToString ()
53 StringBuilder sb
= new StringBuilder ();
56 sb
.Append (cond
.ToString ());
58 sb
.Append (true_stm
.ToString ());
59 if (false_stm
!= null)
60 sb
.Append (false_stm
.ToString ());
62 return sb
.ToString ();
65 internal override bool Resolve (IdentificationTable context
)
71 r
&= ((Exp
) cond
).Resolve (context
, false);
75 r
&= ((Exp
) true_stm
).Resolve (context
, true);
77 r
&= true_stm
.Resolve (context
);
79 if (false_stm
!= null)
81 r
&= ((Exp
) false_stm
).Resolve (context
, true);
83 r
&= false_stm
.Resolve (context
);
87 internal override void Emit (EmitContext ec
)
89 ILGenerator ig
= ec
.ig
;
90 Label false_lbl
= ig
.DefineLabel ();
91 Label merge_lbl
= ig
.DefineLabel ();
92 CodeGenerator
.fall_true (ec
, cond
, false_lbl
);
95 ig
.Emit (OpCodes
.Br
, merge_lbl
);
96 ig
.MarkLabel (false_lbl
);
97 if (false_stm
!= null)
99 ig
.MarkLabel (merge_lbl
);
103 abstract class Jump
: AST
{
104 protected string label
= String
.Empty
;
105 protected object binding
;
107 bool IsLabel (object binding
)
109 return binding
.GetType () == typeof (Labelled
);
112 protected bool ValidLabel ()
114 binding
= SemanticAnalyser
.GetLabel (label
);
115 if (binding
== null || !IsLabel (binding
))
116 throw new Exception ("error JS1026: Label not found");
121 internal class Continue
: Jump
{
122 internal Continue (AST parent
, string label
, int line_number
)
124 this.parent
= parent
;
125 Console
.WriteLine ("Continue.parent = {0}", this.parent
);
127 this.line_number
= line_number
;
130 internal override bool Resolve (IdentificationTable context
)
133 throw new Exception ("A continue can't be outside a iteration stm");
134 if (label
!= String
.Empty
)
135 return ValidLabel ();
139 internal override void Emit (EmitContext ec
)
141 if (label
== String
.Empty
) {
142 ec
.ig
.Emit (OpCodes
.Br
, ec
.LoopBegin
);
145 ec
.ig
.Emit (OpCodes
.Br
, (binding
as Labelled
).InitAddrs
);
149 internal class Break
: Jump
{
151 internal Break (AST parent
, string label
, int line_number
)
153 this.parent
= parent
;
154 Console
.WriteLine ("Break.parent = {0}", this.parent
);
156 this.line_number
= line_number
;
159 internal override bool Resolve (IdentificationTable context
)
161 if (!InLoop
&& !InSwitch
)
162 throw new Exception ("A break statement can't be outside a switch or iteration stm");
163 if (label
!= String
.Empty
)
164 return ValidLabel ();
168 internal override void Emit (EmitContext ec
)
170 if (label
== String
.Empty
) {
171 ec
.ig
.Emit (OpCodes
.Br
, ec
.LoopEnd
);
174 ec
.ig
.Emit (OpCodes
.Br
, (binding
as Labelled
).EndAddrs
);
178 internal class NotVoidReturnEventArgs
: EventArgs
{
181 internal delegate void NotVoidReturnEventHandler (object sender
, NotVoidReturnEventArgs args
);
183 internal class Return
: AST
{
185 internal AST expression
;
186 public event NotVoidReturnEventHandler not_void_return
;
189 internal void OnNotVoidReturn (NotVoidReturnEventArgs args
)
191 if (not_void_return
!= null)
192 not_void_return (this, args
);
195 internal Return (AST parent
, AST exp
, int line_number
)
197 this.parent
= parent
;
199 this.line_number
= line_number
;
200 Function cont_func
= GetContainerFunction
;
201 this.not_void_return
= new NotVoidReturnEventHandler (cont_func
.NotVoidReturnHappened
);
204 public override string ToString ()
206 if (expression
!= null)
207 return expression
.ToString ();
212 internal override bool Resolve (IdentificationTable context
)
215 throw new Exception ("error JS1018: 'return' statement outside of function");
216 if (expression
!= null) {
217 OnNotVoidReturn (null);
218 return expression
.Resolve (context
);
223 internal override void Emit (EmitContext ec
)
225 ILGenerator ig
= ec
.ig
;
226 Label lbl
= ig
.DefineLabel ();
227 LocalBuilder loc
= null;
229 if (expression
!= null) {
230 expression
.Emit (ec
);
231 loc
= ig
.DeclareLocal (typeof (object));
232 ig
.Emit (OpCodes
.Stloc
, loc
);
235 ig
.Emit (OpCodes
.Br
, lbl
);
239 ig
.Emit (OpCodes
.Ldloc
, loc
);
243 internal class DoWhile
: AST
{
247 internal void Init (AST parent
, AST stm
, AST exp
, int line_number
)
249 this.parent
= parent
;
250 Console
.WriteLine ("DoWhile.parent = {0}", this.parent
);
253 this.line_number
= line_number
;
256 internal override bool Resolve (IdentificationTable context
)
261 r
&= stm
.Resolve (context
);
263 r
&= exp
.Resolve (context
);
267 internal override void Emit (EmitContext ec
)
269 ILGenerator ig
= ec
.ig
;
270 Label old_begin
= ec
.LoopBegin
;
271 Label old_end
= ec
.LoopEnd
;
272 Label body_label
= ig
.DefineLabel ();
274 ec
.LoopBegin
= ig
.DefineLabel ();
275 ec
.LoopEnd
= ig
.DefineLabel ();
277 ig
.MarkLabel (body_label
);
282 ig
.MarkLabel (ec
.LoopBegin
);
284 if (parent
.GetType () == typeof (Labelled
))
285 ig
.MarkLabel ((parent
as Labelled
).InitAddrs
);
287 CodeGenerator
.fall_false (ec
, exp
, body_label
);
288 ig
.MarkLabel (ec
.LoopEnd
);
290 ec
.LoopBegin
= old_begin
;
291 ec
.LoopEnd
= old_end
;
296 internal class While
: AST
{
299 internal void Init (AST parent
, AST exp
, AST stm
, int line_number
)
301 this.parent
= parent
;
304 this.line_number
= line_number
;
307 internal override bool Resolve (IdentificationTable context
)
312 r
&= ((Exp
) exp
).Resolve (context
, false);
314 r
&= exp
.Resolve (context
);
316 r
&= stm
.Resolve (context
);
320 internal override void Emit (EmitContext ec
)
322 ILGenerator ig
= ec
.ig
;
323 Label old_begin
= ec
.LoopBegin
;
324 Label old_end
= ec
.LoopEnd
;
326 ec
.LoopBegin
= ig
.DefineLabel ();
327 ec
.LoopEnd
= ig
.DefineLabel ();
329 Label body_label
= ig
.DefineLabel ();
331 ig
.Emit (OpCodes
.Br
, ec
.LoopBegin
);
332 ig
.MarkLabel (body_label
);
337 ig
.MarkLabel (ec
.LoopBegin
);
339 if (parent
.GetType () == typeof (Labelled
))
340 ig
.MarkLabel ((parent
as Labelled
).InitAddrs
);
342 CodeGenerator
.fall_false (ec
, exp
, body_label
);
343 ig
.MarkLabel (ec
.LoopEnd
);
345 ec
.LoopBegin
= old_begin
;
346 ec
.LoopEnd
= old_end
;
349 public override string ToString ()
355 internal class For
: AST
{
357 AST
[] exprs
= new AST
[3];
360 internal For (AST parent
, int line_number
, AST init
, AST test
, AST incr
, AST body
)
362 this.parent
= parent
;
363 this.line_number
= line_number
;
370 internal override bool Resolve (IdentificationTable context
)
373 foreach (AST ast
in exprs
)
375 r
&= ast
.Resolve (context
);
377 r
&= stms
.Resolve (context
);
381 internal override void Emit (EmitContext ec
)
384 ILGenerator ig
= ec
.ig
;
385 Label old_begin
= ec
.LoopBegin
;
386 Label old_end
= ec
.LoopEnd
;
387 Label back
= ig
.DefineLabel ();
388 Label forward
= ig
.DefineLabel ();
396 ec
.LoopBegin
= ig
.DefineLabel ();
397 ec
.LoopEnd
= ig
.DefineLabel ();
400 ig
.MarkLabel (ec
.LoopBegin
);
407 if (tmp
!= null && tmp
is Expression
) {
408 ArrayList t
= ((Expression
) tmp
).exprs
;
409 AST a
= (AST
) t
[t
.Count
- 1];
411 ig
.Emit (OpCodes
.Brfalse
, forward
);
412 else if (a
is Relational
) {
413 ig
.Emit (OpCodes
.Ldc_I4_0
);
414 ig
.Emit (OpCodes
.Conv_R8
);
415 ig
.Emit (OpCodes
.Bge
, forward
);
422 if (parent
.GetType () == typeof (Labelled
))
423 ig
.MarkLabel ((parent
as Labelled
).InitAddrs
);
430 ig
.Emit (OpCodes
.Br
, back
);
431 ig
.MarkLabel (forward
);
432 ig
.MarkLabel (ec
.LoopEnd
);
434 ec
.LoopBegin
= old_begin
;
435 ec
.LoopEnd
= old_end
;
439 public class Switch
: AST
{
442 internal ArrayList case_clauses
;
443 internal ArrayList default_clauses
;
444 internal ArrayList sec_case_clauses
;
446 internal Switch (AST parent
, int line_number
)
448 this.parent
= parent
;
449 this.line_number
= line_number
;
450 case_clauses
= new ArrayList ();
451 default_clauses
= new ArrayList ();
452 sec_case_clauses
= new ArrayList ();
455 internal void AddClause (Clause clause
, ClauseType clause_type
)
457 if (clause_type
== ClauseType
.Case
)
458 case_clauses
.Add (clause
);
459 else if (clause_type
== ClauseType
.CaseAfterDefault
)
460 sec_case_clauses
.Add (clause
);
463 internal override bool Resolve (IdentificationTable context
)
467 r
&= exp
.Resolve (context
);
468 if (case_clauses
!= null)
469 foreach (Clause c
in case_clauses
)
470 r
&= c
.Resolve (context
);
471 if (default_clauses
!= null)
472 foreach (AST dc
in default_clauses
)
473 r
&= dc
.Resolve (context
);
474 if (sec_case_clauses
!= null)
475 foreach (Clause sc
in sec_case_clauses
)
476 r
&= sc
.Resolve (context
);
480 internal override void Emit (EmitContext ec
)
485 ILGenerator ig
= ec
.ig
;
486 Label init_default
= ig
.DefineLabel ();
487 Label end_of_default
= ig
.DefineLabel ();
488 ec
.LoopEnd
= ig
.DefineLabel ();
490 LocalBuilder loc
= ig
.DeclareLocal (typeof (object));
491 ig
.Emit (OpCodes
.Stloc
, loc
);
493 foreach (Clause c
in case_clauses
) {
494 ig
.Emit (OpCodes
.Ldloc
, loc
);
495 c
.EmitConditional (ec
);
498 /* emit conditionals from clauses that come after the default clause */
499 if (sec_case_clauses
!= null && sec_case_clauses
.Count
> 0) {
500 foreach (Clause c
in sec_case_clauses
) {
501 ig
.Emit (OpCodes
.Ldloc
, loc
);
502 c
.EmitConditional (ec
);
505 ig
.Emit (OpCodes
.Br
, init_default
);
507 /* emit the stms from case_clauses */
508 foreach (Clause c
in case_clauses
) {
509 ig
.MarkLabel (c
.matched_block
);
513 ig
.MarkLabel (init_default
);
514 foreach (AST ast
in default_clauses
)
516 ig
.MarkLabel (end_of_default
);
518 if (sec_case_clauses
!= null && sec_case_clauses
.Count
> 0) {
519 foreach (Clause c
in sec_case_clauses
) {
520 ig
.MarkLabel (c
.matched_block
);
524 ig
.MarkLabel (ec
.LoopEnd
);
528 public class Clause
: AST
{
530 internal ArrayList stm_list
;
531 internal Label matched_block
;
533 public Clause (AST parent
)
535 this.parent
= parent
;
536 stm_list
= new ArrayList ();
539 internal void AddStm (AST stm
)
544 internal override bool Resolve (IdentificationTable context
)
548 r
&= exp
.Resolve (context
);
549 foreach (AST ast
in stm_list
)
550 r
&= ast
.Resolve (context
);
554 internal void EmitConditional (EmitContext ec
)
558 ILGenerator ig
= ec
.ig
;
559 matched_block
= ig
.DefineLabel ();
560 ig
.Emit (OpCodes
.Call
, typeof (StrictEquality
).GetMethod ("JScriptStrictEquals"));
561 ig
.Emit (OpCodes
.Brtrue
, matched_block
);
564 internal void EmitStms (EmitContext ec
)
566 ILGenerator ig
= ec
.ig
;
567 foreach (AST ast
in stm_list
)
571 internal override void Emit (EmitContext ec
)
576 internal class Catch
: AST
{
578 internal AST catch_cond
;
581 FieldBuilder field_info
;
582 LocalBuilder local_builder
;
584 internal Catch (string id
, AST catch_cond
, AST stms
, AST parent
, int line_number
)
587 this.catch_cond
= catch_cond
;
589 this.line_number
= line_number
;
592 internal override bool Resolve (IdentificationTable context
)
596 r
&= stms
.Resolve (context
);
600 internal override void Emit (EmitContext ec
)
602 ILGenerator ig
= ec
.ig
;
603 Type t
= typeof (object);
604 bool not_in_func
= parent
== null;
607 field_info
= ec
.type_builder
.DefineField (mangle_id (id
), t
, FieldAttributes
.Public
| FieldAttributes
.Static
);
609 local_builder
= ig
.DeclareLocal (t
);
611 ig
.BeginCatchBlock (typeof (Exception
));
613 ig
.Emit (OpCodes
.Ldarg_0
);
614 ig
.Emit (OpCodes
.Ldfld
, typeof (ScriptObject
).GetField ("engine"));
615 ig
.Emit (OpCodes
.Call
, typeof (Try
).GetMethod ("JScriptExceptionValue"));
616 ig
.Emit (OpCodes
.Stsfld
, field_info
);
618 ig
.Emit (OpCodes
.Ldarg_1
);
619 ig
.Emit (OpCodes
.Call
, typeof (Try
).GetMethod ("JScriptExceptionValue"));
620 ig
.Emit (OpCodes
.Stloc
, local_builder
);
625 internal string mangle_id (string id
)
631 internal class Labelled
: AST
{
637 internal Label InitAddrs
{
638 set { init_addrs = value; }
639 get { return init_addrs; }
642 internal Label EndAddrs
{
643 set { end_addrs = value; }
644 get { return end_addrs; }
647 internal void Init (AST parent
, string name
, AST stm
, int line_number
)
649 this.parent
= parent
;
650 Console
.WriteLine ("labelled.parent = {0}", this.parent
);
653 this.line_number
= line_number
;
656 internal override bool Resolve (IdentificationTable context
)
659 SemanticAnalyser
.AddLabel (name
, this);
660 } catch (ArgumentException e
) {
661 throw new Exception ("error JS1025: Label redefined");
664 stm
.Resolve (context
);
665 SemanticAnalyser
.RemoveLabel (name
);
669 internal override void Emit (EmitContext ec
)
671 ILGenerator ig
= ec
.ig
;
673 init_addrs
= ig
.DefineLabel ();
674 end_addrs
= ig
.DefineLabel ();
677 ig
.MarkLabel (init_addrs
);
681 ig
.MarkLabel (end_addrs
);
684 bool IsLoop (AST ast
)
686 Type t
= ast
.GetType ();
687 return t
== typeof (For
) || t
== typeof (While
) || t
== typeof (DoWhile
) || t
== typeof (ForIn
);
690 public override string ToString ()