Skip to content

Commit d9dcab9

Browse files
authored
Merge branch 'master' into pedrolisboa/attr
2 parents a500592 + 16d9957 commit d9dcab9

122 files changed

Lines changed: 7803 additions & 2676 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.circleci/config.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,11 @@ jobs:
5151

5252
build_min_ocaml:
5353
docker:
54-
- image: ocaml/opam:ubuntu-24.04-ocaml-4.08
54+
- image: ocaml/opam:ubuntu-24.04-ocaml-4.14
5555
working_directory: ~/atd
5656
steps:
5757
- build:
58-
ocaml_version: "4.08"
58+
ocaml_version: "4.14"
5959

6060
workflows:
6161
version: 2

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,6 @@ tmp
3333
# Where we install binaries and other things locally to make them easily
3434
# available for testing (used by atdml)
3535
local/
36+
37+
# Local Claude Code settings
38+
/.claude/settings.local.json

CHANGES.md

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,60 @@
11
unreleased
2+
----------
23

34
* atdml: Add support for `<ocaml attr="...">` on record fields, variant constructors,
45
and variant payload types to attach ppx attributes (e.g. `[@deriving.ord.ignore]`)
5-
----------
66

7-
...
7+
4.1.0 (2026-04-11)
8+
------------------
9+
10+
* Build: OCaml >= 4.14 is now required (previously 4.08). This aligns
11+
all packages with the `yamlx` dependency of `atd-yamlx`.
12+
13+
* Testing: Add a standard JSON round-trip test suite (`standard-tests/`)
14+
that any code generator can opt into. The harness generates code from an
15+
ATD spec, compiles it, feeds JSON to stdin, and checks the output.
16+
atdml is the first backend to run these tests.
17+
18+
* New package: **`atd-yamlx`**. Translates a parsed YAML value
19+
(`YAMLx.value` from the `yamlx` library) into `Atd_jsonlike.AST.t`,
20+
preserving source locations at every node so that ATD-generated reader
21+
functions (`foo_of_jsonlike`) can report precise file/line/column error
22+
messages when deserializing YAML configuration files.
23+
- `of_yamlx_value` returns `(AST.t, string) result`; the raising variant
24+
is `of_yamlx_value_exn`.
25+
- `atd-yamlx/examples/` is a self-contained dune subproject demonstrating
26+
a typed YAML config reader built with `atdml` and `atd-yamlx`.
27+
28+
* All backends: Add `<json repr="object">` on sum types. Tagged variants are
29+
encoded as single-key JSON objects `{"Constructor": payload}` instead of the
30+
default `["Constructor", payload]` arrays. Unit variants are unaffected
31+
(`"Constructor"` strings). This matches Serde's externally-tagged
32+
representation and produces idiomatic YAML (a single-key mapping rather than
33+
a two-element sequence). Supported in: atdml (OCaml), atdpy (Python),
34+
atdts (TypeScript), atdcpp (C++), atdd (D), atdj (Java), atds (Scala).
35+
atdml additionally generates `of_jsonlike` readers automatically.
36+
37+
* New package: **`atd-jsonlike`**. Defines a generic JSON-like AST
38+
(`Atd_jsonlike.AST.t`) with source location information at every node.
39+
Intended as a target type for code generated by ATD tools, so that
40+
reader functions can report precise file/line/column error messages.
41+
Supports JSON numbers via `Atd_jsonlike.Number.t`, which stores all
42+
available representations (`int`, `float`, and `literal` string) for
43+
maximum flexibility.
44+
45+
* atdml: Generate `foo_of_jsonlike` reader functions that accept an
46+
`Atd_jsonlike.AST.t` value and return a typed OCaml value, with error
47+
messages that include the original source location.
48+
- Default output is Yojson-based readers/writers only (no `atd-jsonlike`
49+
dependency unless explicitly requested).
50+
- New `--mode MODE` option (repeatable) selects what to generate.
51+
`MODE` is a mode name or comma-separated list of mode names.
52+
Valid modes: `yojson`, `jsonlike`, `all` (= yojson + jsonlike).
53+
Example: `atdml --mode yojson,jsonlike foo.atd`
54+
- JSON adapters (`<json adapter.ocaml="M">`) are supported for the jsonlike
55+
path: if the adapter module `M` provides `normalize_jsonlike`, it is called
56+
before deserialization by `foo_of_jsonlike`. Inline adapters
57+
(`adapter.to_ocaml`/`adapter.from_ocaml`) do not support jsonlike.
858

959
4.0.0 (2026-03-16)
1060
------------------

Makefile

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
#
2-
# Makefile for developer's convenience.
1+
2+
## Makefile for developer's convenience.
33
# Build logic is implemented with dune.
44
#
55

@@ -59,6 +59,7 @@ test-common:
5959
$(MAKE) -C atd test
6060
$(MAKE) -C atdcat test
6161
$(MAKE) -C atddiff test
62+
$(MAKE) -C atd-jsonlike test
6263

