Advanced Repetition

If we want nested repetition that doesn't consume the whole input, we need a way to end the scope of a Repeat. This is accomplished using a special value given to the constructor. We also wrap the repeat into a separate type so we can easily add other array-manipulating functions.

const repeatNumber = new Repeat(value, "-");

const arr = new Type<number[]>("arr");
arr.setDefault(repeatNumber);

We use a - here as common scope characters like ),] and ; are used by shells like bash and would need to be escaped in a cli.

> mul sum 1 1 1 2
Error: Parser finished but expected type <t.value>.
> mul sum 1 1 1 - 2
6

For fun we add some more array functions.

arr.setFunctions([
  Func("repeat")
    .arg(value)
    .arg(value)
    .setExec((amnt, val): number[] => Array<number>(amnt).fill(val)),
  Func("range")
    .arg(value)
    .setExec((max): number[] =>
      Array.from({ length: max }, (_, index) => index),
    ),
  Func("double")
    .arg(arr)
    .setExec((vals) => vals.map((val) => val * 2)),
]);
> mul 2 sum range 5
20
> sum double range 5
20
l.calc:
 | <t.value> EOI

t.value:
 | "add"      <t.value> <t.value>
 | "mul"      <t.value> <t.value>
 | "sum"      <t.arr>  
 | "pi"      
 | <p.number>

t.arr:
 | "repeat"    <t.value> <t.value>
 | "range"     <t.value>
 | "double"    <t.arr>  
 | <r.t.value>

r.t.value:
 | <t.value> * EOI
 | <t.value> * "-"