Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- module ILCreator
- open System.Reflection
- open System.Reflection.Emit
- open ILInstructions
- open System.Threading
- open System
- open System.IO
- type Meta =
- { currentEnv: Env.Env
- currentTypeBuilder : TypeBuilder }
- let rec evalInstruction meta (il:ILGenerator) instr =
- match instr with
- | PushInt i -> il.Emit(OpCodes.Ldc_I4, i); meta
- | Add -> il.Emit(OpCodes.Add); meta
- | Sub -> il.Emit(OpCodes.Sub); meta
- | Div -> il.Emit(OpCodes.Div); meta
- | Mul -> il.Emit(OpCodes.Mul); meta
- | Gt -> il.Emit(OpCodes.Cgt); meta
- | Lt -> il.Emit(OpCodes.Clt); meta
- | LoadLocal name -> evalLoadLocal meta il name; meta
- | StoreLocal name -> evalStoreLocal meta il name
- | Print -> il.EmitCall(OpCodes.Call,typeof<Console>.GetMethod("WriteLine", [| typeof<int> |]), null); meta
- | Branch (a, b) -> evalBranch meta il a b; meta
- | MethodCall (name, instrs) -> evalMethodCall meta il name instrs; meta
- | _ -> failwith "Expected an instruction!"
- and evalMethodCall meta (il:ILGenerator) methodName instrs =
- evalInstructions meta il instrs
- let { currentTypeBuilder = typeBuilder } = meta
- let methodInfo = typeBuilder.GetMethod(methodName)
- il.EmitCall(OpCodes.Call, methodInfo, [| typeof<int> |])
- and evalLoadLocal meta (il:ILGenerator) name =
- let { currentEnv = env } = meta
- let field = Env.tryGetField name env
- match field with
- | Some(Env.Arg index) -> il.Emit(OpCodes.Ldarg, index)
- | Some(Env.Local index) -> il.Emit(OpCodes.Ldloc, index)
- | None -> failwith "Could not find field!"
- and evalStoreLocal meta (il:ILGenerator) name =
- let { currentEnv = env } = meta
- let (updatedEnv, index) = Env.addLocal name env
- il.DeclareLocal(typeof<int>) |> ignore
- il.Emit(OpCodes.Stloc, index) |> ignore
- { meta with currentEnv = updatedEnv }
- and evalInstructions meta (il:ILGenerator) instrs =
- List.fold (fun env value -> evalInstruction meta il value) meta instrs
- and evalBranch meta (il : ILGenerator) thenInstr elseInstr =
- il.Emit(OpCodes.Ldc_I4_0)
- il.Emit(OpCodes.Ceq)
- let afterIfLabel = il.DefineLabel()
- il.Emit(OpCodes.Brtrue_S, afterIfLabel)
- evalInstructions meta il thenInstr |> ignore
- let afterElseLabel = il.DefineLabel()
- il.Emit(OpCodes.Br_S, afterElseLabel)
- il.MarkLabel(afterIfLabel)
- evalInstructions meta il elseInstr |> ignore
- il.MarkLabel(afterElseLabel)
- let createAssembly name =
- let assemblyName = new AssemblyName(Path.GetFileNameWithoutExtension(name))
- AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Save)
- let createClass (moduleBuilder: ModuleBuilder) name =
- moduleBuilder.DefineType(name, TypeAttributes.Public)
- let createMethod (typeBuilder : TypeBuilder) name args instructions =
- let defineParam (newMethod : MethodBuilder) i arg =
- newMethod.DefineParameter(i + 1, ParameterAttributes.None, arg) |> ignore
- let types = Array.create (List.length args) typeof<int>
- let newMethod = typeBuilder.DefineMethod(name, MethodAttributes.Public ||| MethodAttributes.Static, typeof<int>, types)
- List.iteri (defineParam newMethod) args
- let ilGenerator = newMethod.GetILGenerator()
- let env = Env.ofArgs args
- let meta =
- { currentEnv = env
- currentTypeBuilder = typeBuilder }
- evalInstructions meta ilGenerator instructions |> ignore
- ilGenerator.Emit(OpCodes.Ret)
- newMethod
- let rec generateIL moduleBuilder (assemblyBuilder : AssemblyBuilder) constructs =
- match constructs with
- | Class (name, methods) -> let newClass = createClass moduleBuilder name
- buildMethods newClass assemblyBuilder methods
- newClass.CreateType()
- | _ -> failwith "Expected a class!"
- and buildMethods sourceClass (assemblyBuilder : AssemblyBuilder) methods =
- match methods with
- | Method (name, args, instructions)::rest -> createMethod sourceClass name args instructions |> ignore
- buildMethods sourceClass assemblyBuilder rest
- | EntryMethod (name, args, instructions)::rest -> let newMethod = createMethod sourceClass name args instructions
- assemblyBuilder.SetEntryPoint(newMethod)
- buildMethods sourceClass assemblyBuilder rest
- | [] -> ()
- | _ -> printfn "Expected a method!"
- let produceIL assemblyName constructs =
- let assemblyBuilder = createAssembly assemblyName
- let moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName)
- generateIL moduleBuilder assemblyBuilder constructs |> ignore
- moduleBuilder.CreateGlobalFunctions() |> ignore
- assemblyBuilder.Save(assemblyName) |> ignore
- //let methodBuilderTest (m : MethodBuilder) =
- // m.DefineParameter
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement