Потоковая проверка JSON
liza-json check — первый прикладной шаг Text & Compiler Foundations.
Валидатор написан на Liza; он не строит дерево и не сохраняет текст токенов.
Новые операции runtime и изменения модели владения не требуются.
python3 -m liza build examples/apps/liza_json.liza -o build/liza-json
./build/liza-json check config.json
На Windows используйте build/liza-json.exe. Успех печатает OK.
format пока не поддерживается.
Профиль входа
Основа — RFC 8259. Корнем может быть любое JSON-значение. Повторяющиеся ключи разрешены. Пробелами считаются только SP, TAB, CR и LF. Комментарии, завершающие запятые, NaN и Infinity отклоняются. BOM в начале документа отклоняется.
Весь вход должен быть корректным UTF-8. Escape-последовательности проверяются,
включая пары UTF-16 суррогатов. Одиночный суррогат отклоняется: это намеренно
более строгий профиль Unicode scalar values, чем ABNF RFC, допускающая
непарные суррогаты. Не-символы Unicode не запрещены; \u0000 допустим.
Числа проверяются лексически, без преобразования в f64 или целое число.
Длина числа, строки или файла не ограничена размером чанка. Общий счётчик
входа ограничен u64; превышение возвращает SizeOverflow.
Глубина контейнеров ограничена 64: 65-я открывающая скобка даёт DepthLimit.
Это ограничение ресурса, а не утверждение о синтаксической неверности JSON.
Библиотека
| Операция | Результат |
|---|---|
json.create() |
Независимое значение JsonState |
json.feed(state, data:View<u8>) |
Новое состояние, без удержания view |
json.status(state) |
Option<JsonError>: обнаруженная ошибка или None |
json.finish(state) |
Result<u64,JsonError>: число байтов либо ошибка |
None не означает завершённый документ. finish проверяет EOF как снимок:
после незавершённого снимка можно продолжить feed. Обнаруженная при feed
ошибка сохраняется неизменно; дальнейшие данные игнорируются. Поля состояния
закрыты. Состояние можно копировать; оно не зависит от времени жизни чанка.
JsonError содержит kind и offset. Смещения — абсолютные, байтовые,
с нуля. Ошибка синтаксиса указывает на отвергнутый байт; незавершённый документ
— на конец входа. Ошибка UTF-8 указывает на начало некорректной последовательности.
Непарный суррогат указывает на обратную косую черту первого \u.
Некорректная hex-цифра указывает на саму цифру.
Проверка UTF-8 выполняется перед синтаксическим переходом для каждого байта. Первое обнаруженное нарушение сохраняется независимо от разбиения входа. На EOF незавершённый UTF-8 имеет приоритет перед незавершённым JSON.
Стоимость и CLI
Стек содержит 64 однобайтовых состояния. Остальные поля — скалярные состояния
лексического и UTF-8 автоматов. Память валидатора не растёт вместе с входом;
CLI читает file.read_chunk по 2048 байтов. Нет heap-аллокаций валидатора,
накопления токенов или декодирования строк. Передача состояния по значению
может копировать фиксированный стек; zero-copy исполнения не обещается.
| Код выхода | Значение |
|---|---|
| 0 | Документ принят |
| 1 | Синтаксис, UTF-8 или Unicode escape отвергнут |
| 2 | Неверная командная строка |
| 3 | Ошибка открытия, чтения, закрытия или вывода |
| 4 | Лимит глубины или размера |
Файл закрывается на всех нормальных путях после открытия, в том числе при
ранней ошибке JSON. Ошибка закрытия имеет приоритет над результатом проверки.
Диагностика имеет вид InvalidNumber at byte 12 и выводится в stderr.
Проверка и границы
Нативные тесты O0/O2 подают данные во время исполнения, проверяют разбиения внутри UTF-8, escapes, суррогатных пар и чисел, EOF, границы глубины и длинные токены. Генерируемые документы дополнительно сопоставляются с Python JSON. Это тестирование, не новый эксперимент Verified и не доказательство всех входов.
Текущий API — валидатор синтаксиса, не tokenizer с выдачей событий, DOM,
форматтер или динамический String. Строковые значения не декодируются наружу.
Будущему tokenizer потребуется различать исходный диапазон и декодированный
текст, особенно для escapes и строк, пересекающих чанки.