Skip to content

Commit 2dd75df

Browse files
Ядро FTS на flang: все четыре слоя связались в одну программу
Вычислитель объявлял типы контракта у себя, и связывание давало десять конфликтов FLANG_DUPLICATE_NAME — слои по отдельности работали, а вместе не собирались. Теперь он берёт «Скаляр», «Операнд», «Условие», «Правило» и остальные из слоя печати, как это уже делал парсер. Ещё один конфликт был содержательным: «Итог примера» в парсере — это разобранный пример со списком ошибок, а в вычислителе — результат сверки примера с ожиданием. Одно имя на два разных понятия; в парсере переименовано в «Разбор примера» по образцу соседних «Итог утилиты» и «Итог структуры». Тесты вычислителя разделены: форма модуля проверяется по разбору своего файла, вычисления — по связанной программе. Смешивать их нельзя, иначе требование «функция без примера обязана иметь сумму типов в сигнатуре» распространилось бы на чужой слой, у которого своё правило и свой тест. Итог: `использует «Парсер FTS»` + `использует «Вычислитель утилит»` даёт 217 функций и 66 типов, все функции тотальные, ноль диагностик. Это полное ядро FTS, написанное на самом flang. Проверено: 1051 тест flang, 0 падений.
1 parent a018496 commit 2dd75df

3 files changed

Lines changed: 38 additions & 65 deletions

File tree

flang/core/evaluate.flang

Lines changed: 9 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
модуль «Вычислитель утилит»
2+
использует «Печать JSON» из "json.flang"
23

34
// Вычислитель утилит ядра FTS, написанный на flang.
45
//
@@ -35,64 +36,17 @@
3536
// Скаляр FTS: `type FtsScalar = string | number | boolean | null`. Сумма типов
3637
// вместо объединения TypeScript — единственный способ выразить это в языке,
3738
// где значение имеет ровно один тип.
38-
тип «Скаляр»
39-
вариант «Скаляр строка» содержит «значение»: строка
40-
вариант «Скаляр число» содержит «значение»: число
41-
вариант «Скаляр признак» содержит «значение»: признак
42-
вариант «Скаляр ничто»
43-
44-
тип «Сравнение»
45-
вариант «Равно»
46-
вариант «Не равно»
47-
вариант «Не меньше»
48-
вариант «Не больше»
49-
вариант «Больше»
50-
вариант «Меньше»
51-
52-
тип «Операнд»
53-
вариант «Значение операнда» содержит «скаляр»: «Скаляр»
54-
вариант «Поле операнда» содержит «поле»: строка
55-
вариант «Процент операнда» содержит «процент»: число, «поле»: строка
56-
вариант «Результат операнда»
57-
58-
объект «Условие»
59-
«поле»: строка
60-
«сравнение»: «Сравнение»
61-
«операнд»: «Операнд»
62-
63-
тип «Действие»
64-
вариант «Присвоить» содержит «операнд»: «Операнд»
65-
вариант «Добавить» содержит «операнд»: «Операнд»
66-
67-
объект «Правило»
68-
«имя»: строка
69-
«условия»: список «Условие»
70-
«действие»: «Действие»
71-
72-
объект «Свойство»
73-
«имя»: строка
74-
«сравнение»: «Сравнение»
75-
«операнд»: «Операнд»
39+
40+
41+
42+
43+
44+
7645

7746
// Привязка «имя поля → скаляр». Записи flang тотальны и имеют заранее
7847
// известные поля, поэтому входная запись утилиты — список пар, а не запись.
79-
объект «Привязка»
80-
«имя»: строка
81-
«значение»: «Скаляр»
82-
83-
объект «Пример»
84-
«имя»: строка
85-
«вход»: список «Привязка»
86-
«ожидается»: «Скаляр»
87-
88-
объект «Утилита»
89-
«имя»: строка
90-
«принимает»: строка
91-
«возвращает»: строка
92-
«начальное»: «Скаляр»
93-
«правила»: список «Правило»
94-
«свойства»: список «Свойство»
95-
«примеры»: список «Пример»
48+
49+
9650

9751
// ────────────────────────────── итоги ──────────────────────────────
9852

flang/core/parser.flang

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@
103103
«свойство»: «Свойство»
104104
«ошибки»: список «Диагностика разбора»
105105

106-
объект «Итог примера»
106+
объект «Разбор примера»
107107
«пример»: «Пример»
108108
«ошибки»: список «Диагностика разбора»
109109

@@ -1053,11 +1053,11 @@
10531053

