|
1 | 1 | module Naggum.Assembler.Assembler |
2 | 2 |
|
| 3 | +open System |
| 4 | +open System.Reflection |
3 | 5 | open System.Reflection.Emit |
4 | 6 |
|
5 | 7 | open Naggum.Assembler.Representation |
6 | 8 |
|
7 | | -/// Assembles the intermediate program representation. Returns a list of assemblies ready for saving. |
| 9 | +let private getMethodAttributes (m : MethodDefinition) = |
| 10 | + let empty = enum 0 |
| 11 | + let conditions = |
| 12 | + [ (m.Visibility = Public, MethodAttributes.Public) |
| 13 | + (true, MethodAttributes.Static) ] // TODO: Proper static method detection |
| 14 | + |
| 15 | + conditions |
| 16 | + |> List.map (fun (c, r) -> if c then r else empty) |
| 17 | + |> List.fold (|||) empty |
| 18 | + |
| 19 | +let private findMethod (signature : MethodSignature) = |
| 20 | + // TODO: Add method overload resolution etc. (see ClrGenerator module) |
| 21 | + let ``type`` = signature.ContainingType.Value |
| 22 | + ``type``.GetMethod (signature.Name, Array.ofList signature.ArgumentTypes) |
| 23 | + |
| 24 | +let private buildMethodBody (m : MethodDefinition) (builder : MethodBuilder) = |
| 25 | + let generator = builder.GetILGenerator () |
| 26 | + |
| 27 | + m.Body |
| 28 | + |> List.iter (function |
| 29 | + | Call signature -> |
| 30 | + let methodInfo = findMethod signature |
| 31 | + generator.Emit (OpCodes.Call, methodInfo) |
| 32 | + | Ldstr string -> generator.Emit (OpCodes.Ldstr, string) |
| 33 | + | Ret -> generator.Emit (OpCodes.Ret)) |
| 34 | + |
| 35 | +let private assembleUnit (builder : ModuleBuilder) = function |
| 36 | + | Method m -> |
| 37 | + let name = m.Name |
| 38 | + let attributes = getMethodAttributes m |
| 39 | + let returnType = m.ReturnType |
| 40 | + let argumentTypes = Array.ofList m.ArgumentTypes |
| 41 | + let methodBuilder = builder.DefineGlobalMethod (name, |
| 42 | + attributes, |
| 43 | + returnType, |
| 44 | + argumentTypes) |
| 45 | + buildMethodBody m methodBuilder |
| 46 | + |
| 47 | + |
| 48 | +let private assembleAssembly (assembly : Assembly) = |
| 49 | + let name = AssemblyName assembly.Name |
| 50 | + let domain = AppDomain.CurrentDomain |
| 51 | + let builder = domain.DefineDynamicAssembly (name, |
| 52 | + AssemblyBuilderAccess.Save) |
| 53 | + let fileName = assembly.Name + ".dll" // TODO: Proper file naming |
| 54 | + let moduleBuilder = builder.DefineDynamicModule (assembly.Name, fileName) |
| 55 | + assembly.Units |> List.iter (assembleUnit moduleBuilder) |
| 56 | + builder |
| 57 | + |
| 58 | +/// Assembles the intermediate program representation. Returns a list of |
| 59 | +/// assemblies ready for saving. |
8 | 60 | let assemble (assemblies : Assembly seq) : AssemblyBuilder seq = |
9 | | - Seq.empty |
| 61 | + assemblies |
| 62 | + |> Seq.map assembleAssembly |
0 commit comments