MCPcopy Create free account
hub / github.com/cortex-js/compute-engine / runLoopNested

Function runLoopNested

src/compute-engine/library/control-structures.ts:388–455  ·  view source on GitHub ↗

* Recursive nested iteration over Element clauses, producing a flat list of * body evaluations. Stops early on Break/Return by mutating `state.stopped`.

(
  body: Expression,
  elements: ReadonlyArray<Expression>,
  index: number,
  ce: ComputeEngine,
  results: Expression[],
  state: {
    stopped: boolean;
    broke: boolean;
    value?: Expression;
    count: number;
  }
)

Source from the content-addressed store, hash-verified

386 // order — since 2026-08-15 `And` is a short-circuit form and no
387 // longer sorts; see `canonicalShortCircuit` in `logic.ts`).
388 // Building with `_fn` skipped canonicalization altogether, which
389 // at the time (when `And` still sorted) left the conjunction in
390 // authored order while `.json` (which goes through `structural`)
391 // sorted — so `x{a}{b}` and `x{b}{a}` serialized to identical
392 // MathJSON while `isSame`/`hash` disagreed, and `ce.box(e.json)`
393 // was not `isSame` to `e` (Tycho item-153 seed, the 11
394 // `differs-json-equal` rows). Every view of the tree must come
395 // from the same canonical construction.
396 return ce._fn('When', [
397 inner,
398 ce.function('And', [innerCond, cond.canonical]),
399 ]);
400 }
401 return ce._fn('When', [expr.canonical, cond.canonical]);
402 },
403 evaluate: ([expr, cond], options) => {
404 const ce = options.engine;
405 const c = cond.evaluate();
406
407 // Desmos-style broadcast: a finite indexed collection of booleans
408 // masks element-by-element (one masked branch per element). This
409 // mirrors the boolean-mask branch of `At` in `collections.ts`. Lazy
410 // operators bypass the generic broadcast machinery, so handle it here.
411 if (c.isCollection && c.isFiniteCollection) {
412 const conds = Array.from(c.each()) as Expression[];
413 // A cell is a boolean condition when it types `boolean` — or
414 // `broadcastable<boolean>`, the type of a comparison whose broadcast
415 // outcome is not statically settled (`h(x) ≤ 1` with `h`
416 // undeclared; see `comparisonResultType`,
417 // `library/relational-operator.ts`). Such a cell is a scalar
418 // relation here (it is one element of the materialized mask) and
419 // is held exactly like an undecided `boolean` one; gating on
420 // `boolean` alone left `x{h(x) ≤ [1,2,3]}` un-broadcast as
421 // `When(x, [h(x) ≤ 1, …])`.
422 if (
423 conds.length > 0 &&
424 conds.every(
425 (ci) =>
426 ci.type.matches('boolean') || possiblyElementwiseCondition([ci])
427 )
428 ) {
429 // If `expr` itself evaluates to a finite indexed collection, zip
430 // elementwise (expr_i masked by c_i); otherwise mask the scalar
431 // `expr` by each c_i. Different lengths truncate to the shorter,
432 // matching `At`'s mask alignment.
433 const ev = expr.evaluate(options);
434 const zip = ev.isCollection && ev.isFiniteCollection;
435 const elems = zip ? (Array.from(ev.each()) as Expression[]) : [];
436 const n = zip ? Math.min(conds.length, elems.length) : conds.length;
437 const result: Expression[] = [];
438 for (let i = 0; i < n; i++) {
439 const ci = conds[i];
440 const cis = sym(ci);
441 // The per-element expression: the zipped element, or the scalar.
442 const elem = zip ? elems[i] : ev;
443 if (cis === 'True') result.push(elem);
444 else if (cis === 'False') result.push(ce.symbol('Undefined'));
445 // Indeterminate (symbolic boolean): hold `When` on the element.

Callers 1

runLoopFunction · 0.85

Calls 5

isFunctionFunction · 0.90
isSymbolFunction · 0.90
evaluateMethod · 0.65
eachMethod · 0.65
assignMethod · 0.65

Tested by

no test coverage detected