The generated RootBuilder crashed (undefined behavior on std::vector::back())
when a JSON document's root value was a scalar or null while the schema
declared a non-nullable object or array root. The stack starts empty for
object/array roots, but cbStringData, cbNumberData, and cbBool called
stack_.back() without checking for an empty stack.
Add an empty-stack guard to the three scalar callbacks so they reject
instead of crashing. cbNull already handles the empty-stack case.
Regression tests added for:
- non-nullable object root rejecting null, boolean, number, and string roots
- nullable object root rejecting scalar roots
- nullable array root rejecting scalar roots
Closes#16
The C++ code generator now handles schemas where the top-level type is
nullable ("type": ["object", "null"], ["string", "null"], or
["array", "null"]).
Changes to weaseljson_schemagen.py:
- Rename the inner object struct when the root is a nullable object, so
the `using Root = std::optional<...>` alias no longer conflicts with
`struct Root`.
- Treat nullable root objects and arrays as container roots, emplacing
the inner value before pushing the root frame and pointing the frame at
the contained value.
- For nullable root scalars/enums, engage() now returns a pointer to the
value inside the optional rather than to the optional wrapper itself.
- cbNull() now safely accepts a top-level null when the root is nullable
and rejects it otherwise.
Regression tests added:
- nullable_object.schema.json + test_nullable_root.cpp
- nullable_string.schema.json
- nullable_array.schema.json
Closes#13