Skip to content
This repository
Browse code

Add Wrapper Generator to generator wrapper classes usable from C#

  • Loading branch information...
commit 090ddc1e950ff78d33129a2e8e2b8f7c9f94481c 1 parent 70cccb5
Howard Mansell hmansell authored
6 RProvider.sln
@@ -3,6 +3,8 @@ Microsoft Visual Studio Solution File, Format Version 12.00
3 3 # Visual Studio 2012
4 4 Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "RProvider", "RProvider.fsproj", "{5624F098-BE3F-4C8E-B50F-1CFC9E1E0708}"
5 5 EndProject
  6 +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "RWrapperGenerator", "RWrapperGenerator\RWrapperGenerator.fsproj", "{66A390A5-526A-4BD1-B876-E7425B643C70}"
  7 +EndProject
6 8 Global
7 9 GlobalSection(SolutionConfigurationPlatforms) = preSolution
8 10 Debug|Any CPU = Debug|Any CPU
@@ -13,6 +15,10 @@ Global
13 15 {5624F098-BE3F-4C8E-B50F-1CFC9E1E0708}.Debug|Any CPU.Build.0 = Debug|Any CPU
14 16 {5624F098-BE3F-4C8E-B50F-1CFC9E1E0708}.Release|Any CPU.ActiveCfg = Release|Any CPU
15 17 {5624F098-BE3F-4C8E-B50F-1CFC9E1E0708}.Release|Any CPU.Build.0 = Release|Any CPU
  18 + {66A390A5-526A-4BD1-B876-E7425B643C70}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
  19 + {66A390A5-526A-4BD1-B876-E7425B643C70}.Debug|Any CPU.Build.0 = Debug|Any CPU
  20 + {66A390A5-526A-4BD1-B876-E7425B643C70}.Release|Any CPU.ActiveCfg = Release|Any CPU
  21 + {66A390A5-526A-4BD1-B876-E7425B643C70}.Release|Any CPU.Build.0 = Release|Any CPU
16 22 EndGlobalSection
17 23 GlobalSection(SolutionProperties) = preSolution
18 24 HideSolutionNode = FALSE
17 RWrapperGenerator/App.config
... ... @@ -0,0 +1,17 @@
  1 +<?xml version="1.0" encoding="utf-8" ?>
  2 +<configuration>
  3 + <startup>
  4 + <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  5 + </startup>
  6 + <runtime>
  7 + <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
  8 + <dependentAssembly>
  9 + <assemblyIdentity name="FSharp.Core" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
  10 + <bindingRedirect oldVersion="4.0.0.0" newVersion="4.3.0.0"/>
  11 + <bindingRedirect oldVersion="2.3.5.0" newVersion="4.3.0.0"/>
  12 + <bindingRedirect oldVersion="2.0.0.0" newVersion="4.3.0.0"/>
  13 +
  14 + </dependentAssembly>
  15 + </assemblyBinding>
  16 + </runtime>
  17 +</configuration>
