(
entries: ReadonlyArray<Entry>,
declarations: Declarations,
overrides: CurationOverrides = {}
)
| 1389 | // Never shadow an engine built-in: a shell declaration in this scope |
| 1390 | // would hide the built-in's numeric evaluator and signature, making the |
| 1391 | // self-test environment diverge from the loader's (which skips shells |
| 1392 | // for already-defined names). Heads promoted to built-ins after the |
| 1393 | // corpus declarations table was generated are caught here. |
| 1394 | if (ce.lookupDefinition(name) !== undefined) continue; |
| 1395 | try { |
| 1396 | ce.declare(name, setify(declarations.declarations[name].signature)); |
| 1397 | } catch { |
| 1398 | /* unable to declare (e.g. reserved name) */ |
| 1399 | } |
| 1400 | } |
| 1401 | return ce; |
| 1402 | } |
| 1403 | |
| 1404 | export function compileEntries( |
| 1405 | entries: ReadonlyArray<Entry>, |
| 1406 | declarations: Declarations, |
| 1407 | overrides: CurationOverrides = {} |
| 1408 | ): CompileResult { |
| 1409 | const ce = createScratchEngine(entries, declarations); |
| 1410 | |
| 1411 | const rules: CompiledFungrimRule[] = []; |
| 1412 | const skips: SkipRecord[] = []; |
| 1413 | const sampleKinds: Record<string, 'symbolic' | 'numeric'> = {}; |
| 1414 | const seenUndirected = new Map<string, string>(); |
| 1415 | const transformAllowlist = new Set(overrides.transformAllowlist ?? []); |
| 1416 | |
| 1417 | const skip = (e: Entry, reason: SkipReason, detail?: string): void => { |
| 1418 | skips.push(detail === undefined ? { id: e.id, reason } : { id: e.id, reason, detail }); |
| 1419 | }; |
| 1420 | |
| 1421 | for (const e of [...entries].sort((a, b) => a.id.localeCompare(b.id))) { |
| 1422 | const override = overrides.overrides?.[e.id]; |
| 1423 | |
| 1424 | // 0. Curated exclusion |
| 1425 | if (override?.exclude === true) { |
| 1426 | skip(e, 'curated-exclude', override.note); |
| 1427 | continue; |
| 1428 | } |
| 1429 | |
| 1430 | // 1. Must be an equality with at least two operands. Chained equalities |
| 1431 | // `Equal(a, b, c)` compile as first = last (sound by transitivity; |
| 1432 | // the most-reduced closed form is the final element). |
| 1433 | const formula = e.formula as MathJSON[]; |
| 1434 | if (!Array.isArray(formula) || formula[0] !== 'Equal' || formula.length < 3) { |
| 1435 | skip(e, 'not-equation', Array.isArray(formula) ? String(formula[0]) : undefined); |
| 1436 | continue; |
| 1437 | } |
| 1438 | const lhs = formula[1]; |
| 1439 | const rhs = formula[formula.length - 1]; |
| 1440 | |
| 1441 | // 2. Q3: specific values must be Head(args) = closed form; the 95 |
| 1442 | // symbol/Set/Apply-LHS entries are excluded (no recognition rules). |
| 1443 | if (e.class === 'specific-value') { |
| 1444 | const head = Array.isArray(lhs) ? lhs[0] : undefined; |
| 1445 | if (!Array.isArray(lhs) || head === 'Set' || head === 'Apply') { |
| 1446 | skip(e, 'lhs-not-value-form', Array.isArray(lhs) ? String(head) : 'symbol'); |
| 1447 | continue; |
| 1448 | } |
no test coverage detected