* roottypes.cs: Rename from tree.cs.
[mono.git] / mcs / class / Microsoft.JScript / Microsoft.JScript / CodeGenerator.cs
1 //
2 // CodeGenerator.cs
3 //
4 // Author:
5 //      Cesar Lopez Nataren (cesar@ciencias.unam.mx)
6 //
7 // (C) 2003, 2004 Cesar Lopez Nataren
8 // (C) 2005, Novell, Inc. (http://novell.com)
9 //
10
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 using System;
33 using System.IO;
34 using System.Reflection;
35 using System.Reflection.Emit;
36 using System.Threading;
37 using Microsoft.JScript.Vsa;
38 using System.Collections;
39
40 namespace Microsoft.JScript {
41
42         internal class EmitContext {
43
44                 internal TypeBuilder type_builder;
45                 internal ILGenerator ig;
46                 internal ModuleBuilder mod_builder;
47                 internal MethodBuilder global_code;
48
49                 internal Label LoopBegin, LoopEnd;
50
51                 internal EmitContext (TypeBuilder type_builder, ModuleBuilder mod_builder, ILGenerator ig)
52                 {
53                         this.type_builder = type_builder;
54                         this.mod_builder = mod_builder;
55                         this.ig = ig;
56                 }
57         }
58
59         internal class CodeGenerator {
60
61                 private static string MODULE = "JScript Module";
62                 private static string CORLIB = typeof (object).Assembly.FullName;
63
64                 internal static string mod_name;
65                 internal static AppDomain app_domain;
66                 internal static AssemblyName assembly_name;
67                 internal static AssemblyBuilder assembly_builder;
68                 internal static ModuleBuilder module_builder;
69                 private static int next_type = 0;
70                 private static ArrayList global_types = new ArrayList ();
71                 private static Hashtable global_methods = new Hashtable ();
72                 private static Hashtable source_file_to_type = new Hashtable ();
73
74                 private static string NextType {
75                         get { return "JScript " + next_type++; }
76                 }
77
78                 internal static string Basename (string name)
79                 {
80                         int pos = name.LastIndexOf ('/');
81
82                         if (pos != -1)
83                                 return name.Substring (pos + 1);
84
85                         pos = name.LastIndexOf ('\\');
86                         if (pos != -1)
87                                 return name.Substring (pos + 1);
88
89                         return name;
90                 }
91
92                 internal static string Dirname (string name)
93                 {
94                         int pos = name.LastIndexOf ('/');
95
96                         if (pos != -1)
97                                 return name.Substring (0, pos);
98
99                         pos = name.LastIndexOf ('\\');
100                         if (pos != -1)
101                                 return name.Substring (0, pos);
102
103                         return ".";
104                 }
105
106                 internal static void Init (string file_name)
107                 {
108                         app_domain = Thread.GetDomain ();
109
110                         assembly_name = new AssemblyName ();
111                         assembly_name.Name = Path.GetFileNameWithoutExtension (file_name);
112                         mod_name = MODULE;
113
114                         assembly_builder = app_domain.DefineDynamicAssembly (
115                                              assembly_name,
116                                              AssemblyBuilderAccess.RunAndSave,
117                                              Dirname (file_name));
118
119                         ConstructorInfo ctr_info = typeof (Microsoft.JScript.ReferenceAttribute).GetConstructor (new Type [] { typeof (string) });
120                         assembly_builder.SetCustomAttribute (new CustomAttributeBuilder (ctr_info, new object [] {CORLIB}));
121
122                         module_builder = assembly_builder.DefineDynamicModule (
123                                                mod_name,
124                                                Basename (assembly_name.Name + ".exe"),
125                                                false);
126                 }
127
128                 internal static string trim_extension (string file_name)
129                 {
130                         int index = file_name.LastIndexOf ('.');
131
132                         if (index < 0)
133                                 return file_name;
134                         else
135                                 return file_name.Substring (0, index);
136                 }
137
138                 internal static void Save (string target_name)
139                 {
140                         assembly_builder.Save (CodeGenerator.Basename (target_name));
141                 }
142
143                 internal static void EmitDecls (ScriptBlock prog)
144                 {
145                         if (prog == null)
146                                 return;
147
148                         string next_type = CodeGenerator.NextType;
149
150                         prog.InitTypeBuilder (module_builder, next_type);
151                         prog.InitGlobalCode ();
152
153                         global_types.Add (next_type);
154                         global_methods.Add (next_type, prog.GlobalCode);
155                         source_file_to_type.Add (prog.Location.SourceName, next_type);
156
157                         prog.EmitDecls (module_builder);
158                 }
159
160                 internal static void emit_jscript_main (TypeBuilder tb)
161                 {
162                         emit_jscript_main_constructor (tb);
163                         emit_jscript_main_entry_point (tb);
164                 }
165
166                 internal static void emit_jscript_main_constructor (TypeBuilder tb)
167                 {
168                         ConstructorBuilder cons = tb.DefineConstructor (MethodAttributes.Public, 
169                                                                         CallingConventions.Standard,
170                                                                         new Type [] {});
171                         ILGenerator ig = cons.GetILGenerator ();
172                         ig.Emit (OpCodes.Ldarg_0);
173                         ig.Emit (OpCodes.Call, typeof (Object).GetConstructor (new Type [] {}));
174                         ig.Emit (OpCodes.Ret);
175                 }
176
177                 internal static void emit_jscript_main_entry_point (TypeBuilder tb)
178                 {
179                         MethodBuilder method;
180                         method = tb.DefineMethod ("Main", 
181                                                   MethodAttributes.Public | MethodAttributes.Static,
182                                                   typeof (void), new Type [] {typeof (String [])});
183
184                         method.SetCustomAttribute (new CustomAttributeBuilder 
185                                                    (typeof (STAThreadAttribute).GetConstructor (
186                                                                                         new Type [] {}),
187                                                      new object [] {}));
188
189                         ILGenerator ig = method.GetILGenerator ();
190
191                         ig.DeclareLocal (typeof (GlobalScope));
192
193                         ig.Emit (OpCodes.Ldc_I4_1);
194                         ig.Emit (OpCodes.Ldc_I4_1);
195                         ig.Emit (OpCodes.Newarr, typeof (string));
196                         ig.Emit (OpCodes.Dup);
197                         ig.Emit (OpCodes.Ldc_I4_0);
198
199                         ig.Emit (OpCodes.Ldstr, CORLIB);
200
201                         ig.Emit (OpCodes.Stelem_Ref);
202
203                         ig.Emit (OpCodes.Call,
204                                  typeof (VsaEngine).GetMethod ("CreateEngineAndGetGlobalScope", 
205                                                                new Type [] {typeof (bool), 
206                                                                             typeof (string [])}));      
207                         ig.Emit (OpCodes.Stloc_0);
208
209                         foreach (string type_name in global_types) {
210                                 ig.Emit (OpCodes.Ldloc_0);
211                                 ig.Emit (OpCodes.Newobj, assembly_builder.GetType (type_name).GetConstructor (
212                                                                               new Type [] {typeof (GlobalScope)})); 
213                                 ig.Emit (OpCodes.Call, (MethodInfo) global_methods [type_name]);
214                                 ig.Emit (OpCodes.Pop);
215                         }
216                         ig.Emit (OpCodes.Ret);
217
218                         assembly_builder.SetEntryPoint (method);
219                 }
220
221                 public static void Run (string file_name, ScriptBlock [] blocks)
222                 {
223                         CodeGenerator.Init (file_name);
224
225                         //
226                         // Emit first all the declarations (function and variables)
227                         //
228                         foreach (ScriptBlock script_block in blocks)
229                                 CodeGenerator.EmitDecls (script_block);
230
231                         //
232                         // emit everything that's not a declaration
233                         //
234                         foreach (ScriptBlock script_block in blocks)
235                                 script_block.Emit ();
236
237                         //
238                         // Create the types ('JScript N')
239                         //
240                         foreach (ScriptBlock script_block in blocks)
241                                 script_block.CreateType ();
242                         
243                         //
244                         // Build the default 'JScript Main' class
245                         //
246                         TypeBuilder main_type_builder = module_builder.DefineType ("JScript Main");
247                         emit_jscript_main (main_type_builder);
248                         main_type_builder.CreateType ();
249
250                         CodeGenerator.Save (trim_extension (file_name) + ".exe");
251                 }
252
253                 static void emit_default_case (EmitContext ec, AST ast, OpCode op, Label lbl)
254                 {
255                         ast.Emit (ec);
256                         if (need_convert_to_boolean (ast))
257                                 emit_to_boolean (ast, ec.ig, 0);
258                         ec.ig.Emit (op, lbl);
259                 }
260
261                 static void ft_binary_recursion (EmitContext ec, AST ast, Label lbl)
262                 {
263                         ILGenerator ig = ec.ig;
264                         if (ast is Binary) {
265                                 Binary b = ast as Binary;
266                                 switch (b.op) {
267                                 case JSToken.LogicalOr:
268                                         Label ftLb = ig.DefineLabel ();
269                                         fall_false (ec, b.left, ftLb);
270                                         fall_true (ec, b.right, lbl);
271                                         ig.MarkLabel (ftLb);
272                                         break;
273                                 case JSToken.LogicalAnd:
274                                         fall_true (ec, b.left, lbl);
275                                         fall_true (ec, b.right, lbl);
276                                         break;
277
278                                 case JSToken.LessThan:
279                                         ig.Emit (OpCodes.Ldc_I4_0);
280                                         ig.Emit (OpCodes.Conv_R8);
281                                         ig.Emit (OpCodes.Blt, lbl);
282                                         break;
283
284                                 default:
285                                         ast.Emit (ec);
286                                         ig.Emit (OpCodes.Ldc_I4_1);
287                                         ig.Emit (OpCodes.Call, typeof (Convert).GetMethod ("ToBoolean", new Type [] {typeof (object), typeof (bool)}));
288                                         ig.Emit (OpCodes.Brfalse, lbl);
289                                         break;
290                                 }
291                         }
292                 }
293
294                 static void ft_emit_equality (EmitContext ec, AST ast, Label lbl)
295                 {
296                         ILGenerator ig = ec.ig;
297                         BinaryOp eq = null;
298
299                         if (ast is Equality)
300                                 eq = (Equality) ast;
301                         else if (ast is StrictEquality)
302                                 eq = (StrictEquality) ast;
303
304                         eq.Emit (ec);
305                         switch (eq.op) {
306                         case JSToken.NotEqual:
307                         case JSToken.StrictNotEqual:
308                                 ig.Emit (OpCodes.Brtrue, lbl);
309                                 break;
310                         case JSToken.Equal:
311                         case JSToken.StrictEqual:
312                                 ig.Emit (OpCodes.Brfalse, lbl);
313                                 break;
314                         }
315                 }
316
317                 internal static void fall_true (EmitContext ec, AST ast, Label lbl)
318                 {
319                         Type type = ast.GetType ();
320
321                         if (type == typeof (Expression)) {
322                                 Expression exp = ast as Expression;
323                                 AST last_exp = (AST) exp.exprs [exp.exprs.Count - 1];
324                                 if (exp.exprs.Count >= 2)
325                                         exp.Emit (ec);
326                                 fall_true (ec, last_exp, lbl);
327                         } else if (type == typeof (Binary))
328                                 ft_binary_recursion (ec, ast, lbl);
329                         else if (type == typeof (Equality) || type == typeof (StrictEquality))
330                                 ft_emit_equality (ec, ast, lbl);
331                         else if (type == typeof (Relational))
332                                 ft_emit_relational (ec, (Relational) ast, lbl);
333                         else
334                                 emit_default_case (ec, ast, OpCodes.Brfalse, lbl);
335                 }
336
337                 static void ff_emit_relational (EmitContext ec, AST ast, Label lbl)
338                 {
339                         ILGenerator ig = ec.ig;
340                         Relational r = ast as Relational;
341                         r.Emit (ec);
342
343                         OpCode opcode;
344
345                         switch (r.op) {
346                         case JSToken.LessThan:
347                                 opcode = OpCodes.Blt;
348                                 break;
349
350                         case JSToken.GreaterThan:
351                                 opcode = OpCodes.Bgt;
352                                 break;
353
354                         case JSToken.LessThanEqual:
355                                 opcode = OpCodes.Ble;
356                                 break;
357
358                         case JSToken.GreaterThanEqual:
359                                 opcode = OpCodes.Bge;
360                                 break;
361
362                         default:
363                                 throw new Exception ("unexpected token");
364                         }
365
366                         ig.Emit (OpCodes.Ldc_I4_0);
367                         ig.Emit (OpCodes.Conv_R8);
368                         ig.Emit (opcode, lbl);
369                 }
370
371                 static void ft_emit_relational (EmitContext ec, Relational re, Label lbl)
372                 {
373                         ILGenerator ig = ec.ig;
374
375                         re.Emit (ec);
376                         JSToken op = re.op;
377                         
378                         OpCode opcode;
379
380                         switch (op) {
381                         case JSToken.LessThan:
382                                 opcode = OpCodes.Bge_Un;
383                                 break;
384
385                         case JSToken.GreaterThan:
386                                 opcode = OpCodes.Ble_Un;
387                                 break;
388
389                         case JSToken.LessThanEqual:
390                                 opcode = OpCodes.Bgt_Un;
391                                 break;
392
393                         case JSToken.GreaterThanEqual:
394                                 opcode = OpCodes.Blt_Un;
395                                 break;
396
397                         default:
398                                 Console.WriteLine (re.Location.LineNumber);
399                                 throw new NotImplementedException ();
400                         }
401
402                         ig.Emit (OpCodes.Ldc_I4_0);
403                         ig.Emit (OpCodes.Conv_R8);
404                         ig.Emit (opcode, lbl);
405                 }
406
407                 static void ff_binary_recursion (EmitContext ec, AST ast, Label lbl)
408                 {
409                         ILGenerator ig = ec.ig;
410                         Binary b = ast as Binary;
411
412                         switch (b.op) {
413                         case JSToken.LogicalOr:
414                                 fall_false (ec, b.left, lbl);
415                                 fall_false (ec, b.right, lbl);
416                                 break;
417
418                         case JSToken.LogicalAnd:
419                                 Label ftLb = ig.DefineLabel ();
420                                 fall_true (ec, b.left, ftLb);
421                                 fall_false (ec, b.right, lbl);
422                                 ig.MarkLabel (ftLb);
423                                 break;
424                         }
425                 }
426
427                 static void ff_emit_equality_cond (EmitContext ec, AST ast, Label lbl)
428                 {
429                         ILGenerator ig = ec.ig;
430                         Equality eq = ast as Equality;
431                         eq.Emit (ec);
432
433                         switch (eq.op) {
434                         case JSToken.NotEqual:
435                         case JSToken.Equal:
436                                 ig.Emit (OpCodes.Brfalse, lbl);
437                                 break;
438                         }
439                 }
440                         
441                 internal static void fall_false (EmitContext ec, AST ast, Label lbl)
442                 {
443                         Type type = ast.GetType ();
444
445                         if (type == typeof (Expression)) {  
446                                 Expression exp = ast as Expression;
447
448                                 if (exp.Size > 1)
449                                         exp.Emit (ec);
450
451                                 AST last_exp = (AST) exp.exprs [exp.exprs.Count - 1];
452
453                                 if (last_exp is Relational)
454                                         ff_emit_relational (ec, last_exp, lbl);
455                                 else if (last_exp is Binary)
456                                         ff_binary_recursion (ec, last_exp, lbl);
457                                 else if (last_exp is Identifier || last_exp is BooleanConstant)
458                                         emit_default_case (ec, last_exp, OpCodes.Brtrue, lbl);
459                                 else if (last_exp is Equality) 
460                                         ff_emit_equality_cond (ec, last_exp, lbl);
461                                 else {
462                                         Console.WriteLine ("WARNING: fall_false, last_exp.GetType () == {0}, {1}", last_exp, ast.Location.LineNumber);
463                                 }
464                         } else if (type == typeof (Binary))
465                                 ff_binary_recursion (ec, ast, lbl);
466                         else if (type == typeof (Relational))
467                                 ff_emit_relational (ec, ast, lbl);
468                         else 
469                                 emit_default_case (ec, ast, OpCodes.Brtrue, lbl);
470                 }
471
472                 internal static void emit_to_boolean (AST ast, ILGenerator ig, int i)
473                 {
474                         ig.Emit (OpCodes.Ldc_I4, i);
475                         ig.Emit (OpCodes.Call, typeof (Convert).GetMethod ("ToBoolean", 
476                                                                            new Type [] { typeof (object), typeof (Boolean)}));
477                 }
478
479                 internal static bool need_convert_to_boolean (AST ast)
480                 {
481                         if (ast == null)
482                                 return false;
483
484                         if (ast is Identifier)
485                                 return true;
486                         else if (ast is Expression) {
487                                 Expression exp = ast as Expression;
488                                 int n = exp.exprs.Count - 1;
489                                 AST tmp = (AST) exp.exprs [n];
490                                 if (tmp is Equality || tmp is Relational || tmp is BooleanConstant)
491                                         return false;
492                                 else
493                                         return true;
494                         } else
495                                 return false;
496                 }
497                 
498                 //
499                 // Loads a current VsaEngine
500                 //
501                 internal static void load_engine (bool in_function, ILGenerator ig)
502                 {
503                         //
504                         // If we are in a function declaration at global level,
505                         // we must load the engine associated to the current 'JScript N' instance,
506                         // otherwise pick up the engine at second place in method's signature.
507                         //
508                         if (in_function)
509                                 ig.Emit (OpCodes.Ldarg_1);
510                         else {
511                                 ig.Emit (OpCodes.Ldarg_0);
512                                 ig.Emit (OpCodes.Ldfld, typeof (ScriptObject).GetField ("engine"));
513                         }
514                 }
515                 
516                 internal static void emit_get_default_this (ILGenerator ig, bool inFunction) 
517                 {
518                         CodeGenerator.load_engine (inFunction, ig);
519                         ig.Emit (OpCodes.Call, typeof (VsaEngine).GetMethod ("ScriptObjectStackTop"));
520                         Type iact_obj = typeof (IActivationObject);
521                         ig.Emit (OpCodes.Castclass, iact_obj);
522                         ig.Emit (OpCodes.Callvirt, iact_obj.GetMethod ("GetDefaultThisObject"));
523                 }
524
525                 internal static object variable_defined_in_current_scope (string id)
526                 {
527                         return TypeManager.defined_in_current_scope (id);
528                 }
529
530                 internal static void load_local_vars (ILGenerator ig, bool inFunction)
531                 {
532                         int n = 0;
533                         Type stack_frame = typeof (StackFrame);
534
535                         CodeGenerator.load_engine (inFunction, ig);
536                                                 
537                         ig.Emit (OpCodes.Call, typeof (VsaEngine).GetMethod ("ScriptObjectStackTop"));
538                         ig.Emit (OpCodes.Castclass, stack_frame);
539                         ig.Emit (OpCodes.Ldfld, stack_frame.GetField ("localVars"));
540                         
541                         object [] locals = TypeManager.CurrentLocals;
542                         n = locals != null ? locals.Length : 0;
543                         object local = null;
544
545                         for (int i = 0; i < n; i++) {
546                                 local = locals [i];
547                                 if (local is LocalBuilder) {
548                                         ig.Emit (OpCodes.Dup);
549                                         ig.Emit (OpCodes.Ldc_I4, i);
550                                         ig.Emit (OpCodes.Ldloc, (LocalBuilder) local);
551                                         ig.Emit (OpCodes.Stelem_Ref);
552                                 }
553                         }
554                         ig.Emit (OpCodes.Pop);
555                 }
556                         
557                 internal static void locals_to_stack_frame (ILGenerator ig, int lexical_depth, int lexical_difference, bool inFunction)
558                 {
559                         CodeGenerator.emit_parents (inFunction, lexical_difference, ig);
560                         ig.Emit (OpCodes.Dup);
561                         
562                         Type stack_frame = typeof (StackFrame);
563                         ig.Emit (OpCodes.Castclass, stack_frame);
564                         ig.Emit (OpCodes.Ldfld, stack_frame.GetField ("localVars"));
565                         
566                         DictionaryEntry [] locals = TypeManager.LocalsAtDepth (lexical_depth);
567
568                         int i = 0;
569                         foreach (DictionaryEntry entry in locals) {
570                                 if (entry.Value is LocalBuilder) {
571                                         ig.Emit (OpCodes.Dup);
572                                         ig.Emit (OpCodes.Ldc_I4, i);
573                                         ig.Emit (OpCodes.Ldloc, (short) i++);
574                                         ig.Emit (OpCodes.Stelem_Ref);
575                                 }
576                         }
577                         ig.Emit (OpCodes.Pop);
578                         //
579                         // FIXME: what determine this?
580                         //
581                         ig.Emit (OpCodes.Call, typeof (ScriptObject).GetMethod ("GetParent"));
582                         ig.Emit (OpCodes.Pop);
583                 }
584
585                 internal static void emit_parents (bool inFunction, int lexical_difference, ILGenerator ig)
586                 {
587                         CodeGenerator.load_engine (inFunction, ig);
588                         ig.Emit (OpCodes.Call, typeof (VsaEngine).GetMethod ("ScriptObjectStackTop"));
589                         for (int i = 0; i < lexical_difference; i++)
590                                 ig.Emit (OpCodes.Call, typeof (ScriptObject).GetMethod ("GetParent"));
591                 }
592
593                 internal static void EmitBox (ILGenerator ig, object obj)
594                 {
595                         if (obj == null) 
596                                 return;
597
598                         Type box_type = GetBoxType (obj);
599
600                         if (box_type == null)
601                                 ;
602                         else
603                                 ig.Emit (OpCodes.Box, box_type);
604                 }
605
606                 internal static void EmitConv (ILGenerator ig, Type type)
607                 {
608                         TypeCode tc = Type.GetTypeCode (type);
609                         
610                         switch (tc) {
611                         case TypeCode.Double:
612                                 ig.Emit (OpCodes.Conv_R8);
613                                 break;
614
615                         default:
616                                 throw new NotImplementedException ();
617                         }
618                 }
619
620                 private static Type GetBoxType (object obj)
621                 {
622                         if (obj is ByteConstant || obj is ShortConstant || obj is IntConstant)
623                                 return typeof (int);
624                         else if (obj is LongConstant)
625                                 return typeof (long);
626                         else if (obj is FloatConstant || obj is DoubleConstant)
627                                 return typeof (double);
628                         else if (obj is BooleanConstant || obj is StrictEquality || obj is Equality)
629                                 return typeof (bool);
630                         else if (obj is Unary) {
631                                 Unary unary = (Unary) obj;
632                                 JSToken oper = unary.oper;
633                                 AST operand = unary.operand;
634                                 
635                                 if (oper == JSToken.Minus || oper == JSToken.Plus ||
636                                     oper == JSToken.Increment || oper == JSToken.Decrement ||
637                                     oper == JSToken.BitwiseNot)
638                                         return GetBoxType (operand);
639                                 else if (oper == JSToken.LogicalNot || oper == JSToken.Delete)
640                                         return typeof (bool);
641                         } else if (obj is Identifier) {
642                                 Identifier id = (Identifier) obj;
643                                 string name = id.name.Value;
644                                 if  (name == "NaN" || name == "Infinity")
645                                         return typeof (double);
646                         } else if (obj is Binary) {
647                                 Binary bin = obj as Binary;
648                                 if (bin.AccessField && !bin.LateBinding) {
649                                         MemberInfo binding = bin.Binding;
650                                         MemberTypes member_type = binding.MemberType;
651                                         if (member_type == MemberTypes.Property)
652                                                 return ((PropertyInfo) binding).PropertyType;
653                                 }
654                         } else if (obj is Relational) {
655                                 Relational re = (Relational) obj;
656                                 if (re.op == JSToken.In)
657                                         return typeof (bool);
658                         }
659                         return null;
660                 }
661
662                 internal static void emit_default_value (ILGenerator ig, ParameterInfo param)
663                 {
664                         Type param_type = param.ParameterType;
665
666                         if (param_type == typeof (Double))
667                                 ig.Emit (OpCodes.Ldc_R8, GlobalObject.NaN);
668                         else if (param_type == typeof (object))
669                                 ig.Emit (OpCodes.Ldsfld, typeof (Missing).GetField ("Value"));
670                         else
671                                 throw new NotImplementedException ();
672                 }
673
674                 internal static void EmitRelationalComp (ILGenerator ig, Relational re)
675                 {
676                         JSToken op = re.op;
677
678                         if (op == JSToken.Instanceof)
679                                 return;
680                         else if (op == JSToken.In) {
681                                 ig.Emit (OpCodes.Box, typeof (bool));
682                                 return;
683                         }
684
685                         Label true_case = ig.DefineLabel ();
686                         Label box_to_bool = ig.DefineLabel ();
687
688                         ig.Emit (OpCodes.Ldc_I4_0);
689                         ig.Emit (OpCodes.Conv_R8);
690
691                         OpCode opcode;
692
693                         switch (op) {
694                         case JSToken.LessThan:
695                                 opcode = OpCodes.Blt;
696                                 break;
697
698                         case JSToken.LessThanEqual:
699                                 opcode = OpCodes.Ble;
700                                 break;
701
702                         case JSToken.GreaterThan:
703                                 opcode = OpCodes.Bgt;
704                                 break;
705
706                         case JSToken.GreaterThanEqual:
707                                 opcode = OpCodes.Bge;
708                                 break;
709
710                         default:
711                                 Console.WriteLine (re.Location.LineNumber);
712                                 throw new NotImplementedException ();
713                         }
714
715                         ig.Emit (opcode, true_case);
716                         ig.Emit (OpCodes.Ldc_I4_0);
717                         ig.Emit (OpCodes.Br, box_to_bool);
718                         ig.MarkLabel (true_case);
719                         ig.Emit (OpCodes.Ldc_I4_1);
720                         ig.MarkLabel (box_to_bool);
721                         ig.Emit (OpCodes.Box, typeof (bool));
722                 }
723
724                 internal static string GetTypeName (string srcName)
725                 {
726                         return (string) source_file_to_type [srcName];
727                 }
728
729                 internal static void EmitAssignAsExp (EmitContext ec, AST ast)
730                 {
731                         Assign assign = (Assign) ast;
732                         LocalBuilder builder = assign.EmitAndReturnBuilder (ec);
733                         ec.ig.Emit (OpCodes.Ldloc, builder);
734                 }
735         }
736 }