Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
0caefea
adaptations for sdk 9.0 and 10.0
Martin521 Jun 3, 2025
4216737
review follow-up
Martin521 Jun 4, 2025
10b59bb
update dockerfile also to sdk 9
Martin521 Jun 4, 2025
c68f23c
Update to dotnet 10
nojaf Nov 14, 2025
b3db7ec
Don't print formatted code
nojaf Nov 14, 2025
13b26a7
Fix parsing errors using anonymous records and code quotations (#18603)
nojaf Nov 14, 2025
736b616
Fix warn scopes trivia for fantomas #18637
nojaf Nov 14, 2025
599c6d5
Mark Range.Zero as obsolete in favor of Range.range0 #18664
nojaf Nov 14, 2025
c888913
Allow typed bindings(and!) in CE without parentheses #18682
nojaf Nov 14, 2025
dbd36b4
Merge branch 'main' into WarnScopes
nojaf Nov 14, 2025
2aa9efd
Use Synbinding to model and! #18805
nojaf Nov 14, 2025
e95be89
Update FCS to Remove LetOrUseKeyword from SynExprLetOrUseTrivia #19090
nojaf Nov 14, 2025
114f27a
WIP: deal with IN keyword
nojaf Dec 2, 2025
b13e469
Update and! in tests
nojaf Dec 2, 2025
0e0b888
Simplify oak.fsx
nojaf Dec 2, 2025
4a0fe9c
Don't print trivia twice
nojaf Dec 5, 2025
2ab6359
Fix remaining tests
nojaf Dec 5, 2025
d4891c3
Remove outdated test info
nojaf Dec 5, 2025
866bd4b
Merge branch 'main' into WarnScopes
nojaf Dec 5, 2025
41cf9a8
Combine filter and map
nojaf Dec 5, 2025
f822830
Fix input of scripts
nojaf Dec 5, 2025
6976f77
Fix typo
nojaf Dec 5, 2025
0833842
Fix docs build
dawedawe Dec 5, 2025
112e324
Clean up
nojaf Dec 6, 2025
5c830e2
Merge branch 'main' into WarnScopes
nojaf Dec 6, 2025
bce93df
Trigger CI
nojaf Dec 8, 2025
451e001
Try fix devcontainer
nojaf Dec 11, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM mcr.microsoft.com/dotnet/sdk:8.0.400
FROM mcr.microsoft.com/dotnet/sdk:10.0.100

# Avoid warnings by switching to noninteractive
ENV DEBIAN_FRONTEND=noninteractive
Expand All @@ -19,8 +19,16 @@ RUN apt-get update \
&& apt-get -y install git iproute2 procps lsb-release \
#
# Create a non-root user to use if preferred - see https://aka.ms/vscode-remote/containers/non-root-user.
&& groupadd --gid $USER_GID $USERNAME \
&& useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -m $USERNAME \
# Create group if it doesn't exist (handle case where GID already exists)
&& if ! getent group $USERNAME > /dev/null 2>&1; then \
groupadd --gid $USER_GID $USERNAME 2>/dev/null || \
(EXISTING_GROUP=$(getent group $USER_GID | cut -d: -f1) && groupmod -n $USERNAME $EXISTING_GROUP); \
fi \
# Create user if it doesn't exist (handle case where UID already exists)
&& if ! getent passwd $USERNAME > /dev/null 2>&1; then \
useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -m $USERNAME 2>/dev/null || \
(EXISTING_USER=$(getent passwd $USER_UID | cut -d: -f1) && usermod -l $USERNAME -d /home/$USERNAME -m $EXISTING_USER); \
fi \
# [Optional] Add sudo support for the non-root user
&& apt-get install -y sudo \
&& echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME\
Expand Down
4 changes: 2 additions & 2 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,6 @@
// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "dotnet tool restore && dotnet restore",

// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
"remoteUser": "root"
// Use the non-root user created in the Dockerfile. More info: https://aka.ms/dev-containers-non-root.
"remoteUser": "vscode"
}
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ Some common use cases include:

<!-- Versions -->
<PropertyGroup>
<FCSCommitHash>e668b90e3c087e5fba8a855e502af60bf35be45e</FCSCommitHash>
<FCSCommitHash>43932b4c7984d6562e91e5f1484868cd4f5befcf</FCSCommitHash>
</PropertyGroup>

