diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index e1ecfc8..bec6d2d 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -3,14 +3,14 @@
"isRoot": true,
"tools": {
"fantomas": {
- "version": "8.0.0",
+ "version": "8.0.4",
"commands": [
"fantomas"
],
"rollForward": false
},
"fsdocs-tool": {
- "version": "23.0.0-alpha.4",
+ "version": "23.0.0-alpha.8",
"commands": [
"fsdocs"
],
diff --git a/.github/workflows/pull-requests.yml b/.github/workflows/pull-requests.yml
index 0ab560f..6c3da2d 100644
--- a/.github/workflows/pull-requests.yml
+++ b/.github/workflows/pull-requests.yml
@@ -47,3 +47,4 @@ jobs:
uses: github/codeql-action/upload-sarif@b96794f015dfd88f77b49b1c93e0fa7110f94c63 # v4.38.0
with:
sarif_file: ./analysis.sarif
+ category: fsharp-analyzers
diff --git a/.github/workflows/push-main.yml b/.github/workflows/push-main.yml
index 182252d..fbc6695 100644
--- a/.github/workflows/push-main.yml
+++ b/.github/workflows/push-main.yml
@@ -52,6 +52,7 @@ jobs:
uses: github/codeql-action/upload-sarif@b96794f015dfd88f77b49b1c93e0fa7110f94c63 # v4.38.0
with:
sarif_file: ./analysis.sarif
+ category: fsharp-analyzers
- name: Build documentation
run: dotnet fsi build.fsx -p Docs
- name: Upload documentation
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6b354f5..691d620 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,8 +1,9 @@
# Changelog
-## [Unreleased]
+## [13.0.0] - 2026-09-24
### Changed
+* **Breaking:** the generated lexer and parser are written to the intermediate folder (`obj/...`) instead of next to the grammar, so they stay out of the source tree and `dotnet clean` removes them. Reference the generated files as `$(FsLexOutputFolder)Lexer.fs` and `$(FsYaccOutputFolder)Parser.fs(i)`. The build fails with an explanation when a project still compiles `Parser.fs` or `Lexer.fs` next to the grammar. Set `FsLexYaccOutputToIntermediate` to `false` to keep the old location. [#247](https://github.com/fsprojects/FsLexYacc/issues/247)
* Lower the required `FSharp.Core` from `10.1.400` to `10.0.100`. [#253](https://github.com/fsprojects/FsLexYacc/pull/253)
### Fixed
diff --git a/build.fsx b/build.fsx
index d30dfb7..d38da67 100755
--- a/build.fsx
+++ b/build.fsx
@@ -141,11 +141,11 @@ let generatedSources =
"src/FsYacc.Core/fsyaccpars.fsi"
]
+/// JsonLexAndYaccExample is not listed: it uses the default output to the intermediate folder, so
+/// its generated sources live under obj and go away with `dotnet clean`. LexAndYaccMiniProject
+/// opts out with FsLexYaccOutputToIntermediate=false.
let generatedTestSources =
[
- "tests/JsonLexAndYaccExample/Lexer.fs"
- "tests/JsonLexAndYaccExample/Parser.fs"
- "tests/JsonLexAndYaccExample/Parser.fsi"
"tests/LexAndYaccMiniProject/Lexer.fs"
"tests/LexAndYaccMiniProject/Parser.fs"
"tests/LexAndYaccMiniProject/Parser.fsi"
diff --git a/docs/content/fslex.md b/docs/content/fslex.md
index e326235..51ce415 100644
--- a/docs/content/fslex.md
+++ b/docs/content/fslex.md
@@ -22,8 +22,8 @@ Or you can add it to your build project via entries like this:
--module Lexer --unicode
-
-
+
+The generated files are written to the intermediate folder (`obj/...`). See [MSBuild support](fsyacc.html) for how to reference them, or how to write them next to the grammar instead.
Lexer syntax
diff --git a/docs/content/fsyacc.md b/docs/content/fsyacc.md
index 3a56673..fee414f 100644
--- a/docs/content/fsyacc.md
+++ b/docs/content/fsyacc.md
@@ -93,6 +93,30 @@ But you must manually add `FsLex` andd `FsYacc` entries inside of an `ItemGroup`
--unicode
+The generated `.fs` and `.fsi` files are written to the intermediate folder (`obj/...`), so they stay out of your source tree and `dotnet clean` removes them. Reference them through `FsLexOutputFolder` and `FsYaccOutputFolder`:
+
+
+
+ --module Parser
+
+
+ --unicode
+
+
+
+
+
+
+Setting `FsLexOutputFolder` or `FsYaccOutputFolder` yourself takes precedence. The default relies on `FsLexYacc.targets` being imported after the SDK targets, which is how the NuGet package imports it. If you import the targets file yourself from the project body, the build fails with an error telling you so.
+
+To write the generated files next to the grammar instead, as FsLexYacc 12 and earlier did, set `FsLexYaccOutputToIntermediate` to `false`:
+
+
+ false
+
+
+When upgrading from FsLexYacc 12, a project that still compiles `Parser.fs` or `Lexer.fs` next to the grammar fails the build, because those copies are no longer regenerated. Change the `Compile` items as shown above and delete the old generated files, or opt out.
+
When the grammar has shift/reduce or reduce/reduce conflicts, `FsYacc` prints only how many there are. To see each conflict, with the state, the terminal and the two actions involved, add `-v` in the `OtherFlags` section. That writes a `.fsyacc.output` listing file next to the generated parser containing the conflicts and the LALR tables:
diff --git a/docs/content/jsonParserExample.md b/docs/content/jsonParserExample.md
index 37a6bf0..8ebfb9e 100644
--- a/docs/content/jsonParserExample.md
+++ b/docs/content/jsonParserExample.md
@@ -114,7 +114,7 @@ Reload/Open the project and add the following code to ``Parser.fsy``:
| value { [$1] }
| rev_values COMMA value { $3 :: $1 }
-This file is describing parsing rules and tokens. When you build the project, a new file called ``Parser.fs`` will be created in the project root directory. Include it in your project.
+This file is describing parsing rules and tokens. When you build the project, a new file called ``Parser.fs`` will be created in the intermediate folder (``obj/...``). Include it in your project with ````.
Lets take a closer look at the parser definition (``Parser.fsy)``. At the very top of the file there is a section for ``open`` statements. You can open any namespace or module you want. We need only ``JsonParsing`` where we defined our ``JsonValue`` structure. All open statements should be between `` %{`` and ``%}``.
@@ -215,7 +215,7 @@ Reload/Open the project and add the following code to ``Lexer.fsl:``
| [^ '"' '\\']+ { read_string (str + (lexeme lexbuf)) false lexbuf }
| eof { raise (Exception ("String is not terminated")) }
-When you build the project, a new file called ``Lexer.fs`` will be created in the project root directory. Include it in your project after ``Parser.fs``.
+When you build the project, a new file called ``Lexer.fs`` will be created in the intermediate folder. Include it in your project after ``Parser.fs`` with ````.
The first part of a lexer is simply F# code enclosed in ``{}``. It defines a module, opens namespaces and defines helper functions. The ``lexeme`` function will extract the matched string from the buffer. The ``newline`` function updates the buffer position to skip new line characters. Notice that we open the Parser module which contains the union type with the tokens. We will use them in our productions.
diff --git a/src/FsLexYacc.Build.Tasks/FsLexYacc.targets b/src/FsLexYacc.Build.Tasks/FsLexYacc.targets
index 2d825dd..9750d21 100644
--- a/src/FsLexYacc.Build.Tasks/FsLexYacc.targets
+++ b/src/FsLexYacc.Build.Tasks/FsLexYacc.targets
@@ -22,13 +22,61 @@ Copyright (C) Microsoft Corporation. All rights reserved.
dotnet
+
+
+ true
+
+
+
+ $(IntermediateOutputPath)
+ $(IntermediateOutputPath)
+
+
+
+
+
+
+
+ <_FsLexYaccNextToGrammar Include="@(FsLex->'%(RootDir)%(Directory)%(Filename).fs');@(FsLex->'%(RootDir)%(Directory)%(Filename).fsi')" />
+ <_FsLexYaccNextToGrammar Include="@(FsYacc->'%(RootDir)%(Directory)%(Filename).fs');@(FsYacc->'%(RootDir)%(Directory)%(Filename).fsi')" />
+ <_FsLexYaccGenerated Include="@(FsLex->'$(FsLexOutputFolder)%(Filename).fs');@(FsLex->'$(FsLexOutputFolder)%(Filename).fsi')" />
+ <_FsLexYaccGenerated Include="@(FsYacc->'$(FsYaccOutputFolder)%(Filename).fs');@(FsYacc->'$(FsYaccOutputFolder)%(Filename).fsi')" />
+ <_FsLexYaccNextToGrammar Remove="@(_FsLexYaccGenerated->'%(FullPath)')" />
+ <_FsLexYaccCompiled Include="@(Compile->'%(FullPath)')" />
+ <_FsLexYaccNotCompiled Include="@(_FsLexYaccNextToGrammar)" Exclude="@(_FsLexYaccCompiled)" />
+ <_FsLexYaccStaleCompile Include="@(_FsLexYaccNextToGrammar)" Exclude="@(_FsLexYaccNotCompiled)" />
+
+
+
+
+ DependsOnTargets="FsLexYaccCheckOutputFolders"
+ BeforeTargets="CoreCompile">
@@ -46,7 +94,8 @@ Copyright (C) Microsoft Corporation. All rights reserved.
Inputs="@(FsYacc)"
Outputs="@(FsYacc->'$(FsYaccOutputFolder)%(Filename).fs');@(FsYacc->'$(FsYaccOutputFolder)%(Filename).fsi')"
Condition="'@(FsYacc)'!=''"
- BeforeTargets="CoreCompile">
+ DependsOnTargets="FsLexYaccCheckOutputFolders"
+ BeforeTargets="CoreCompile">
diff --git a/tests/JsonLexAndYaccExample/.gitignore b/tests/JsonLexAndYaccExample/.gitignore
deleted file mode 100644
index 12bea09..0000000
--- a/tests/JsonLexAndYaccExample/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-Lexer.fs
-Lexer.fsi
-Parser.fs
-Parser.fsi
diff --git a/tests/JsonLexAndYaccExample/JsonLexAndYaccExample.fsproj b/tests/JsonLexAndYaccExample/JsonLexAndYaccExample.fsproj
index 030b188..3c0a1bd 100644
--- a/tests/JsonLexAndYaccExample/JsonLexAndYaccExample.fsproj
+++ b/tests/JsonLexAndYaccExample/JsonLexAndYaccExample.fsproj
@@ -1,5 +1,12 @@
-
-
+
+
+
+
Exe
net10.0
@@ -14,8 +21,8 @@
--unicode
-
-
+
+
@@ -25,5 +32,6 @@
-
-
\ No newline at end of file
+
+
+
diff --git a/tests/LexAndYaccMiniProject/LexAndYaccMiniProject.fsproj b/tests/LexAndYaccMiniProject/LexAndYaccMiniProject.fsproj
index c3db814..3c9c6dd 100644
--- a/tests/LexAndYaccMiniProject/LexAndYaccMiniProject.fsproj
+++ b/tests/LexAndYaccMiniProject/LexAndYaccMiniProject.fsproj
@@ -5,6 +5,8 @@
net10.0
..\..\src\FsLex\bin\$(Configuration)\net10.0
..\..\src\FsYacc\bin\$(Configuration)\net10.0
+
+ false