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.
NuGet (aspect) | |
---|---|
NuGet (functional) | |
NuGet (inheritable) | |
Issue status | |
Pull req |
- "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).
- 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).
- "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 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 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.
- 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).
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.
- Blog post: About Expandable F# Compiler project - F# Advent Calendar in English 2016
- This post is 23th "F# Advent Calendar in English 2016"
- (In japanese)