<PropertyGroup>
Expand Down
2 changes: 1 addition & 1 deletion Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="FSharp.Core" Version="8.0.100"/>
<PackageVersion Include="FSharp.Core" Version="9.0.300"/>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I no longer remember how this stuff works, but can we stick to dotnet 8 SDK and versions? Or do you really need 9?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Due to the new nullness-related constructs, compiling the current compiler service requires 9.0 or higher for both fsc and FSharp.Core.
That's why I wrote above that this PR might be a draft one for quite some time.
I am assuming you might want to wait for the LTS SDK 10.
Regarding features I don't think there is a big pressure to move. The current Fantomas can deal with sources that contain nullness constructs or #warnon.
It is just that the changes accumulate. I naively just wanted to make the changes for "scoped nowarn" but found I had to deal with three other breaking changes also.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have any more details on that? What exactly in FSharp.Core 9 does any of this depend on?

Copy link
Contributor Author

@Martin521 Martin521 Jun 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have any more details on that? What exactly in FSharp.Core 9 does any of this depend on?

It is all about nullness.
If I compile with SDK 9.0.300 and FSharp.Core 8.0.100, I get 85 errors in the Fantomas.FCS project, mostly about unknown objnull and NonNull.

<PackageVersion Include="System.Collections.Immutable" Version="8.0.0" />
<PackageVersion Include="System.Diagnostics.DiagnosticSource" Version="8.0.1" />
<PackageVersion Include="System.Memory" Version="4.6.0" />
Expand Down
6 changes: 6 additions & 0 deletions build.fsx
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,8 @@ pipeline "Init" {
"src/Compiler/Utilities/NullnessShims.fs"
"src/Compiler/Utilities/Activity.fsi"
"src/Compiler/Utilities/Activity.fs"
"src/Compiler/Utilities/Caches.fsi"
"src/Compiler/Utilities/Caches.fs"
"src/Compiler/Utilities/sformat.fsi"
"src/Compiler/Utilities/sformat.fs"
"src/Compiler/Utilities/sr.fsi"
Expand Down Expand Up @@ -301,6 +303,10 @@ pipeline "Init" {
"src/Compiler/SyntaxTree/SyntaxTree.fs"
"src/Compiler/SyntaxTree/SyntaxTreeOps.fsi"
"src/Compiler/SyntaxTree/SyntaxTreeOps.fs"
"src/Compiler/SyntaxTree/WarnScopes.fsi"
"src/Compiler/SyntaxTree/WarnScopes.fs"
"src/Compiler/SyntaxTree/LexerStore.fsi"
"src/Compiler/SyntaxTree/LexerStore.fs"
"src/Compiler/SyntaxTree/ParseHelpers.fsi"
"src/Compiler/SyntaxTree/ParseHelpers.fs"
"src/Compiler/SyntaxTree/LexHelpers.fsi"
Expand Down
9 changes: 9 additions & 0 deletions docs/docs/contributors/Transforming.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,15 @@ let a =
Depending on the defines `[]` or `["DEBUG"]`, the AST will be different.
The tree will also be created based on a single code path.

You can use your locally installed F# compiler to parse a file and view the AST via:

```shell
# Tip: figure out the location of your installed sdk
whereis dotnet
# Invoke the parser
dotnet '/Users/nojaf/Library/Application Support/dnvm/dn/sdk/10.0.100/FSharp/fsc.dll' --parseonly --ast foo.fs
```

### Transform untyped AST to Oak

The untyped syntax tree from the F# compiler is used as an intermediate representation of source code in the process of transforming a text file to binary.
Expand Down
33 changes: 18 additions & 15 deletions docs/docs/end-users/GeneratingCode.fsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,22 +56,25 @@ let implementationSyntaxTree =
[ BindingNode(
None,
None,
MultipleTextsNode([ SingleTextNode("let", Range.Zero) ], Range.Zero),
MultipleTextsNode([ SingleTextNode("let", Range.range0) ], Range.range0),
false,
None,
None,
Choice1Of2(IdentListNode([ IdentifierOrDot.Ident(SingleTextNode("a", Range.Zero)) ], Range.Zero)),
Choice1Of2(
IdentListNode([ IdentifierOrDot.Ident(SingleTextNode("a", Range.range0)) ], Range.range0)
),
None,
[],
None,
SingleTextNode("=", Range.Zero),
Expr.Constant(Constant.FromText(SingleTextNode("0", Range.Zero))),
Range.Zero
SingleTextNode("=", Range.range0),
Expr.Constant(Constant.FromText(SingleTextNode("0", Range.range0))),
None,
Range.range0
)
|> ModuleDecl.TopLevelBinding ],
Range.Zero
Range.range0
) ],
Range.Zero
Range.range0
)

open Fantomas.Core
Expand All @@ -92,7 +95,7 @@ Let's deconstruct a couple of things:

- The `functionName ` of binding contains the name or is a pattern.
- The `expr` ([Expr](../../reference/fantomas-core-syntaxoak-expr.html)) represents the F# syntax expression.
- Because there is no actual source code, all ranges will be `Range.Zero`.
- Because there is no actual source code, all ranges will be `Range.range0`.

