2 // Expression.cs: Everything related to expressions
5 // Cesar Lopez Nataren (cesar@ciencias.unam.mx)
7 // (C) 2003, 2004 Cesar Lopez Nataren
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
.Collections
;
34 using System
.Reflection
;
35 using System
.Reflection
.Emit
;
36 using Microsoft
.JScript
.Vsa
;
38 namespace Microsoft
.JScript
{
40 public abstract class Exp
: AST
{
41 internal bool no_effect
;
42 internal abstract bool Resolve (IdentificationTable context
, bool no_effect
);
45 public class Unary
: UnaryOp
{
47 internal Unary (AST parent
, JSToken oper
)
53 public override string ToString ()
55 StringBuilder sb
= new StringBuilder ();
57 if (oper
!= JSToken
.None
)
58 sb
.Append (oper
+ " ");
61 sb
.Append (operand
.ToString ());
63 return sb
.ToString ();
66 internal override bool Resolve (IdentificationTable context
)
71 if (oper
!= JSToken
.Increment
&& oper
!= JSToken
.Decrement
)
72 r
= ((Exp
) operand
).Resolve (context
, no_effect
);
73 r
= ((AST
) operand
).Resolve (context
);
77 internal override bool Resolve (IdentificationTable context
, bool no_effect
)
79 this.no_effect
= no_effect
;
80 return Resolve (context
);
83 internal override void Emit (EmitContext ec
)
87 if (oper
!= JSToken
.Minus
)
91 internal void emit_unary_op (EmitContext ec
)
93 ILGenerator ig
= ec
.ig
;
96 ig
.Emit (OpCodes
.Call
, typeof (Typeof
).GetMethod ("JScriptTypeof"));
102 internal class Binary
: BinaryOp
, IAssignable
{
107 internal Binary (AST parent
, AST left
, JSToken op
)
108 : this (parent
, left
, null, op
)
112 internal Binary (AST parent
, AST left
, AST right
, JSToken op
)
113 : base (left
, right
, op
)
115 this.parent
= parent
;
118 public override string ToString ()
120 StringBuilder sb
= new StringBuilder ();
121 sb
.Append (left
.ToString () + " ");
123 if (op
!= JSToken
.None
)
124 sb
.Append (op
+ " ");
127 sb
.Append (right
.ToString ());
129 return sb
.ToString ();
132 internal override bool Resolve (IdentificationTable context
)
136 r
&= left
.Resolve (context
);
138 if (op
== JSToken
.AccessField
&& right
is IAccesible
)
139 r
&= ((IAccesible
) right
).ResolveFieldAccess (left
);
141 r
&= right
.Resolve (context
);
145 internal override bool Resolve (IdentificationTable context
, bool no_effect
)
147 this.no_effect
= no_effect
;
148 return Resolve (context
);
151 public bool ResolveAssign (IdentificationTable context
, AST right_side
)
153 if (op
== JSToken
.LeftBracket
|| op
== JSToken
.AccessField
) {
154 this.no_effect
= false;
156 this.right_side
= right_side
;
157 return Resolve (context
);
159 throw new Exception ("error JS5008: Illegal assignment");
162 internal override void Emit (EmitContext ec
)
164 ILGenerator ig
= ec
.ig
;
165 if (op
== JSToken
.None
) {
168 } else if (op
== JSToken
.LogicalAnd
|| op
== JSToken
.LogicalOr
)
169 emit_jumping_code (ec
);
170 else if (op
== JSToken
.LeftBracket
) {
172 get_default_this (ig
);
176 } else if (op
== JSToken
.AccessField
) {
177 if (left
is Identifier
) {
178 Identifier parent
= left
as Identifier
;
179 switch (parent
.name
) {
181 MathObject math_obj
= new MathObject ();
182 Type math_obj_type
= math_obj
.GetType ();
183 Identifier property
= right
as Identifier
;
185 switch (property
.name
) {
186 /* value properties of the math object */
206 v
= math_obj
.SQRT1_2
;
212 /* function properties of the math object */
220 ig
.Emit (OpCodes
.Call
, typeof (Convert
).GetMethod ("ToNumber", new Type
[] { typeof (object) }
));
221 ig
.Emit (OpCodes
.Call
, math_obj_type
.GetMethod (property
.name
));
222 ig
.Emit (OpCodes
.Box
, typeof (double));
225 ig
.Emit (OpCodes
.Ldc_R8
, v
);
226 ig
.Emit (OpCodes
.Box
, typeof (Double
));
229 if (right
is Identifier
)
230 emit_late_binding (ec
);
243 ig
.Emit (OpCodes
.Pop
);
246 void emit_late_binding (EmitContext ec
)
248 LocalBuilder local_lb
= init_late_binding (ec
);
249 emit_late_get_or_set (ec
, local_lb
);
252 LocalBuilder
init_late_binding (EmitContext ec
)
254 ILGenerator ig
= ec
.ig
;
255 Type lb_type
= typeof (LateBinding
);
257 LocalBuilder local
= ig
.DeclareLocal (lb_type
);
259 string prop_name
= (right
as Identifier
).name
;
260 ig
.Emit (OpCodes
.Ldstr
, prop_name
);
261 ig
.Emit (OpCodes
.Newobj
, lb_type
.GetConstructor (new Type
[] {typeof (string)}
));
262 ig
.Emit (OpCodes
.Stloc
, local
);
267 void emit_late_get_or_set (EmitContext ec
, LocalBuilder local
)
269 ILGenerator ig
= ec
.ig
;
271 ig
.Emit (OpCodes
.Ldloc
, local
);
272 ig
.Emit (OpCodes
.Dup
);
276 ig
.Emit (OpCodes
.Ldarg_0
);
277 ig
.Emit (OpCodes
.Ldfld
, typeof (ScriptObject
).GetField ("engine"));
278 ig
.Emit (OpCodes
.Call
, typeof (Convert
).GetMethod ("ToObject"));
280 Type lb_type
= typeof (LateBinding
);
282 ig
.Emit (OpCodes
.Stfld
, lb_type
.GetField ("obj"));
285 right_side
.Emit (ec
);
286 ig
.Emit (OpCodes
.Call
, lb_type
.GetMethod ("SetValue"));
288 ig
.Emit (OpCodes
.Call
, lb_type
.GetMethod ("GetNonMissingValue"));
291 internal void get_default_this (ILGenerator ig
)
293 if (parent
== null || parent
.GetType () == typeof (ScriptBlock
)) {
294 ig
.Emit (OpCodes
.Ldarg_0
);
295 ig
.Emit (OpCodes
.Ldfld
, typeof (ScriptObject
).GetField ("engine"));
297 ig
.Emit (OpCodes
.Ldarg_1
);
299 ig
.Emit (OpCodes
.Call
, typeof (Microsoft
.JScript
.Vsa
.VsaEngine
).GetMethod ("ScriptObjectStackTop"));
300 Type iact_obj
= typeof (IActivationObject
);
301 ig
.Emit (OpCodes
.Castclass
, iact_obj
);
302 ig
.Emit (OpCodes
.Callvirt
, iact_obj
.GetMethod ("GetDefaultThisObject"));
305 internal void emit_access (EmitContext ec
)
307 ILGenerator ig
= ec
.ig
;
308 ig
.Emit (OpCodes
.Ldc_I4_1
);
309 ig
.Emit (OpCodes
.Newarr
, typeof (object));
310 ig
.Emit (OpCodes
.Dup
);
311 ig
.Emit (OpCodes
.Ldc_I4_0
);
314 ig
.Emit (OpCodes
.Stelem_Ref
);
317 if (right_side
!= null)
318 right_side
.Emit (ec
);
319 ig
.Emit (OpCodes
.Call
, typeof (LateBinding
).GetMethod ("SetIndexedPropertyValueStatic"));
321 ig
.Emit (OpCodes
.Ldc_I4_0
);
322 ig
.Emit (OpCodes
.Ldc_I4_1
);
324 if (parent
== null || parent
.GetType () == typeof (ScriptBlock
)) {
325 ig
.Emit (OpCodes
.Ldarg_0
);
326 ig
.Emit (OpCodes
.Ldfld
, typeof (ScriptObject
).GetField ("engine"));
328 ig
.Emit (OpCodes
.Ldarg_1
);
329 ig
.Emit (OpCodes
.Call
, typeof (LateBinding
).GetMethod ("CallValue"));
333 internal void emit_op_eval (ILGenerator ig
)
337 ig
.Emit (OpCodes
.Callvirt
, typeof (Plus
).GetMethod ("EvaluatePlus"));
342 case JSToken
.Multiply
:
343 ig
.Emit (OpCodes
.Call
, typeof (NumericBinary
).GetMethod ("EvaluateNumericBinary"));
345 case JSToken
.BitwiseAnd
:
346 case JSToken
.BitwiseXor
:
347 case JSToken
.BitwiseOr
:
348 case JSToken
.LeftShift
:
349 case JSToken
.RightShift
:
350 case JSToken
.UnsignedRightShift
:
351 ig
.Emit (OpCodes
.Call
, typeof (BitwiseBinary
).GetMethod ("EvaluateBitwiseBinary"));
356 internal void emit_jumping_code (EmitContext ec
)
358 ILGenerator ig
= ec
.ig
;
359 Type t
= typeof (bool);
360 Label false_label
= ig
.DefineLabel ();
361 Label exit_label
= ig
.DefineLabel ();
362 CodeGenerator
.fall_true (ec
, this, false_label
);
363 ig
.Emit (OpCodes
.Ldc_I4_1
);
364 ig
.Emit (OpCodes
.Box
, t
);
365 ig
.Emit (OpCodes
.Br
, exit_label
);
366 ig
.MarkLabel (false_label
);
367 ig
.Emit (OpCodes
.Ldc_I4_0
);
368 ig
.Emit (OpCodes
.Box
, t
);
369 ig
.MarkLabel (exit_label
);
372 internal void emit_operator (ILGenerator ig
)
374 LocalBuilder local_builder
= null;
377 if (op
== JSToken
.Plus
) {
379 local_builder
= ig
.DeclareLocal (t
);
380 ig
.Emit (OpCodes
.Newobj
, t
.GetConstructor (new Type
[] {}));
381 ig
.Emit (OpCodes
.Stloc
, local_builder
);
382 ig
.Emit (OpCodes
.Ldloc
, local_builder
);
384 } else if (op
== JSToken
.Minus
) {
385 t
= typeof (NumericBinary
);
386 local_builder
= ig
.DeclareLocal (t
);
387 ig
.Emit (OpCodes
.Ldc_I4_S
, (byte) 47);
388 } else if (op
== JSToken
.LeftShift
) {
389 t
= typeof (BitwiseBinary
);
390 local_builder
= ig
.DeclareLocal (t
);
391 ig
.Emit (OpCodes
.Ldc_I4_S
, (byte) 61);
392 } else if (op
== JSToken
.RightShift
) {
393 t
= typeof (BitwiseBinary
);
394 local_builder
= ig
.DeclareLocal (t
);
395 ig
.Emit (OpCodes
.Ldc_I4_S
, (byte) 62);
396 } else if (op
== JSToken
.UnsignedRightShift
) {
397 t
= typeof (BitwiseBinary
);
398 local_builder
= ig
.DeclareLocal (t
);
399 ig
.Emit (OpCodes
.Ldc_I4_S
, (byte) 63);
400 } else if (op
== JSToken
.Multiply
) {
401 t
= typeof (NumericBinary
);
402 local_builder
= ig
.DeclareLocal (t
);
403 ig
.Emit (OpCodes
.Ldc_I4_S
, (byte) 64);
404 } else if (op
== JSToken
.Divide
) {
405 t
= typeof (NumericBinary
);
406 local_builder
= ig
.DeclareLocal (t
);
407 ig
.Emit (OpCodes
.Ldc_I4_S
, (byte) 65);
408 } else if (op
== JSToken
.Modulo
) {
409 t
= typeof (NumericBinary
);
410 local_builder
= ig
.DeclareLocal (t
);
411 ig
.Emit (OpCodes
.Ldc_I4_S
, (byte) 66);
412 } else if (op
== JSToken
.BitwiseOr
) {
413 t
= typeof (BitwiseBinary
);
414 local_builder
= ig
.DeclareLocal (t
);
415 ig
.Emit (OpCodes
.Ldc_I4_S
, (byte) 50);
416 } else if (op
== JSToken
.BitwiseXor
) {
417 t
= typeof (BitwiseBinary
);
418 local_builder
= ig
.DeclareLocal (t
);
419 ig
.Emit (OpCodes
.Ldc_I4_S
, (byte) 51);
420 } else if (op
== JSToken
.BitwiseAnd
) {
421 t
= typeof (BitwiseBinary
);
422 local_builder
= ig
.DeclareLocal (t
);
423 ig
.Emit (OpCodes
.Ldc_I4_S
, (byte) 52);
425 ig
.Emit (OpCodes
.Newobj
, t
.GetConstructor (new Type
[] {typeof (int)}
));
426 ig
.Emit (OpCodes
.Stloc
, local_builder
);
427 ig
.Emit (OpCodes
.Ldloc
, local_builder
);
431 public class Conditional
: Exp
{
433 AST cond_exp
, true_exp
, false_exp
;
435 internal Conditional (AST parent
, AST expr
, AST trueExpr
, AST falseExpr
)
437 this.cond_exp
= expr
;
438 this.true_exp
= trueExpr
;
439 this.false_exp
= falseExpr
;
442 public override string ToString ()
444 StringBuilder sb
= new StringBuilder ();
446 if (cond_exp
!= null)
447 sb
.Append (cond_exp
.ToString () + " ");
448 if (true_exp
!= null)
449 sb
.Append (true_exp
.ToString () + " ");
450 if (false_exp
!= null)
451 sb
.Append (false_exp
.ToString ());
453 return sb
.ToString ();
456 internal override bool Resolve (IdentificationTable context
)
459 if (cond_exp
!= null)
460 r
&= cond_exp
.Resolve (context
);
461 if (true_exp
!= null)
462 r
&= true_exp
.Resolve (context
);
463 if (false_exp
!= null)
464 r
&= false_exp
.Resolve (context
);
468 internal override bool Resolve (IdentificationTable context
, bool no_effect
)
470 this.no_effect
= no_effect
;
471 return Resolve (context
);
474 internal override void Emit (EmitContext ec
)
476 ILGenerator ig
= ec
.ig
;
477 Label false_label
= ig
.DefineLabel ();
478 Label merge_label
= ig
.DefineLabel ();
479 CodeGenerator
.fall_true (ec
, cond_exp
, false_label
);
480 if (true_exp
!= null)
482 ig
.Emit (OpCodes
.Br
, merge_label
);
483 ig
.MarkLabel (false_label
);
484 if (false_exp
!= null)
486 ig
.MarkLabel (merge_label
);
488 ig
.Emit (OpCodes
.Pop
);
492 internal interface ICallable
{
493 void AddArg (AST arg
);
496 public class Call
: Exp
, ICallable
{
498 internal AST member_exp
;
501 internal Call (AST parent
, AST exp
)
503 this.parent
= parent
;
504 this.member_exp
= exp
;
505 this.args
= new Args ();
508 public override string ToString ()
510 StringBuilder sb
= new StringBuilder ();
511 if (member_exp
!= null)
512 sb
.Append (member_exp
.ToString () + " ");
514 sb
.Append (args
.ToString ());
515 return sb
.ToString ();
518 public void AddArg (AST arg
)
523 internal override bool Resolve (IdentificationTable context
)
527 if (member_exp
!= null) {
528 BuiltIn binding
= (BuiltIn
) SemanticAnalyser
.ObjectSystemContains (member_exp
.ToString ());
529 if (binding
!= null) {
530 if (!binding
.IsFunction
)
531 throw new Exception ("error JS5002: function expected.");
532 if (!binding
.IsConstructor
)
533 n
= binding
.NumOfArgs
;
535 r
&= member_exp
.Resolve (context
);
538 args
.DesiredNumOfArgs
= n
;
539 if (member_exp
.ToString () == "print")
541 r
&= args
.Resolve (context
);
546 internal override bool Resolve (IdentificationTable context
, bool no_effect
)
548 this.no_effect
= no_effect
;
549 return Resolve (context
);
552 internal override void Emit (EmitContext ec
)
554 ILGenerator ig
= ec
.ig
;
555 if (member_exp
.ToString () == "print") {
557 int n
= args
.Size
- 1;
559 if (n
== -1) { // no args
560 ig
.Emit (OpCodes
.Ldstr
, "");
561 ig
.Emit (OpCodes
.Call
, typeof (ScriptStream
).GetMethod ("WriteLine"));
565 Type script_stream
= typeof (ScriptStream
);
566 MethodInfo write
= script_stream
.GetMethod ("Write");
567 MethodInfo writeline
= script_stream
.GetMethod ("WriteLine");
568 MethodInfo to_string
= typeof (Convert
).GetMethod ("ToString",
569 new Type
[] { typeof (object), typeof (bool) }
);
570 for (int i
= 0; i
<= n
; i
++) {
571 ast
= args
.get_element (i
);
574 if (ast
is StringLiteral
)
577 ig
.Emit (OpCodes
.Ldc_I4_1
);
578 ig
.Emit (OpCodes
.Call
, to_string
);
582 ig
.Emit (OpCodes
.Call
, writeline
);
584 ig
.Emit (OpCodes
.Call
, write
);
587 object binding
= SemanticAnalyser
.ObjectSystemContains (member_exp
.ToString ());
590 binding
= TypeManager
.GetMethod (member_exp
.ToString ());
592 if (binding
== null) {
597 if (IsGlobalObjectMethod (binding
)) {
599 member_exp
.Emit (ec
);
600 } else if (IsConstructorProperty (binding
)) {
601 member_exp
.Emit (ec
);
602 EmitBuiltInArgs (ec
);
604 } else if (binding
is MethodBuilder
) {
605 emit_func_call ((MethodBuilder
) binding
, ec
);
610 ec
.ig
.Emit (OpCodes
.Pop
);
614 void emit_late_call (EmitContext ec
)
616 ILGenerator ig
= ec
.ig
;
618 if (member_exp
is Binary
) {
619 Binary bin
= member_exp
as Binary
;
620 if (bin
.right
is Identifier
) {
621 Identifier rside
= bin
.right
as Identifier
;
622 Type lb_type
= typeof (LateBinding
);
624 LocalBuilder lb
= ig
.DeclareLocal (lb_type
);
626 ig
.Emit (OpCodes
.Ldstr
, rside
.name
);
627 ig
.Emit (OpCodes
.Newobj
, lb_type
.GetConstructor (new Type
[] {typeof (string)}
));
628 ig
.Emit (OpCodes
.Stloc
, lb
);
629 init_late_binding (ec
, lb
);
630 setup_late_call_args (ec
);
631 ig
.Emit (OpCodes
.Call
, typeof (LateBinding
).GetMethod ("Call"));
634 member_exp
.Emit (ec
);
635 setup_late_call_args (ec
);
636 ig
.Emit (OpCodes
.Call
, typeof (LateBinding
).GetMethod ("CallValue"));
639 get_global_scope_or_this (ec
.ig
);
640 member_exp
.Emit (ec
);
641 setup_late_call_args (ec
);
642 ig
.Emit (OpCodes
.Call
, typeof (LateBinding
).GetMethod ("CallValue"));
644 ec
.ig
.Emit (OpCodes
.Pop
);
648 internal void get_global_scope_or_this (ILGenerator ig
)
650 if (parent
== null || parent
.GetType () == typeof (ScriptBlock
)) {
651 ig
.Emit (OpCodes
.Ldarg_0
);
652 ig
.Emit (OpCodes
.Ldfld
, typeof (ScriptObject
).GetField ("engine"));
654 ig
.Emit (OpCodes
.Ldarg_1
);
656 ig
.Emit (OpCodes
.Call
, typeof (Microsoft
.JScript
.Vsa
.VsaEngine
).GetMethod ("ScriptObjectStackTop"));
657 Type iact_obj
= typeof (IActivationObject
);
658 ig
.Emit (OpCodes
.Castclass
, iact_obj
);
661 //FIXME: when is each of them (GetGlobalScope | GetDefaultThisObject?
663 // ig.Emit (OpCodes.Callvirt, iact_obj.GetMethod ("GetGlobalScope"));
664 ig
.Emit (OpCodes
.Callvirt
, iact_obj
.GetMethod ("GetDefaultThisObject"));
667 void init_late_binding (EmitContext ec
, LocalBuilder local
)
669 ILGenerator ig
= ec
.ig
;
671 ig
.Emit (OpCodes
.Ldloc
, local
);
672 ig
.Emit (OpCodes
.Dup
);
674 AST left
= (member_exp
as Binary
).left
;
677 ig
.Emit (OpCodes
.Ldarg_0
);
678 ig
.Emit (OpCodes
.Ldfld
, typeof (ScriptObject
).GetField ("engine"));
679 ig
.Emit (OpCodes
.Call
, typeof (Convert
).GetMethod ("ToObject"));
681 Type lb_type
= typeof (LateBinding
);
683 ig
.Emit (OpCodes
.Stfld
, lb_type
.GetField ("obj"));
686 void setup_late_call_args (EmitContext ec
)
688 ILGenerator ig
= ec
.ig
;
691 ig
.Emit (OpCodes
.Ldc_I4
, n
);
692 ig
.Emit (OpCodes
.Newarr
, typeof (object));
694 for (int i
= 0; i
< n
; i
++) {
695 ig
.Emit (OpCodes
.Dup
);
696 ig
.Emit (OpCodes
.Ldc_I4
, i
);
697 args
.get_element (i
).Emit (ec
);
698 ig
.Emit (OpCodes
.Stelem_Ref
);
701 ig
.Emit (OpCodes
.Ldc_I4_0
);
702 ig
.Emit (OpCodes
.Ldc_I4_0
);
705 ig
.Emit (OpCodes
.Ldarg_1
);
707 ig
.Emit (OpCodes
.Ldarg_0
);
708 ig
.Emit (OpCodes
.Ldfld
, typeof (ScriptObject
).GetField ("engine"));
712 void emit_func_call (MethodBuilder mb
, EmitContext ec
)
714 ILGenerator ig
= ec
.ig
;
715 FieldInfo engine
= typeof (ScriptObject
).GetField ("engine");
716 ig
.Emit (OpCodes
.Ldarg_0
);
717 ig
.Emit (OpCodes
.Ldfld
, engine
);
718 ig
.Emit (OpCodes
.Call
, typeof (VsaEngine
).GetMethod ("ScriptObjectStackTop"));
719 Type iact_obj
= typeof (IActivationObject
);
720 ig
.Emit (OpCodes
.Castclass
, iact_obj
);
721 ig
.Emit (OpCodes
.Callvirt
, iact_obj
.GetMethod ("GetDefaultThisObject"));
722 ig
.Emit (OpCodes
.Ldarg_0
);
723 ig
.Emit (OpCodes
.Ldfld
, engine
);
727 ig
.Emit (OpCodes
.Call
, mb
);
729 if (!return_void (mb
) && no_effect
)
730 ig
.Emit (OpCodes
.Pop
);
733 bool return_void (MethodBuilder mb
)
735 return mb
.ReturnType
== typeof (void);
738 void EmitBuiltInArgs (EmitContext ec
)
740 ILGenerator ig
= ec
.ig
;
743 if (n
>= 1 && (member_exp
.ToString () == "String" || member_exp
.ToString () == "Boolean" || member_exp
.ToString () == "Number")) {
744 args
.get_element (0).Emit (ec
);
748 ig
.Emit (OpCodes
.Ldc_I4
, n
);
749 ig
.Emit (OpCodes
.Newarr
, typeof (object));
750 for (int i
= 0; i
< n
; i
++) {
751 ig
.Emit (OpCodes
.Dup
);
752 ig
.Emit (OpCodes
.Ldc_I4
, i
);
753 args
.get_element (i
).Emit (ec
);
754 ig
.Emit (OpCodes
.Stelem_Ref
);
758 void EmitInvoke (EmitContext ec
)
760 ILGenerator ig
= ec
.ig
;
761 string name
= member_exp
.ToString ();
763 bool boolean
= false;
768 type
= typeof (ObjectConstructor
);
771 type
= typeof (FunctionConstructor
);
774 type
= typeof (ArrayConstructor
);
777 type
= typeof (StringConstructor
);
780 type
= typeof (BooleanConstructor
);
784 type
= typeof (NumberConstructor
);
788 type
= typeof (DateConstructor
);
791 type
= typeof (RegExpConstructor
);
796 case "ReferenceError":
800 type
= typeof (ErrorConstructor
);
803 ig
.Emit (OpCodes
.Call
, type
.GetMethod ("Invoke"));
805 ig
.Emit (OpCodes
.Box
, typeof (Boolean
));
807 ig
.Emit (OpCodes
.Box
, typeof (Double
));
810 bool IsConstructorProperty (object binding
)
812 if (!(binding
is BuiltIn
))
815 string name
= (binding
as BuiltIn
).Name
;
817 return (name
== "Object" || name
== "Function" || name
== "Array" || name
== "String" || name
== "Boolean" || name
== "Number" || name
== "Date" || name
== "RegExp" || name
== "Error" || name
== "EvalError" || name
== "RangeError" || name
== "ReferenceError" || name
== "SyntaxError" || name
== "TypeError" || name
== "URIError");
820 bool IsGlobalObjectMethod (object binding
)
822 if (binding
== null || binding
.GetType () != typeof (BuiltIn
))
825 BuiltIn bind
= binding
as BuiltIn
;
833 case "decodeURIComponent":
835 case "encodeURIComponent":
843 interface IAccesible
{
844 bool ResolveFieldAccess (AST parent
);
847 internal class Identifier
: Exp
, IAssignable
, IAccesible
{
849 internal string name
;
850 internal AST binding
;
851 internal bool assign
;
853 MemberInfo
[] members
= null;
855 internal Identifier (AST parent
, string id
)
857 this.parent
= parent
;
861 public override string ToString ()
866 internal override bool Resolve (IdentificationTable context
)
869 return SemanticAnalyser
.print
;
870 object bind
= context
.Contains (name
);
872 bind
= SemanticAnalyser
.ObjectSystemContains (name
);
874 throw new Exception ("variable not found: " + name
);
875 binding
= bind
as AST
;
879 internal override bool Resolve (IdentificationTable context
, bool no_effect
)
881 this.no_effect
= no_effect
;
882 return Resolve (context
);
885 public bool ResolveAssign (IdentificationTable context
, AST right_side
)
888 this.no_effect
= false;
889 this.right_side
= right_side
;
890 if (name
!= String
.Empty
)
891 return Resolve (context
);
895 public bool ResolveFieldAccess (AST parent
)
897 if (parent
is Identifier
) {
898 Identifier p
= parent
as Identifier
;
900 AST binding
= (AST
) SemanticAnalyser
.ObjectSystemContains (p
.name
);
901 if (binding
!= null && binding
is BuiltIn
)
902 return IsBuiltInObjectProperty (p
.name
, name
);
907 bool IsBuiltInObjectProperty (string obj_name
, string prop_name
)
910 if (obj_name
== "Math") {
911 type
= typeof (MathObject
);
912 members
= type
.FindMembers (MemberTypes
.Field
| MemberTypes
.Method
,
913 BindingFlags
.Public
| BindingFlags
.Static
,
914 Type
.FilterName
, prop_name
);
915 if (members
!= null && members
.Length
> 0)
918 throw new Exception ("error: JS0438: Object doesn't support this property or method");
923 internal override void Emit (EmitContext ec
)
925 ILGenerator ig
= ec
.ig
;
926 if (assign
&& right_side
!= null)
927 right_side
.Emit (ec
);
928 if (binding
is FormalParam
) {
929 FormalParam f
= binding
as FormalParam
;
930 ig
.Emit (OpCodes
.Ldarg_S
, f
.pos
);
931 } else if (binding
is VariableDeclaration
|| binding
is Try
) {
932 FieldInfo field_info
= extract_field_info (binding
);
933 LocalBuilder local_builder
= extract_local_builder (binding
);
935 if (field_info
!= null) {
937 ig
.Emit (OpCodes
.Stsfld
, field_info
);
939 ig
.Emit (OpCodes
.Ldsfld
, field_info
);
940 } else if (local_builder
!= null) {
942 ig
.Emit (OpCodes
.Stloc
, local_builder
);
944 ig
.Emit (OpCodes
.Ldloc
, local_builder
);
946 } else if (binding
is BuiltIn
)
948 else if (binding
is FunctionDeclaration
)
949 load_script_func (ec
, (FunctionDeclaration
) binding
);
951 //Console.WriteLine ("class Identifier, binding = {0}, method Emit, DID NOT EMIT ANYTHING, binding.GetType = {1}", binding, binding.GetType ());
953 if (!assign
&& no_effect
)
954 ig
.Emit (OpCodes
.Pop
);
957 void load_script_func (EmitContext ec
, FunctionDeclaration binding
)
959 ILGenerator ig
= ec
.ig
;
960 TypeBuilder type
= ec
.type_builder
;
961 FieldInfo method
= type
.GetField (binding
.func_obj
.name
);
963 ig
.Emit (OpCodes
.Ldsfld
, method
);
965 throw new Exception ("method " + binding
.func_obj
.name
+ " not found");
968 internal FieldInfo
extract_field_info (AST a
)
972 if (a
is VariableDeclaration
)
973 r
= ((VariableDeclaration
) a
).field_info
;
975 r
= ((Try
) a
).field_info
;
979 internal LocalBuilder
extract_local_builder (AST a
)
981 LocalBuilder r
= null;
982 if (a
is VariableDeclaration
)
983 r
= ((VariableDeclaration
) a
).local_builder
;
985 r
= ((Try
) a
).local_builder
;
990 public class Args
: AST
{
992 internal ArrayList elems
;
993 int num_of_args
= -1;
994 internal bool is_print
;
998 elems
= new ArrayList ();
1001 internal void Add (AST e
)
1006 internal int DesiredNumOfArgs
{
1009 num_of_args
= value;
1013 internal bool IsPrint
{
1014 set { is_print = value; }
1017 internal override bool Resolve (IdentificationTable context
)
1019 int i
, n
= elems
.Count
;
1023 if (!is_print
&& num_of_args
>= 0 && n
> num_of_args
)
1024 Console
.WriteLine ("warning JS1148: There are too many arguments. The extra arguments will be ignored");
1025 for (i
= 0; i
< n
; i
++) {
1026 tmp
= (AST
) elems
[i
];
1027 r
&= tmp
.Resolve (context
);
1032 internal AST
get_element (int i
)
1034 if (i
>= 0 && i
< elems
.Count
)
1035 return (AST
) elems
[i
];
1041 get { return elems.Count; }
1044 internal override void Emit (EmitContext ec
)
1046 int i
= 0, n
= elems
.Count
;
1050 ast
= get_element (i
);
1054 } while (i
< n
|| i
< num_of_args
);
1056 if (num_of_args
> n
) {
1057 ILGenerator ig
= ec
.ig
;
1058 for (int j
= 0; j
< num_of_args
- 1; j
++)
1059 ig
.Emit (OpCodes
.Ldsfld
, typeof (Missing
).GetField ("Value"));;
1064 public class Expression
: Exp
{
1066 internal ArrayList exprs
;
1068 internal Expression (AST parent
)
1070 this.parent
= parent
;
1071 exprs
= new ArrayList ();
1074 internal void Add (AST a
)
1079 public override string ToString ()
1081 int size
= exprs
.Count
;
1085 StringBuilder sb
= new StringBuilder ();
1087 for (i
= 0; i
< size
; i
++)
1088 sb
.Append (exprs
[i
].ToString ());
1091 return sb
.ToString ();
1093 } else return String
.Empty
;
1096 internal override bool Resolve (IdentificationTable context
)
1102 n
= exprs
.Count
- 1;
1104 for (i
= 0; i
< n
; i
++) {
1107 r
&= ((Exp
) e
).Resolve (context
, true);
1109 r
&= ((AST
) e
).Resolve (context
);
1114 r
&= ((Assign
) e
).Resolve (context
);
1116 r
&= ((Exp
) e
).Resolve (context
, no_effect
);
1118 ((AST
) e
).Resolve (context
);
1123 internal override bool Resolve (IdentificationTable context
, bool no_effect
)
1125 this.no_effect
= no_effect
;
1126 return Resolve (context
);
1129 internal override void Emit (EmitContext ec
)
1131 int i
, n
= exprs
.Count
;
1134 for (i
= 0; i
< n
; i
++) {
1135 exp
= (AST
) exprs
[i
];
1141 internal class Assign
: BinaryOp
{
1143 internal bool is_embedded
;
1145 internal Assign (AST parent
, AST left
, AST right
, JSToken op
, bool is_embedded
)
1146 : base (left
, right
, op
)
1148 this.parent
= parent
;
1149 this.is_embedded
= is_embedded
;
1153 // after calling Resolve, left contains all the
1154 // information about the assignment
1156 internal override bool Resolve (IdentificationTable context
)
1160 if (left
is IAssignable
)
1161 r
= ((IAssignable
) left
).ResolveAssign (context
, right
);
1163 throw new Exception ("(" + line_number
+ ",0): error JS5008: Illegal assignment");
1165 r
&=((Exp
) right
).Resolve (context
, false);
1167 r
&= right
.Resolve (context
);
1171 internal override bool Resolve (IdentificationTable context
, bool no_effect
)
1176 internal override void Emit (EmitContext ec
)
1178 ILGenerator ig
= ec
.ig
;
1181 Console
.WriteLine ("embedded assignments not supported yet");
1182 Environment
.Exit (-1);
1187 public override string ToString ()
1189 string l
= left
.ToString ();
1190 string r
= right
.ToString ();
1191 return l
+ " = " + r
;
1195 internal class New
: AST
, ICallable
{
1200 internal New (AST parent
, AST exp
)
1202 this.parent
= parent
;
1204 this.args
= new Args ();
1207 public void AddArg (AST arg
)
1212 internal override bool Resolve (IdentificationTable context
)
1216 r
&= exp
.Resolve (context
);
1218 r
&= args
.Resolve (context
);
1222 internal override void Emit (EmitContext ec
)
1230 void emit_args (EmitContext ec
)
1232 ILGenerator ig
= ec
.ig
;
1234 ig
.Emit (OpCodes
.Ldc_I4
, args
.Size
);
1235 ig
.Emit (OpCodes
.Newarr
, typeof (object));
1237 for (int i
= 0; i
< n
; i
++) {
1238 ig
.Emit (OpCodes
.Dup
);
1239 ig
.Emit (OpCodes
.Ldc_I4
, i
);
1240 args
.get_element (i
).Emit (ec
);
1241 ig
.Emit (OpCodes
.Stelem_Ref
);
1244 ig
.Emit (OpCodes
.Call
, typeof (ArrayConstructor
).GetMethod ("CreateInstance"));
1248 internal interface IAssignable
{
1249 bool ResolveAssign (IdentificationTable context
, AST right_side
);
1252 internal class BuiltIn
: AST
{
1254 bool allowed_as_const
;
1255 bool allowed_as_func
;
1257 internal BuiltIn (string name
, bool allowed_as_const
, bool allowed_as_func
)
1260 this.allowed_as_const
= allowed_as_const
;
1261 this.allowed_as_func
= allowed_as_func
;
1264 internal override bool Resolve (IdentificationTable context
)
1269 internal string Name
{
1270 get { return name; }
1273 internal bool IsConstructor
{
1274 get { return allowed_as_const; }
1277 internal bool IsFunction
{
1278 get { return allowed_as_func; }
1281 internal int NumOfArgs
{
1283 Type global_object
= typeof (GlobalObject
);
1284 MethodInfo method
= global_object
.GetMethod (name
);
1285 return method
.GetParameters ().Length
;
1289 internal override void Emit (EmitContext ec
)
1291 ILGenerator ig
= ec
.ig
;
1292 Type go
= typeof (GlobalObject
);
1294 /* value properties of the Global Object */
1296 ig
.Emit (OpCodes
.Ldc_R8
, Double
.NaN
);
1297 ig
.Emit (OpCodes
.Box
, typeof (Double
));
1300 ig
.Emit (OpCodes
.Ldc_R8
, Double
.PositiveInfinity
);
1301 // FIXME: research when not to generate the Boxing
1302 ig
.Emit (OpCodes
.Box
, typeof (Double
));
1305 ig
.Emit (OpCodes
.Ldnull
);
1307 /* function properties of the Global Object */
1309 throw new NotImplementedException ();
1312 ig
.Emit (OpCodes
.Call
, go
.GetMethod ("parseInt"));
1313 ig
.Emit (OpCodes
.Box
, typeof (Double
));
1316 ig
.Emit (OpCodes
.Call
, go
.GetMethod ("parseFloat"));
1317 ig
.Emit (OpCodes
.Box
, typeof (Double
));
1320 ig
.Emit (OpCodes
.Call
, go
.GetMethod ("isNaN"));
1321 ig
.Emit (OpCodes
.Box
, typeof (bool));
1324 ig
.Emit (OpCodes
.Call
, go
.GetMethod ("isFinite"));
1325 ig
.Emit (OpCodes
.Box
, typeof (bool));
1328 ig
.Emit (OpCodes
.Call
, go
.GetMethod ("decodeURI"));
1330 case "decodeURIComponent":
1331 ig
.Emit (OpCodes
.Call
, go
.GetMethod ("decodeURIComponent"));
1334 ig
.Emit (OpCodes
.Call
, go
.GetMethod ("encodeURI"));
1336 case "encodeURIComponent":
1337 ig
.Emit (OpCodes
.Call
, go
.GetMethod ("encodeURIComponent"));
1339 /* constructor properties of the Global object */
1341 ig
.Emit (OpCodes
.Call
, go
.GetProperty ("Object").GetGetMethod ());
1344 ig
.Emit (OpCodes
.Call
, go
.GetProperty ("Function").GetGetMethod ());
1347 ig
.Emit (OpCodes
.Call
, go
.GetProperty ("Array").GetGetMethod ());
1350 ig
.Emit (OpCodes
.Call
, go
.GetProperty ("String").GetGetMethod ());
1353 ig
.Emit (OpCodes
.Call
, go
.GetProperty ("Boolean").GetGetMethod ());
1356 ig
.Emit (OpCodes
.Call
, go
.GetProperty ("Number").GetGetMethod ());
1359 ig
.Emit (OpCodes
.Call
, go
.GetProperty ("Date").GetGetMethod ());
1360 throw new NotImplementedException ();
1363 ig
.Emit (OpCodes
.Call
, go
.GetProperty ("RegExp").GetGetMethod ());
1366 ig
.Emit (OpCodes
.Call
, go
.GetProperty ("Error").GetGetMethod ());
1369 ig
.Emit (OpCodes
.Call
, go
.GetProperty ("EvalError").GetGetMethod ());
1372 ig
.Emit (OpCodes
.Call
, go
.GetProperty ("RangeError").GetGetMethod ());
1375 case "ReferenceError":
1376 ig
.Emit (OpCodes
.Call
, go
.GetProperty ("ReferenceError").GetGetMethod ());
1380 ig
.Emit (OpCodes
.Call
, go
.GetProperty ("SyntaxError").GetGetMethod ());
1384 ig
.Emit (OpCodes
.Call
, go
.GetProperty ("TypeError").GetGetMethod ());
1388 ig
.Emit (OpCodes
.Call
, go
.GetProperty ("URIError").GetGetMethod ());
1390 /* other properties of the Global object */
1392 ig
.Emit (OpCodes
.Call
, go
.GetProperty ("Math").GetGetMethod ());
1395 throw new Exception ("This is BuiltIn " + name
);