F# 3.0 Type Provider 正規表現のCompile-time構文チェック

アローハ マハロー


さてType Provider第一弾として紹介するのは
正規表現のCompile-time構文チェック」です。

このように第一型引数で文字列をパターン文字列を渡すことでコンパイル時にパターン文字列の構文チェックを行えます。

type CheckRegex= Regex<".*">

もし不正なパターン文字列が指定された場合は、下記のようなユーザーライクなエラーメッセージが表示されます。



下記がRegex Type Providerのコードです。

namespace TypeProviders.DesignTime

open System
open System.Collections.Generic
open System.Linq.Expressions
open System.Globalization
open System.Reflection
open System.Diagnostics
open Microsoft.FSharp.Core.CompilerServices
open Internal.Utilities.TypeProvider.Emit
open System.IO
open System.Text.RegularExpressions

[<assembly: TypeProviderAssembly>]
do()

type ProvidedType(name, ns, assembly) =
  inherit Type()
  let mutable IsErasedFlag = 1073741824
  let mutable attributes = (TypeAttributes.Public ||| TypeAttributes.Sealed ||| enum IsErasedFlag) 
  override x.GetConstructorImpl(flags: BindingFlags, binder: Binder, cc: CallingConventions, paramTypes: Type[], modifiers: ParameterModifier[]) =  null
  override x.GetMethodImpl(name: string, flags: BindingFlags, binder: Binder, cc: CallingConventions, paramTypes: Type[], modifiers: ParameterModifier[]) = null
  override x.GetPropertyImpl(name: string, flags: BindingFlags, binder: Binder, t: Type, paramTypes: Type[], modifiers: ParameterModifier[]) = null
  override x.GetAttributeFlagsImpl() = attributes
  override x.IsArrayImpl() = false
  override x.IsByRefImpl() = false
  override x.IsPointerImpl() = false
  override x.IsPrimitiveImpl() = false
  override x.IsCOMObjectImpl() = false
  override x.HasElementTypeImpl() = false
  override x.GetMembers(flags: BindingFlags) = [||]
  override x.GUID = Guid.Empty
  override x.InvokeMember(name: string, flags: BindingFlags, binder: Binder, instance: obj, parameters: obj[], modifiers: ParameterModifier[], culture: CultureInfo, names: string[]) = null
  override x.Module = null: Module
  override x.Assembly = assembly
  override x.FullName = sprintf "%s.%s" ns name
  override x.Namespace = ns
  override x.AssemblyQualifiedName = sprintf "%s.%s, %s" ns name assembly.FullName
  override x.BaseType = null
  override x.GetConstructors(flags: BindingFlags) = [||]
  override x.GetMethods(flags: BindingFlags) = [||]
  override x.GetField(name: string, flags: BindingFlags) = null
  override x.GetFields(flags: BindingFlags) = [||]
  override x.GetInterface(name: string, inherited: Boolean) =  null
  override x.GetInterfaces() = [||]
  override x.GetEvent(name: string, flags: BindingFlags) = null
  override x.GetEvents(flags: BindingFlags) =  [||]
  override x.GetProperties(flags: BindingFlags) = [||]
  override x.GetNestedTypes(flags: BindingFlags) = [||]
  override x.GetNestedType(name: string, flags: BindingFlags) = null
  override x.GetElementType() = null
  override x.UnderlyingSystemType = null
  override x.Name = name
  override x.GetCustomAttributes(inherited: Boolean) = [||]
  override x.GetCustomAttributes(t: Type, inherited: Boolean) = [||]
  override x.GetCustomAttributesData() = new ResizeArray<_>() :> IList<_>
  override x.IsDefined(t: Type, inherited: Boolean) = false
  override x.IsSecurityCritical with get() = false
  override x.IsSecuritySafeCritical with get() = false
  override x.IsSecurityTransparent with get() = false
  override x.GetDefaultMembers() = [||]
  override x.GetEnumValues() = [||] :> Array
  member x.IsErased
    with get() = (attributes &&& enum IsErasedFlag) <> TypeAttributes.NotPublic
    and set value =
      if value then
        attributes <- attributes ||| (enum IsErasedFlag)
      else
        attributes <- attributes &&& ~~~ (enum IsErasedFlag)

[<TypeProvider>]
type TypeProviderRoot() =
  let theAssembly = typeof<TypeProviderRoot>.Assembly
  let invalidate = new Event<EventHandler,EventArgs>()
  let ns = "TypeProviders"
  let regexType = ProvidedType ("Regex" , ns, theAssembly, IsErased = true)

  interface ITypeProvider with
    [<CLIEvent>]
    member x.Invalidate = invalidate.Publish
    member x.GetNamespaces() = [| x |] 
    member x.GetStaticParameters(typeWithoutArguments: Type) = 
      [| new ProvidedParameter("pattern", typeof<string>) |]
    member x.ApplyStaticArguments(typeWithoutArguments: Type, typeNameWithArguments: string,  staticArguments: obj[]) = 
      new Regex(staticArguments.[0] :?> string) |> ignore
      ProvidedType (typeNameWithArguments , ns, theAssembly, IsErased = true) :> Type
    member x.GetInvokerExpression(syntheticMethodBase: MethodBase, parameters: ParameterExpression[]) = null: Expression 
    member x.Dispose() = ()
  interface IProvidedNamespace with
    member x.NamespaceName with get() = ns
    member x.GetNestedNamespaces() = [||]
    member x.GetTypes() = [| regexType |]
    member x.ResolveTypeName(typeName: string) = regexType:>Type

今回のコードはbleisとの合作です。
Enjoy F# 3.0 !