-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathGenerateEventAssembly.cs
More file actions
678 lines (643 loc) · 23.5 KB
/
Copy pathGenerateEventAssembly.cs
File metadata and controls
678 lines (643 loc) · 23.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;
namespace LuaInterface
{
/*
* Structure to store a type and the return types of
* its methods (the type of the returned value and out/ref
* parameters).
*/
struct LuaClassType
{
public Type klass;
public Type[][] returnTypes;
}
/*
* Common interface for types generated from tables. The method
* returns the table that overrides some or all of the type's methods.
*/
public interface ILuaGeneratedType
{
LuaTable __luaInterface_getLuaTable();
}
/*
* Class used for generating delegates that get a function from the Lua
* stack as a delegate of a specific type.
*
* Author: Fabio Mascarenhas
* Version: 1.0
*/
class DelegateGenerator
{
private ObjectTranslator translator;
private Type delegateType;
public DelegateGenerator(ObjectTranslator translator,Type delegateType)
{
this.translator=translator;
this.delegateType=delegateType;
}
public object extractGenerated(IntPtr luaState,int stackPos)
{
return CodeGeneration.Instance.GetDelegate(delegateType,translator.getFunction(luaState,stackPos));
}
}
/*
* Class used for generating delegates that get a table from the Lua
* stack as a an object of a specific type.
*
* Author: Fabio Mascarenhas
* Version: 1.0
*/
class ClassGenerator
{
private ObjectTranslator translator;
private Type klass;
public ClassGenerator(ObjectTranslator translator,Type klass)
{
this.translator=translator;
this.klass=klass;
}
public object extractGenerated(IntPtr luaState,int stackPos)
{
return CodeGeneration.Instance.GetClassInstance(klass,translator.getTable(luaState,stackPos));
}
}
/*
* Dynamically generates new types from existing types and
* Lua function and table values. Generated types are event handlers,
* delegates, interface implementations and subclasses.
*
* Author: Fabio Mascarenhas
* Version: 1.0
*/
class CodeGeneration
{
private Type eventHandlerParent=typeof(LuaEventHandler);
private Dictionary<Type, Type> eventHandlerCollection=new Dictionary<Type, Type>();
private Type delegateParent=typeof(LuaDelegate);
private Dictionary<Type, Type> delegateCollection=new Dictionary<Type, Type>();
private Type classHelper=typeof(LuaClassHelper);
private Dictionary<Type, LuaClassType> classCollection=new Dictionary<Type, LuaClassType>();
private AssemblyName assemblyName;
private AssemblyBuilder newAssembly;
private ModuleBuilder newModule;
private int luaClassNumber=1;
private static readonly CodeGeneration instance = new CodeGeneration();
static CodeGeneration()
{
}
private CodeGeneration()
{
// Create an assembly name
assemblyName=new AssemblyName( );
assemblyName.Name="LuaInterface_generatedcode";
// Create a new assembly with one module.
newAssembly=Thread.GetDomain().DefineDynamicAssembly(
assemblyName, AssemblyBuilderAccess.Run);
newModule=newAssembly.DefineDynamicModule("LuaInterface_generatedcode");
}
/*
* Singleton instance of the class
*/
public static CodeGeneration Instance
{
get
{
return instance;
}
}
/*
* Generates an event handler that calls a Lua function
*/
private Type GenerateEvent(Type eventHandlerType)
{
string typeName;
lock(this)
{
typeName = "LuaGeneratedClass" + luaClassNumber;
luaClassNumber++;
}
// Define a public class in the assembly, called typeName
TypeBuilder myType=newModule.DefineType(typeName,TypeAttributes.Public,eventHandlerParent);
// Defines the handler method. Its signature is void(object,<subclassofEventArgs>)
Type[] paramTypes = new Type[2];
paramTypes[0]=typeof(object);
paramTypes[1]=eventHandlerType;
Type returnType=typeof(void);
MethodBuilder handleMethod=myType.DefineMethod("HandleEvent",
MethodAttributes.Public|MethodAttributes.HideBySig,
returnType,paramTypes);
// Emits the IL for the method. It loads the arguments
// and calls the handleEvent method of the base class
ILGenerator generator=handleMethod.GetILGenerator( );
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Ldarg_2);
MethodInfo miGenericEventHandler;
miGenericEventHandler=eventHandlerParent.GetMethod("handleEvent");
generator.Emit(OpCodes.Call,miGenericEventHandler);
// returns
generator.Emit(OpCodes.Ret);
// creates the new type
return myType.CreateType();
}
/*
* Generates a type that can be used for instantiating a delegate
* of the provided type, given a Lua function.
*/
private Type GenerateDelegate(Type delegateType)
{
string typeName;
lock(this)
{
typeName = "LuaGeneratedClass" + luaClassNumber;
luaClassNumber++;
}
// Define a public class in the assembly, called typeName
TypeBuilder myType=newModule.DefineType(typeName,TypeAttributes.Public,delegateParent);
// Defines the delegate method with the same signature as the
// Invoke method of delegateType
MethodInfo invokeMethod=delegateType.GetMethod("Invoke");
ParameterInfo[] paramInfo=invokeMethod.GetParameters();
Type[] paramTypes=new Type[paramInfo.Length];
Type returnType=invokeMethod.ReturnType;
// Counts out and ref params, for use later
int nOutParams=0; int nOutAndRefParams=0;
for(int i=0;i<paramTypes.Length;i++)
{
paramTypes[i]=paramInfo[i].ParameterType;
if((!paramInfo[i].IsIn) && paramInfo[i].IsOut)
nOutParams++;
if(paramTypes[i].IsByRef)
nOutAndRefParams++;
}
int[] refArgs=new int[nOutAndRefParams];
MethodBuilder delegateMethod=myType.DefineMethod("CallFunction",
invokeMethod.Attributes,
returnType,paramTypes);
// Generates the IL for the method
ILGenerator generator=delegateMethod.GetILGenerator( );
generator.DeclareLocal(typeof(object[])); // original arguments
generator.DeclareLocal(typeof(object[])); // with out-only arguments removed
generator.DeclareLocal(typeof(int[])); // indexes of out and ref arguments
if(!(returnType == typeof(void))) // return value
generator.DeclareLocal(returnType);
else
generator.DeclareLocal(typeof(object));
// Initializes local variables
generator.Emit(OpCodes.Ldc_I4,paramTypes.Length);
generator.Emit(OpCodes.Newarr,typeof(object));
generator.Emit(OpCodes.Stloc_0);
generator.Emit(OpCodes.Ldc_I4,paramTypes.Length-nOutParams);
generator.Emit(OpCodes.Newarr,typeof(object));
generator.Emit(OpCodes.Stloc_1);
generator.Emit(OpCodes.Ldc_I4,nOutAndRefParams);
generator.Emit(OpCodes.Newarr,typeof(int));
generator.Emit(OpCodes.Stloc_2);
// Stores the arguments in the local variables
for(int iArgs=0,iInArgs=0,iOutArgs=0;iArgs<paramTypes.Length;iArgs++)
{
generator.Emit(OpCodes.Ldloc_0);
generator.Emit(OpCodes.Ldc_I4,iArgs);
generator.Emit(OpCodes.Ldarg,iArgs+1);
if(paramTypes[iArgs].IsByRef)
{
if(paramTypes[iArgs].GetElementType().IsValueType)
{
generator.Emit(OpCodes.Ldobj,paramTypes[iArgs].GetElementType());
generator.Emit(OpCodes.Box,paramTypes[iArgs].GetElementType());
} else generator.Emit(OpCodes.Ldind_Ref);
}
else
{
if(paramTypes[iArgs].IsValueType)
generator.Emit(OpCodes.Box,paramTypes[iArgs]);
}
generator.Emit(OpCodes.Stelem_Ref);
if(paramTypes[iArgs].IsByRef)
{
generator.Emit(OpCodes.Ldloc_2);
generator.Emit(OpCodes.Ldc_I4,iOutArgs);
generator.Emit(OpCodes.Ldc_I4,iArgs);
generator.Emit(OpCodes.Stelem_I4);
refArgs[iOutArgs]=iArgs;
iOutArgs++;
}
if(paramInfo[iArgs].IsIn || (!paramInfo[iArgs].IsOut))
{
generator.Emit(OpCodes.Ldloc_1);
generator.Emit(OpCodes.Ldc_I4,iInArgs);
generator.Emit(OpCodes.Ldarg,iArgs+1);
if(paramTypes[iArgs].IsByRef)
{
if(paramTypes[iArgs].GetElementType().IsValueType)
{
generator.Emit(OpCodes.Ldobj,paramTypes[iArgs].GetElementType());
generator.Emit(OpCodes.Box,paramTypes[iArgs].GetElementType());
}
else generator.Emit(OpCodes.Ldind_Ref);
}
else
{
if(paramTypes[iArgs].IsValueType)
generator.Emit(OpCodes.Box,paramTypes[iArgs]);
}
generator.Emit(OpCodes.Stelem_Ref);
iInArgs++;
}
}
// Calls the callFunction method of the base class
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldloc_0);
generator.Emit(OpCodes.Ldloc_1);
generator.Emit(OpCodes.Ldloc_2);
MethodInfo miGenericEventHandler;
miGenericEventHandler=delegateParent.GetMethod("callFunction");
generator.Emit(OpCodes.Call,miGenericEventHandler);
// Stores return value
if(returnType == typeof(void))
{
generator.Emit(OpCodes.Pop);
generator.Emit(OpCodes.Ldnull);
}
else if(returnType.IsValueType)
{
generator.Emit(OpCodes.Unbox,returnType);
generator.Emit(OpCodes.Ldobj,returnType);
} else generator.Emit(OpCodes.Castclass,returnType);
generator.Emit(OpCodes.Stloc_3);
// Stores new value of out and ref params
for(int i=0;i<refArgs.Length;i++)
{
generator.Emit(OpCodes.Ldarg,refArgs[i]+1);
generator.Emit(OpCodes.Ldloc_0);
generator.Emit(OpCodes.Ldc_I4,refArgs[i]);
generator.Emit(OpCodes.Ldelem_Ref);
if(paramTypes[refArgs[i]].GetElementType().IsValueType)
{
generator.Emit(OpCodes.Unbox,paramTypes[refArgs[i]].GetElementType());
generator.Emit(OpCodes.Ldobj,paramTypes[refArgs[i]].GetElementType());
generator.Emit(OpCodes.Stobj,paramTypes[refArgs[i]].GetElementType());
}
else
{
generator.Emit(OpCodes.Castclass,paramTypes[refArgs[i]].GetElementType());
generator.Emit(OpCodes.Stind_Ref);
}
}
// Returns
if(!(returnType == typeof(void)))
generator.Emit(OpCodes.Ldloc_3);
generator.Emit(OpCodes.Ret);
// creates the new type
return myType.CreateType();
}
/*
* Generates an implementation of klass, if it is an interface, or
* a subclass of klass that delegates its virtual methods to a Lua table.
*/
public void GenerateClass(Type klass,out Type newType,out Type[][] returnTypes)
{
string typeName;
lock(this)
{
typeName = "LuaGeneratedClass" + luaClassNumber;
luaClassNumber++;
}
TypeBuilder myType;
// Define a public class in the assembly, called typeName
if(klass.IsInterface)
myType=newModule.DefineType(typeName,TypeAttributes.Public,typeof(object),new Type[] { klass,typeof(ILuaGeneratedType) });
else
myType=newModule.DefineType(typeName,TypeAttributes.Public,klass,new Type[] { typeof(ILuaGeneratedType) });
// Field that stores the Lua table
FieldBuilder luaTableField=myType.DefineField("__luaInterface_luaTable",typeof(LuaTable),FieldAttributes.Public);
// Field that stores the return types array
FieldBuilder returnTypesField=myType.DefineField("__luaInterface_returnTypes",typeof(Type[][]),FieldAttributes.Public);
// Generates the constructor for the new type, it takes a Lua table and an array
// of return types and stores them in the respective fields
ConstructorBuilder constructor=
myType.DefineConstructor(MethodAttributes.Public,CallingConventions.Standard,new Type[] { typeof(LuaTable),typeof(Type[][]) });
ILGenerator generator=constructor.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0);
if(klass.IsInterface)
generator.Emit(OpCodes.Call,typeof(object).GetConstructor(Type.EmptyTypes));
else
generator.Emit(OpCodes.Call,klass.GetConstructor(Type.EmptyTypes));
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Stfld,luaTableField);
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldarg_2);
generator.Emit(OpCodes.Stfld,returnTypesField);
generator.Emit(OpCodes.Ret);
// Generates overriden versions of the klass' public virtual methods
MethodInfo[] classMethods=klass.GetMethods();
returnTypes=new Type[classMethods.Length][];
int i=0;
foreach(MethodInfo method in classMethods)
{
if(klass.IsInterface)
{
GenerateMethod(myType,method,
MethodAttributes.HideBySig|MethodAttributes.Virtual|MethodAttributes.NewSlot,
i,luaTableField,returnTypesField,false,out returnTypes[i]);
i++;
}
else
{
if(!method.IsPrivate && !method.IsFinal && method.IsVirtual)
{
GenerateMethod(myType,method,(method.Attributes|MethodAttributes.NewSlot)^MethodAttributes.NewSlot,i,
luaTableField,returnTypesField,true,out returnTypes[i]);
i++;
}
}
}
// Generates an implementation of the __luaInterface_getLuaTable method
MethodBuilder returnTableMethod=myType.DefineMethod("__luaInterface_getLuaTable",
MethodAttributes.Public|MethodAttributes.HideBySig|MethodAttributes.Virtual,
typeof(LuaTable),new Type[0]);
myType.DefineMethodOverride(returnTableMethod,typeof(ILuaGeneratedType).GetMethod("__luaInterface_getLuaTable"));
generator=returnTableMethod.GetILGenerator();
generator.Emit(OpCodes.Ldfld,luaTableField);
generator.Emit(OpCodes.Ret);
// Creates the type
newType=myType.CreateType();
}
/*
* Generates an overriden implementation of method inside myType that delegates
* to a function in a Lua table with the same name, if the function exists. If it
* doesn't the method calls the base method (or does nothing, in case of interface
* implementations).
*/
private void GenerateMethod(TypeBuilder myType,MethodInfo method,MethodAttributes attributes,
int methodIndex,FieldInfo luaTableField,FieldInfo returnTypesField,bool generateBase,out Type[] returnTypes)
{
ParameterInfo[] paramInfo=method.GetParameters();
Type[] paramTypes=new Type[paramInfo.Length];
List<Type> returnTypesList=new List<Type>();
// Counts out and ref parameters, for later use,
// and creates the list of return types
int nOutParams=0; int nOutAndRefParams=0;
Type returnType=method.ReturnType;
returnTypesList.Add(returnType);
for(int i=0;i<paramTypes.Length;i++)
{
paramTypes[i]=paramInfo[i].ParameterType;
if((!paramInfo[i].IsIn) && paramInfo[i].IsOut)
nOutParams++;
if(paramTypes[i].IsByRef)
{
returnTypesList.Add(paramTypes[i].GetElementType());
nOutAndRefParams++;
}
}
int[] refArgs=new int[nOutAndRefParams];
returnTypes=returnTypesList.ToArray();
// Generates a version of the method that calls the base implementation
// directly, for use by the base field of the table
if(generateBase)
{
MethodBuilder baseMethod=myType.DefineMethod("__luaInterface_base_"+method.Name,
MethodAttributes.Private|MethodAttributes.NewSlot|MethodAttributes.HideBySig,
returnType,paramTypes);
ILGenerator generatorBase=baseMethod.GetILGenerator();
generatorBase.Emit(OpCodes.Ldarg_0);
for(int i=0;i<paramTypes.Length;i++)
generatorBase.Emit(OpCodes.Ldarg,i+1);
generatorBase.Emit(OpCodes.Call,method);
if(returnType == typeof(void))
generatorBase.Emit(OpCodes.Pop);
generatorBase.Emit(OpCodes.Ret);
}
// Defines the method
MethodBuilder methodImpl=myType.DefineMethod(method.Name,attributes,
returnType,paramTypes);
// If it's an implementation of an interface tells what method it
// is overriding
if(myType.BaseType.Equals(typeof(object)))
myType.DefineMethodOverride(methodImpl,method);
ILGenerator generator=methodImpl.GetILGenerator( );
generator.DeclareLocal(typeof(object[])); // original arguments
generator.DeclareLocal(typeof(object[])); // with out-only arguments removed
generator.DeclareLocal(typeof(int[])); // indexes of out and ref arguments
if(!(returnType == typeof(void))) // return value
generator.DeclareLocal(returnType);
else
generator.DeclareLocal(typeof(object));
// Initializes local variables
generator.Emit(OpCodes.Ldc_I4,paramTypes.Length);
generator.Emit(OpCodes.Newarr,typeof(object));
generator.Emit(OpCodes.Stloc_0);
generator.Emit(OpCodes.Ldc_I4,paramTypes.Length-nOutParams+1);
generator.Emit(OpCodes.Newarr,typeof(object));
generator.Emit(OpCodes.Stloc_1);
generator.Emit(OpCodes.Ldc_I4,nOutAndRefParams);
generator.Emit(OpCodes.Newarr,typeof(int));
generator.Emit(OpCodes.Stloc_2);
generator.Emit(OpCodes.Ldloc_1);
generator.Emit(OpCodes.Ldc_I4_0);
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldfld,luaTableField);
generator.Emit(OpCodes.Stelem_Ref);
// Stores the arguments into the local variables, as needed
for(int iArgs=0,iInArgs=1,iOutArgs=0;iArgs<paramTypes.Length;iArgs++)
{
generator.Emit(OpCodes.Ldloc_0);
generator.Emit(OpCodes.Ldc_I4,iArgs);
generator.Emit(OpCodes.Ldarg,iArgs+1);
if(paramTypes[iArgs].IsByRef)
{
if(paramTypes[iArgs].GetElementType().IsValueType)
{
generator.Emit(OpCodes.Ldobj,paramTypes[iArgs].GetElementType());
generator.Emit(OpCodes.Box,paramTypes[iArgs].GetElementType());
}
else generator.Emit(OpCodes.Ldind_Ref);
}
else
{
if(paramTypes[iArgs].IsValueType)
generator.Emit(OpCodes.Box,paramTypes[iArgs]);
}
generator.Emit(OpCodes.Stelem_Ref);
if(paramTypes[iArgs].IsByRef)
{
generator.Emit(OpCodes.Ldloc_2);
generator.Emit(OpCodes.Ldc_I4,iOutArgs);
generator.Emit(OpCodes.Ldc_I4,iArgs);
generator.Emit(OpCodes.Stelem_I4);
refArgs[iOutArgs]=iArgs;
iOutArgs++;
}
if(paramInfo[iArgs].IsIn || (!paramInfo[iArgs].IsOut))
{
generator.Emit(OpCodes.Ldloc_1);
generator.Emit(OpCodes.Ldc_I4,iInArgs);
generator.Emit(OpCodes.Ldarg,iArgs+1);
if(paramTypes[iArgs].IsByRef)
{
if(paramTypes[iArgs].GetElementType().IsValueType)
{
generator.Emit(OpCodes.Ldobj,paramTypes[iArgs].GetElementType());
generator.Emit(OpCodes.Box,paramTypes[iArgs].GetElementType());
}
else generator.Emit(OpCodes.Ldind_Ref);
}
else
{
if(paramTypes[iArgs].IsValueType)
generator.Emit(OpCodes.Box,paramTypes[iArgs]);
}
generator.Emit(OpCodes.Stelem_Ref);
iInArgs++;
}
}
// Gets the function the method will delegate to by calling
// the getTableFunction method of class LuaClassHelper
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldfld,luaTableField);
generator.Emit(OpCodes.Ldstr,method.Name);
generator.Emit(OpCodes.Call,classHelper.GetMethod("getTableFunction"));
Label lab1=generator.DefineLabel();
generator.Emit(OpCodes.Dup);
generator.Emit(OpCodes.Brtrue_S,lab1);
// Function does not exist, call base method
generator.Emit(OpCodes.Pop);
if(!method.IsAbstract)
{
generator.Emit(OpCodes.Ldarg_0);
for(int i=0;i<paramTypes.Length;i++)
generator.Emit(OpCodes.Ldarg,i+1);
generator.Emit(OpCodes.Call,method);
if(returnType == typeof(void))
generator.Emit(OpCodes.Pop);
generator.Emit(OpCodes.Ret);
generator.Emit(OpCodes.Ldnull);
} else
generator.Emit(OpCodes.Ldnull);
Label lab2=generator.DefineLabel();
generator.Emit(OpCodes.Br_S,lab2);
generator.MarkLabel(lab1);
// Function exists, call using method callFunction of LuaClassHelper
generator.Emit(OpCodes.Ldloc_0);
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldfld,returnTypesField);
generator.Emit(OpCodes.Ldc_I4,methodIndex);
generator.Emit(OpCodes.Ldelem_Ref);
generator.Emit(OpCodes.Ldloc_1);
generator.Emit(OpCodes.Ldloc_2);
generator.Emit(OpCodes.Call,classHelper.GetMethod("callFunction"));
generator.MarkLabel(lab2);
// Stores the function return value
if(returnType == typeof(void))
{
generator.Emit(OpCodes.Pop);
generator.Emit(OpCodes.Ldnull);
}
else if(returnType.IsValueType)
{
generator.Emit(OpCodes.Unbox,returnType);
generator.Emit(OpCodes.Ldobj,returnType);
}
else generator.Emit(OpCodes.Castclass,returnType);
generator.Emit(OpCodes.Stloc_3);
// Sets return values of out and ref parameters
for(int i=0;i<refArgs.Length;i++)
{
generator.Emit(OpCodes.Ldarg,refArgs[i]+1);
generator.Emit(OpCodes.Ldloc_0);
generator.Emit(OpCodes.Ldc_I4,refArgs[i]);
generator.Emit(OpCodes.Ldelem_Ref);
if(paramTypes[refArgs[i]].GetElementType().IsValueType)
{
generator.Emit(OpCodes.Unbox,paramTypes[refArgs[i]].GetElementType());
generator.Emit(OpCodes.Ldobj,paramTypes[refArgs[i]].GetElementType());
generator.Emit(OpCodes.Stobj,paramTypes[refArgs[i]].GetElementType());
}
else
{
generator.Emit(OpCodes.Castclass,paramTypes[refArgs[i]].GetElementType());
generator.Emit(OpCodes.Stind_Ref);
}
}
// Returns
if(!(returnType == typeof(void)))
generator.Emit(OpCodes.Ldloc_3);
generator.Emit(OpCodes.Ret);
}
/*
* Gets an event handler for the event type that delegates to the eventHandler Lua function.
* Caches the generated type.
*/
public LuaEventHandler GetEvent(Type eventHandlerType, LuaFunction eventHandler)
{
Type eventConsumerType;
if (eventHandlerCollection.ContainsKey(eventHandlerType))
{
eventConsumerType=eventHandlerCollection[eventHandlerType];
}
else
{
eventConsumerType=GenerateEvent(eventHandlerType);
eventHandlerCollection[eventHandlerType] = eventConsumerType;
}
LuaEventHandler luaEventHandler=(LuaEventHandler)Activator.CreateInstance(eventConsumerType);
luaEventHandler.handler=eventHandler;
return luaEventHandler;
}
/*
* Gets a delegate with delegateType that calls the luaFunc Lua function
* Caches the generated type.
*/
public Delegate GetDelegate(Type delegateType, LuaFunction luaFunc)
{
List<Type> returnTypes=new List<Type>();
Type luaDelegateType;
if (delegateCollection.ContainsKey(delegateType))
{
luaDelegateType=delegateCollection[delegateType];
}
else
{
luaDelegateType=GenerateDelegate(delegateType);
delegateCollection[delegateType] = luaDelegateType;
}
MethodInfo methodInfo=delegateType.GetMethod("Invoke");
returnTypes.Add(methodInfo.ReturnType);
foreach(ParameterInfo paramInfo in methodInfo.GetParameters())
if(paramInfo.ParameterType.IsByRef)
returnTypes.Add(paramInfo.ParameterType);
LuaDelegate luaDelegate=(LuaDelegate)Activator.CreateInstance(luaDelegateType);
luaDelegate.function=luaFunc;
luaDelegate.returnTypes=returnTypes.ToArray();
return Delegate.CreateDelegate(delegateType,luaDelegate,"CallFunction");
}
/*
* Gets an instance of an implementation of the klass interface or
* subclass of klass that delegates public virtual methods to the
* luaTable table.
* Caches the generated type.
*/
public object GetClassInstance(Type klass, LuaTable luaTable)
{
LuaClassType luaClassType;
if (classCollection.ContainsKey(klass))
{
luaClassType=classCollection[klass];
}
else
{
luaClassType=new LuaClassType();
GenerateClass(klass,out luaClassType.klass,out luaClassType.returnTypes);
classCollection[klass] = luaClassType;
}
return Activator.CreateInstance(luaClassType.klass,new object[] {luaTable,luaClassType.returnTypes});
}
}
}