yeslogic / doodle

6 stars 1 forks source link

[lang-model]: Numerically-predicated repeat-intercalation (`moderate`, `niche`, `spec`) #191

Open archaephyrryx opened 4 months ago

archaephyrryx commented 4 months ago

Our current definition in doodle_formats::format:;jpeg gives the following specification for thge initial field "scan-data" in the sub-definition of "jpeg.scan-data"

            (
                "scan-data",
                repeat(alts([
                    // FIXME: Extract into separate ECS repetition
                    ("mcu", mcu.call()), // TODO: repeat(mcu),
                    // FIXME: Restart markers should cycle in order from rst0-rst7
                    ("rst0", rst0.call()),
                    ("rst1", rst1.call()),
                    ("rst2", rst2.call()),
                    ("rst3", rst3.call()),
                    ("rst4", rst4.call()),
                    ("rst5", rst5.call()),
                    ("rst6", rst6.call()),
                    ("rst7", rst7.call()),
                ])),
            ),

What we ideally want is some way of specifying the following format:

scan-data = scan-data-segments ;

scan-data-segments = segment (rst0 segment (rst1 segment (rst2 segment (rst3 segment (rst4 segment (rst5 segment (rst6 segment (rst7 scan-data-segments)? )? )? )? )? )? )? )? ;

segment = mcu+;

We currently have no way of calling a self-referential format, nor do we have any way of specifying an intercalated repeat that injects particular format-elements in between repetitions of another format.

A proposed language extension that would solve this problem would be IntercalateRepeatIndex(varname, X, F)

with the following semantics:

decode(IntercalateRepeatIndex(varname, X, F)):
    sequence = []
    index = 0
    loop:
         if let elem = decode(X):
              push elem to end of sequence
              set scope-local variable "<varname>" to the current value of index
              if let some marker = decode(F):
                  index = index + 1
              else:
                  break
         else:
             break
    return sequence

Example using such an abstraction:

Format::IntercalateRepeatIndex("reset-counter", repeat1(mcu.call()), Format::Match(
     Expr::Arith(Arith::Mod, Box::new(var("reset-counter")), Box::new(Expr::U32(8))),
     vec![
         (Pattern::U32(0), rst0.call()),
         /* ... */
         (Pattern::U32(7), rst1.call()),
     ]
))