Skip to content

Commit 843a9dd

Browse files
committed
feat(language): describe canonical module interfaces
1 parent dd17d62 commit 843a9dd

13 files changed

Lines changed: 1318 additions & 169 deletions

File tree

language/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ hgl_apply_warnings(hgl_graph_ir)
155155
# descriptor-only checking.
156156
add_library(hgl_descriptor STATIC
157157
src/descriptor/module_descriptor.cpp
158+
src/descriptor/module_descriptor_json.cpp
158159
)
159160
add_library(hgl::descriptor ALIAS hgl_descriptor)
160161
target_compile_features(hgl_descriptor PUBLIC cxx_std_23)

language/docs/design/decisions/0004-json-module-descriptors.md

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# ADR 0004: Module descriptors use canonical versioned JSON
22

3-
Status: accepted; reader and complete interface schema pending
3+
Status: accepted; writer implemented, reader and native ABI metadata pending
44

55
## Context
66

@@ -9,9 +9,9 @@ authors can review, build tools can transport, and `hgl check` can eventually
99
consume without loading executable code. The representation must not depend on
1010
C++ object layout, compiler ABI, parser internals, or a running hgraph registry.
1111

12-
The first producer is the HGL C++ backend itself. It needs to establish the
13-
envelope and package inventories before the following slices add complete type,
14-
constraint, lifecycle, and fingerprint records.
12+
The first producer is the HGL C++ backend itself. The descriptor must carry
13+
enough structured source interface data for a later reader to check imports
14+
without reparsing HGL or loading executable code.
1515

1616
## Decision
1717

@@ -20,18 +20,38 @@ Use UTF-8 JSON with the format identity `hgl.module` and an integer
2020

2121
- module identity and HGL release version;
2222
- automatically public operators, exported structures, and exported functions;
23+
- generic and ordinary parameters, results, default values, struct parents and
24+
effective fields;
25+
- canonical type, compile-time-expression, and constraint records reachable
26+
from those public declarations and implementation candidates;
2327
- implementation-to-operator bindings and required provider identities;
2428
- generated public headers, known CMake packages and imported targets; and
2529
- the generated C++ registration symbol.
2630

2731
The canonical emitter uses a fixed object-member order, lexically sorts and
28-
deduplicates set-like arrays, escapes every JSON control character, and writes
29-
one trailing line feed. A reader must treat object-member order and insignificant
32+
deduplicates set-like identity and build inventories, preserves semantic operand
33+
order inside expressions, escapes every JSON control character, and writes one
34+
trailing line feed. A reader must treat object-member order and insignificant
3035
whitespace as irrelevant, reject duplicate members and unsupported format
3136
versions, and ignore unknown members within a supported version. Adding an
3237
optional member is compatible; changing or removing existing meaning requires a
3338
new `format_version`.
3439

40+
Declarations and candidates refer into three descriptor-local schema arenas:
41+
`types`, `constant_expressions`, and `constraints`. Records are assigned by
42+
visiting exported structures, local operators, exported functions, and provider
43+
implementations in that order, with each group ordered by stable identity.
44+
References are unsigned JSON integers and a missing optional reference is
45+
`null`; record IDs have no meaning outside their descriptor. Generic type and
46+
const parameters also retain a declaration-scoped binding identity, so repeated
47+
names from different contracts never alias.
48+
49+
Integer and floating-point literal payloads are tagged strings. This preserves
50+
the full i64 range and HGL's `inf`, `-inf`, and `nan` values without depending on
51+
a JSON consumer's numeric range or its handling of non-standard JSON tokens.
52+
Booleans remain JSON booleans, strings remain strings, and temporal values use
53+
their canonical HGL spelling together with their temporal kind.
54+
3555
Descriptor fingerprints will be computed over the canonical semantic form, not
3656
over arbitrary input whitespace. The fingerprint field itself is excluded from
3757
that input. Its algorithm and placement are intentionally left to the
@@ -49,9 +69,10 @@ install or aggregate it deliberately.
4969
formatting, registry access, and dynamic loading.
5070
- Scripted compilation and AOT generation retain the identical descriptor
5171
bytes with their other build artifacts.
52-
- The initial file is not yet sufficient for descriptor-only type checking;
53-
signatures, constraints, ownership/effects, lifecycle ABI, and fingerprints
54-
remain explicit Stage F work.
72+
- The file now contains structured HGL signatures, struct layouts, defaults,
73+
generic bindings, and constraints. Descriptor reading, dependency closure,
74+
phase/effect/ownership policy, lifecycle ABI, and fingerprints remain
75+
explicit Stage F work before descriptor-only checking is complete.
5576