The more you interact with AST/Oak, the easier you pick up which node represents what.

Expand Down Expand Up @@ -141,18 +144,18 @@ Please make sure you construct the same Oak as Fantomas would.
*)

// You typically make some helper functions along the way
let text v = SingleTextNode(v, Range.Zero)
let text v = SingleTextNode(v, Range.range0)

let mkCodeFromExpression (e: Expr) =
Oak([], [ ModuleOrNamespaceNode(None, [ ModuleDecl.DeclExpr e ], Range.Zero) ], Range.Zero)
Oak([], [ ModuleOrNamespaceNode(None, [ ModuleDecl.DeclExpr e ], Range.range0) ], Range.range0)
|> CodeFormatter.FormatOakAsync
|> Async.RunSynchronously
|> printfn "%s"

let numberExpr = Expr.Constant(Constant.FromText(text "7"))

let wrappedNumber =
Expr.Paren(ExprParenNode(text "(", numberExpr, text ")", Range.Zero))
Expr.Paren(ExprParenNode(text "(", numberExpr, text ")", Range.range0))

mkCodeFromExpression wrappedNumber
(*** include-output ***)
Expand Down Expand Up @@ -187,16 +190,16 @@ Oak (1,0-1,16)

let lambdaExpr =
let body: Expr =
ExprInfixAppNode(Expr.Ident(text "a"), text "+", Expr.Ident(text "b"), Range.Zero)
ExprInfixAppNode(Expr.Ident(text "a"), text "+", Expr.Ident(text "b"), Range.range0)
|> Expr.InfixApp

ExprLambdaNode(
text "fun",
[ Pattern.Named(PatNamedNode(None, text "a", Range.Zero))
Pattern.Named(PatNamedNode(None, text "b", Range.Zero)) ],
[ Pattern.Named(PatNamedNode(None, text "a", Range.range0))
Pattern.Named(PatNamedNode(None, text "b", Range.range0)) ],
text "->",
body,
Range.Zero
Range.range0
)
|> Expr.Lambda

Expand Down
2 changes: 1 addition & 1 deletion global.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"sdk": {
"version": "8.0.400",
"version": "10.0.100",
"rollForward": "latestPatch"
}
}
20 changes: 20 additions & 0 deletions scripts/ast.fsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#r "../artifacts/bin/Fantomas.FCS/debug/Fantomas.FCS.dll"

open System.IO

match Array.tryHead fsi.CommandLineArgs with
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Useful to test out the local compiler and view changes that Fantomas Tools might not yet have.

| Some scriptPath ->
let scriptFile = FileInfo(scriptPath)
let sourceFile = FileInfo(Path.Combine(__SOURCE_DIRECTORY__, __SOURCE_FILE__))

if scriptFile.FullName = sourceFile.FullName then
let inputPath = fsi.CommandLineArgs.[fsi.CommandLineArgs.Length - 1]
let sample = File.ReadAllText(inputPath)
let isSignature = inputPath.EndsWith(".fsi")

let ast =
Fantomas.FCS.Parse.parseFile isSignature (Fantomas.FCS.Text.SourceText.ofString sample) []
|> fst

ast |> printfn "%A"
| _ -> printfn "Usage: dotnet fsi ast.fsx <input file>"
36 changes: 36 additions & 0 deletions scripts/oak.fsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#r "../artifacts/bin/Fantomas.FCS/debug/Fantomas.FCS.dll"
#r "../artifacts/bin/Fantomas.Core/debug/Fantomas.Core.dll"

open System.Threading.Tasks
open Fantomas.Core

let parseOak (input: string) (isSignature: bool) : Task<string> =
task {
try
let! oaks = CodeFormatter.ParseOakAsync(isSignature, input)

match Array.tryHead oaks with
| None -> return "No Oak found in input"
| Some(oak, _) -> return (string oak)

with ex ->
return $"Error while parsing to Oak: %A{ex}"
}

open System.IO

match Array.tryHead fsi.CommandLineArgs with
| Some scriptPath ->
let scriptFile = FileInfo(scriptPath)
let sourceFile = FileInfo(Path.Combine(__SOURCE_DIRECTORY__, __SOURCE_FILE__))

if scriptFile.FullName = sourceFile.FullName then
let inputPath = fsi.CommandLineArgs.[fsi.CommandLineArgs.Length - 1]
let sample = File.ReadAllText(inputPath)
let isSignature = inputPath.EndsWith(".fsi")

parseOak sample isSignature
|> Async.AwaitTask
|> Async.RunSynchronously
|> printfn "%s"
| _ -> printfn "Usage: dotnet fsi oak.fsx <input file>"
2 changes: 1 addition & 1 deletion src/Fantomas.Benchmarks/Fantomas.Benchmarks.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
Expand Down
Loading