Lap Feature - SergeiGolos/wod-wiki GitHub Wiki
{{ ... }}
The Lap Feature will allow for different grouping behaviors in workout scripts. Currently, leaf nodes are identified by checking if node.children.length == 0
. This approach doesn't support lap-based grouping where multiple exercises are considered part of a single timed section.
(30) :60 EMOM
+ 5 Pullups
+ 10 Pushups
+ 15 Air Squats
In this example, the +
symbols indicate a "LapFragment" and all three exercises should be treated as a single 60-second section, repeated 30 times.
(3)
400m Run
21 KB Swings 53lb
12 Pullups
In this case, there's no lap indicator, so we do 3 rounds where each exercise is executed in sequence.
-
Update the
StatementNode
InterfaceAdd an
isLeaf
property to theStatementNode
interface intimer.types.ts
:export interface StatementNode { id: number; parent?: number; next?: number; rounds?: number; children: number[]; meta: SourceCodeMetadata; fragments: StatementFragment[]; isLeaf?: boolean; // New property to explicitly define a node as a leaf }
-
Modify the Parser Visitor
Update
timer.visitor.ts
to set theisLeaf
property based on the presence ofLapFragment
:// Inside the wodBlock method in MdTimerInterpreter class wodBlock(ctx: any): StatementNode { let statement = { fragments: [] as StatementFragment[] } as StatementNode; ctx.lap && statement.fragments.push(...this.visit(ctx.lap)); // ... existing code ... statement.meta = this.combineMeta( statement.fragments.map((fragment: any) => fragment.meta) ); statement.id = statement.meta.startOffset; const rounds = fragmentTo<RoundsFragment>(statement, 'rounds')?.count ?? 0; statement.rounds = rounds; // Determine if this is a leaf node with lap fragments const lapFragments = statement.fragments.filter(f => f.type === 'lap'); statement.isLeaf = lapFragments.length > 0; return statement; }
-
Update the Runtime Logic
Modify
timer.runtime.ts
to use the newisLeaf
property instead of checking for children length:// Inside the gotoBlock method in TimerRuntime class gotoBlock(node: StatementNode | undefined): IRuntimeBlock { // ... existing code ... // if Leaf (use isLeaf explicitly or fall back to checking children) if (node.isLeaf === true || node.children.length == 0) { const leaf = this.script.goto(node.id); const compiledBlock = this.jit.compile(this.trace!, leaf); this.onSetCursor(compiledBlock); return this.current = compiledBlock; } // ... existing code for handling non-leaf nodes ... }
-
Update RuntimeJit Logic
Ensure that
RuntimeJit.compile()
method properly handles statements with both anisLeaf
property and children. The compile method should group all child elements of a lap node into a single block instead of treating them individually.
-
Backward Compatibility
- Existing workouts without lap fragments will continue to work as before
- The
isLeaf
property defaults to undefined, so the old check forchildren.length == 0
works as a fallback
-
Node Traversal Logic
- When a node is marked as a leaf but has children, those children should be treated as part of the same logical unit
- The runtime should not navigate to the child nodes individually but process them together
-
Compile-Time vs. Runtime Behavior
- The determination of "leafness" happens at compile time in the visitor
- The runtime respects this property when navigating the workout
-
Classic Round Structure
- Verify that workouts with rounds and no lap indicators still work as before
- Example:
(3) 400m Run, 21 KB Swings 53lb, 12 Pullups
-
Lap Fragment Structure
- Verify that workouts with lap indicators treat the child elements as a single unit
- Example:
(30) :60 EMOM, + 5 Pullups, + 10 Pushups, + 15 Air Squats
-
Mixed Structure
- Verify that workouts can contain both lap-based and classic sections
- Example:
(3) 400m Run (30) :60 EMOM + 5 Pullups + 10 Pushups + 15 Air Squats
- Add the
isLeaf
property to theStatementNode
interface - Update the
MdTimerInterpreter
to setisLeaf
based on lap fragments - Modify
TimerRuntime.gotoBlock
to check for theisLeaf
property - Update
RuntimeJit.compile
to handle lap fragments correctly - Add tests for the new functionality
- Update documentation to explain lap fragments
- StatementNode interface:
src/core/timer.types.ts
- Parser visitor:
src/core/parser/timer.visitor.ts
- Runtime execution:
src/core/runtime/timer.runtime.ts
- JIT compilation:
src/core/runtime/RuntimeJit.ts