Monday, May 16, 2011

Hello CodeDOM -- building C# and F# code from F#

A five-finger exercise in CodeDOM using the "Hello World" example from F# -- more interesting stuff to follow later:

module ProofOfConcept
open System.CodeDom
open System.CodeDom.Compiler
open System.IO
open Microsoft.CSharp
open Microsoft.FSharp.Compiler.CodeDom
let GenerateCode(compileunit: CodeCompileUnit) (provider:CodeDomProvider) =
// Build the output file name.
let sourceFile = Path.ChangeExtension("HelloWorld.", provider.FileExtension)
// Create a TextWriter to a StreamWriter to the output file.
use sw = new StreamWriter(sourceFile, false)
let tw = new IndentedTextWriter(sw, " ")
// Generate source code using the code provider.
provider.GenerateCodeFromCompileUnit(compileunit, tw,
new CodeGeneratorOptions())
tw.Close()
sourceFile
let GenerateCSharpCode(compileunit: CodeCompileUnit) =
// Generate the code with the C# code provider.
let provider = new CSharpCodeProvider();
GenerateCode compileunit provider
let GenerateFSharpCode(compileunit: CodeCompileUnit) =
// Generate the code with the F# code provider.
let provider = new FSharpCodeProvider();
GenerateCode compileunit provider
[<EntryPoint>]
let main a =
let compileUnit = new CodeCompileUnit()
let samples = new CodeNamespace("Samples")
samples.Imports.Add(new CodeNamespaceImport("System"))
compileUnit.Namespaces.Add( samples ) |> ignore
let class1 = new CodeTypeDeclaration("Class1")
samples.Types.Add(class1) |> ignore
let start = new CodeEntryPointMethod();
let cs1 = new CodeMethodInvokeExpression(
new CodeTypeReferenceExpression("System.Console"),
"WriteLine", new CodePrimitiveExpression("Hello CodeDOM World!"))
start.Statements.Add(cs1) |> ignore
class1.Members.Add( start ) |> ignore
GenerateCSharpCode compileUnit |> ignore
GenerateFSharpCode compileUnit |> ignore
0
view raw gistfile1.fs hosted with ❤ by GitHub

which yields up

//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:2.0.50727.4211
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Samples {
using System;
public class Class1 {
public static void Main() {
System.Console.WriteLine("Hello CodeDOM World!");
}
}
}
view raw gistfile1.cs hosted with ❤ by GitHub

which isn't StyleCop compliant, but is otherwise well formatted; and

//------------------------------------------------------------------------------
// <autogenerated>
// This code was generated by a tool.
// Runtime Version: 2.0.50727.4211
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </autogenerated>
//------------------------------------------------------------------------------
namespace global
namespace Samples
// Generated by F# CodeDom
#nowarn "49" // uppercase argument names
#nowarn "67" // this type test or downcast will always hold
#nowarn "66" // this upcast is unnecessary - the types are identical
#nowarn "58" // possible incorrect indentation..
#nowarn "57" // do not use create_DelegateEvent
#nowarn "51" // address-of operator can occur in the code
#nowarn "1183" // unused 'this' reference
open System
exception ReturnException2ea1f686ef3e4730bedf29e248ff4aab of obj
exception ReturnNoneException2ea1f686ef3e4730bedf29e248ff4aab
[<AutoOpen>]
module FuncConvertFinalOverload2ea1f686ef3e4730bedf29e248ff4aab =
// This extension member adds to the FuncConvert type and is the last resort member in the method overloading rules.
type global.Microsoft.FSharp.Core.FuncConvert with
/// A utility function to convert function values from tupled to curried form
static member FuncFromTupled (f:'T -> 'Res) = f
type
Class1 = class
new() as this =
{
}
static member UnnamedMethod_0 () =
System.Console.WriteLine("Hello CodeDOM World!") |> ignore
end
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module __EntryPoint =
[<EntryPoint>]
let Main (args:string[]) =
Class1.UnnamedMethod_0()
0
view raw gistfile1.fs hosted with ❤ by GitHub

which is a little idiosyncratic; the GUID-named types seem to be there in case of need from some construct that is not actually used in this simple example.

Now it just comes down to assembling to code object graph for something practical.

No comments :