Skip to content

Kiln 1.3.0

Choose a tag to compare

@AxDSan AxDSan released this 13 Sep 02:39
· 142 commits to main since this release

XML: reading the tables data ships in

Kiln could read JSON and INI. It could not read XML, which is the format a great
many data tables ship in — including tables written for a Chinese market in 2008:
a GB2312 declaration over bytes that are really GBK, Chinese in the comment
blocks, CRLF line endings, and one self-closing element per row.

use xml reads those files as bytes and hands bytes back. Nothing is
decoded
, so a declaration that lies about its own encoding is a non-event
rather than a parse error, and an element name in Chinese comes back as that
name. Decoding stays a deliberate, separate step.

  • A 134KB table of 535 elements and 7,164 attributes: every element name, every
    ID and all 10,362 attributes are byte-identical to Python's ElementTree

    reading the same file through iconv.
  • Nothing is decoded, nothing is copied while walking, and nothing recurses —
    open elements are a heap stack, so a deeply nested layout cannot overflow the
    machine stack.
  • An empty name means any element, which is how a table is walked when every
    row is named differently.
  • A missing attribute answers "" and leaves the error slot clear — most
    attributes are optional — with xml_has_attr as the predicate that separates
    absent from present-and-empty.
  • A malformed document is refused with the line: line 41: expected </Swords>, found </Weapons>.

use encoding: the codepages data files use

encoding_decode and encoding_encode convert between UTF-8 text and the
codepages those files are written in. No conversion table ships: GBK alone is
23,940 mappings, and a hand-copied table is how a decoder ends up 99% right and
silently wrong on a name. It asks the platform instead — iconv on POSIX, the
Win32 codepage API on Windows — through a thin shim, with Latin-1 and both UTF-16
byte orders written out because each is a byte loop.

gbk, gb2312, cp936, gb18030, big5, shift-jis, latin1, utf-16le,
utf-16be and utf-8 all resolve, and encoding_known says whether this build
can do one before a program depends on it.

  • Decoding a 134KB GBK file is byte-identical to iconv, and re-encoding
    returns the original 134,212 bytes.
  • Two decoders, deliberately. encoding_decode refuses input that is not of
    the encoding and names the byte that failed; encoding_decode_lossy replaces
    it with U+FFFD and carries on, which is what .NET's StreamReader does by
    default. A program replacing one needs the second.
  • encoding_encode is strict in both directions: text that is not UTF-8 is
    refused rather than written out as a quietly wrong name.

db: statements that do not hold the loop

Every db_* call was synchronous, so a query inside an event handler held every
other event until it answered. On loopback that is a millisecond and invisible,
which is exactly how a timing problem survives every local test.

db_exec_async, db_exec_async_n, db_query_async and db_query_async_n run a
statement on a worker thread and answer a request id. db_req_ready is the poll;
db_req_rows, db_req_columns, db_req_text, db_req_is_null and
db_req_error are the reading side; db_req_free releases the answer.

  • A statement that took 780ms: the event loop turned 39 times while it
    ran. A synchronous call gets one turn, because the statement runs inside it.
  • The connection belongs to the worker until the answer is claimed. db_exec,
    db_query, the transactions and db_close refuse it by name — two threads on
    one connection is a crash in the MySQL client and corruption in SQLite, not a
    race to be survived.
  • The worker never calls into the runtime: no kn_malloc, no error slot, no
    handle table. Every handle a program sees is still built by the program, on its
    own thread, when it claims the answer.
  • The worker runs the same code the synchronous path runs, so the tested surface
    did not move.

Getting a release out

RELEASING.md and tools/check-release.sh: a release touches more surfaces than
the compiler — the generated reference, the landing page's counts, the README's
counts and unpack lines, the book's table of contents, the limitations page — and
the four that can be checked mechanically now are, in one command.

Compatibility

Nothing a 1.2.0 program can see changes. New kits and new commands, no language
change, and no structure in the ABI moved or changed value — KILN_ABI_VERSION
stays at 4 and a library built against it keeps loading.