{0 Getting development on stanc3 up and running locally}

{1 Setup}
{2 Using Opam and Dune}

The recommended way to develop stanc3 is using [opam]
and [dune] on a Unix-like system (MacOS or Linux).
See {!windows} for tips on developing on Windows.

This requires you have [make], [git], [curl], and [m4]
installed via apt, homebrew, or your system's package manager.

{ol
 {- Download the repository (or your fork of it) from Github}
 {- Install the necessary {!page-dependencies} by running

[cd scripts; bash -x ./setup_dev_env.sh].

   If you already have opam installed, you can instead run

[opam update; opam install --deps-only --with-test .]

   If you wish to {e install} stanc on your system, you can run the above
[opam] command without [--deps-only].}

 {- You can now build a stanc binary by running [make]. If this succeeds,
  you have the required software.}
}


{2:windows Windows development}
We recommend using {{:https://docs.microsoft.com/en-us/windows/wsl/install}
Windows Subsystem for Linux (WSL)} for development on Windows. While this
will not produce native-Windows binaries by default (though they can be
{{!page-dependencies.xcomp}cross-compiled}), it is far easier to use and set up than the other options
for Windows development.

Once you have installed and configured WSL, you can proceed through the steps above
through the WSL shell.


{2:nix Alternative: Using Nix}

{{:https://nixos.org/nix/}Nix} is a declarative package manager with a focus on reproducible builds.
We provide the ability to use Nix to build, test and run Stanc3. We recommend trying the [opam]
instructions first if you are not an existing Nix user, with these as a backup.

If you have nix installed, you can build Stanc3 by running the following command in the [stanc3] directory:

[nix-build]

The binary will be in [result/bin/stanc]. It may take a minute the first time you run it.
Alternatively, the following is sometimes a faster way to build:

[nix-shell --command "dune build"]

To run the test suite, run:

[nix-shell --command "dune build --profile release @runtest"]

To install Stanc3 to your system, run:

[nix-env -i -f default.nix]

To drop into a sandboxed development shell with all of the build dependencies
of Stanc3 plus packages for an OCaml development environment
([dune], [ocp-indent], [ocamlformat], [merlin] and [utop]), run:

[nix-shell]


{1 Development}
{2 Useful commands}

{3 Testing}
Once you have the necessary software, you can make your edits to the source files in [src/] and
tests in [test/]. Running the command [dune runtest] (or [make test]) will show any test output
which is different from the expected output. In our continuous integration, this results in test
failures. If you are knowingly changing the output, and the differences highlighted by
[dune runtest] look correct, you can run [dune promote] to change the expected output to match
your current tests.

{4 Test coverage}

We have support for computing test coverage using the {{:https://github.com/aantron/bisect_ppx}bisect_ppx}
library. To generate a coverage report, run [make testcoverage]. This will print a summary of the
coverage to the terminal, and generate a detailed HTML report in the [_coverage] directory.
This report can be opened in a web browser.

Code coverage of the master branch is available on {{:https://app.codecov.io/gh/stan-dev/stanc3}codecov.io}.

{3 Code formatting}
We recommend setting up your editor to use OCamlformat automatically. This will
differ by editor, but is possible in most popular editors such as Emacs, VSCode, etc.
See {!editors} for more specific tips.

If you would like to manually run the auto-formatter on all OCaml code in the repository,
run [make format]. Similar to the above, you will need to run [dune promote] to accept these
changes into the code.

If you would like to run the formatter before each commit (recommended), run

[scripts/hooks/install_hooks.sh]

Note: [ocamlformat] does not support [.mly] or [.mll] files used in the frontend.

{3 Updating the parser error messages}
If the parser has been edited, the command [dune build @update_messages] will add any
new error states to the [parser.messages] file. These will say

[TODO: PARSER MESSAGE NEEDED HERE.]

See {{!page-parser_messages}adding or changing the syntax error messages} for more information.

Note that python3 is required to run this command.

{3 Building these docs}

Docs can be built with [make doc]. This will generate a [_build/default/_doc/_html/index.html] file
which can be opened in a web browser.

{2:cmdstan Developing with stanc3 and CmdStan}

In order to use the locally built development version of stanc3 with CmdStan,
you need to set the [STANC3] makefile variable in the make/local file in CmdStan. Example:

[STANC3=relative/or/absolute/path/to/the/cloned/stanc3/folder]

This will automatically rebuild the stanc3 binary used in CmdStan if a change was made to the
stanc3 source files.

{2:editors Editor advice}
For working on this project, we recommend using either VSCode or Emacs as an editor, due to their good OCaml support through
{{:https://github.com/ocaml/merlin}Merlin}: syntax highlighting, auto-completion, type inference, automatic case splitting, and more.
For people who prefer a GUI and have not memorized all Emacs or Vim keystrokes, VSCode might have the less steep learning curve.
Anything with Merlin support is fine.

{3 Setting up VSCode}
Install instructions for VSCode can be found {{:https://code.visualstudio.com/docs/setup/setup-overview}here}.

{b For Windows users}: We recommend using {{:https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-wsl}Remote - WSL}
to program within WSL from a native Windows installation of VSCode. This extension allows you to connect to the
WSL instance as if it is a remote machine, removing the need for an X11 server or other method of running a
Linux GUI app directly.

Once in VSCode (on any platform), simply install the {{:https://github.com/reasonml-editor/vscode-reasonml}OCaml extension}
and you should be ready to go.

{3 Setting up Emacs}
The best way to edit OCaml in Emacs is through {{:https://github.com/ocaml/tuareg}Tuareg mode}.

To get full Merlin support, you will need to run [opam user-setup install] after installing
Merlin in our {{!page-dependencies.dev}dev dependencies}.

If you use {{:https://github.com/jwiegley/use-package}[use-package.el]}, this snippet should set up Tuareg+Merlin+OCamlformat

{[
(use-package tuareg
  :config
  (electric-indent-mode 0)
  (face-spec-set
   'tuareg-font-lock-constructor-face
   '((((class color) (background light)) (:foreground "SaddleBrown"))
     (((class color) (background dark)) (:foreground "burlywood1"))))
  (add-hook 'tuareg-mode-hook
            (lambda ()
              (prettify-symbols-mode 0))))
(use-package merlin
  :config
  (add-hook 'tuareg-mode-hook 'merlin-mode t)
  (with-eval-after-load 'company
    (add-to-list 'company-backends 'merlin-company-backend)))

(require 'ocamlformat)
(add-hook 'tuareg-mode-hook
          (lambda ()
            (define-key tuareg-mode-map (kbd "C-M-<tab>") #'ocamlformat)
            (add-hook 'before-save-hook #'ocamlformat-before-save)))
]}

{2 Finding your way around the code}

Even to an experienced OCaml developer, there are certain practices
in the stanc3 codebase which might be unfamiliar. We have tried to document
those on our {{!page-core_ideas}Core ideas} page.


{2 Advanced development}

{3 Fuzzing}

OCaml has {{:https://v2.ocaml.org/manual/afl-fuzz.html}support} for building binaries
instrumented for use with the{{:https://aflplus.plus/}AFL++} fuzzing tool.
This requires a new opam switch which includes the [ocaml-option-afl] base package.

{[
opam switch create "stanc-fuzz" --packages "ocaml-option-afl,ocaml.4.14.1"
eval $(opam env)
./scripts/install_build_deps.sh
]}

After this, the normal build process will produce a binary ready for fuzzing.

{3 Profiling}

Profiling support is not directly provided in the stanc3 repository, but you can use the
{{:https://github.com/LexiFi/landmarks}Landmarks} library to profile the code.

This requires editing the [dune] files in the [src/] directory to include the landmarks library,
similar to how the [bisect_ppx] library is instrumented by default.

{[
(instrumentation
  (backend landmarks --auto))
]}

You can then build a profiled version of the code by running
[dune build src/stanc/stanc.exe --instrument-with landmarks --force].

To configure the profiler at runtime, consult the Landmarks documentation. A
good starting command is

{[
OCAML_LANDMARKS="on,output=prof.txt" stanc.exe mymodel.stan
]}

