OCaml Weekly News
Hello
Here is the latest OCaml Weekly News, for the week of January 02 to 09, 2024.
Table of Contents
- Odoc module index bookmarklet
- create-melange-app 1.0.0 - A CLI for quickly becoming productive with Melange
- What’s possible with Melange
- Ocaml-ts-mode - Emacs ocaml major mode using tree sitter
- Using Menhir to parse into idiomatic JS (TypeScript) structures
- Play with project-wide occurrences for OCaml!
- New release of Menhir (20231231)
- Ocsigen: summary of recent releases
- sarif 0.1.0 - Static Analysis Results Interchange Format (SARIF) For OCaml
- Other OCaml News
- Old CWN
Odoc module index bookmarklet
Yawar Amin announced
Hello, I made a bookmarklet that injects an index of a module’s contents into the sidebar of an odoc-generated module documentation page. For example, if you go to https://aantron.github.io/dream/ , and run the bookmarklet, you will see:
create-melange-app 1.0.0 - A CLI for quickly becoming productive with Melange
Dillon Mulroy announced
Hello y’all 👋
I have been working on creating a scaffolding tool aimed at enabling JavaScript and TypeScript developers to quickly become familiar and productive with OCaml, ReasonML, and Melange. The developer experience, tooling, and project setup is opinionated and meant to be familiar and friendly for folks coming from that ecosystem.
So, without further ado, I’m excited to announce create-melange-app, 1.0.0!
Get started by simply running npm create melange-app@latest
and completing the questions that the CLI will guide you through.
Project setup:
Scaffolding:
✨Your new Melange app ✨
You can find the code/projected generated in this example here: https://github.com/dmmulroy/create-melange-app-example
I’ve tried to take great care to provide as much helpful information for developers unfamiliar with our ecosystem as possible. You’ll find many of the scaffolded files commented with explanations, examples, and additional resources aimed at quickly becoming productive with OCaml, ReasonML, and Melange.
Looking forward 👀
I have a lot of ideas around making bindings easier and more pleasant to write for manage, along with some delightful ways to integrate them into CMA.
But first…
We’re rewriting to native OCaml using
MintTea! Currently create-melange-app
is written using Melange and
Ink, a library for rendering React components too the terminal.
When I started CMA, OCaml didn’t have a great TUI story for easily making delightful experiences (plus I wanted an excuse to go deeper with Melange, and doesn’t a CLI written with OCaml and React sound ridiculous? 😂)
I would love for CMA itself to be a great OSS project for beginners with OCaml to get involved with and learn with and I’m aiming to bring as many people along for that ride as I can :)
You can follow my development of CMA on my twitch channel where I live stream OCaml content every M-F 7am - 10am ET
Thanks y’all! 🐫
What’s possible with Melange
David Sancho announced
Hi
Since dune got the integration with Melange (and Ahrefs migrated to Melange https://discuss.ocaml.org/t/ahrefs-is-now-built-with-melange/12107) I wanted to write about the benefits of using it.
I wrote a blog post comparing Melange with the previous compiler (BuckleScript/ReScript) and what’s possible. I tried to be objetive and focus only on the technical parts of it.
The link to the post is: https://sancho.dev/blog/whats-possible-with-melange
Hope you like it, and feel free to ask anything!
Ocaml-ts-mode - Emacs ocaml major mode using tree sitter
Malcolm announced
This weekend I got interested in emacs major modes based on treesitter, so I decided to implement
ocaml-ts-mode
. The code can be found here:
https://github.com/terrateamio/ocaml-ts-mode
It was actually very easy thanks to the hard work others have done in creating the treesitter grammar.
It supports:
- Syntax highlighting of
.ml
and.mli
files. - Initial indentation support (this is probably currently broken in multiple places)
C-c C-a
- Switch between.ml
and.mli
files for a module.
This is less feature rich than Tuareg mode, so I don’t know if it replaces it. If anything, maybe it could be integrated into tuareg mode.
I have no experience writing elisp so this probably has obvious mistakes. Contributions welcome!
Enjoy!
Malcolm then added
Whoops, in my excitement learning about treesitter I didn’t notice that there already is an ocaml-ts-mode. That one is probably the preferred one to use. I’ll probably direct any of my development towards it. But learning how to make a major mode was a fun experience.
Using Menhir to parse into idiomatic JS (TypeScript) structures
Archive: https://discuss.ocaml.org/t/using-menhir-to-parse-into-idiomatic-js-typescript-structures/13809/1
Shon announced
Hello and Happy New Year!
As we all know, despite being named an Objective Categorical Abstract Machine Language, OCaml is Obviously a Completely Awesome [Meta Language](https://en.wikipedia.org/wiki/ML_(programming_language)). The awesomeness is founded on the wonderful language, but obviously completed by the extraordinary ecosystem of tools and techniques that take life in that language. :stuck_out_tongue_winking_eye:
This is a note to share a solution I hacked together using a handful of these awesome tools in our lovely language, but also a request for any suggestions on a more elegant solution to the problem posed.
The Problem
I wanted to use Menhir and Sedlex to write a fault-tolerant, incremental parser for a preexisting project that has an intermediate representation (IR), and a bunch of other tools, written in TypeScript.
Non-solutions
Unfortunately, achieving this outcome was not quite as simple as adding a
(mode js)
to dune to have the generated parser compiled by
Js_os_ocaml (Jsoo) . Of course, that does work like a charm, and if we could justify rewriting everything in OCaml, we’d be able to produce JS easy as pie. But for interop with the existing TypeScript code this won’t fly. We need to parse into JS
objects that represent the IR in a human-readable way, ideally matching our existing TypeScript types, but Jsoo gives something like this.
> parser.parse('def foo(a,b) = 123') [ 0, [ 0, [ 0, [Array], [Array] ], 0 ] ]
My next thought was to use Melange: it seems to be a great project with a lot of excellent work going in to it, and, iiuc, its purpose is precisely to compile OCaml into idiomatic(ish) JS. But I hit a road block right away, which led me to ask https://discuss.ocaml.org/t/what-are-the-limits-and-prerequisites-of-using-dependencies-with-melange/13688 and to try something else.
A Solution
Fortunately, the wealth of shining jewels-of-tools in the OCaml ecosystem made this short work. The solution I ended up with is hacky as heck, but its doing what I needed:
- I define our types using the excellent atd.
-
I generate OCaml and TypeScript representations of the types, along with JSON serializers, via a dune config like
(library (public_name lang_ir) (libraries atdgen)) ;; The OCaml ser/de-serializers (rule (targets lang_ir_j.ml lang_ir_j.mli) (deps lang_ir.atd) (action (run atdgen -j -j-std %{deps}))) ;; The OCaml types (rule (targets lang_ir_t.ml lang_ir_t.mli) (deps lang_ir.atd) (action (run atdgen -t %{deps}))) ;; The TypeScript types and ser/de (rule (targets lang_ir.ts) (deps lang_ir.atd) (action (run atdts %{deps}))) ;; Conversion of the TypeScript into vanilla JS so I can test it with node (rule (targets lang_ir.js) (deps lang_ir.ts) (action (run npx tsc %{deps})))
- I use menhir and sedlex to define a parser that produces inhabitants of the OCaml types generated in
lang_ir_t.ml
. (Working out the incremental, fault-tolerant parsing was its own exhilarating side quest, but I’ll save a report on that for it’s own post.) -
Then I use Jsoo to run the parser in JS and then serialize its optimized but inscritable representation into the JSON dictated by atd:
open Lang_parser_lib open Js_of_ocaml (* Export functions *) (* See https://ocsigen.org/js_of_ocaml/latest/manual/rev-bindings *) let _ = Js.export_all (object%js method parse s = let lexbuf = Sedlexing.Utf8.from_string s in match parse lexbuf with (* run the parser *) | Some t -> Lang_ir.Quint_ir_j.string_of_t t (* produce a JSON string from the result*) | None -> "" end)
-
And, finally, I make a little
wrapper.js
that invokes the atd-generated deserializer to parse into the TypeScript representation:var ir = require('./_build/default/ir/lang_ir.js') var parser = require('./_build/default/js/lang_parser.bc.js') exports.parse = function (s) { return ir.readT(JSON.parse(parser.parse(s))) }
The result
I now can use the wrapper script to parse into the nice TypeScript (compatible) structures I need:
[me@comp mparsing]$ node > var p = require('./wrapper.js') undefined > p.parse("def foo(a,b) = 123") [ { loc: { start_: [Object], end_: [Object] }, v: { name: 'foo', params: [Array], body: [Object] } } ]
I have three hopes for this post:
- I hope to contribute yet another note celebrating the virtues of our extraordinary programming language ecosystem.
- I hope it might be useful for others who need to solve similar problems.
- I hope there is a more elegant way to achieve this result (namely, without having to go through serialization) and that one of y’all can point the way.
:heart: :camel:
Play with project-wide occurrences for OCaml!
Archive: https://discuss.ocaml.org/t/ann-preview-play-with-project-wide-occurrences-for-ocaml/13814/1
vds announced
Hi fellow camelers 👋, I am very pleased to announce that every one can now try the upcoming project-wide occurrences feature for Merlin and OCaml-LSP.
This feature involves changes to multiple packages such as ocaml
,
merlin
, ocaml-lsp
and dune
so we decided to prepare a custom opam repository to make it easy for adventurous people to install the feature, play with it, and most-importantly… break it ! We hope you will have as much fun
querying around your codebases as we do :-)
Requirements for this preview:
- Have projects compatible with OCaml 4.14.2.
- These projects build with Dune. (The tools themselves are build-system agnostic, but this preview only include rules for Dune.)
- You use an LSP-based editor plugin. (We do plan to bring basic support to the vanilla
emacs
andvim
modes for Merlin.)
What the feature does…
- ✅ Returns every usages of types, values, constructors and labels in
ml
andmli
files in the workspace - ✅ Returns direct usages of modules (like
M
ininclude M
) - ✅ Can be called on any such usage of a value or on its definition itself
…what is does not do yet:
- ❌ Return declarations related to searched values in both ml and mli files. This will come in a second iteration.
- ❌ Occurrences of modules appearing in paths: like
M
andN
inM.N.P
. This will also arrive later. - ⚠️ Renaming is experimental and not as smart as one would expect (with regard to punning and other syntactic tricks).
…and known caveats:
- ⚠️ Interaction with PPX might give unexpected results depending on the specifics of the PPX.
- ⚠️ Values whose definition cannot be determined statically (like items of a first-class module) won’t be searched project-wide. For the same reason, walues coming from libraries that do not install their
cmt
files won’t be searched project-wide.
Demo
In the following demo, the feature is used to rename a symbol in Merlin. Since the name appears in one declaration, this last occurrence still needs to be replaced by hand for the build to succeed:
Setup
You can find detailed setup instruction in the custom opam repository. In short:
- Add the repository to your opam installation:
opam repo add index https://github.com/voodoos/opam-repository-index.git
- Create a switch (global or local) with the
+index
ocaml variant:opam switch create --repositories=default,index 4.14.2+index
- Install
merlin
,ocaml-lsp
and the indexer:opam install indexing-tools
- Build the index with your project:
dune build @ocaml-index @your-usual-target-maybe-install-or-all --watch
References and renaming queries should return result on the entire workspace.
Feedback
Please do not hesitate to share any feedback on the feature here or by opening an issue on the repository :slightly_smiling_face:
New release of Menhir (20231231)
François Pottier announced
It is my pleasure to announce a new version of Menhir, 20231231. It should be available now:
opam update opam install menhir.20231231
The main new features are as follows:
-
The new command line switch
--unparsing
(which must be used in conjunction with--table
) causes Menhir to generate an unparsing API. In short, unparsing is the process of transforming abstract syntax trees back into text. The unparsing API is intended to help users write correct unparsers, but does not automate the whole process.For more details, please see the paper Correct, Fast LR(1) Unparsing.
The unparsing API requires linking with the library
MenhirCST
, and requires OCaml 4.08. -
Attributes can now be attached with a production. (In previous versions of Menhir, attributes could be attached only with a symbol, with a specific occurrence of a symbol in the right-hand side of a production, or with the whole grammar.) This is achieved by letting one or more attributes appear immediately after the semantic action.
During the two grammar transformation phases (expansion of parameterized nonterminal symbols and elimination of
%inline
nonterminal symbols), the[@name]
attributes attached with productions receive special treatment, so as to allow each production to receive a unique name.
Ocsigen: summary of recent releases
Vincent Balat announced
We do not announce very often our releases on this forum. Here is a roundup of recent releases to make amends.
Many releases of Js_of_ocaml last year, with important features like the support of OCaml 5 effects, global dead-code elimination, support for modern JavaScript and a huge list of improvements and fixes. There is now also a new backend for js_of_ocaml, Wasm_of_ocaml written by @vouillon, to compile to WebAssembly. It can be used as a replacement for js_of_ocaml with very few changes.
Eliom, the OCaml Web framework, has now reached version 10.2. Amongst the most recent changes:
- The Dune-based build system is now the default one for client-server apps
- compatibility with OCaml 5
- Reactive programming: Update to recent versions of js_of_ocaml, which support weak pointers
- Documentation improvements
An experimental version is also available to build WASM applications with wasm_of_ocaml
Ocsigen-Start version 6.1
- removes a dependency on Ocamlnet to make it compatible with OCaml 5. No default email function is now provided. Warning: this might be a regression if you use the default email-sending function.
- updates the dune-based build system
Tyxml 4.6 was released with fixes on some tags and options.
Several maintenance releases of Ocsigen-Toolkit
The Ocsigen team wishes you a happy new year!
sarif 0.1.0 - Static Analysis Results Interchange Format (SARIF) For OCaml
Geoffrey Borough announced
Hi folks, I announce the initial release of sarif version 0.1.0, a library for processing and validating the SARIF format. If you are familiar with static analysis and/or code scanner like Semgrep or Snyk etc, SARIF is one of the output format that people generate and share after scanning, the specification itself is quite big and convoluted.
My motivation for making this library is that there seems to be no definitive library for SARIF in the OCaml ecosystem, and even companies like Semgrep relies on some python glue code to generate the format. Given OCaml’s importance in the static analysis scene I thought it would be nice if this gets over the line :slight_smile:
Code: https://github.com/gborough/sarif
Documentation: https://gborough.github.io/sarif/sarif/sarif/index.html (Package available very soon in opam-repository pending PR approval)
Have a nice day!
Other OCaml News
From the ocaml.org blog
Here are links from many OCaml blogs aggregated at the ocaml.org blog.
Old CWN
If you happen to miss a CWN, you can send me a message and I’ll mail it to you, or go take a look at the archive or the RSS feed of the archives.
If you also wish to receive it every week by mail, you may subscribe to the caml-list.