How to add a new frontend to `ortac` -- a tutorial -------------------------------------------------- `ortac` is organised in a modular way that makes it easy to add a new behaviour. The new behaviour is implemented by a frontend. ## The new files In order to add a new frontend to `ortac` it is necessary to create the following files in the `ortac` file tree: ``` |- src |- newfrontend |- dune |- ortac_newfrontend.ml |- ortac_newfrontend.mli ``` `ortac_newfrontend.mli` exposes one function: `generate: string -> unit` that takes the path of the original module's signature as argument and should print the generated code on `stdout` `ortac_newfrontend.ml` contains at least three things. First, a module `M` which signature is `Ortac_core.Backend.S` (**todo**: change name). This module define an expression `prelude` that is a `Ppxlib.structure` corresponding to the code that will be inserted before the wrapper. Its main function is to open `Ortac_runtime` and to give the opportunity to redefine some of its functions. There are two functions in `Ortac_runtime` that are especially interesting to redefine: - `register : t -> error -> unit` - `report : t -> unit` The first allows specialisation of the set errors that will be reported, and the latter allows specialisation of the way errors are reported. For example, if we don't want to report errors occurring during a specification verification, we will redefine `register` this way: ``` let register t e = match e with | Specification_failure _ -> () | e -> t.errors <- e :: t.errors ``` The second thing that `ortac_newfrontend.ml` defines is always the same: `module G = Ortac_core.Ortac.Make (M)`. That define the function `M.signature: string -> Gospel.Tast.signature -> Ppxlib.structure`. This function generate the wrapper with the runtime defined in the module `M`. The third thing that `ortac_newfrontend.ml` defines is the function `generate`. This function makes use of `M.signature` to generate the code, but can also add some custom code if necessary. ## A new runtime If the new frontend needs a runtime, it is possible to add it in the file tree as follow: ``` |- ortac-runtime-newfrontend.opam |- src |- newfrontend |- dune |- ortac_newfrontend.ml |- ortac_newfrontend.mli |- runtime |- dune |- ortac_runtime_newfrontend.ml |- ortac_runtime_newfrontend.mli ``` `ortac_runtime_newfrontend` is a package (it will be called by the generated code, which should not depends on `ortac`, so it is necessary to add the `ortac-runtime-newfrontend.opam` file. ## Commande line parsing In `bin/cli.ml`, we should add the newfrontend to the variant `frontend` and completing the corresponding pattern matching in `frontend_printer`, `frontend_parser` and `main`. In `main`, the branch `Newfrontend` should call `Ortac_newfrontend.generate`