5677
## Alternatives
5778

language/docs/design/native-interface.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Native interface
22

3-
Status: accepted boundary; JSON envelope implemented, complete schema and ABI remain
3+
Status: accepted boundary; HGL interface schema implemented, native metadata and ABI remain
44

55
## Purpose
66

@@ -53,10 +53,12 @@ For every exposed native declaration the descriptor records:
5353

5454
The serialized representation is the canonical, versioned JSON selected in
5555
[ADR 0004](decisions/0004-json-module-descriptors.md). The current compiler
56-
emits its envelope, public/provider inventories, and generated build metadata;
57-
complete signatures, constraints, phase/effect/ownership policy, lifecycle ABI,
58-
and fingerprints remain to be added. The native-package authoring API is not yet
59-
chosen. No HGL declaration syntax is implied by this list.
56+
emits its envelope, public/provider inventories, structured HGL signatures,
57+
struct layouts, defaults, canonical types and constraints, and generated build
58+
metadata. Descriptor reading and dependency closure,
59+
phase/effect/ownership policy, lifecycle ABI, and fingerprints remain to be
60+
added. The native-package authoring API is not yet chosen. No HGL declaration
61+
syntax is implied by this list.
6062

6163
## Native declaration categories
6264

language/docs/design/roadmap.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,8 @@ HGraph IR; unsupported language-depth items remain explicit roadmap work.
228228
### F. Constrained native interface
229229

230230
- [x] choose and version a reviewable descriptor representation;
231+
- [x] emit structured public/provider signatures, struct layouts, defaults,
232+
canonical types, and generic constraints;
231233
- choose and version the lifecycle ABI;
232234
- provide a native-package authoring API which emits descriptors and normalized
233235
wrappers;

language/docs/developer-guide/compiler-and-lowering.md

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1011,11 +1011,23 @@ registry, loader, or C++ formatter dependency. `hgl emit-cpp` writes
10111011
`<stem>.hgl-module.json` beside the generated source, and scripted native builds
10121012
retain the same bytes in their content-addressed artifacts.
10131013

1014-
Version 1 currently materializes the module/version envelope, public declaration
1015-
identities and categories, implementation/provider inventories, baseline build
1016-
requirements, and the generated registration symbol. This is a staging
1017-
checkpoint, not descriptor-only checking: canonical signature and constraint
1018-
records, effect/ownership policy, lifecycle entry points, and fingerprints are
1014+
Version 1 materializes the module/version envelope, public declarations,
1015+
implementation/provider inventories, baseline build requirements, and the
1016+
generated registration symbol. Public structures, operators, functions, and
1017+
implementation candidates reference structured signatures and three
1018+
descriptor-local arenas for canonical types, compile-time expressions, and
1019+
constraints. Only records reachable from those surfaces are retained; private
1020+
body types do not leak into the package interface.
1021+
1022+
Record IDs are assigned by a fixed traversal of declarations ordered by stable
1023+
identity and are meaningful only inside that descriptor. A symbol type carries
1024+
both its nominal spelling and, for a generic parameter, its declaration-scoped
1025+
binding identity. Defaults and const-generic bounds remain expression trees,
1026+
not strings to be reparsed. Tagged textual i64/f64 payloads retain the full i64
1027+
range and non-finite HGL floats while keeping the output valid JSON.
1028+
1029+
This is still not descriptor-only checking: a reader and locked dependency
1030+
closure, effect/ownership policy, lifecycle entry points, and fingerprints are
10191031
the following Stage F slices.
10201032

