( xs: ReadonlyArray<Expression> )
| 69 | } |
| 70 | |
| 71 | /** |
| 72 | * Like {@link flatten}, but ellipsis-fold barriers are held back. |
| 73 | * |
| 74 | * Lifts `Sequence`/`Nothing` and nested `operator` applications recursively, |
| 75 | * exactly like `flatten`, EXCEPT that an operand which is a fold-barrier |
| 76 | * product (a `Multiply` carrying a `ContinuationPlaceholder` at any depth) is |
| 77 | * pushed back WHOLE: splicing it would smuggle the placeholder into the |
| 78 | * enclosing fold. Because the lift is recursive, a barrier wrapped in a |
| 79 | * `Sequence` — e.g. `Multiply(Sequence(Multiply(a, ContinuationPlaceholder)), b)` |
| 80 | * — is caught too, which a top-level-only barrier check would miss. |
| 81 | * |
| 82 | * The third argument mirrors `flatten`'s: when `true` (the default) the |
| 83 | * operands are made canonical before being examined. |
| 84 | */ |
| 85 | export function flattenHoldingBarriers< |
| 86 | T extends ReadonlyArray<Expression> | Expression[], |
| 87 | >(ops: T, operator: string, canonicalize = true): T { |
| 88 | const xs: ReadonlyArray<Expression> = |
| 89 | !canonicalize || ops.every((x) => x.isCanonical) |
| 90 | ? ops |
| 91 | : ops.map((x) => x.canonical); |
| 92 | |
| 93 | const ys: Expression[] = []; |
| 94 | for (const x of xs) { |
| 95 | // Hold barrier-bearing products back, whole |
| 96 | if (isFoldBarrierProduct(x)) { |
no test coverage detected