10541054
тотальная функция «Разобрать пример»
10551055
принимает «группа»: «Группа»
1056-
возвращает «Итог примера»
1056+
возвращает «Разбор примера»
10571057
пусть «имя» равно «Прочитать всё имя» от («Пропустить слова» от («группа».«заголовок».«слова») и 1)
10581058
пусть «сбор» равно свёртка («группа».«тело») начиная с «Начальный сбор примера» как «акк» и «строка» → «Шаг примера» от «акк» и «строка»
10591059
пусть «без ожидания» равно если «сбор».«есть ожидание» то «Без ошибок» иначе («Ошибка разбора» от "FTS_UTILITY_EXAMPLE" и (соединить ["пример ", («В ёлочках» от («имя».«имя»)), " требует строку 'ожидается'"] по ""))
1060-
запись «Итог примера» с «пример» равным (запись «Пример» с «имя» равным («имя».«имя») и «вход» равным («сбор».«вход») и «ожидается» равным («сбор».«ожидается»)) и «ошибки» равным («Слить ошибки» от («Слить ошибки» от («имя».«ошибки») и («сбор».«ошибки»)) и «без ожидания»)
1060+
запись «Разбор примера» с «пример» равным (запись «Пример» с «имя» равным («имя».«имя») и «вход» равным («сбор».«вход») и «ожидается» равным («сбор».«ожидается»)) и «ошибки» равным («Слить ошибки» от («Слить ошибки» от («имя».«ошибки») и («сбор».«ошибки»)) и «без ожидания»)
10611061

10621062
// ──────────────────────────────── утилита ───────────────────────────────────
10631063

flang/test/core-evaluate.test.mjs

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,15 @@ import { checkTypes } from "../src/types.mjs"
3434
const root = fileURLToPath(new URL("../../", import.meta.url))
3535
const файл = new URL("../core/evaluate.flang", import.meta.url)
3636
const исходник = readFileSync(файл, "utf8")
37-
const программа = parse(исходник, "core/evaluate.flang")
37+
/* Модуль берёт типы документа из соседнего слоя печати («использует «Печать
38+
JSON»»), поэтому разбирается со связыванием: без него «Скаляр» и остальные
39+
типы контракта остались бы необъявленными. */
40+
const { linkProgram } = await import("../src/link.mjs")
41+
const связано = await linkProgram(fileURLToPath(файл), исходник, parse)
42+
const { diagnostics: связывание, ...программа } = связано
43+
/* Отдельно — разбор одного файла: проверки формы модуля обязаны смотреть на
44+
то, что написано здесь, а не на объявления, пришедшие из слоя печати. */
45+
const модуль = parse(исходник, "core/evaluate.flang")
3846
const типы = checkTypes(программа)
3947
const тотальность = checkTotality(программа)
4048

@@ -122,12 +130,20 @@ const кодОшибки = (ошибка) =>
122130
/* ───────────────────────────── слои языка ───────────────────────────────── */
123131

124132
test("evaluate.flang: разбор даёт контракт SPEC, раздел 5", () => {
125-
assert.equal(программа.flang, 1)
126-
assert.equal(программа.module, "Вычислитель утилит")
127-
assert.ok(Array.isArray(программа.functions))
128-
assert.ok(программа.functions.length > 0)
133+
assert.equal(модуль.flang, 1)
134+
assert.equal(модуль.module, "Вычислитель утилит")
135+
assert.ok(Array.isArray(модуль.functions))
136+
assert.ok(модуль.functions.length > 0)
129137
/* Детерминированность: повторный разбор даёт побайтово тот же AST. */
130-
assert.equal(JSON.stringify(parse(исходник, "core/evaluate.flang")), JSON.stringify(программа))
138+
assert.equal(JSON.stringify(parse(исходник, "core/evaluate.flang")), JSON.stringify(модуль))
139+
})
140+
141+
test("evaluate.flang: связывание со слоем печати проходит без диагностик", () => {
142+
assert.deepEqual(связывание, [], "типы контракта берутся из json.flang, и это обязано связываться молча")
143+
assert.ok(
144+
программа.functions.length > модуль.functions.length,
145+
"связанная программа обязана содержать функции обоих слоёв",
146+
)
131147
})
132148

133149
test("evaluate.flang: типы без диагностик", () => {
@@ -165,8 +181,11 @@ test("evaluate.flang: без примера остаются только фун
165181
«ожидается» записывается, но у функций, которые тянут за собой состояние
166182
вычисления («Итог»), пример был бы длиннее самой функции. Всё остальное
167183
обязано быть показано примером. */
184+
/* Проверяется свой модуль: за функции слоя печати отвечает его собственный
185+
тест, и требовать от них примеров здесь значило бы дублировать чужое
186+
правило. Суммы типов берутся из связанной программы — они объявлены там. */
168187
const суммы = new Set((программа.types ?? []).filter((тип) => тип.kind === "sum").map((тип) => тип.name))
169-
for (const fn of программа.functions) {
188+
for (const fn of модуль.functions) {
170189
if ((fn.examples ?? []).length > 0) continue
171190
const типыСигнатуры = [fn.returns, ...(fn.params ?? []).map((параметр) => параметр.type)]
172191
assert.ok(

0 commit comments

Comments
 (0)