122 RWrapperGenerator/Program.fs
... ... @@ -0,0 +1,122 @@
  1 +open RProvider.RInterop
  2 +open RProvider.RInteropInternal
  3 +open System.IO
  4 +open System
  5 +open System.Collections.Generic
  6 +open System.Globalization
  7 +
  8 +let preamble = @"
  9 +using System;
  10 +using RDotNet;
  11 +using RProvider;
  12 +
  13 +namespace RWrappers {
  14 +"
  15 +
  16 +// Attempt to encode C# identifier rules from http://msdn.microsoft.com/en-us/library/aa664670(v=VS.71).aspx
  17 +let isValidIdentifier (identifier: string) =
  18 + let isLetterCharacter c =
  19 + match Char.GetUnicodeCategory(c) with
  20 + | UnicodeCategory.LowercaseLetter | UnicodeCategory.UppercaseLetter | UnicodeCategory.LetterNumber
  21 + | UnicodeCategory.ModifierLetter | UnicodeCategory.OtherLetter | UnicodeCategory.TitlecaseLetter -> true
  22 + | _ -> false
  23 +
  24 + let isValidStartCharacter c =
  25 + isLetterCharacter c || c = '_'
  26 +
  27 + let isValidPartCharacter c =
  28 + match Char.GetUnicodeCategory(c) with
  29 + | UnicodeCategory.DecimalDigitNumber | UnicodeCategory.ConnectorPunctuation | UnicodeCategory.SpacingCombiningMark | UnicodeCategory.Format -> true
  30 + | _ when isLetterCharacter c -> true
  31 + | _ -> false
  32 +
  33 + let identifier = identifier.Replace("_","__").Replace(".", "_")
  34 + isValidStartCharacter identifier.[0] && Array.TrueForAll(identifier.ToCharArray(), Predicate<char> isValidPartCharacter)
  35 +
  36 +// C# Keywords from http://msdn.microsoft.com/en-us/library/aa664671(v=vs.71)
  37 +let isKeyword = function
  38 + | "abstract" | "as" | "base" | "bool" | "break" | "byte" | "case" | "catch" | "char" | "checked" | "class"
  39 + | "const" | "continue" | "decimal" | "default" | "delegate" | "do" | "double" | "else" | "enum" | "event"
  40 + | "explicit" | "extern" | "false" | "finally" | "fixed" | "float" | "for" | "foreach" | "goto" | "if" | "implicit"
  41 + | "in" | "int" | "interface" | "internal" | "is" | "lock" | "long" | "namespace" | "new" | "null" | "object" | "operator"
  42 + | "out" | "override" | "params" | "private" | "protected" | "public" | "readonly" | "ref" | "return" | "sbyte" | "sealed"
  43 + | "short" | "sizeof" | "stackalloc" | "static" | "string" | "struct" | "switch" | "this" | "throw" | "true" | "try"
  44 + | "typeof" | "uint" | "ulong" | "unchecked" | "unsafe" | "ushort" | "using" | "virtual" | "void" | "volatile" | "while" -> true
  45 + | _ -> false
  46 +
  47 +let rec safeName name =
  48 + if isKeyword name then
  49 + // This prefixes allows us to use keywords as identifiers
  50 + "@" + name
  51 + else
  52 + // Dots are so common that we replace with underscore, and we replace underscore with double-underscore.
  53 + name.Replace("_","__").Replace(".", "_")
  54 +
  55 +let internal generateProperty (writer: TextWriter) (packageName: string) (name: string) =
  56 + fprintfn writer "\t\tpublic static SymbolicExpression %s { get { return RInterop.call(\"%s\", \"%s\", emptyArr, emptyArr); } }\n" (safeName name) packageName name
  57 +
  58 +let internal generateFunction (writer: TextWriter) (packageName: string) (name: string) (args: RParameter list) (hasVarArgs: bool) =
  59 + let argArr = [|
  60 + for arg in args -> sprintf "object %s = null" (safeName arg)
  61 + if hasVarArgs then yield "params object[] paramArray"
  62 + |]
  63 +
  64 + fprintfn writer "\t\tpublic static SymbolicExpression %s(%s) {" (safeName name) (String.Join(", ", argArr))
  65 + let argsPass = String.Join(", ", args |> List.map safeName |> List.toArray)
  66 + fprintfn writer "\t\t\tvar namedArgs = new object[] { %s };" argsPass
  67 + fprintfn writer "\t\t\treturn RInterop.call(\"%s\", \"%s\", namedArgs, %s);" packageName name (if hasVarArgs then "paramArray" else "emptyArr")
  68 + fprintfn writer "\t\t}\n"
  69 +
  70 +let generatePackage (writer: TextWriter) (exposedNames: HashSet<string>) (packageName: string) =
  71 + //fprintfn writer "\tpublic class %s {" (safeName packageName)
  72 + //fprintfn writer "\t\tprivate static object[] emptyArr = new object[0];"
  73 +
  74 + loadPackage packageName
  75 +
  76 + for name, rval in Map.toSeq (getBindings packageName) do
  77 + let name = if exposedNames.Contains(name) then packageName + "." + name else name
  78 +
  79 + match rval with
  80 + | RValue.Value -> generateProperty writer packageName name
  81 + | RValue.Function(args, hasVarArgs) -> if isValidIdentifier name then generateFunction writer packageName name args hasVarArgs
  82 +
  83 + ignore <| exposedNames.Add(name)
  84 +
  85 + //fprintfn writer "}"
  86 +
  87 +let parseArgs (argv: string[]) =
  88 + Map.ofSeq [
  89 + for arg in argv ->
  90 + let idx = arg.IndexOf("=")
  91 + if idx < 0 then
  92 + let k = if arg.[0] = '/' then arg.Substring(1) else arg
  93 + k, k
  94 + else
  95 + let k = if arg.[0] = '/' then arg.Substring(1, idx - 1) else arg.Substring(0, idx)
  96 + let v = arg.Substring(idx + 1)
  97 + k, v
  98 + ]
  99 +
  100 +[<EntryPoint>]
  101 +let main argv =
  102 + let args = parseArgs argv
  103 + let outFile, packages =
  104 + match (args.TryFind "outFile"), (args.TryFind "packages") with
  105 + | Some outFile, Some packages -> outFile, packages
  106 + | _ -> failwithf "Usage:\n\nRWrapperGenerator outFile=<outfilename> packages=<PackageNames>\nwhere PackageNames is a comma-separated list of R package names"
  107 +
  108 + use writer = new StreamWriter(outFile)
  109 +
  110 + fprintfn writer "%s" preamble
  111 +
  112 + let exposedNames = new HashSet<string>()
  113 +
  114 + fprintfn writer "\tpublic class R {"
  115 + fprintfn writer "\t\tprivate static object[] emptyArr = new object[0];\n"
  116 +
  117 + Seq.iter (generatePackage writer exposedNames) (packages.Split([|','|], StringSplitOptions.RemoveEmptyEntries))
  118 +
  119 + fprintfn writer "\t}"
  120 + fprintfn writer "}"
  121 +
  122 + 0
82 RWrapperGenerator/RWrapperGenerator.fsproj
... ... @@ -0,0 +1,82 @@
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  3 + <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
  4 + <PropertyGroup>
  5 + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
  6 + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
  7 + <SchemaVersion>2.0</SchemaVersion>
  8 + <ProjectGuid>66a390a5-526a-4bd1-b876-e7425b643c70</ProjectGuid>
  9 + <OutputType>Exe</OutputType>
  10 + <RootNamespace>RWrapperGenerator</RootNamespace>
  11 + <AssemblyName>RWrapperGenerator</AssemblyName>
  12 + <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
  13 + <Name>RWrapperGenerator</Name>
  14 + </PropertyGroup>
  15 + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
  16 + <DebugSymbols>true</DebugSymbols>
  17 + <DebugType>full</DebugType>
  18 + <Optimize>false</Optimize>
  19 + <Tailcalls>false</Tailcalls>
  20 + <OutputPath>bin\Debug\</OutputPath>
  21 + <DefineConstants>DEBUG;TRACE</DefineConstants>
  22 + <WarningLevel>3</WarningLevel>
  23 + <PlatformTarget>AnyCPU</PlatformTarget>
  24 + <DocumentationFile>bin\Debug\RWrapperGenerator.XML</DocumentationFile>
  25 + <Prefer32Bit>true</Prefer32Bit>
  26 + <StartArguments>/outFile=c:\temp\out.cs /packges=base,stats,graphics,grDevices,tseries,zoo</StartArguments>
  27 + </PropertyGroup>
  28 + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
  29 + <DebugType>pdbonly</DebugType>
  30 + <Optimize>true</Optimize>
  31 + <Tailcalls>true</Tailcalls>
  32 + <OutputPath>bin\Release\</OutputPath>
  33 + <DefineConstants>TRACE</DefineConstants>
  34 + <WarningLevel>3</WarningLevel>
  35 + <PlatformTarget>AnyCPU</PlatformTarget>
  36 + <DocumentationFile>bin\Release\RWrapperGenerator.XML</DocumentationFile>
  37 + <Prefer32Bit>true</Prefer32Bit>
  38 + </PropertyGroup>
  39 + <ItemGroup>
  40 + <Reference Include="mscorlib" />
  41 + <Reference Include="FSharp.Core, Version=4.3.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
  42 + <Private>True</Private>
  43 + </Reference>
  44 + <Reference Include="RDotNet">
  45 + <HintPath>..\..\Sierra\3rdParty\RProvider\RDotNet.dll</HintPath>
  46 + </Reference>
  47 + <Reference Include="RDotNet.NativeLibrary">
  48 + <HintPath>..\..\Sierra\3rdParty\RProvider\RDotNet.NativeLibrary.dll</HintPath>
  49 + </Reference>
  50 + <Reference Include="System" />
  51 + <Reference Include="System.ComponentModel.Composition" />
  52 + <Reference Include="System.Core" />
  53 + <Reference Include="System.Numerics" />
  54 + </ItemGroup>
  55 + <ItemGroup>
  56 + <None Include="App.config" />
  57 + <Compile Include="..\ProvidedTypes-0.2.fsi">
  58 + <Link>ProvidedTypes-0.2.fsi</Link>
  59 + </Compile>
  60 + <Compile Include="..\ProvidedTypes-0.2.fs">
  61 + <Link>ProvidedTypes-0.2.fs</Link>
  62 + </Compile>
  63 + <Compile Include="..\CharacterDeviceInterceptor.fs">
  64 + <Link>CharacterDeviceInterceptor.fs</Link>
  65 + </Compile>
  66 + <Compile Include="..\RInterop.fs">
  67 + <Link>RInterop.fs</Link>
  68 + </Compile>
  69 + <Compile Include="Program.fs" />
  70 + </ItemGroup>
  71 + <PropertyGroup>
  72 + <MinimumVisualStudioVersion Condition="'$(MinimumVisualStudioVersion)' == ''">11</MinimumVisualStudioVersion>
  73 + </PropertyGroup>
  74 + <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')" />
  75 + <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
  76 + Other similar extension points exist, see Microsoft.Common.targets.
  77 + <Target Name="BeforeBuild">
  78 + </Target>
  79 + <Target Name="AfterBuild">
  80 + </Target>
  81 + -->
  82 +</Project>

0 comments on commit 090ddc1

Please sign in to comment.
Something went wrong with that request. Please try again.