Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Add Wrapper Generator to generator wrapper classes usable from C#

  • Loading branch information...
commit 090ddc1e950ff78d33129a2e8e2b8f7c9f94481c 1 parent 70cccb5
@hmansell hmansell authored
View
6 RProvider.sln
@@ -3,6 +3,8 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "RProvider", "RProvider.fsproj", "{5624F098-BE3F-4C8E-B50F-1CFC9E1E0708}"
EndProject
+Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "RWrapperGenerator", "RWrapperGenerator\RWrapperGenerator.fsproj", "{66A390A5-526A-4BD1-B876-E7425B643C70}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -13,6 +15,10 @@ Global
{5624F098-BE3F-4C8E-B50F-1CFC9E1E0708}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5624F098-BE3F-4C8E-B50F-1CFC9E1E0708}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5624F098-BE3F-4C8E-B50F-1CFC9E1E0708}.Release|Any CPU.Build.0 = Release|Any CPU
+ {66A390A5-526A-4BD1-B876-E7425B643C70}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {66A390A5-526A-4BD1-B876-E7425B643C70}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {66A390A5-526A-4BD1-B876-E7425B643C70}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {66A390A5-526A-4BD1-B876-E7425B643C70}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
View
17 RWrapperGenerator/App.config
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+ <startup>
+ <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
+ </startup>
+ <runtime>
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+ <dependentAssembly>
+ <assemblyIdentity name="FSharp.Core" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
+ <bindingRedirect oldVersion="4.0.0.0" newVersion="4.3.0.0"/>
+ <bindingRedirect oldVersion="2.3.5.0" newVersion="4.3.0.0"/>
+ <bindingRedirect oldVersion="2.0.0.0" newVersion="4.3.0.0"/>
+
+ </dependentAssembly>
+ </assemblyBinding>
+ </runtime>
+</configuration>
View
122 RWrapperGenerator/Program.fs
@@ -0,0 +1,122 @@
+open RProvider.RInterop
+open RProvider.RInteropInternal
+open System.IO
+open System
+open System.Collections.Generic
+open System.Globalization
+
+let preamble = @"
+using System;
+using RDotNet;
+using RProvider;
+
+namespace RWrappers {
+"
+
+// Attempt to encode C# identifier rules from http://msdn.microsoft.com/en-us/library/aa664670(v=VS.71).aspx
+let isValidIdentifier (identifier: string) =
+ let isLetterCharacter c =
+ match Char.GetUnicodeCategory(c) with
+ | UnicodeCategory.LowercaseLetter | UnicodeCategory.UppercaseLetter | UnicodeCategory.LetterNumber
+ | UnicodeCategory.ModifierLetter | UnicodeCategory.OtherLetter | UnicodeCategory.TitlecaseLetter -> true
+ | _ -> false
+
+ let isValidStartCharacter c =
+ isLetterCharacter c || c = '_'
+
+ let isValidPartCharacter c =
+ match Char.GetUnicodeCategory(c) with
+ | UnicodeCategory.DecimalDigitNumber | UnicodeCategory.ConnectorPunctuation | UnicodeCategory.SpacingCombiningMark | UnicodeCategory.Format -> true
+ | _ when isLetterCharacter c -> true
+ | _ -> false
+
+ let identifier = identifier.Replace("_","__").Replace(".", "_")
+ isValidStartCharacter identifier.[0] && Array.TrueForAll(identifier.ToCharArray(), Predicate<char> isValidPartCharacter)
+
+// C# Keywords from http://msdn.microsoft.com/en-us/library/aa664671(v=vs.71)
+let isKeyword = function
+ | "abstract" | "as" | "base" | "bool" | "break" | "byte" | "case" | "catch" | "char" | "checked" | "class"
+ | "const" | "continue" | "decimal" | "default" | "delegate" | "do" | "double" | "else" | "enum" | "event"
+ | "explicit" | "extern" | "false" | "finally" | "fixed" | "float" | "for" | "foreach" | "goto" | "if" | "implicit"
+ | "in" | "int" | "interface" | "internal" | "is" | "lock" | "long" | "namespace" | "new" | "null" | "object" | "operator"
+ | "out" | "override" | "params" | "private" | "protected" | "public" | "readonly" | "ref" | "return" | "sbyte" | "sealed"
+ | "short" | "sizeof" | "stackalloc" | "static" | "string" | "struct" | "switch" | "this" | "throw" | "true" | "try"
+ | "typeof" | "uint" | "ulong" | "unchecked" | "unsafe" | "ushort" | "using" | "virtual" | "void" | "volatile" | "while" -> true
+ | _ -> false
+
+let rec safeName name =
+ if isKeyword name then
+ // This prefixes allows us to use keywords as identifiers
+ "@" + name
+ else
+ // Dots are so common that we replace with underscore, and we replace underscore with double-underscore.
+ name.Replace("_","__").Replace(".", "_")
+
+let internal generateProperty (writer: TextWriter) (packageName: string) (name: string) =
+ fprintfn writer "\t\tpublic static SymbolicExpression %s { get { return RInterop.call(\"%s\", \"%s\", emptyArr, emptyArr); } }\n" (safeName name) packageName name
+
+let internal generateFunction (writer: TextWriter) (packageName: string) (name: string) (args: RParameter list) (hasVarArgs: bool) =
+ let argArr = [|
+ for arg in args -> sprintf "object %s = null" (safeName arg)
+ if hasVarArgs then yield "params object[] paramArray"
+ |]
+
+ fprintfn writer "\t\tpublic static SymbolicExpression %s(%s) {" (safeName name) (String.Join(", ", argArr))
+ let argsPass = String.Join(", ", args |> List.map safeName |> List.toArray)
+ fprintfn writer "\t\t\tvar namedArgs = new object[] { %s };" argsPass
+ fprintfn writer "\t\t\treturn RInterop.call(\"%s\", \"%s\", namedArgs, %s);" packageName name (if hasVarArgs then "paramArray" else "emptyArr")
+ fprintfn writer "\t\t}\n"
+
+let generatePackage (writer: TextWriter) (exposedNames: HashSet<string>) (packageName: string) =
+ //fprintfn writer "\tpublic class %s {" (safeName packageName)
+ //fprintfn writer "\t\tprivate static object[] emptyArr = new object[0];"
+
+ loadPackage packageName
+
+ for name, rval in Map.toSeq (getBindings packageName) do
+ let name = if exposedNames.Contains(name) then packageName + "." + name else name
+
+ match rval with
+ | RValue.Value -> generateProperty writer packageName name
+ | RValue.Function(args, hasVarArgs) -> if isValidIdentifier name then generateFunction writer packageName name args hasVarArgs
+
+ ignore <| exposedNames.Add(name)
+
+ //fprintfn writer "}"
+
+let parseArgs (argv: string[]) =
+ Map.ofSeq [
+ for arg in argv ->
+ let idx = arg.IndexOf("=")
+ if idx < 0 then
+ let k = if arg.[0] = '/' then arg.Substring(1) else arg
+ k, k
+ else
+ let k = if arg.[0] = '/' then arg.Substring(1, idx - 1) else arg.Substring(0, idx)
+ let v = arg.Substring(idx + 1)
+ k, v
+ ]
+
+[<EntryPoint>]
+let main argv =
+ let args = parseArgs argv
+ let outFile, packages =
+ match (args.TryFind "outFile"), (args.TryFind "packages") with
+ | Some outFile, Some packages -> outFile, packages
+ | _ -> failwithf "Usage:\n\nRWrapperGenerator outFile=<outfilename> packages=<PackageNames>\nwhere PackageNames is a comma-separated list of R package names"
+
+ use writer = new StreamWriter(outFile)
+
+ fprintfn writer "%s" preamble
+
+ let exposedNames = new HashSet<string>()
+
+ fprintfn writer "\tpublic class R {"
+ fprintfn writer "\t\tprivate static object[] emptyArr = new object[0];\n"
+
+ Seq.iter (generatePackage writer exposedNames) (packages.Split([|','|], StringSplitOptions.RemoveEmptyEntries))
+
+ fprintfn writer "\t}"
+ fprintfn writer "}"
+
+ 0
View
82 RWrapperGenerator/RWrapperGenerator.fsproj
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>66a390a5-526a-4bd1-b876-e7425b643c70</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <RootNamespace>RWrapperGenerator</RootNamespace>
+ <AssemblyName>RWrapperGenerator</AssemblyName>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <Name>RWrapperGenerator</Name>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <Tailcalls>false</Tailcalls>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <WarningLevel>3</WarningLevel>
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ <DocumentationFile>bin\Debug\RWrapperGenerator.XML</DocumentationFile>
+ <Prefer32Bit>true</Prefer32Bit>
+ <StartArguments>/outFile=c:\temp\out.cs /packges=base,stats,graphics,grDevices,tseries,zoo</StartArguments>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <Tailcalls>true</Tailcalls>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <WarningLevel>3</WarningLevel>
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ <DocumentationFile>bin\Release\RWrapperGenerator.XML</DocumentationFile>
+ <Prefer32Bit>true</Prefer32Bit>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="mscorlib" />
+ <Reference Include="FSharp.Core, Version=4.3.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="RDotNet">
+ <HintPath>..\..\Sierra\3rdParty\RProvider\RDotNet.dll</HintPath>
+ </Reference>
+ <Reference Include="RDotNet.NativeLibrary">
+ <HintPath>..\..\Sierra\3rdParty\RProvider\RDotNet.NativeLibrary.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.ComponentModel.Composition" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Numerics" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="App.config" />
+ <Compile Include="..\ProvidedTypes-0.2.fsi">
+ <Link>ProvidedTypes-0.2.fsi</Link>
+ </Compile>
+ <Compile Include="..\ProvidedTypes-0.2.fs">
+ <Link>ProvidedTypes-0.2.fs</Link>
+ </Compile>
+ <Compile Include="..\CharacterDeviceInterceptor.fs">
+ <Link>CharacterDeviceInterceptor.fs</Link>
+ </Compile>
+ <Compile Include="..\RInterop.fs">
+ <Link>RInterop.fs</Link>
+ </Compile>
+ <Compile Include="Program.fs" />
+ </ItemGroup>
+ <PropertyGroup>
+ <MinimumVisualStudioVersion Condition="'$(MinimumVisualStudioVersion)' == ''">11</MinimumVisualStudioVersion>
+ </PropertyGroup>
+ <Import Project="$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets" Condition=" Exists('$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets')" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
Please sign in to comment.
Something went wrong with that request. Please try again.