lawref.canon
Канонический JSON-emitter (WP-04; SPEC §208 + errata E-0002).
Правила v1 (кросс-языковой контракт с engines/lawc/law-canon — байтовая идентичность проверяется в CI):
- UTF-8, без незначащего whitespace;
- все строки (ключи и значения) ОБЯЗАНЫ быть в NFC — иначе CanonError: NFC-
нормализация — обязанность normalizer-а, emitter только проверяет. Исключений
нет: исходные байты official text block (SPEC §13), отличные от NFC, несёт
base64-поле
texts[].exactBytes(§28, errata E-0248), а не строкаtext; - ключи объектов сортируются по code points (== порядок байтов UTF-8 — одинаково в Python и Rust); коллизия ключей после NFC — ошибка;
- JSON-числа допускаются только целые в диапазоне i64 (SPEC §18: binary float запрещён; Decimal/Rational сериализуются строками в canonical form §208 — форму строки обеспечивает normalizer);
- массивы сохраняют порядок; для document-режима top-level “nodes” сортируется по stable ID (§208: unordered node sets — по stable ID); сортировка semantic sets по element hash и commutative operands по semantic hash — обязанность normalizer-а (§207.1), сюда документы приходят уже нормализованными;
- экранирование строк зафиксировано явно (совпадает в обеих реализациях):
"-> ",\-> \, управляющие < U+0020 — \b \t \n \f \r либо \u00xx (строчные hex); остальное — сырой UTF-8.
Classes
| Name | Description |
|---|---|
CanonError | Нарушение канонических правил §208. |
Functions
| Name | Description |
|---|---|
canonical_bytes | Канонические байты (§208). document=True сортирует top-level nodes по ID. |
canonical_decimal | Каноническая форма Decimal §208 (errata E-0052). |
canonical_rational | Каноническая форма Rational §208/§35 (errata E-0213). |
canonical_bytesfunction#
def canonical_bytes(value: Any, *, document: bool = True) -> bytesКанонические байты (§208). document=True сортирует top-level nodes по ID.
Нормализация записи значения (errata E-0052, E-0213) применяется ВСЕГДА, а не только к документу: канонические байты обязаны быть каноническими независимо от производителя, а CLIR приходит и не от компилятора.
canonical_decimalfunction#
def canonical_decimal(text: str) -> str | NoneКаноническая форма Decimal §208 (errata E-0052).
«canonical non-exponent string: 0, -12, 0.125, -3.5; без leading
zeros, trailing fractional zeros и negative zero», и там же нормативный
пример: «source 12.50, 1.25e3 normalizes соответственно в 12.5,
1250». Зеркало law_canon::canonical_decimal; кросс-языковой контракт
G-M1a держит их байтово равными.
None — вход не десятичное число: значение чужого вида (Text, Date, Rational) обязано пройти невредимым, а не быть испорченным нормализацией.
Считается СТРОКОЙ, а не Decimal/float: float запрещён §18, а перенос точки цифр не меняет.
canonical_rationalfunction#
def canonical_rational(text: str) -> str | NoneКаноническая форма Rational §208/§35 (errata E-0213).
§35: «в canonical serialization представляется несократимой дробью».
Знак стоит у ЧИСЛИТЕЛЯ, знаменатель строго положителен — той же записью,
какую §168.1 уже требует от ground-позиции утверждения. 15/100 → 3/20,
1/-2 → -1/2, -3/-6 → 1/2, 0/7 → 0/1. 5/1 остаётся дробью:
вид значения не зависит от значения (§58), и целое здесь не появляется.
None — вход не дробь §208 (чужой вид, незаконная лексика E-0203) либо знаменатель нулевой: такая запись обязана пройти каноном невредимой, чтобы её отверг читатель литерала своей диагностикой (§48, E-0152), а не канон.
Зеркало law_canon::canonical_rational; кросс-языковой контракт G-M1a
держит их байтово равными. Носитель — целые Python (§35, E-0159: разрядность
Rational не ограничена), делитель — math.gcd над int.
Documentation for Arxo. Writings — blog.arxo.io.
Anonymous visit counts on stats.arxo.io, no cookies.