**** Merged from MCS ****
[mono-project.git] / mcs / class / Microsoft.JScript / Microsoft.JScript / expression.cs
blob25e46b25b556e222c05349ab45044405ce7b1b3c
1 //
2 // Expression.cs: Everything related to expressions
3 //
4 // Author:
5 // Cesar Lopez Nataren (cesar@ciencias.unam.mx)
6 //
7 // (C) 2003, 2004 Cesar Lopez Nataren
8 //
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:
18 //
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 //
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.
31 using System;
32 using System.Text;
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)
49 this.parent = parent;
50 this.oper = oper;
53 public override string ToString ()
55 StringBuilder sb = new StringBuilder ();
57 if (oper != JSToken.None)
58 sb.Append (oper + " ");
60 if (operand != null)
61 sb.Append (operand.ToString ());
63 return sb.ToString ();
66 internal override bool Resolve (IdentificationTable context)
68 bool r = false;
70 if (operand is Exp)
71 if (oper != JSToken.Increment && oper != JSToken.Decrement)
72 r = ((Exp) operand).Resolve (context, no_effect);
73 r = ((AST) operand).Resolve (context);
74 return r;
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)
85 if (operand != null)
86 operand.Emit (ec);
87 if (oper != JSToken.Minus)
88 emit_unary_op (ec);
91 internal void emit_unary_op (EmitContext ec)
93 ILGenerator ig = ec.ig;
94 switch (oper) {
95 case JSToken.Typeof:
96 ig.Emit (OpCodes.Call, typeof (Typeof).GetMethod ("JScriptTypeof"));
97 break;
102 internal class Binary : BinaryOp, IAssignable {
104 bool assign;
105 AST right_side;
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 + " ");
126 if (right != null)
127 sb.Append (right.ToString ());
129 return sb.ToString ();
132 internal override bool Resolve (IdentificationTable context)
134 bool r = true;
135 if (left != null)
136 r &= left.Resolve (context);
137 if (right != null)
138 if (op == JSToken.AccessField && right is IAccesible)
139 r &= ((IAccesible) right).ResolveFieldAccess (left);
140 else
141 r &= right.Resolve (context);
142 return r;
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;
155 this.assign = true;
156 this.right_side = right_side;
157 return Resolve (context);
158 } else
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) {
166 if (left != null)
167 left.Emit (ec);
168 } else if (op == JSToken.LogicalAnd || op == JSToken.LogicalOr)
169 emit_jumping_code (ec);
170 else if (op == JSToken.LeftBracket) {
171 if (!assign)
172 get_default_this (ig);
173 if (left != null)
174 left.Emit (ec);
175 emit_access (ec);
176 } else if (op == JSToken.AccessField) {
177 if (left is Identifier) {
178 Identifier parent = left as Identifier;
179 switch (parent.name) {
180 case "Math":
181 MathObject math_obj = new MathObject ();
182 Type math_obj_type = math_obj.GetType ();
183 Identifier property = right as Identifier;
184 double v = 0;
185 switch (property.name) {
186 /* value properties of the math object */
187 case "E":
188 v = math_obj.E;
189 break;
190 case "LN10":
191 v = math_obj.LN10;
192 break;
193 case "LN2":
194 v = math_obj.LN2;
195 break;
196 case "LOG2E":
197 v = math_obj.LOG2E;
198 break;
199 case "LOG10E":
200 v = math_obj.LOG10E;
201 break;
202 case "PI":
203 v = math_obj.PI;
204 break;
205 case "SQRT1_2":
206 v = math_obj.SQRT1_2;
207 break;
208 case "SQRT2":
209 v = math_obj.SQRT2;
210 break;
212 /* function properties of the math object */
213 case "abs":
214 case "acos":
215 case "asin":
216 case "atan":
217 case "atan2":
218 case "sin":
219 case "cos":
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));
223 return;
225 ig.Emit (OpCodes.Ldc_R8, v);
226 ig.Emit (OpCodes.Box, typeof (Double));
227 break;
228 default:
229 if (right is Identifier)
230 emit_late_binding (ec);
231 break;
234 } else {
235 emit_operator (ig);
236 if (left != null)
237 left.Emit (ec);
238 if (right != null)
239 right.Emit (ec);
240 emit_op_eval (ig);
242 if (no_effect)
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);
264 return 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);
274 left.Emit (ec);
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"));
284 if (assign) {
285 right_side.Emit (ec);
286 ig.Emit (OpCodes.Call, lb_type.GetMethod ("SetValue"));
287 } else
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"));
296 } else
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);
312 if (right != null)
313 right.Emit (ec);
314 ig.Emit (OpCodes.Stelem_Ref);
316 if (assign) {
317 if (right_side != null)
318 right_side.Emit (ec);
319 ig.Emit (OpCodes.Call, typeof (LateBinding).GetMethod ("SetIndexedPropertyValueStatic"));
320 } else {
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"));
327 } else
328 ig.Emit (OpCodes.Ldarg_1);
329 ig.Emit (OpCodes.Call, typeof (LateBinding).GetMethod ("CallValue"));
333 internal void emit_op_eval (ILGenerator ig)
335 switch (op) {
336 case JSToken.Plus:
337 ig.Emit (OpCodes.Callvirt, typeof (Plus).GetMethod ("EvaluatePlus"));
338 break;
339 case JSToken.Minus:
340 case JSToken.Divide:
341 case JSToken.Modulo:
342 case JSToken.Multiply:
343 ig.Emit (OpCodes.Call, typeof (NumericBinary).GetMethod ("EvaluateNumericBinary"));
344 break;
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"));
352 break;
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;
375 Type t = null;
377 if (op == JSToken.Plus) {
378 t = typeof (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);
383 return;
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)
458 bool r = true;
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);
465 return r;
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)
481 true_exp.Emit (ec);
482 ig.Emit (OpCodes.Br, merge_label);
483 ig.MarkLabel (false_label);
484 if (false_exp != null)
485 false_exp.Emit (ec);
486 ig.MarkLabel (merge_label);
487 if (no_effect)
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;
499 internal Args args;
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 () + " ");
513 if (args != null)
514 sb.Append (args.ToString ());
515 return sb.ToString ();
518 public void AddArg (AST arg)
520 args.Add (arg);
523 internal override bool Resolve (IdentificationTable context)
525 bool r = true;
526 int n = -1;
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);
537 if (args != null) {
538 args.DesiredNumOfArgs = n;
539 if (member_exp.ToString () == "print")
540 args.IsPrint = true;
541 r &= args.Resolve (context);
543 return r;
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") {
556 AST ast;
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"));
562 return;
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);
572 ast.Emit (ec);
574 if (ast is StringLiteral)
576 else {
577 ig.Emit (OpCodes.Ldc_I4_1);
578 ig.Emit (OpCodes.Call, to_string);
581 if (i == n)
582 ig.Emit (OpCodes.Call, writeline);
583 else
584 ig.Emit (OpCodes.Call, write);
586 } else {
587 object binding = SemanticAnalyser.ObjectSystemContains (member_exp.ToString ());
589 if (binding == null)
590 binding = TypeManager.GetMethod (member_exp.ToString ());
592 if (binding == null) {
593 emit_late_call (ec);
594 return;
597 if (IsGlobalObjectMethod (binding)) {
598 args.Emit (ec);
599 member_exp.Emit (ec);
600 } else if (IsConstructorProperty (binding)) {
601 member_exp.Emit (ec);
602 EmitBuiltInArgs (ec);
603 EmitInvoke (ec);
604 } else if (binding is MethodBuilder) {
605 emit_func_call ((MethodBuilder) binding, ec);
606 return;
609 if (no_effect)
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"));
632 } else {
633 bin.left.Emit (ec);
634 member_exp.Emit (ec);
635 setup_late_call_args (ec);
636 ig.Emit (OpCodes.Call, typeof (LateBinding).GetMethod ("CallValue"));
638 } else {
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"));
643 if (no_effect)
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"));
653 } else
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;
675 left.Emit (ec);
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;
689 int n = args.Size;
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);
704 if (InFunction)
705 ig.Emit (OpCodes.Ldarg_1);
706 else {
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);
725 args.Emit (ec);
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;
741 int n = args.Size;
743 if (n >= 1 && (member_exp.ToString () == "String" || member_exp.ToString () == "Boolean" || member_exp.ToString () == "Number")) {
744 args.get_element (0).Emit (ec);
745 return;
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 ();
762 Type type = null;
763 bool boolean = false;
764 bool number = false;
766 switch (name) {
767 case "Object":
768 type = typeof (ObjectConstructor);
769 break;
770 case "Function":
771 type = typeof (FunctionConstructor);
772 break;
773 case "Array":
774 type = typeof (ArrayConstructor);
775 break;
776 case "String":
777 type = typeof (StringConstructor);
778 break;
779 case "Boolean":
780 type = typeof (BooleanConstructor);
781 boolean = true;
782 break;
783 case "Number":
784 type = typeof (NumberConstructor);
785 number = true;
786 break;
787 case "Date":
788 type = typeof (DateConstructor);
789 break;
790 case "RegExp":
791 type = typeof (RegExpConstructor);
792 break;
793 case "Error":
794 case "EvalError":
795 case "RangeError":
796 case "ReferenceError":
797 case "SyntaxError":
798 case "TypeError":
799 case "URIError":
800 type = typeof (ErrorConstructor);
801 break;
803 ig.Emit (OpCodes.Call, type.GetMethod ("Invoke"));
804 if (boolean)
805 ig.Emit (OpCodes.Box, typeof (Boolean));
806 if (number)
807 ig.Emit (OpCodes.Box, typeof (Double));
810 bool IsConstructorProperty (object binding)
812 if (!(binding is BuiltIn))
813 return false;
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))
823 return false;
825 BuiltIn bind = binding as BuiltIn;
826 switch (bind.Name) {
827 case "eval":
828 case "parseInt":
829 case "parseFloat":
830 case "isNaN":
831 case "isFinite":
832 case "decodeURI":
833 case "decodeURIComponent":
834 case "encodeURI":
835 case "encodeURIComponent":
836 return true;
837 default:
838 return false;
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;
852 AST right_side;
853 MemberInfo [] members = null;
855 internal Identifier (AST parent, string id)
857 this.parent = parent;
858 this.name = id;
861 public override string ToString ()
863 return name;
866 internal override bool Resolve (IdentificationTable context)
868 if (name == "print")
869 return SemanticAnalyser.print;
870 object bind = context.Contains (name);
871 if (bind == null)
872 bind = SemanticAnalyser.ObjectSystemContains (name);
873 if (bind == null)
874 throw new Exception ("variable not found: " + name);
875 binding = bind as AST;
876 return true;
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)
887 this.assign = true;
888 this.no_effect = false;
889 this.right_side = right_side;
890 if (name != String.Empty)
891 return Resolve (context);
892 return true;
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);
904 return true;
907 bool IsBuiltInObjectProperty (string obj_name, string prop_name)
909 Type type;
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)
916 return true;
917 else
918 throw new Exception ("error: JS0438: Object doesn't support this property or method");
920 return false;
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) {
936 if (assign)
937 ig.Emit (OpCodes.Stsfld, field_info);
938 else
939 ig.Emit (OpCodes.Ldsfld, field_info);
940 } else if (local_builder != null) {
941 if (assign)
942 ig.Emit (OpCodes.Stloc, local_builder);
943 else
944 ig.Emit (OpCodes.Ldloc, local_builder);
946 } else if (binding is BuiltIn)
947 binding.Emit (ec);
948 else if (binding is FunctionDeclaration)
949 load_script_func (ec, (FunctionDeclaration) binding);
950 else
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);
962 if (method != null)
963 ig.Emit (OpCodes.Ldsfld, method);
964 else
965 throw new Exception ("method " + binding.func_obj.name + " not found");
968 internal FieldInfo extract_field_info (AST a)
970 FieldInfo r = null;
972 if (a is VariableDeclaration)
973 r = ((VariableDeclaration) a).field_info;
974 else if (a is Try)
975 r = ((Try) a).field_info;
976 return r;
979 internal LocalBuilder extract_local_builder (AST a)
981 LocalBuilder r = null;
982 if (a is VariableDeclaration)
983 r = ((VariableDeclaration) a).local_builder;
984 else if (a is Try)
985 r = ((Try) a).local_builder;
986 return r;
990 public class Args : AST {
992 internal ArrayList elems;
993 int num_of_args = -1;
994 internal bool is_print;
996 internal Args ()
998 elems = new ArrayList ();
1001 internal void Add (AST e)
1003 elems.Add (e);
1006 internal int DesiredNumOfArgs {
1007 set {
1008 if (!(value < 0))
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;
1020 AST tmp;
1021 bool r = true;
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);
1029 return r;
1032 internal AST get_element (int i)
1034 if (i >= 0 && i < elems.Count)
1035 return (AST) elems [i];
1036 else
1037 return null;
1040 internal int Size {
1041 get { return elems.Count; }
1044 internal override void Emit (EmitContext ec)
1046 int i = 0, n = elems.Count;
1047 AST ast;
1049 do {
1050 ast = get_element (i);
1051 if (ast != null)
1052 ast.Emit (ec);
1053 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)
1076 exprs.Add (a);
1079 public override string ToString ()
1081 int size = exprs.Count;
1083 if (size > 0) {
1084 int i;
1085 StringBuilder sb = new StringBuilder ();
1087 for (i = 0; i < size; i++)
1088 sb.Append (exprs [i].ToString ());
1090 sb.Append ("\n");
1091 return sb.ToString ();
1093 } else return String.Empty;
1096 internal override bool Resolve (IdentificationTable context)
1098 int i, n;
1099 object e;
1100 bool r = true;
1102 n = exprs.Count - 1;
1104 for (i = 0; i < n; i++) {
1105 e = exprs [i];
1106 if (e is Exp)
1107 r &= ((Exp) e).Resolve (context, true);
1108 else
1109 r &= ((AST) e).Resolve (context);
1111 e = exprs [n];
1112 if (e is Exp)
1113 if (e is Assign)
1114 r &= ((Assign) e).Resolve (context);
1115 else
1116 r &= ((Exp) e).Resolve (context, no_effect);
1117 else
1118 ((AST) e).Resolve (context);
1120 return r;
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;
1132 AST exp;
1134 for (i = 0; i < n; i++) {
1135 exp = (AST) exprs [i];
1136 exp.Emit (ec);
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)
1158 bool r;
1160 if (left is IAssignable)
1161 r = ((IAssignable) left).ResolveAssign (context, right);
1162 else
1163 throw new Exception ("(" + line_number + ",0): error JS5008: Illegal assignment");
1164 if (right is Exp)
1165 r &=((Exp) right).Resolve (context, false);
1166 else
1167 r &= right.Resolve (context);
1168 return r;
1171 internal override bool Resolve (IdentificationTable context, bool no_effect)
1173 return true;
1176 internal override void Emit (EmitContext ec)
1178 ILGenerator ig = ec.ig;
1180 if (is_embedded) {
1181 Console.WriteLine ("embedded assignments not supported yet");
1182 Environment.Exit (-1);
1184 left.Emit (ec);
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 {
1197 AST exp;
1198 Args args;
1200 internal New (AST parent, AST exp)
1202 this.parent = parent;
1203 this.exp = exp;
1204 this.args = new Args ();
1207 public void AddArg (AST arg)
1209 args.Add (arg);
1212 internal override bool Resolve (IdentificationTable context)
1214 bool r = true;
1215 if (exp != null)
1216 r &= exp.Resolve (context);
1217 if (args != null)
1218 r &= args.Resolve (context);
1219 return r;
1222 internal override void Emit (EmitContext ec)
1224 if (exp != null)
1225 exp.Emit (ec);
1226 if (args != null)
1227 emit_args (ec);
1230 void emit_args (EmitContext ec)
1232 ILGenerator ig = ec.ig;
1233 int n = args.Size;
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 {
1253 string name;
1254 bool allowed_as_const;
1255 bool allowed_as_func;
1257 internal BuiltIn (string name, bool allowed_as_const, bool allowed_as_func)
1259 this.name = name;
1260 this.allowed_as_const = allowed_as_const;
1261 this.allowed_as_func = allowed_as_func;
1264 internal override bool Resolve (IdentificationTable context)
1266 return true;
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 {
1282 get {
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);
1293 switch (name) {
1294 /* value properties of the Global Object */
1295 case "NaN":
1296 ig.Emit (OpCodes.Ldc_R8, Double.NaN);
1297 ig.Emit (OpCodes.Box, typeof (Double));
1298 break;
1299 case "Infinity":
1300 ig.Emit (OpCodes.Ldc_R8, Double.PositiveInfinity);
1301 // FIXME: research when not to generate the Boxing
1302 ig.Emit (OpCodes.Box, typeof (Double));
1303 break;
1304 case "undefined":
1305 ig.Emit (OpCodes.Ldnull);
1306 break;
1307 /* function properties of the Global Object */
1308 case "eval":
1309 throw new NotImplementedException ();
1310 case "parseInt":
1312 ig.Emit (OpCodes.Call, go.GetMethod ("parseInt"));
1313 ig.Emit (OpCodes.Box, typeof (Double));
1314 break;
1315 case "parseFloat":
1316 ig.Emit (OpCodes.Call, go.GetMethod ("parseFloat"));
1317 ig.Emit (OpCodes.Box, typeof (Double));
1318 break;
1319 case "isNaN":
1320 ig.Emit (OpCodes.Call, go.GetMethod ("isNaN"));
1321 ig.Emit (OpCodes.Box, typeof (bool));
1322 break;
1323 case "isFinite":
1324 ig.Emit (OpCodes.Call, go.GetMethod ("isFinite"));
1325 ig.Emit (OpCodes.Box, typeof (bool));
1326 break;
1327 case "decodeURI":
1328 ig.Emit (OpCodes.Call, go.GetMethod ("decodeURI"));
1329 break;
1330 case "decodeURIComponent":
1331 ig.Emit (OpCodes.Call, go.GetMethod ("decodeURIComponent"));
1332 break;
1333 case "encodeURI":
1334 ig.Emit (OpCodes.Call, go.GetMethod ("encodeURI"));
1335 break;
1336 case "encodeURIComponent":
1337 ig.Emit (OpCodes.Call, go.GetMethod ("encodeURIComponent"));
1338 break;
1339 /* constructor properties of the Global object */
1340 case "Object":
1341 ig.Emit (OpCodes.Call, go.GetProperty ("Object").GetGetMethod ());
1342 break;
1343 case "Function":
1344 ig.Emit (OpCodes.Call, go.GetProperty ("Function").GetGetMethod ());
1345 break;
1346 case "Array":
1347 ig.Emit (OpCodes.Call, go.GetProperty ("Array").GetGetMethod ());
1348 break;
1349 case "String":
1350 ig.Emit (OpCodes.Call, go.GetProperty ("String").GetGetMethod ());
1351 break;
1352 case "Boolean":
1353 ig.Emit (OpCodes.Call, go.GetProperty ("Boolean").GetGetMethod ());
1354 break;
1355 case "Number":
1356 ig.Emit (OpCodes.Call, go.GetProperty ("Number").GetGetMethod ());
1357 break;
1358 case "Date":
1359 ig.Emit (OpCodes.Call, go.GetProperty ("Date").GetGetMethod ());
1360 throw new NotImplementedException ();
1361 break;
1362 case "RegExp":
1363 ig.Emit (OpCodes.Call, go.GetProperty ("RegExp").GetGetMethod ());
1364 break;
1365 case "Error":
1366 ig.Emit (OpCodes.Call, go.GetProperty ("Error").GetGetMethod ());
1367 break;
1368 case "EvalError":
1369 ig.Emit (OpCodes.Call, go.GetProperty ("EvalError").GetGetMethod ());
1370 break;
1371 case "RangeError":
1372 ig.Emit (OpCodes.Call, go.GetProperty ("RangeError").GetGetMethod ());
1373 break;
1375 case "ReferenceError":
1376 ig.Emit (OpCodes.Call, go.GetProperty ("ReferenceError").GetGetMethod ());
1377 break;
1379 case "SyntaxError":
1380 ig.Emit (OpCodes.Call, go.GetProperty ("SyntaxError").GetGetMethod ());
1381 break;
1383 case "TypeError":
1384 ig.Emit (OpCodes.Call, go.GetProperty ("TypeError").GetGetMethod ());
1385 break;
1387 case "URIError":
1388 ig.Emit (OpCodes.Call, go.GetProperty ("URIError").GetGetMethod ());
1389 break;
1390 /* other properties of the Global object */
1391 case "Math":
1392 ig.Emit (OpCodes.Call, go.GetProperty ("Math").GetGetMethod ());
1393 break;
1394 default:
1395 throw new Exception ("This is BuiltIn " + name);