# tree-sitter-fsharp

tree-sitter grammar for F# (still WIP)
Based on [the 4.1 F# language specification](https://fsharp.org/specs/language-spec/4.1/FSharpSpec-4.1-latest.pdf) (Mostly, Appendix A)
and the [F# compiler parser](https://github.com/dotnet/fsharp/blob/main/src/Compiler/pars.fsy)

## Getting started

First, run `npm install` to install the `tree-sitter cli`.
Next, the grammar can be build using `npm run build`, or used to parse a file with `npm run parse $file`

### Project structure

This project defined two parser:

- [./fsharp/grammar.js](./fsharp/grammar.js)`fsharp` grammar.
- [./fsharp_signature/grammar.js](./fsharp_signature/grammar.js) defines the grammar for signature files

In addition to the `grammar.js` files each parser depends on a common external scanner found at [./common/scanner.h](./common/scanner.h).
The external scanner is responsible for parsing newlines and comments and keeps track of indentation to open and close scopes.

each grammar starts with the `file` node at the beginning of the rules.

### Adding to neovim

tree-sitter-fsharp isn't supported out-of-the box by [nvim-treesitter](https://github.com/nvim-treesitter/nvim-treesitter).
However, nvim-treesitter has [instructions for how to manually add unsupported parsers](https://github.com/nvim-treesitter/nvim-treesitter?tab=readme-ov-file#adding-parsers).

For tree-sitter-fsharp, this involves three steps:

1. Update your Neovim config for nvim-treesitter to refer to tree-sitter-fsharp.
2. Run `:TSInstall fsharp` inside Neovim.
3. Copy the files from [./queries/](./queries) to the neovim config directory at`$XDG_CONFIG_HOME/nvim/queries/fsharp/` - see [the Adding queries section of the nvim-treesitter README](https://github.com/nvim-treesitter/nvim-treesitter?tab=readme-ov-file#adding-queries).

The config you need is this (you can use a local path for `url` if you prefer):

```lua
local parser_config = require('nvim-treesitter.parsers').get_parser_configs()
parser_config.fsharp = {
  install_info = {
    url = 'https://github.com/ionide/tree-sitter-fsharp',
    branch = 'main',
    files = { 'src/scanner.c', 'src/parser.c' },
    location = "fsharp"
  },
  requires_generate_from_grammar = false,
  filetype = 'fsharp',
}
```

## Development

The `package.json` defines some helpful targets for developing the grammar:

- `npm run build` rebuilds all parser.
- `npm test` runs all tests for both parsers.
- `npm run parse $file` run the `fsharp` parser on `$file` and outputs the parse tree.
- `npm run debug $file` run the `fsharp` parser on `$file` and prints debug information.

## How to contribute

Clone the project and start playing around with it.
If you find a code example which fails to parse, please reduce it to a minimal example and added to the corpus (`fsharp/test/corpus/*.txt`) as a test case.

For an introduction to developing tree-sitter parsers the [official documentation](https://tree-sitter.github.io/tree-sitter/creating-parsers) is a good reference point.

PRs fleshing out the grammar or fixing bugs are welcome!
