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.
32 using System
.Reflection
;
33 using System
.Reflection
.Emit
;
34 using System
.Threading
;
35 using Microsoft
.JScript
.Vsa
;
36 using System
.Runtime
.CompilerServices
;
38 namespace Microsoft
.JScript
{
40 internal class EmitContext
{
42 internal TypeBuilder type_builder
;
43 internal ILGenerator ig
;
44 internal ModuleBuilder mod_builder
;
46 internal Label LoopBegin
, LoopEnd
;
48 internal EmitContext (TypeBuilder type
)
52 if (type_builder
!= null) {
53 MethodBuilder global_code
= type_builder
.DefineMethod (
55 MethodAttributes
.Public
,
56 typeof (System
.Object
),
58 ig
= global_code
.GetILGenerator ();
62 internal EmitContext (TypeBuilder type_builder
, ModuleBuilder mod_builder
, ILGenerator ig
)
64 this.type_builder
= type_builder
;
65 this.mod_builder
= mod_builder
;
70 public class CodeGenerator
{
72 private static string MODULE
= "JScript Module";
74 internal static string mod_name
;
75 internal static AppDomain app_domain
;
76 internal static AssemblyName assembly_name
;
77 internal static AssemblyBuilder assembly_builder
;
78 internal static ModuleBuilder module_builder
;
80 internal static void Init (string file_name
)
82 app_domain
= Thread
.GetDomain ();
84 assembly_name
= new AssemblyName ();
85 assembly_name
.Name
= trim_extension (file_name
);
89 assembly_builder
= app_domain
.DefineDynamicAssembly (
91 AssemblyBuilderAccess
.RunAndSave
);
93 ConstructorInfo ctr_info
= typeof (Microsoft
.JScript
.ReferenceAttribute
).GetConstructor (new Type
[] { typeof (string) }
);
94 // FIXME: find out which is the blob.
95 byte [] blob
= new byte [] {};
96 assembly_builder
.SetCustomAttribute (ctr_info
, blob
);
98 module_builder
= assembly_builder
.DefineDynamicModule (
100 assembly_name
.Name
+ ".exe",
104 internal static string trim_extension (string file_name
)
106 int index
= file_name
.LastIndexOf ('.');
111 return file_name
.Substring (0, index
);
114 internal static void Save (string target_name
)
116 assembly_builder
.Save (target_name
);
119 internal static void Emit (AST prog
)
124 TypeBuilder type_builder
;
125 type_builder
= module_builder
.DefineType ("JScript 0", TypeAttributes
.Public
);
127 type_builder
.SetParent (typeof (GlobalScope
));
128 type_builder
.SetCustomAttribute (new CustomAttributeBuilder
129 (typeof (CompilerGlobalScopeAttribute
).GetConstructor (new Type
[] {}), new object [] {}
));
131 EmitContext ec
= new EmitContext (type_builder
);
132 ec
.mod_builder
= module_builder
;
133 ILGenerator global_code
= ec
.ig
;
135 emit_default_script_constructor (ec
);
136 emit_default_init_global_code (global_code
);
138 emit_default_end_global_code (global_code
);
139 ec
.type_builder
.CreateType ();
142 // Build the default 'JScript Main' class
144 ec
.type_builder
= module_builder
.DefineType ("JScript Main");
145 emit_jscript_main (ec
.type_builder
);
146 ec
.type_builder
.CreateType ();
149 internal static void emit_default_init_global_code (ILGenerator ig
)
151 ig
.Emit (OpCodes
.Ldarg_0
);
152 ig
.Emit (OpCodes
.Ldfld
, typeof (ScriptObject
).GetField ("engine"));
153 ig
.Emit (OpCodes
.Ldarg_0
);
154 ig
.Emit (OpCodes
.Call
,
155 typeof (VsaEngine
).GetMethod ("PushScriptObject",
156 new Type
[] { typeof (ScriptObject)}
));
159 internal static void emit_default_end_global_code (ILGenerator ig
)
161 ig
.Emit (OpCodes
.Ldnull
);
162 ig
.Emit (OpCodes
.Ldarg_0
);
163 ig
.Emit (OpCodes
.Ldfld
, typeof (ScriptObject
).GetField ("engine"));
164 ig
.Emit (OpCodes
.Call
, typeof (VsaEngine
).GetMethod ("PopScriptObject"));
165 ig
.Emit (OpCodes
.Pop
);
166 ig
.Emit (OpCodes
.Ret
);
169 internal static void emit_default_script_constructor (EmitContext ec
)
171 ConstructorBuilder cons_builder
;
172 TypeBuilder tb
= ec
.type_builder
;
173 cons_builder
= tb
.DefineConstructor (MethodAttributes
.Public
,
174 CallingConventions
.Standard
,
175 new Type
[] { typeof (GlobalScope) }
);
177 ILGenerator ig
= cons_builder
.GetILGenerator ();
178 ig
.Emit (OpCodes
.Ldarg_0
);
179 ig
.Emit (OpCodes
.Ldarg_1
);
180 ig
.Emit (OpCodes
.Dup
);
181 ig
.Emit (OpCodes
.Ldfld
,
182 typeof (ScriptObject
).GetField ("engine"));
184 ig
.Emit (OpCodes
.Call
,
185 typeof (GlobalScope
).GetConstructor (new Type
[] {typeof (GlobalScope
),
186 typeof (VsaEngine
)}));
187 ig
.Emit (OpCodes
.Ret
);
190 internal static void emit_jscript_main (TypeBuilder tb
)
192 emit_jscript_main_constructor (tb
);
193 emit_jscript_main_entry_point (tb
);
196 internal static void emit_jscript_main_constructor (TypeBuilder tb
)
198 ConstructorBuilder cons
= tb
.DefineConstructor (MethodAttributes
.Public
,
199 CallingConventions
.Standard
,
201 ILGenerator ig
= cons
.GetILGenerator ();
202 ig
.Emit (OpCodes
.Ldarg_0
);
203 ig
.Emit (OpCodes
.Call
, typeof (Object
).GetConstructor (new Type
[] {}));
204 ig
.Emit (OpCodes
.Ret
);
207 internal static void emit_jscript_main_entry_point (TypeBuilder tb
)
209 MethodBuilder method
;
210 method
= tb
.DefineMethod ("Main",
211 MethodAttributes
.Public
| MethodAttributes
.Static
,
212 typeof (void), new Type
[] {typeof (String [])}
);
214 method
.SetCustomAttribute (new CustomAttributeBuilder
215 (typeof (STAThreadAttribute
).GetConstructor (
219 ILGenerator ig
= method
.GetILGenerator ();
221 ig
.DeclareLocal (typeof (GlobalScope
));
223 ig
.Emit (OpCodes
.Ldc_I4_1
);
224 ig
.Emit (OpCodes
.Ldc_I4_1
);
225 ig
.Emit (OpCodes
.Newarr
, typeof (string));
226 ig
.Emit (OpCodes
.Dup
);
227 ig
.Emit (OpCodes
.Ldc_I4_0
);
229 ig
.Emit (OpCodes
.Ldstr
,
230 "mscorlib, Version=1.0.3300.0, Culture=neutral, Pub" +
231 "licKeyToken=b77a5c561934e089");
233 ig
.Emit (OpCodes
.Stelem_Ref
);
235 ig
.Emit (OpCodes
.Call
,
236 typeof (VsaEngine
).GetMethod ("CreateEngineAndGetGlobalScope",
237 new Type
[] {typeof (bool),
238 typeof (string [])}));
239 ig
.Emit (OpCodes
.Stloc_0
);
240 ig
.Emit (OpCodes
.Ldloc_0
);
242 ig
.Emit (OpCodes
.Newobj
,
243 assembly_builder
.GetType ("JScript 0").GetConstructor (
244 new Type
[] {typeof (GlobalScope)}
));
245 ig
.Emit (OpCodes
.Call
,
246 assembly_builder
.GetType ("JScript 0").GetMethod (
247 "Global Code", new Type
[] {}));
248 ig
.Emit (OpCodes
.Pop
);
249 ig
.Emit (OpCodes
.Ret
);
251 assembly_builder
.SetEntryPoint (method
);
254 public static void Run (string file_name
, AST prog
)
256 CodeGenerator
.Init (file_name
);
257 CodeGenerator
.Emit (prog
);
258 CodeGenerator
.Save (trim_extension (file_name
) + ".exe");
261 internal static void fall_true (EmitContext ec
, AST ast
, Label lbl
)
263 ILGenerator ig
= ec
.ig
;
265 if (ast
.GetType () == typeof (Expression
)) {
266 Expression exp
= ast
as Expression
;
268 AST last_exp
= (AST
) exp
.exprs
[exp
.exprs
.Count
- 1];
270 if (last_exp
is Binary
) {
271 Binary b
= last_exp
as Binary
;
273 case JSToken
.LogicalOr
:
274 Label ftLb
= ig
.DefineLabel ();
275 fall_false (ec
, b
.left
, ftLb
);
276 fall_true (ec
, b
.right
, lbl
);
279 case JSToken
.LogicalAnd
:
280 fall_true (ec
, b
.left
, lbl
);
281 fall_true (ec
, b
.right
, lbl
);
284 case JSToken
.LessThan
:
285 ig
.Emit (OpCodes
.Ldc_I4_0
);
286 ig
.Emit (OpCodes
.Conv_R8
);
287 ig
.Emit (OpCodes
.Blt
, lbl
);
290 } else if (last_exp
is Equality
) {
291 Equality eq
= last_exp
as Equality
;
293 case JSToken
.NotEqual
:
294 ig
.Emit (OpCodes
.Brtrue
, lbl
);
297 ig
.Emit (OpCodes
.Brfalse
, lbl
);
300 if (need_convert_to_boolean (ast
))
301 emit_to_boolean (ast
, ig
, 0);
302 ig
.Emit (OpCodes
.Brtrue
, lbl
);
308 if (need_convert_to_boolean (ast
))
309 emit_to_boolean (ast
, ig
, 0);
310 ig
.Emit (OpCodes
.Brfalse
, lbl
);
314 internal static void fall_false (EmitContext ec
, AST ast
, Label lbl
)
316 ILGenerator ig
= ec
.ig
;
318 if (ast
.GetType () == typeof (Expression
)) {
319 Expression exp
= ast
as Expression
;
321 AST last_exp
= (AST
) exp
.exprs
[exp
.exprs
.Count
- 1];
323 if (last_exp
is Relational
) {
324 Relational r
= last_exp
as Relational
;
326 case JSToken
.LessThan
:
327 ig
.Emit (OpCodes
.Ldc_I4_0
);
328 ig
.Emit (OpCodes
.Conv_R8
);
329 ig
.Emit (OpCodes
.Blt
, lbl
);
332 } else if (last_exp
is Binary
) {
333 Binary b
= last_exp
as Binary
;
335 case JSToken
.LogicalOr
:
336 fall_false (ec
, b
.left
, lbl
);
337 fall_false (ec
, b
.right
, lbl
);
340 case JSToken
.LogicalAnd
:
341 Label ftLb
= ig
.DefineLabel ();
342 fall_true (ec
, b
.left
, ftLb
);
343 fall_false (ec
, b
.right
, lbl
);
348 if (need_convert_to_boolean (ast
))
349 emit_to_boolean (ast
, ig
, 0);
350 ig
.Emit (OpCodes
.Brtrue
, lbl
);
355 if (need_convert_to_boolean (ast
))
356 emit_to_boolean (ast
, ig
, 0);
357 ig
.Emit (OpCodes
.Brtrue
, lbl
);
362 internal static void emit_to_boolean (AST ast
, ILGenerator ig
, int i
)
364 ig
.Emit (OpCodes
.Ldc_I4
, i
);
365 ig
.Emit (OpCodes
.Call
, typeof (Convert
).GetMethod ("ToBoolean",
366 new Type
[] { typeof (object), typeof (Boolean)}
));
369 internal static bool need_convert_to_boolean (AST ast
)
374 if (ast
is Identifier
)
376 else if (ast
is Expression
) {
377 Expression exp
= ast
as Expression
;
378 int n
= exp
.exprs
.Count
- 1;
379 AST tmp
= (AST
) exp
.exprs
[n
];
380 if (tmp
is Equality
|| tmp
is Relational
|| tmp
is BooleanLiteral
)