| 82 | } |
| 83 | |
| 84 | export function extractRules(filePath: string): ExtractResult { |
| 85 | const src = stripComments(readFileSync(filePath, 'utf8')); |
| 86 | // Blank-line cells — but rules may contain internal blank lines (e.g. |
| 87 | // where a comment was stripped, or in If[TrueQ[$LoadShowSteps], …] |
| 88 | // cells), so merge fragments until brackets balance and the cell does |
| 89 | // not end mid-definition. |
| 90 | const fragments = src.split(/\n\s*\n/).map((c) => c.trim()); |
| 91 | const cells: string[] = []; |
| 92 | for (const frag of fragments) { |
| 93 | if (frag === '') continue; |
| 94 | const prev = cells.length > 0 ? cells[cells.length - 1] : undefined; |
| 95 | const prevIncomplete = |
| 96 | prev !== undefined && |
| 97 | (bracketBalance(prev) > 0 || /(:=|\/;|[+\-*/^,]|&&|\|\|)$/.test(prev)); |
| 98 | if (prevIncomplete) cells[cells.length - 1] = prev + '\n' + frag; |
| 99 | else cells.push(frag); |
| 100 | } |
| 101 | |
| 102 | const ruleCells = cells.filter( |
| 103 | (c) => c.startsWith('Int[') || c.startsWith('If[TrueQ[$LoadShowSteps]') |
| 104 | ); |
| 105 | |
| 106 | const rules: RubiRule[] = []; |
| 107 | const errors: ExtractResult['errors'] = []; |
| 108 | |
| 109 | ruleCells.forEach((cell, i) => { |
| 110 | const index = i + 1; |
| 111 | try { |
| 112 | let expr = parseWL(cell); |
| 113 | // If[TrueQ[$LoadShowSteps], <ShowStep variant>, <plain rule>] — |
| 114 | // keep the plain (non-display) definition. |
| 115 | const cond = asCall(expr, 'If'); |
| 116 | if (cond && cell.startsWith('If[TrueQ[$LoadShowSteps]')) { |
| 117 | if (cond.length !== 4) |
| 118 | throw new Error('unexpected $LoadShowSteps If shape'); |
| 119 | expr = cond[3]; |
| 120 | } |
| 121 | rules.push(normalizeRule(index, expr, cell)); |
| 122 | } catch (e) { |
| 123 | errors.push({ index, error: String(e), source: cell }); |
| 124 | } |
| 125 | }); |
| 126 | applyUpstreamCorrections(filePath, rules); |
| 127 | return { rules, errors }; |
| 128 | } |
| 129 | |
| 130 | /** |
| 131 | * Corrections for verified bugs in the frozen Rubi 4.17.3.0 source. Each entry |