10211033
A descriptor separates its importable interface from its provider inventory.

language/docs/user-guide/modules-and-tools.md

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -258,13 +258,52 @@ generated `operators` namespace contains transparent type aliases rather than
258258
derived marker classes, so the registry contract visible in the source is the
259259
exact hgraph `Operator` type.
260260

261-
The JSON sidecar is canonical and versioned. Its first checkpoint records the
262-
module and language versions, public declaration identities, operator
263-
implementations and provider requirements, generated header, baseline hgraph
264-
CMake dependency, and registration symbol. Complete imported signatures,
265-
constraints, native ownership/effect declarations, lifecycle entry points, and
266-
fingerprints are not implemented yet, so this checkpoint does not provide
267-
descriptor-only `hgl check`.
261+
The JSON sidecar is canonical and versioned. It records the module and language
262+
versions; public structures, operators, and functions; implementation
263+
candidates and provider requirements; and the generated build boundary. Its
264+
structured schema records preserve generic bindings, parameters and results,
265+
struct inheritance and effective fields, defaults and rolling bounds, nominal
266+
type applications, and `requires` constraints. Integer and float literal
267+
payloads are tagged strings so the full i64 range and non-finite floats remain
268+
valid JSON.
269+
270+
For example, a generic operator points to descriptor-local type records rather
271+
than embedding source text that another tool would need to parse:
272+
273+
```json
274+
{
275+
"category": "operator",
276+
"identity": "examples.windows.summarize",
277+
"signature": {
278+
"generic_parameters": [
279+
{
280+
"name": "T",
281+
"kind": "type",
282+
"binding": "examples.windows.summarize::T",
283+
"type": null
284+
}
285+
],
286+
"parameters": [
287+
{
288+
"name": "window",
289+
"kind": "signal",
290+
"binding": "examples.windows.summarize::window",
291+
"type": 1,
292+
"default": null
293+
}
294+
],
295+
"result": 2,
296+
"requires": null
297+
}
298+
}
299+
```
300+
301+
The `type`, `result`, `default`, and `requires` numbers refer to records in the
302+
same file's `schema` object. They have no identity outside that one descriptor.
303+
304+
Descriptor loading, transitive dependency locking, native ownership/effect
305+
declarations, lifecycle entry points, and fingerprints are not implemented yet,
306+
so this checkpoint does not provide descriptor-only `hgl check`.
268307

269308
A package is a CMake project. `hgl_add_module()`, installed with `hgl` in
270309
`lib/cmake/hgl/HglLanguage.cmake`, runs `emit-cpp` at build time and compiles

language/src/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ them.
1111
| `semantics/` | name binding, nominal hierarchy, generic argument roles, function classification | syntax plus descriptors to resolved names and shapes |
1212
| `ir/` | source-ranged HIR, canonical types, substitutions, constraint solving, phase/effect completion | resolved frontend state to typed HIR |
1313
| `hgraph_ir/` | canonical execution-facing types, compile-time expressions, constraints, typed source-order declaration handles, struct contracts, operator and callable interfaces | typed HIR to executable composition and runtime-node plans |
14-
| `descriptor/` | versioned module descriptor model and canonical JSON serialization | hgraph IR to reviewable package metadata |
14+
| `descriptor/` | versioned module/interface schema, deterministic HGraph-IR snapshot, and canonical JSON serialization | hgraph IR to reviewable package metadata |
1515
| `wiring/` | direct walk over hgraph IR | hgraph IR to public erased wiring calls |
1616
| `codegen/` | hgraph-IR declaration, interface, dependency, composition-body, and runtime-body emission | hgraph IR to formatted C++ and build artifacts |
1717
| `driver/` | commands, native build/cache/load, REPL orchestration | assemble inputs and invoke passes |

0 commit comments

Comments
 (0)