6364
# Test only the OCaml backends
6465
.PHONY: test-ocaml

atd-jsonlike.opam

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
# This file is generated by dune, edit dune-project instead
2+
opam-version: "2.0"
3+
synopsis: "Generic JSON-like AST for use with ATD code generators"
4+
description: """
5+
atd-jsonlike provides a generic tree type for representing JSON-like data
6+
(JSON, YAML, TOML, etc.) for use as a target type in code generated by ATD
7+
tools such as atdml."""
8+
maintainer: [
9+
"Louis Roché <louis@louisroche.net>"
10+
"Martin Jambon <martin@mjambon.com>"
11+
"Rudi Grinberg <me@rgrinberg.com>"
12+
]
13+
authors: [
14+
"Martin Jambon <martin@mjambon.com>"
15+
"Martin Jambon <martin@r2c.dev>"
16+
"Rudi Grinberg <rudi.grinberg@gmail.com>"
17+
"Martin Jambon <github@mjambon.com>"
18+
"Alexandre Bourquelot <alexandre.bourquelot@ahrefs.com>"
19+
"oleksiy <oleksiy.golovko@ahrefs.com>"
20+
"Ivan Jager <aij+git@mrph.org>"
21+
"Martin Jambon <martin@semgrep.com>"
22+
"Gregoire Lionnet <gregoire.lionnet@ahrefs.com>"
23+
"Sebastien Mondet <sebastien.mondet@ahrefs.com>"
24+
"David Sheets <sheets@alum.mit.edu>"
25+
"Rudi Grinberg <me@rgrinberg.com>"
26+
"Martin Jambon <martin@esper.com>"
27+
"Rytis Jonynas <rytis.jonynas@ahrefs.com>"
28+
"Jeff Meister <nanaki@gmail.com>"
29+
"Raman Varabets <roman.vorobets@gmail.com>"
30+
"Carmelo Piccione <carmelo.piccione@gmail.com>"
31+
"Louis <louis.roche@ahrefs.com>"
32+
"Caio Wakamatsu <caio.wakamatsu@ahrefs.com>"
33+
"Marek Kubica <marek@tarides.com>"
34+
"Daniel Weil <danweil68@gmail.com>"
35+
"Egor Chemokhonenko <egor.chemohonenko@ahrefs.com>"
36+
"Gabriel Scherer <gabriel.scherer@gmail.com>"
37+
"Javier Chavarri <javier.chavarri@gmail.com>"
38+
"Louis Roché (Ahrefs) <louis.roche@ahrefs.com>"
39+
"Matthew McQuaid <matthew@returntocorp.com>"
40+
"Raman Varabets <raman+git@ahrefs.com>"
41+
"koonwen <koonwen@gmail.com>"
42+
"tzm <frank@boldsolutions.de>"
43+
"Mathieu Baudet <mathieubaudet@fb.com>"
44+
"Oleksiy Golovko <alexei.golovko@gmail.com>"
45+
"Rauan Mayemir <rauan@mayemir.io>"
46+
"Seb Mondet <seb@mondet.org>"
47+
"Alexandre Bourquelot <alexandre.bourquelot@gmail.com>"
48+
"Carmelo Piccione <cep1@solvuu.com>"
49+
"Hyeseong Kim <hey@hyeseong.kim>"
50+
"John Billings <john@monkeynut.org>"
51+
"Louis Roché <louis@louisroche.net>"
52+
"Mathieu Barbin <mathieu.barbin@gmail.com>"
53+
"Zach Yannes <zach@returntocorp.com>"
54+
"Antonin Décimo <antonin@tarides.com>"
55+
"Brendan Long <self@brendanlong.com>"
56+
"Chris Yocum <cyocum@gmail.com>"
57+
"Kate <kit.ty.kate@disroot.org>"
58+
"Louis Roché <louis.roche@ahrefs.com>"
59+
"Pavel Antoshkin <pavel.antoshkin@ahrefs.com>"
60+
"Pierre Boutillier <pierre.boutillier@laposte.net>"
61+
"Shon Feder <shon.feder@key.me>"
62+
"metanivek <metanivek@gmail.com>"
63+
"sebastiantoh <sebas.tsj.98@gmail.com>"
64+
"Anurag Soni <anuragsoni.13@gmail.com>"
65+
"Arjun Ravi Narayan <arjunravinarayan@gmail.com>"
66+
"Asya-kawai <kawai-toshiki@aintek.xyz>"
67+
"Christophe Troestler <christophe.Troestler@umons.ac.be>"
68+
"Corentin Leruth <corentin.leruth@gmail.com>"
69+
"Damien Doligez <ddoligez@janestreet.com>"
70+
"Daniel M <dan.mntg@gmail.com>"
71+
"Ding Xiang Fei <dingxiangfei2009@protonmail.ch>"
72+
"Enrico Tassi <Enrico.Tassi@Inria.fr>"
73+
"François Pottier <francois.pottier@inria.fr>"
74+
"Javier Chávarri <javier.chavarri@gmail.com>"
75+
"Jonas Bergler <jonas@bergler.name>"
76+
"Kate <kit-ty-kate@exn.st>"
77+
"Koon Wen Lee <koonwen@gmail.com>"
78+
"Louis <mail+github@louisroche.net>"
79+
"Louis Roché <louis@cryptosense.com>"
80+
"Stephane Legrand <slegrand45@gmail.com>"
81+
"Vincent Bernardoff <vb@luminar.eu.org>"
82+
"Zach <zachyannes@gmail.com>"
83+
"haoyang <haoyang@esper.co>"
84+
"pmundkur <prashanth.mundkur@gmail.com>"
85+
"rr0gi <igor@ahrefs.com>"
86+
"ygrek <ygrek@autistici.org>"
87+
]
88+
license: "BSD-3-Clause"
89+
homepage: "https://github.com/ahrefs/atd"
90+
bug-reports: "https://github.com/ahrefs/atd/issues"
91+
depends: [
92+
"dune" {>= "3.18"}
93+
"ocaml" {>= "4.14"}
94+
"re" {>= "1.9.0"}
95+
"testo" {>= "0.3.0" & with-test}
96+
"odoc" {with-doc}
97+
]
98+
dev-repo: "git+https://github.com/ahrefs/atd.git"
99+
x-maintenance-intent: ["(latest)"]
100+
build: [
101+
["dune" "subst"] {dev}
102+
[
103+
"dune"
104+
"build"
105+
"-p"
106+
name
107+
"-j"
108+
jobs
109+
"@install"
110+
"@doc" {with-doc}
111+
]
112+
]

