feat(stdlib): Tiled P0 — XML reader + base64 decode + gzip framing (#67)
All checks were successful
bootstrap / cfree-fixpoint (push) Successful in 20s
ci / build-and-test (push) Successful in 1m43s
commit-lint / conventional-commits (push) Successful in 2s
docs / build-and-deploy (push) Successful in 27s

The three parsing primitives the TMX path needs that were not already in
the tree (zlib inflate + the JSON reader already shipped):

- Xml.* — a minimal, deterministic pure-Ludic XML reader for the
  element/attribute/CDATA subset TMX/TSX/TX use, spliced on demand. Handles
  nested elements, single/double-quoted attributes, text + <![CDATA[…]]>,
  comments, the <?xml?> prolog and <!DOCTYPE>, the five predefined entities
  and numeric character references.
- Base64.* — standard base64 (RFC 4648) decode + a matching pure-Ludic
  encoder; the decoder ignores the whitespace Tiled wraps into <data>.
  Splicing Base64.* also pulls in inflate.ludic so a plain tool can run the
  full base64 -> zlib/gzip decode chain.
- z_gunzip — gzip framing (RFC 1952) over the existing DEFLATE inflater:
  skip the 10-byte header + optional fields, inflate the body, ignore the
  CRC32/ISIZE trailer.

Golden corpus vendored under assets/tiled-fixtures/ (mapeditor/tiled
examples, attributed, + hand-authored multi-encoding fixtures). New
example library/tiled_p0.ludic proves all three (21 assertions); docs
pages + inventory added so check-impl stays green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-01 14:04:49 +03:00
parent 0b149a6876
commit 79776d1f6a
35 changed files with 20549 additions and 18415 deletions

View file

@ -0,0 +1,7 @@
---
id: xml
title: Xml
order: 40
---
A minimal, deterministic XML reader for the element/attribute/CDATA subset the native Tiled formats (TMX/TSX/TX) use. <a href="xml-parse"><code>Xml.parse</code></a> turns a document into an element tree; the accessors read a node's <a href="xml-tag"><code>tag</code></a>, <a href="xml-text"><code>text</code></a>, attributes (<a href="xml-attr"><code>Xml.attr</code></a>/<a href="xml-attr_int"><code>Xml.attr_int</code></a>/<a href="xml-has"><code>Xml.has</code></a>) and children (<a href="xml-child"><code>Xml.child</code></a>/<a href="xml-find"><code>Xml.find</code></a>/<a href="xml-count"><code>Xml.count</code></a>). It expands the five predefined entities and numeric character references, skips the <code>&lt;?xml?&gt;</code> prolog, comments and <code>&lt;!DOCTYPE&gt;</code>, and is best-effort rather than validating — the same contract as <a href="json"><code>Json</code></a>. Spliced on demand when a program mentions <code>Xml.*</code>.

View file

@ -0,0 +1,14 @@
---
id: xml-attr
name: Xml.attr
category: xml
kind: namespace-method
tokens: Xml.attr
sig: Xml.attr(node, key: string) -> string
tip: An attribute's value by name.
order: 4
ns: Xml
member: attr
---
Returns the value of attribute <code>key</code> (entity-decoded), or <code>""</code> if the element has no such attribute. Use <a href="xml-has"><code>Xml.has</code></a> to distinguish an empty value from an absent one.

View file

@ -0,0 +1,14 @@
---
id: xml-attr_count
name: Xml.attr_count
category: xml
kind: namespace-method
tokens: Xml.attr_count
sig: Xml.attr_count(node) -> int
tip: How many attributes the element has.
order: 7
ns: Xml
member: attr_count
---
Returns the number of attributes on <code>node</code>.

View file

@ -0,0 +1,14 @@
---
id: xml-attr_int
name: Xml.attr_int
category: xml
kind: namespace-method
tokens: Xml.attr_int
sig: Xml.attr_int(node, key: string, dflt: int) -> int
tip: An attribute parsed as an integer.
order: 5
ns: Xml
member: attr_int
---
Returns attribute <code>key</code> parsed as a signed decimal integer, or <code>dflt</code> when the attribute is absent.

View file

@ -0,0 +1,14 @@
---
id: xml-child
name: Xml.child
category: xml
kind: namespace-method
tokens: Xml.child
sig: Xml.child(node, index: int) -> xml
tip: A child element by index.
order: 9
ns: Xml
member: child
---
Returns the child element at <code>index</code> in document order, or an empty node if the index is out of range.

View file

@ -0,0 +1,14 @@
---
id: xml-child_count
name: Xml.child_count
category: xml
kind: namespace-method
tokens: Xml.child_count
sig: Xml.child_count(node) -> int
tip: How many child elements.
order: 8
ns: Xml
member: child_count
---
Returns the number of direct child elements of <code>node</code> (text and comments are not children).

View file

@ -0,0 +1,14 @@
---
id: xml-count
name: Xml.count
category: xml
kind: namespace-method
tokens: Xml.count
sig: Xml.count(node, tag: string) -> int
tip: How many children have a given tag.
order: 11
ns: Xml
member: count
---
Returns how many direct children of <code>node</code> are named <code>tag</code> — e.g. the number of <code>&lt;layer&gt;</code> elements in a map.

View file

@ -0,0 +1,14 @@
---
id: xml-find
name: Xml.find
category: xml
kind: namespace-method
tokens: Xml.find
sig: Xml.find(node, tag: string) -> xml
tip: The first child with a given tag.
order: 10
ns: Xml
member: find
---
Returns the first direct child of <code>node</code> whose tag is <code>tag</code>, or an empty node if there is none.

View file

@ -0,0 +1,14 @@
---
id: xml-has
name: Xml.has
category: xml
kind: namespace-method
tokens: Xml.has
sig: Xml.has(node, key: string) -> int
tip: Whether an attribute is present.
order: 6
ns: Xml
member: has
---
Returns <code>1</code> if <code>node</code> carries attribute <code>key</code>, else <code>0</code>.

View file

@ -0,0 +1,14 @@
---
id: xml-parse
name: Xml.parse
category: xml
kind: namespace-method
tokens: Xml.parse
sig: Xml.parse(text: string) -> xml
tip: Parse XML text into an element tree.
order: 1
ns: Xml
member: parse
---
Parses an XML document and returns its root element (or an empty node if there is none). Handles nested elements, single- and double-quoted attributes, text/<code>&lt;![CDATA[…]]&gt;</code> content, comments, the <code>&lt;?xml?&gt;</code> prolog and <code>&lt;!DOCTYPE&gt;</code>. Best-effort, not validating.

View file

@ -0,0 +1,14 @@
---
id: xml-tag
name: Xml.tag
category: xml
kind: namespace-method
tokens: Xml.tag
sig: Xml.tag(node) -> string
tip: The element's tag name.
order: 2
ns: Xml
member: tag
---
Returns the element name of <code>node</code> (e.g. <code>tileset</code>), or <code>""</code> for the empty node.

View file

@ -0,0 +1,14 @@
---
id: xml-text
name: Xml.text
category: xml
kind: namespace-method
tokens: Xml.text
sig: Xml.text(node) -> string
tip: The element's character data.
order: 3
ns: Xml
member: text
---
Returns the concatenated character data of <code>node</code> — the CSV inside a <code>&lt;data encoding="csv"&gt;</code> element, or a <code>&lt;property&gt;</code> value, lands here (entity-decoded).