Repository navigation
kdl: KDL 2.0 parser, writer and struct marshaler (consensus version) - #6
Conversation
d3d4d90 to
31dd860
Compare
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Schema validation currently occurs after parsing, and optional omitempty fields are encoded incorrectly.
Get a fresh assessment by requesting another Copilot review.
Review effort: Balanced
Findings: 2
Open (3)
What changed in this PR
Replaces the previous implementation with a consensus KDL 2.0 parser, canonical writer, data model, and V struct marshaler.
Changes:
- Adds strict parsing, writing, typed accessors, and struct encoding/decoding.
- Vendors the official conformance suite and adds extensive tests.
- Reorganizes examples, documentation, licensing, and CI.
| File | Description |
|---|---|
kdl.v |
Defines the public data model and accessors. |
parser.v |
Implements KDL 2.0 parsing. |
scanner.v |
Handles tokens, numbers, Unicode, and escapes. |
writer.v |
Produces canonical KDL output. |
marshal.v |
Implements struct encoding and decoding. |
*_test.v |
Tests parsing, writing, marshaling, regressions, fuzzing, and conformance. |
examples/** |
Adds updated usage examples. |
tests/test_cases/input/** |
Vendors 338 official parser fixtures. |
tests/test_cases/expected_kdl/** |
Vendors expected output for valid fixtures. |
tests/test_cases/{README,LICENSE,CC-BY-SA-4.0}.txt |
Documents fixture provenance and licensing. |
coerce/**, document/**, parser/**, relaxed/**, tokenizer/** |
Removes the superseded implementation. |
example/**, tests/{document,options,unicode}_test.v |
Removes obsolete examples and tests. |
README.md, LICENSE, v.mod |
Updates API documentation, licensing, and metadata. |
.github/workflows/ci.yml |
Tests both V compilers across supported platforms. |
.gitattributes, .gitignore |
Configures fixture preservation and build exclusions. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
31dd860 to
636a0c4
Compare
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Decoding has schema-validation and numeric-underflow defects, and Windows CI can pass without running module checks.
Get a fresh assessment by requesting another Copilot review.
Review effort: Balanced
Findings: 4
636a0c4 to
5b71121
Compare
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Schema-validation ordering, optional omitempty behavior, and skipped Windows validation leave correctness and coverage gaps.
Get a fresh assessment by requesting another Copilot review.
Review effort: Balanced
Findings: 2
Open (3)
5b71121 to
a37fb66
Compare
a37fb66 to
f95561f
Compare
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Optional-struct decoding can discard configured defaults, and one schema error template is grammatically incorrect.
Get a fresh assessment by requesting another Copilot review.
Review effort: Balanced
Findings: 1
Open (2)
Resolved since last review (2)
f95561f to
adc2597
Compare
Co-authored-by: Jengro777 <avey777@outlook.com>
Co-authored-by: Jengro777 <avey777@outlook.com>
Co-authored-by: Jengro777 <avey777@outlook.com>
adc2597 to
112304a
Compare
|
Although the PR has been merged, the code organization is not very good. |


kdl: KDL 2.0 parser, writer and struct marshaler
@Jengro777, this is the consensus version we discussed in vlang/v#28819, built from your implementation and mine; the details of what comes from where are below. It is opened here because
vlang/kdlis still empty and cannot take a pull request yet; it replaces the current content of this repository, in six commits.kdlreads and writes KDL 2.0 documents and maps them to V structs.A document is a list of nodes; a node has a name, arguments, properties and children; a value is
string | i64 | f64 | bool | Null | BigIntwith an optional type annotation. Syntax errors carry a line and a column. The writer produces the canonical form of the specification.encodeanddecodemap a struct to a document: each field is a node, scalars inside a node are properties, structs and lists are children, and field tags (arg,args,props,child,omitempty,skip) cover the other layouts. Decoding fills the fields it finds, keeps defaults for the others, ignores what it does not know, and reports the rest with a typed error and a path such asserver.route[1].timeout: expected f64, got string.The module passes the official kdl-org test suite, vendored in
tests/test_cases: the 95 invalid documents are rejected, the 243 valid ones produce the expected canonical output (floats compared asf64) and round-trip.Where it comes from
This merges the two implementations proposed for vlib, vlang/v#28819 and vlang/v#27724 (vlang-community/kdl). The parser, writer and data model are those of #28819, the smaller of the two and the one that passed the whole official suite. The struct marshaling, its tags and its examples come from #27724, rewritten on this data model with stricter decoding: typed errors instead of silent coercions, and the struct validated before any data is read. Commits that reuse that work carry
Co-authored-by: Jengro777.Two features of #27724 are left out for now and will each get an issue: the relaxed parsing modes (NGINX-style identifiers,
key: value,10ms) and a writer that keeps the original formatting and comments.Compilers and performance
The tests run with the new compiler, with the automatic fallback disabled, and with
-old-compiler; CI covers Linux, macOS and Windows on V master plus an old-compiler job. A few constructs are written in a specific way to work around compiler behaviour, each with a comment in the code: with the old compiler under-prod, passing a large struct by value before every call made the writer quadratic (vlang/v#28418), so the internals pass references; with the new compiler, options are unwrapped withorrather thanif x := optinside generics, nodes are built in place rather than pushed as filled locals, and one wrong-code case aroundstrings.Builderis avoided by binding anifexpression first (a reproducer will be reported).Parsing and encoding allocate about 2 KB per node, so on documents beyond roughly 100 000 nodes the Boehm collector dominates: 640 000 flat nodes (35 MB) parse in 12.7 s by default and in 0.7 s with
GC_INITIAL_HEAP_SIZE=8G, which the README documents. Reducing that footprint would change the public types and make the API less direct (properties as an ordered list instead of a map, an annotation flag instead of?string), so it is left for a later discussion.