Skip to content

fscx-projects/fscx-sample-filters

Repository files navigation

Expandable F# compiler (fscx) sample filters

fscx-projects

Expandable F# compiler (fscx) is an alternative F# compiler which enables to replace F#'s AST at compile time. This repository contains sample filter source codes.

  • TODO: This project is still work in progress, and need more documents.

Status

NuGet (aspect) NuGet fscx-sample-aspect-filter
NuGet (functional) NuGet fscx-sample-functional-filter
NuGet (inheritable) NuGet fscx-sample-inheritable-filter
Issue status Issue Stats
Pull req PR Stats

What's "filter" ?

  • "fscx filter" is attaching for F# build process by fscx.
  • This repository contains "sample_functional_filter" and "sample_inheritable_filter" projects, both equals applying results for insert code "function entry-exit logging out (System.Console.WriteLine)" AUTOMATED. Thats mean AOP (aspect oriented paradigm).

Try to use sample filter:

  • Add NuGet package "fscx-sample-functional-filter" or "fscx-sample-inheritable-filter" for your F# project.
  • Build, and try execute your code or disassemble (by ILSpy and like).

Guide for sample filter projects:

  • "sample_functional_filter" project are contains how to compose F#'s AST for using "Functional visitor pattern".
  • "sample_inheritable_filter" project are contains how to compose F#'s AST for using "Traditional tree visitor pattern".
  • "fscx-enabled" project are containing sample target codes with appling for "fscx-sample-functional-filter" NuGet package.
  • "fscx-enabled-main" is main executable project referencing for "fscx-enabled".
  • "no-fscx-enabled*" are different for not applied filter package.

Functional visitor implementation:

  • "Functional filter" is using for functional visitor patterns with F#'s AST (FSharp.Compiler.Services untyped AST).
    • If you are implemented visitor functions, try declare class with inherit from "DeclareAstFunctionalVisitor" class.
    • "DeclareAstFunctionalVisitor" are abstract classes, generic version and non-generic version. Generic argument is "Context type". Context is depending any information holds for your implementations. Implicit applied "NoContext" type for non-generic version.
// Functional visitor pattern (Not use custom context):
let outerVisitor
   (defaultVisitor: (FscxVisitorContext<NoContext> * SynExpr -> SynExpr),
    context: FscxVisitorContext<NoContext>,  // (NoContext: Non custom context type)
    expr: SynExpr) : SynExpr option =

  match expr with
  | SynExpr.Quote(operator, _, _, _, _) ->
    // DEBUG
    printfn "%A" operator
    None  // (None is default visiting)

  | SynExpr.App(exprAtomicFlag, isInfix, funcExpr, argExpr, range) ->
    match funcExpr with
      // ...

  | _ ->
    None  // (None is default visiting)
 
// Declare your own functional visitor.
// Type name for free.
type InsertLoggingVisitor() =
  inherit DeclareAstFunctionalVisitor(outerVisitor)

Inheritable visitor implementation:

  • "Inheritable filter" is using for traditional visitor patterns with F#'s AST.
    • If you are implemented visitor class inherit from "AstInheritableVisitor" class.
    • "AstInheritableVisitor" are abstract classes, generic version and non-generic version. Generic argument is "Context type" likely DeclareAstFunctionalVisitor.
    • This class likely "System.Linq.Expressions.ExpressionVisitor" class.
// Inheritable visitor pattern (Non generic version: Not use custom context):
// Type name for free.
type InsertLoggingVisitor() =
  inherit AstInheritableVisitor()

  override __.VisitExpr_Quote(context, operator, isRaw, quoteSynExpr, isFromQueryExpression, range) =
    // DEBUG
    printfn "%A" operator
    base.VisitExpr_Quote(context, operator, isRaw, quoteSynExpr, isFromQueryExpression, range)

  override this.VisitExpr_App(context, exprAtomicFlag, isInfix, funcExpr, argExpr, range) =
    match funcExpr with
      // ...
  • Default visiting is derivng from AstInheritableVisitor class.
  • Hooking point are "BeforeVisit*" or "Visit*".
    • "BeforeVisit" is givening for all NON-VISITED args.
    • "Visit" is givening for all VISITED args.

Build the package:

  • TODO: Need more informations...

Pack to the filter package, using NuGet with following sample nuspec definitions:

<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
  <metadata>
    <id>fscx-sample-filter</id>
    <version>0.6.2-pre</version>
    <title>fscx-sample-filter</title>
    <authors>Kouji Matsui</authors>
    <owners>Kouji Matsui</owners>
    <summary>Expandable F# compiler's sample custom filter package.</summary>
    <description>Expandable F# compiler's sample custom filter package.</description>
    <copyright>Author: Kouji Matsui, bleis-tift</copyright>
    <projectUrl>http://github.com/fscx-projects/fscx</projectUrl>
    <iconUrl>https://raw.githubusercontent.com/fscx-projects/fscx/master/docs/files/img/fscx_128.png</iconUrl>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <releaseNotes>Expandable F# compiler's sample custom filter package.</releaseNotes>
    <tags>fscx</tags>
    <dependencies>
      <!-- Including fscx dependency is highly recommended. -->
      <dependency id="FSharp.Expandable.Compiler.Build" version="0.7.5" />
    </dependencies>
  </metadata>
  <files>
    <!-- Add filter binaries (and pdb files if needed) into "build" package folder. -->
    <!-- Note that it's not "lib" folder because we should avoid to get these assemblies referenced automatically. -->
    <file src="bin/Debug/sample_filter.dll" target="build" />
    <file src="bin/Debug/sample_filter.pdb" target="build" />
  </files>
</package>
  • Important: Package version must applied "-pre". Because current FSharp.Compiler.Services package (6.0.2) depended pre-released .NET Core assembly (System.Reflection.Metadata.dll, 1.4.1-beta-24227-04).

Debugging filter:

Built your own filter package, try filter debugging with MSBuild custom debug property flag below (fscx-enabled.fsproj):

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.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>
    <Name>fscx-enabled</Name>
    <!-- ... -->
    <RootNamespace>fscx_enabled</RootNamespace>
    <AssemblyName>fscx_enabled</AssemblyName>
    
    <!-- Add debug flag (default is false) -->
    <FscxDebug>true</FscxDebug>
  </PropertyGroup>
  
  <!-- ... -->
  • If "FscxDebug" property is true, then show message box by fscx from MSBuild, and you can attach debugger.

Message box

Resources

Maintainer(s)

About

Expandable F# compiler (fscx) sample filter codes.

Resources

License

Stars

Watchers

Forks

Packages

No packages published