Make F# AST parser available without all of FCS
I have some projects which want to manipulate F# ASTs. Doing so generally requires a dependency on the full FSharp.Compiler.Services, as I understand it, and that's a pretty heavyweight dependency; for example, it requires the latest FSharp.Core.
Concrete example: I recently wrote an expect-testing framework WoofWare.Expect, which just wants to do dumb string manipulation, locating string literals and doing source text replacement on them.
Describe the solution you'd like
Separate out AST parsing into a separate NuGet package with extremely lightweight dependencies (old FSharp.Core, etc). This should be sufficient to obtain and inspect ASTs. Ideally it would be possible to use this library to do some very basic output of F# source code for a given AST, but that's not completely necessary (Fantomas is the correct tool for that).
It would be fine to have this library extremely tightly version-coupled to FCS.
Describe alternatives you've considered
None
I think one could try to pull the necessary files in a separate project, and put together the needed seams/stubs in order for it to at least compile.
This would be first approach, needed to evaluate if it is even needed to do something more.
parseFile in the Fantomas.FCS package might do exactly what you want.
(It is not the newest FCS version though, but the one selected for Fantomas.)
Oh interesting - I had forgotten that Fantomas vendors a standalone copy of the AST code! (In that case, this is probably only really worth doing to help Fantomas maintenance.)
Would it be possible to try that as a standalone .fsproj with references to existing files up to the SyntaxTree folder (and removing what is not needed) ?
If there are scenarios that make Fantomas maintenance of the copy difficult, we could accept a new CI leg which would be suited for that.
I think there is more value to this proposal - while on the call with @Martin521 and @baronfel on the possibility of having "dotnet run app.fs" supported in the .NET SDK, having a slimmer F# lexer+parser would be for sure an advantage.
(and one could also do more focused attempts to make that package AOT friendly)
I am right now doing some experiments in that direction - will take time though.
If we could make it so that upgrades are non-breaking for consumers, that would be amazing. That is, there should be a way to use this AST library such that upgrading the library doesn't cause you to have to make code changes (so of course you need all your pattern matches to be non-exhaustive). One way to do this is simply to ship every FSharp.Core's AST as a collection of active patterns in their own namespace (like how FCS's TAST is provided in Exprs.fs, but each version of F# is defined a stable namespace that never changes), rather than encouraging people to access the fundamental DU that defines the AST:
namespace FCS.V10
let (|Call|_|) (expr : AST) =
// call through to the actual AST here
...
(One could probably get away with shipping just one set of these active patterns, but that feels like the kind of decision that's appealing now and then locks us into sadness later.)
The same approach could be used to produce ASTs too, although this time it looks more like normal helper functions than active patterns.
If we could make it so that upgrades are non-breaking for consumers, that would be amazing. That is, there should be a way to use this AST library such that upgrading the library doesn't cause you to have to make code changes (so of course you need all your pattern matches to be non-exhaustive).
The namespaced-by-major-version AST (/active patterns) idea sounds interesting.
That would, however, mean that FCS consumers couldn't access any improvements or additions to the AST made after a major release until the following year, though — unless they bypassed the active patterns and looked at the underlying DU anyway. Or perhaps they could open F.C.S.VNext, but that would presumably likewise be subject to breaking changes throughout the intervening year until the next major version was cut...
I think it's reasonable to call that "by design"? If the AST changes after the release of v10, the changes are reflected straight away in an unstable .V11 namespace, but you expect those to break sometimes because the version of the language you're using is preview.
I think it's reasonable to call that "by design"? If the AST changes after the release of v10, the changes are reflected straight away in an unstable
.V11namespace, but you expect those to break sometimes because the version of the language you're using is preview.
I agree, I just have some recollection of maybe things like FsAutoComplete and Fantomas intentionally consuming the latest version to take advantage of improvements/additions/fixes. But maybe I'm misremembering, or maybe consumers like those two in particular would be fine sticking with the actual AST.