<commit_before>﻿namespace RProvider

open System
open System.ComponentModel.Composition
open System.ComponentModel.Composition.Hosting
open System.Reflection
open System.IO
open System.Diagnostics
open System.Numerics
open System.Threading
open System.Collections.Generic
open System.Linq
open RDotNet

/// Interface to use via MEF
type IConvertToR<'inType> =     
    abstract member Convert : REngine * 'inType -> SymbolicExpression

// Support conversion to an explicitly requested type.
type IConvertFromR<'outType> =     
    abstract member Convert : SymbolicExpression -> Option<'outType>

// Supporting IDefaultConvertFromR indicates that you provide a default converter
type IDefaultConvertFromR =     
    abstract member Convert : SymbolicExpression -> Option<obj>


[<AutoOpen>]
module Helpers = 
    open RDotNet.Internals

    /// Construct named params to pass to function
    let namedParams (s: seq<string*_>) = dict <| Seq.map (fun (n,v) -> n, box v) s

    let (|CharacterVector|_|) (sexp: SymbolicExpression)  = if sexp.Type = SymbolicExpressionType.CharacterVector then Some(sexp.AsCharacter()) else None
    let (|ComplexVector|_|)   (sexp: SymbolicExpression)  = if sexp.Type = SymbolicExpressionType.ComplexVector   then Some(sexp.AsComplex()) else None
    let (|IntegerVector|_|)   (sexp: SymbolicExpression)  = if sexp.Type = SymbolicExpressionType.IntegerVector   then Some(sexp.AsInteger()) else None
    let (|LogicalVector|_|)   (sexp: SymbolicExpression)  = if sexp.Type = SymbolicExpressionType.LogicalVector   then Some(sexp.AsLogical()) else None
    let (|NumericVector|_|)   (sexp: SymbolicExpression)  = if sexp.Type = SymbolicExpressionType.NumericVector   then Some(sexp.AsNumeric()) else None

    let (|Function|_|)        (sexp: SymbolicExpression)  = 
        if sexp.Type = SymbolicExpressionType.BuiltinFunction || sexp.Type = SymbolicExpressionType.Closure || sexp.Type = SymbolicExpressionType.SpecialFunction then 
            Some(sexp.AsFunction()) else None

    let (|BuiltinFunction|_|) (sexp: SymbolicExpression)  = if sexp.Type = SymbolicExpressionType.BuiltinFunction then Some(sexp.AsFunction() :?> BuiltinFunction) else None
    let (|Closure|_|)         (sexp: SymbolicExpression)  = if sexp.Type = SymbolicExpressionType.Closure then Some(sexp.AsFunction() :?> Closure) else None
    let (|SpecialFunction|_|) (sexp: SymbolicExpression)  = if sexp.Type = SymbolicExpressionType.SpecialFunction then Some(sexp.AsFunction() :?> SpecialFunction) else None

    let (|Environment|_|)   (sexp: SymbolicExpression)    = if sexp.Type = SymbolicExpressionType.Environment  then Some(sexp.AsEnvironment()) else None
    let (|Expression|_|)    (sexp: SymbolicExpression)    = if sexp.Type = SymbolicExpressionType.ExpressionVector then Some(sexp.AsExpression()) else None
    let (|Language|_|)      (sexp: SymbolicExpression)    = if sexp.Type = SymbolicExpressionType.LanguageObject then Some(sexp.AsLanguage()) else None
    let (|List|_|)          (sexp: SymbolicExpression)    = if sexp.Type = SymbolicExpressionType.List then Some(sexp.AsList()) else None     
    let (|Pairlist|_|)      (sexp: SymbolicExpression)    = if sexp.Type = SymbolicExpressionType.Pairlist then Some(sexp :?> Pairlist) else None     
    let (|Null|_|)          (sexp: SymbolicExpression)    = if sexp.Type = SymbolicExpressionType.Null then Some() else None
    let (|Symbol|_|)        (sexp: SymbolicExpression)    = if sexp.Type = SymbolicExpressionType.Symbol then Some(sexp.AsSymbol()) else None

