(fn, args, makeNode, options)
| 316 | * @return - Either a Node representing a binary expression or Fraction |
| 317 | */ |
| 318 | function foldOp (fn, args, makeNode, options) { |
| 319 | const first = args.shift() |
| 320 | |
| 321 | // In the following reduction, sofar always has one of the three following |
| 322 | // forms: [NODE], [CONSTANT], or [NODE, CONSTANT] |
| 323 | const reduction = args.reduce((sofar, next) => { |
| 324 | if (!isNode(next)) { |
| 325 | const last = sofar.pop() |
| 326 | |
| 327 | if (isNode(last)) { |
| 328 | return [last, next] |
| 329 | } |
| 330 | // Two constants in a row, try to fold them into one |
| 331 | try { |
| 332 | sofar.push(_eval(fn, [last, next], options)) |
| 333 | return sofar |
| 334 | } catch (ignoreandcontinue) { |
| 335 | sofar.push(last) |
| 336 | // fall through to Node case |
| 337 | } |
| 338 | } |
| 339 | |
| 340 | // Encountered a Node, or failed folding -- |
| 341 | // collapse everything so far into a single tree: |
| 342 | sofar.push(_ensureNode(sofar.pop())) |
| 343 | const newtree = (sofar.length === 1) ? sofar[0] : makeNode(sofar) |
| 344 | return [makeNode([newtree, _ensureNode(next)])] |
| 345 | }, [first]) |
| 346 | |
| 347 | if (reduction.length === 1) { |
| 348 | return reduction[0] |
| 349 | } |
| 350 | // Might end up with a tree and a constant at the end: |
| 351 | return makeNode([reduction[0], _toNode(reduction[1])]) |
| 352 | } |
| 353 | |
| 354 | // destroys the original node and returns a folded one |
| 355 | function foldFraction (node, options) { |
no test coverage detected
searching dependent graphs…