Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
90cde16
c: emit form-1 table files and restore wire conformance
gafferongames Sep 7, 2026
21e354c
c: satisfy GCC fallthrough checks and refresh benchmark tables
gafferongames Sep 7, 2026
475cb68
Merge remote-tracking branch 'origin/main' into codex/c-table-wire
gafferongames Sep 7, 2026
6e6b14b
c: carry fixed table kinds, unions, text and defaults
gafferongames Sep 7, 2026
e8efb3d
c: declare wide-storage CI dependency and satisfy lint
gafferongames Sep 7, 2026
4a861db
c: use kind dispatch in union array reads
gafferongames Sep 7, 2026
1564954
c: implement table graph and blob file wire
gafferongames Sep 7, 2026
ba3d846
c: implement table maps, lists and collection extents
gafferongames Sep 7, 2026
2842a22
c: integrate reference collection recovery repairs
gafferongames Sep 7, 2026
069de05
c: write canonical table cooks and expose block refusal reasons
gafferongames Sep 8, 2026
dedbe1a
Emit the complete C unit registry and repair table bounds
gafferongames Sep 8, 2026
bb61510
Align nested message payloads at their batch position
gafferongames Sep 8, 2026
3fda8a8
Implement C bitpacked message batches and announcements
gafferongames Sep 8, 2026
af04533
Encode nested message bodies once at their batch position
gafferongames Sep 8, 2026
b7898a2
Report wide-string arm bounds in the shared view listing
gafferongames Sep 8, 2026
393301a
Reconcile reviewed reference list and flags widening repairs
gafferongames Sep 8, 2026
08df02d
Implement bounded C retention and apply table review repairs
gafferongames Sep 8, 2026
e16c0ec
Reconcile shared region and collection decoder repairs
gafferongames Sep 8, 2026
b1efdd7
Gate C retention with mutations and a drop-field negative control
gafferongames Sep 8, 2026
4939d9a
Refuse oversized builder map counts before narrowing or decoding
gafferongames Sep 8, 2026
5bf519d
Close compiled wide and collection reference regressions
gafferongames Sep 8, 2026
88fac6d
Refuse hidden union-arm collection extents in C++ (#724)
gafferongames Sep 8, 2026
8126097
Reset counted-array storage beyond a replacement prefix (#725)
gafferongames Sep 8, 2026
efeefbe
Count C map-key widening once per field
gafferongames Sep 8, 2026
0dd1330
Reconcile reference review callers and emitted source pins
gafferongames Sep 8, 2026
aa782a8
c: finish table coverage and make generated messages portable
gafferongames Sep 8, 2026
37a7a44
Merge main and preserve both completed table carrier sets
gafferongames Sep 8, 2026
2954ba6
c: validate pointer arm framing before reporting pointee mismatches
gafferongames Sep 8, 2026
e53473d
tablewire: discard orphan map retention on a later occurrence
gafferongames Sep 8, 2026
6ae11e6
tables: reset only the previously live counted-array tail
gafferongames Sep 8, 2026
6dd9ff7
Restore counted-array tails in the shared wire oracle
gafferongames Sep 8, 2026
2c22dac
Make C tail reset storage bounds explicit and finish review notes
gafferongames Sep 8, 2026
5a56426
Separate C control rebuilds and pin dropped message map keys
gafferongames Sep 8, 2026
8deda5d
Probe message map keys before decoding their values
gafferongames Sep 8, 2026
604e362
Name repeated map fields in retention occurrence rules
gafferongames Sep 8, 2026
c669665
Preserve map widening across repeated message keys
gafferongames Sep 8, 2026
8065952
Integrate completed C and Go table backends for landing
gafferongames Sep 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 24 additions & 24 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,37 +37,37 @@

| feature | cpp | c | rust | go | cs | java | js | dart | elixir | swift | ts | lua | clojure | python | ruby | kotlin | gdscript | zig | odin | haxe |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| fixed class on the table wire (its previous form; the current id-table form is its own row below) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| fixed class on the table wire (wire-form coverage below) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| text form, fixed class | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| reflection descriptors | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| block form, read side | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| cook open | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| build version | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| variable class (pointers, the flat node table) | ✅ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| text form, variable class | ✅ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| variable class (pointers, the flat node table) | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| text form, variable class | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| block form, build side | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| cook write in the runtime | ✅ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| wide scalars (128-bit) on the table wire | ✅ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| unions whose arms are tables | ✅ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| arrays of pointers | ✅ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| arrays of unions | ✅ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| optional arrays | ✅ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| blobs (*bytes, *string) | ✅ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| the wire fuzzer gate | ✅ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| maps | ✅ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| union arms of any field type | ✅ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| string, bytes and flags defaults, and renaming a table | ✅ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| renaming variants, arms and type fields | ✅ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| the 64-bit id-table wire, enum and escape kinds | ✅ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| JSON in and out of one table instance | ✅ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| wstring(N) on the table wire (#522) | ✅ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| unbounded arrays | ✅ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| the message form | ✅ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| bitpacked table message form | ✅ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| retain-unknown | ✅ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| cook write in the runtime | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| wide scalars (128-bit) on the table wire | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| unions whose arms are tables | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| arrays of pointers | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| arrays of unions | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| optional arrays | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| blobs (*bytes, *string) | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| the wire fuzzer gate | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| maps | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| union arms of any field type | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| string, bytes and flags defaults, and renaming a table | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| renaming variants, arms and type fields | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| the 64-bit id-table wire, enum and escape kinds | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| JSON in and out of one table instance | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| wstring(N) on the table wire (#522) | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| unbounded arrays | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| the message form | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| bitpacked table message form | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| retain-unknown | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| doc comments and tags in the descriptors | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| the unit registry, UnitView | ✅ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| widening on read, and the refusal reasons | ✅ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| the unit registry, UnitView | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| widening on read, and the refusal reasons | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |

Go supports the complete table surface through caller-owned regions, mutable
arena builders and cooks. `test-go` covers all eighteen conformance surfaces,
Expand Down
54 changes: 54 additions & 0 deletions compiler/issue710_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,34 @@ func TestIssue710TableRecovery(t *testing.T) {
}
cpp.WriteString("return 0;}\n")
issue710CompileRun(t, dir, "c++", ".cpp", cpp.String())
cfiles, err := c.Generate(u, "c", Options{})
if err != nil {
t.Fatal(err)
}
cdir := t.TempDir()
for name, data := range cfiles {
if err := os.WriteFile(filepath.Join(cdir, name), data, 0644); err != nil {
t.Fatal(err)
}
}
checks := []string{
`Text v; TableReport r={0}; if(!text_load(&v,wire,sizeof(wire),&r) || !r.malformed || v.after!=42 || v.label_length!=8 || strcmp(v.label,"untitled")) return 1;`,
`Rows v; TableReport r={0}; if(!rows_load(&v,wire,sizeof(wire),&r) || !r.malformed || v.after!=42 || v.items_count!=1 || v.items[0].value!=7) return 2;`,
`MappingBuilder b; TableReport r={0}; int ok; if(!mapping_builder_init(&b))return 3; ok=mapping_load_builder(&b,wire,sizeof(wire),&r); if(!ok || !r.malformed || mapping_builder_root(&b)->after!=42 || mapping_builder_root(&b)->items.count) return 4; mapping_builder_shutdown(&b);`,
`Keyed v; TableReport r={0}; if(!keyed_load(&v,wire,sizeof(wire),&r) || !r.malformed || v.after!=42 || v.items[0].value!=7 || v.items[1].value!=55) return 5;`,
}
var csrc strings.Builder
csrc.WriteString("#include \"ProbeTable.h\"\nint main(void){\n")
for i, tc := range cases {
csrc.WriteString("{const uint8_t wire[]={")
for _, b := range tc.wire {
fmt.Fprintf(&csrc, "%d,", b)
}
csrc.WriteString("};" + checks[i] + "}\n")
}
csrc.WriteString("return 0;}\n")
issue710CompileRun(t, cdir, "cc", ".c", csrc.String())

}

func issue710CompileRun(t *testing.T, dir, compiler, ext, source string) {
Expand Down Expand Up @@ -338,6 +366,32 @@ func TestIssue710ListRefusal(t *testing.T) {
}
cpp.WriteString("return 0;}\n")
issue710CompileRun(t, dir, "c++", ".cpp", cpp.String())
cfiles, err := New().Generate(u, "c", Options{})
if err != nil {
t.Fatal(err)
}
cdir := t.TempDir()
for name, data := range cfiles {
if err := os.WriteFile(filepath.Join(cdir, name), data, 0644); err != nil {
t.Fatal(err)
}
}
var csrc strings.Builder
csrc.WriteString("#include \"ProbeTable.h\"\nint main(void){\n")
for _, tc := range []struct {
root, fn string
body []byte
}{{"Lists", "lists", body}, {"Nested", "nested", nested}, {"KeyedLists", "keyed_lists", keyed}} {
wire := issue710Wire(tc.body, ids...)
csrc.WriteString("{const uint8_t wire[]={")
for _, b := range wire {
fmt.Fprintf(&csrc, "%d,", b)
}
fmt.Fprintf(&csrc, "};%sBuilder b;TableReport r={0};int reason=0;if(!%s_builder_init(&b))return 1;if(%s_load_builder(&b,wire,sizeof(wire),&r) || r.malformed || r.unknown || r.kind_mismatch || %s_builder_root(&b)->after) return 2;if(%s_load_measure_ex(wire,sizeof(wire),NULL,&reason)!=-1 || reason!=11)return 3;%s_builder_shutdown(&b); }\n", tc.root, tc.fn, tc.fn, tc.fn, tc.fn, tc.fn)
}
csrc.WriteString("return 0;}\n")
issue710CompileRun(t, cdir, "cc", ".c", csrc.String())

}

func TestIssue710CTableBounds(t *testing.T) {
Expand Down
6 changes: 3 additions & 3 deletions compiler/packetvaluedefaults_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func TestPacketValueDefaultsCarriers(t *testing.T) {

func TestPacketValueDefaultsBesideUnrelatedTable(t *testing.T) {
u := unitFromSource(t, packetValueDefaultsUnit+"\ntable Counter { number int32 }\n")
for _, target := range []string{"c", "go", "rust", "java", "js", "dart", "elixir"} {
for _, target := range []string{"rust", "java", "js", "dart", "elixir"} {
if _, err := New().Generate(u, target, Options{}); err != nil {
t.Fatalf("%s: an unrelated table must not turn packet defaults into table defaults: %v", target, err)
}
Expand Down Expand Up @@ -101,7 +101,7 @@ type Loose
src := "package vdef\nflags Caps { Jump, Crouch }\n" +
tc.decl + " Badge {\n" + fields + "}\n" + tc.edge + packet
u := unitFromSource(t, src)
for _, target := range []string{"c", "rust", "java", "js", "dart", "elixir"} {
for _, target := range []string{"rust", "java", "js", "dart", "elixir"} {
_, err := New().Generate(u, target, Options{})
if err == nil {
t.Fatal("table-closure defaults accepted without table reset and elision support")
Expand All @@ -113,7 +113,7 @@ type Loose
t.Errorf("refusal does not name %q: %v", want, err)
}
}
if strings.Contains(err.Error(), "Loose.label") || !strings.Contains(err.Error(), "generate with --lang cpp, --lang cs and --lang go, or drop the default") {
if strings.Contains(err.Error(), "Loose.label") || !strings.Contains(err.Error(), "generate with --lang c, --lang cpp, --lang cs and --lang go, or drop the default") {
t.Errorf("table refusal includes a supported packet field or names %s as a table carrier: %v", target, err)
}
}
Expand Down
6 changes: 3 additions & 3 deletions compiler/packetvoidarms_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,12 @@ func TestScalarArmInTypeBodyIsRefusedByCheck(t *testing.T) {
}
}

func TestPacketVoidArmSupportPreservesCTableRefusal(t *testing.T) {
func TestPacketAndTableVoidArmsInC(t *testing.T) {
u := unitFromSource(t, strings.Replace(voidArmInTypeBody, "type FireCommand", "table FireCommand", 1))
c := New()
_, err := c.Generate(u, "c", Options{})
if err == nil || !strings.Contains(err.Error(), "payload-free arm in a table closure") || !strings.Contains(err.Error(), "WeaponFire") {
t.Fatalf("C must retain its named table-closure refusal, got %v", err)
if err != nil {
t.Fatalf("C refused a supported table payload-free arm: %v", err)
}
if _, err := c.Generate(u, "cpp", Options{}); err != nil {
t.Fatalf("C++ must retain its existing table payload-free support: %v", err)
Expand Down
6 changes: 6 additions & 0 deletions compiler/packetwidetext_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ func TestPacketWideTextRefusesTableClosure(t *testing.T) {
continue
}
_, err := New().Generate(u, target, nil)
if target == "c" {
if err != nil {
t.Errorf("C refused table wide text: %v", err)
}
continue
}
if err == nil || !strings.Contains(err.Error(), "table closure") || !strings.Contains(err.Error(), "wstring(N)") {
t.Errorf("%s failed to refuse the table-wide closure: %v", target, err)
}
Expand Down
15 changes: 15 additions & 0 deletions compiler/repeatedarraytail_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"encoding/hex"
"fmt"
"path/filepath"
"strings"
"testing"
)

Expand All @@ -29,6 +30,16 @@ func TestRepeatedArrayTailDefaults(t *testing.T) {
#define CHECK(x) do{if(!(x)){fprintf(stderr,"tail defaults line %%d: %%s\n",__LINE__,#x);return 1;}}while(0)
static const uint8_t wire[]={%s};
`, cppWire(wire))
t.Run("c-bounded-extent", func(t *testing.T) {
// Replace the first array count with UINT64_MAX, preserving its L.
// Only the two encoded elements exist; extent must stop at EOF.
mutant := append([]byte(nil), wire[:5]...)
mutant[3] += 9
mutant = append(mutant, 255, 255, 255, 255, 255, 255, 255, 255, 255, 1)
mutant = append(mutant, wire[6:]...)
source := strings.Replace(common, cppWire(wire), cppWire(mutant), 1)
runCTableWireProbe(t, u, source+`int main(void){CHECK(hand_load_measure(wire,sizeof(wire))==88);return 0;}`)
})
t.Run("cpp", func(t *testing.T) {
files, err := New().Generate(u, "cpp", Options{})
if err != nil {
Expand All @@ -37,4 +48,8 @@ static const uint8_t wire[]={%s};
referenceCompileRun(t, files, common+`using namespace armdemo;
int main(){TableReport report;int64_t n=HandLoadMeasure(wire,sizeof(wire));CHECK(n>0);uint8_t * region=(uint8_t*)malloc(n);const Hand * r=HandLoad(region,n,wire,sizeof(wire),&report);CHECK(r);CHECK(report.malformed);CHECK(r->entries_count==0);CHECK(r->entries[1].type==CarryType::None);HandBuilder b;CHECK(HandLoadBuilder(b,wire,sizeof(wire),&report));CHECK(b.GetRoot()->entries[1].type==CarryType::None);CHECK(HandCookMeasure(b)>0);free(region);return 0;}`)
})
t.Run("c", func(t *testing.T) {
runCTableWireProbe(t, u, common+`
int main(void){TableReport report={0};int64_t n=hand_load_measure(wire,sizeof(wire));CHECK(n>0);uint8_t * region=(uint8_t*)malloc((size_t)n);const Hand * r=hand_load(region,n,wire,sizeof(wire),&report);CHECK(r);CHECK(report.malformed);CHECK(r->entries_count==0);CHECK(r->entries[1].type==0);free(region);return 0;}`)
})
}
26 changes: 20 additions & 6 deletions compiler/tablesc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,15 @@ func TestCTableRuntimeNamesAreClaimed(t *testing.T) {
if err != nil {
t.Fatal(err)
}
ident := regexp.MustCompile(`\b(?:Table|kTable|table_|BuildVersion)[A-Za-z0-9_]*\b`)
// Include a fixed unit to check the allocation-free runtime as well.
fixed, err := New().Generate(unitFromSource(t, runtimeSrc), "c", Options{})
if err != nil {
t.Fatal(err)
}
for name, data := range fixed {
files["fixed-"+name] = data
}
ident := regexp.MustCompile(`\b(?:(?:Table|kTable|table_|BuildVersion|schema_allocate|schema_release|schema_assert|schema_fatal)[A-Za-z0-9_]*|announce(?:_measure|_read)?)\b`)
// the unit's own type names start with Table for a schema that declares one;
// the corpus here declares none, and the file base does, so the two file
// spellings the include lines carry are excluded by name rather than by a
Expand Down Expand Up @@ -151,14 +159,20 @@ func TestCExternalsCarryThePackage(t *testing.T) {
// must not become a collision the day a table gains a pointer (§11) — so the
// scan needs a corpus where every name is actually emitted.
const cRuntimeSrc = runtimeSrc + `
table ScalarLeaf { value uint32 }
table Node
{
value int32
next *Node
}
table Collections { items []Node
rows map[string(8)]Node
}

`

// TestCForceInlineStopsAtTheVariableClass is the C twin of the reference's
// TestCForceInlineStopsAtTheVariableClass also leaves composite bodies plain
// to keep deep by-value closures from expanding during compilation. It is the C twin of the reference's
// recursion guard (schema#343). The force-inline qualifier carries the fixed
// class's bodies and stops there, because that is the class whose save/load
// call graph cannot hold a cycle: a fixed table nests by value, and a by-value
Expand All @@ -179,8 +193,8 @@ func TestCForceInlineStopsAtTheVariableClass(t *testing.T) {
t.Fatal("no ProbeTable.h")
}
for _, want := range []string{
"static SCHEMA_UNUSED SCHEMA_PROBE_TABLE_INLINE int config_save_body( TableWriter * w, const Config * value )",
"static SCHEMA_UNUSED SCHEMA_PROBE_TABLE_INLINE int config_load_body( TableReader * r, Config * value )",
"static SCHEMA_UNUSED SCHEMA_PROBE_TABLE_INLINE int scalar_leaf_save_body( TableWriter * w, const ScalarLeaf * value )",
"static SCHEMA_UNUSED SCHEMA_PROBE_TABLE_INLINE int scalar_leaf_load_body( TableReader * r, ScalarLeaf * value )",
"static SCHEMA_UNUSED SCHEMA_PROBE_TABLE_INLINE void table_writer_put32( TableWriter * w, uint32_t v )",
"static SCHEMA_UNUSED SCHEMA_PROBE_TABLE_INLINE uint32_t table_reader_get32( TableReader * r )",
} {
Expand Down Expand Up @@ -277,8 +291,8 @@ func TestCGeneratorMacrosAreOwned(t *testing.T) {
continue
}
// anything carrying the schema's own prefix is a macro the
// DECLARATIONS asked for, in either spelling the emitter uses
if strings.Contains(m[1], "ZQQ") || strings.Contains(m[1], "Zqq") {
// DECLARATIONS asked for, in the upper, Pascal and C snake spellings the emitter uses
if strings.Contains(m[1], "ZQQ") || strings.Contains(m[1], "Zqq") || strings.HasPrefix(m[1], "zqq_") {
continue
}
owned[m[1]] = true
Expand Down
Loading
Loading