atd-jsonlike/Makefile

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
DUNE ?= dune
2+
3+
.PHONY: build
4+
build:
5+
$(DUNE) build
6+
7+
.PHONY: test
8+
test: build
9+
$(DUNE) build tests/test.exe
10+
./test

atd-jsonlike/README.md

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# atd-jsonlike
2+
3+
Generic JSON-like AST for use with ATD code generators.
4+
5+
## Overview
6+
7+
`atd-jsonlike` defines a simple AST type for representing JSON-like data
8+
(JSON, YAML, TOML, …) with source location information attached to every
9+
node. Its primary consumer is [atdml](../atdml/): the `foo_of_jsonlike`
10+
functions generated by `atdml` accept an `Atd_jsonlike.AST.t` value and
11+
return a typed OCaml value, with error messages that include the original
12+
file/line/column from the AST.
13+
14+
## Modules
15+
16+
### `AST`
17+
18+
```ocaml
19+
type t =
20+
| Null of Loc.t
21+
| Bool of Loc.t * bool
22+
| Number of Loc.t * Number.t
23+
| String of Loc.t * string
24+
| Array of Loc.t * t list
25+
| Object of Loc.t * (Loc.t * string * t) list
26+
```
27+
28+
Every node carries a `Loc.t` so that reader functions can report precise
29+
locations in error messages via `AST.loc_msg`.
30+
31+
`Object` entries also carry a per-key `Loc.t` for the key itself (the
32+
outer `Loc.t` covers the whole key-value pair).
33+
34+
### `Number`
35+
36+
`Number.t` stores all available representations of a JSON number so that
37+
readers can pick whichever form fits their target type:
38+
39+
```ocaml
40+
type t = private {
41+
int: int option;
42+
float: float option;
43+
literal: string option;
44+
}
45+
```
46+
47+
| Source | `int` | `float` | `literal` |
48+
|--------|-------|---------|-----------|
49+
| `of_int 42` | `Some 42` | `Some 42.` | `Some "42"` |
50+
| `of_float 1.5` | `None` | `Some 1.5` | `None` |
51+
| `of_float 3.0` | `Some 3` | `Some 3.` | `None` |
52+
| `of_string_opt "1.2e3"` | `None` | `Some 1200.` | `Some "1.2e3"` |
53+
| `of_string_opt "1e400"` | `None` | `None` | `Some "1e400"` |
54+
55+
Rules enforced by the constructors:
56+
- `literal`, when set, is always a valid JSON number string (no `+42`, no
57+
leading zeros, no `NaN`).
58+
- All set fields are mutually consistent (same numeric value).
59+
- At least one field is always set.
60+
61+
`of_float` does not populate `literal` because it operates on a binary
62+
float that has already lost the original text. Use `of_string_opt` when
63+
you are parsing from source text and want to preserve the literal.
64+
65+
### `Loc` and `Pos`
66+
67+
`Loc.t` is a half-open source range (start + end `Pos.t`) plus an
68+
optional file path. `Pos.t` is a `{ row; column }` pair, both 0-based
69+
(rows and columns are displayed as 1-based in error messages).
70+
71+
## Building and testing
72+
73+
```sh
74+
cd atd-jsonlike
75+
make # build
76+
make test # run unit tests
77+
```

0 commit comments

Comments
 (0)