module internal RInteropInternal =
    type RParameter = {
        Name: string
        Optional: bool
    }

    type HasVarArgs = bool

    type RValue =
        | Function of RParameter list * HasVarArgs
        | Value

    open Microsoft.Win32

    let characterDevice = new CharacterDeviceInterceptor()

    // If the registry is set up, use that for configuring the path
    let rCore = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\R-core")
    if rCore <> null then
        let is64bit = Environment.Is64BitProcess
        let subKeyName = if is64bit then "R64" else "R"
        let key = rCore.OpenSubKey(subKeyName)
        if key = null then
            failwithf "SOFTWARE\R-core exists but subkey %s does not exist" subKeyName

        let installPath = key.GetValue("InstallPath") :?> string
        let binPath = Path.Combine(installPath, "bin", if is64bit then "x64" else "i386")

        // Set the path
        Environment.SetEnvironmentVariable("PATH", Environment.GetEnvironmentVariable("PATH") + ";" + binPath)

    let engine = REngine.CreateInstance("RProvider")
    do engine.Initialize(null, characterDevice)

    let private mefContainer = 
        lazy
            // Look for plugins co-located with RProvider.dll
            let assem = typeof<IConvertToR<_>>.Assembly
            let catalog = new DirectoryCatalog(Path.GetDirectoryName(assem.Location),"*.Plugin.dll")
            new CompositionContainer(catalog)
                
    let internal toRConv = Collections.Generic.Dictionary<Type, REngine -> obj -> SymbolicExpression>()

    /// Register a function that will convert from a specific type to a value in R.
    /// Alternatively, you can build a MEF plugin that exports IConvertToR.
    /// registerToR is more suitable for experimentation in F# interactive.
    let registerToR<'inType> (conv: REngine -> 'inType -> SymbolicExpression) = 
        let conv' rengine (value: obj) = unbox value |> conv rengine 
        toRConv.[typeof<'inType>] <- conv'<commit_msg>Trap RDotNet initialization errors and enrich exception<commit_after>﻿namespace RProvider

open System
open System.ComponentModel.Composition
open System.ComponentModel.Composition.Hosting
open System.Reflection
open System.IO
open System.Diagnostics
open System.Numerics
open System.Threading
open System.Collections.Generic
open System.Linq
open RDotNet

/// Interface to use via MEF
type IConvertToR<'inType> =     
    abstract member Convert : REngine * 'inType -> SymbolicExpression

// Support conversion to an explicitly requested type.
type IConvertFromR<'outType> =     
    abstract member Convert : SymbolicExpression -> Option<'outType>

// Supporting IDefaultConvertFromR indicates that you provide a default converter
type IDefaultConvertFromR =     
    abstract member Convert : SymbolicExpression -> Option<obj>


[<AutoOpen>]
module Helpers = 
    open RDotNet.Internals

    /// Construct named params to pass to function
    let namedParams (s: seq<string*_>) = dict <| Seq.map (fun (n,v) -> n, box v) s

    let (|CharacterVector|_|) (sexp: SymbolicExpression)  = if sexp.Type = SymbolicExpressionType.CharacterVector then Some(sexp.AsCharacter()) else None
    let (|ComplexVector|_|)   (sexp: SymbolicExpression)  = if sexp.Type = SymbolicExpressionType.ComplexVector   then Some(sexp.AsComplex()) else None
    let (|IntegerVector|_|)   (sexp: SymbolicExpression)  = if sexp.Type = SymbolicExpressionType.IntegerVector   then Some(sexp.AsInteger()) else None
    let (|LogicalVector|_|)   (sexp: SymbolicExpression)  = if sexp.Type = SymbolicExpressionType.LogicalVector   then Some(sexp.AsLogical()) else None
    let (|NumericVector|_|)   (sexp: SymbolicExpression)  = if sexp.Type = SymbolicExpressionType.NumericVector   then Some(sexp.AsNumeric()) else None

    let (|Function|_|)        (sexp: SymbolicExpression)  = 
        if sexp.Type = SymbolicExpressionType.BuiltinFunction || sexp.Type = SymbolicExpressionType.Closure || sexp.Type = SymbolicExpressionType.SpecialFunction then 
            Some(sexp.AsFunction()) else None

    let (|BuiltinFunction|_|) (sexp: SymbolicExpression)  = if sexp.Type = SymbolicExpressionType.BuiltinFunction then Some(sexp.AsFunction() :?> BuiltinFunction) else None
    let (|Closure|_|)         (sexp: SymbolicExpression)  = if sexp.Type = SymbolicExpressionType.Closure then Some(sexp.AsFunction() :?> Closure) else None
    let (|SpecialFunction|_|) (sexp: SymbolicExpression)  = if sexp.Type = SymbolicExpressionType.SpecialFunction then Some(sexp.AsFunction() :?> SpecialFunction) else None

    let (|Environment|_|)   (sexp: SymbolicExpression)    = if sexp.Type = SymbolicExpressionType.Environment  then Some(sexp.AsEnvironment()) else None
    let (|Expression|_|)    (sexp: SymbolicExpression)    = if sexp.Type = SymbolicExpressionType.ExpressionVector then Some(sexp.AsExpression()) else None
    let (|Language|_|)      (sexp: SymbolicExpression)    = if sexp.Type = SymbolicExpressionType.LanguageObject then Some(sexp.AsLanguage()) else None
    let (|List|_|)          (sexp: SymbolicExpression)    = if sexp.Type = SymbolicExpressionType.List then Some(sexp.AsList()) else None     
    let (|Pairlist|_|)      (sexp: SymbolicExpression)    = if sexp.Type = SymbolicExpressionType.Pairlist then Some(sexp :?> Pairlist) else None     
    let (|Null|_|)          (sexp: SymbolicExpression)    = if sexp.Type = SymbolicExpressionType.Null then Some() else None
    let (|Symbol|_|)        (sexp: SymbolicExpression)    = if sexp.Type = SymbolicExpressionType.Symbol then Some(sexp.AsSymbol()) else None

module internal RInteropInternal =
    type RParameter = {
        Name: string
        Optional: bool
    }

    type HasVarArgs = bool

    type RValue =
        | Function of RParameter list * HasVarArgs
        | Value

    open Microsoft.Win32

    let characterDevice = new CharacterDeviceInterceptor()

    // If the registry is set up, use that for configuring the path
    let rCore = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\R-core")
    if rCore <> null then
        let is64bit = Environment.Is64BitProcess
        let subKeyName = if is64bit then "R64" else "R"
        let key = rCore.OpenSubKey(subKeyName)
        if key = null then
            failwithf "SOFTWARE\R-core exists but subkey %s does not exist" subKeyName

        let installPath = key.GetValue("InstallPath") :?> string
        let binPath = Path.Combine(installPath, "bin", if is64bit then "x64" else "i386")

        // Set the path
        Environment.SetEnvironmentVariable("PATH", Environment.GetEnvironmentVariable("PATH") + ";" + binPath)

    let engine = 
        try
            let engine = REngine.CreateInstance("RProvider")
            do engine.Initialize(null, characterDevice)
            engine
        with
        | e -> raise(Exception("Initialization of R.NET failed", e))

    let private mefContainer = 
        lazy
            // Look for plugins co-located with RProvider.dll
            let assem = typeof<IConvertToR<_>>.Assembly
            let catalog = new DirectoryCatalog(Path.GetDirectoryName(assem.Location),"*.Plugin.dll")
            new CompositionContainer(catalog)
                
    let internal toRConv = Collections.Generic.Dictionary<Type, REngine -> obj -> SymbolicExpression>()

    /// Register a function that will convert from a specific type to a value in R.
    /// Alternatively, you can build a MEF plugin that exports IConvertToR.
    /// registerToR is more suitable for experimentation in F# interactive.
    let registerToR<'inType> (conv: REngine -> 'inType -> SymbolicExpression) = 
        let conv' rengine (value: obj) = unbox value |> conv rengine 
        toRConv.[typeof<'inType>] <- conv'
{'fraction_non_alphanumeric': 0.09699441439843957, 'fraction_numerical': 0.003014451635783314, 'mean_word_length': 3.5301204819277108, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 56, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2697147', 'n_tokens_mistral': 3291, 'n_tokens_neox': 3258, 'n_words': 918}