-
Notifications
You must be signed in to change notification settings - Fork 69
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Wrapper Generator to generator wrapper classes usable from C#
- Loading branch information
hmansell
committed
Sep 6, 2012
1 parent
70cccb5
commit 090ddc1
Showing
4 changed files
with
227 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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> |