/*
Java 17 -- Loops and recursion
while, do-while, for, for-each, recursion
No em dashes anywhere -- use plain hyphens or rewrite the sentence.
*/
STEPPER_REGISTRY.register("java-17/loops", {
label: 'Loops and recursion',
panelConfig: {
stack: true,
heap: false,
custom: false,
legend: [
{ color:'#1d5799', border:'#9dc0e8', label:'Currently running frame' },
{ color:'#68655f', border:'#d4d1cc', label:'Paused, waiting to resume' },
{ color:'#a0540a', border:'#e8c070', label:'Variable just assigned' },
{ color:'#095e40', border:'#90d4b8', label:'Holding a value' },
{ color:'#3d3490', border:'#b0a8e0', label:'Reference (array or object)' },
]
},
scenarios: [
/* ------------------------------------------------------------------ */
/* 1. while loop */
/* ------------------------------------------------------------------ */
{
label: 'while loop',
lines: [
{ code: [['tok-kw','static '],['tok-kw','void '],['tok-meth','main'],['tok-op','(String[] args) {']] },
{ code: [['',' '],['tok-type','int '],['tok-op','count = '],['tok-num','0'],['tok-op',';']] },
{ code: [['',' '],['tok-kw','while '],['tok-op','(count < '],['tok-num','3'],['tok-op',') {']] },
{ code: [['',' '],['tok-op','count++;']] },
{ code: [['',' '],['tok-op','}']] },
{ code: [['',' '],['tok-op','System.out.println('],['tok-str','"Done"'],['tok-op',');']] },
{ code: [['tok-op','}']] },
],
steps: [
{ line:0, stack:[{name:'main()',vars:[],active:true}],
expl:{label:'Program starts', text:'Java enters main() and pushes a new frame onto the call stack.'} },
{ line:1, stack:[{name:'main()',vars:[{n:'count',v:'0',fresh:true}],active:true}],
expl:{label:'Variable declared', text:'int count = 0 creates a local variable initialized to 0.'} },
{ line:2, tokenRange:[2,3], stack:[{name:'main()',vars:[{n:'count',v:'0',fresh:false}],active:true}],
expl:{label:'Condition: true', text:'Java evaluates count < 3. Since 0 < 3, the condition is true and the loop body runs.'} },
{ line:3, stack:[{name:'main()',vars:[{n:'count',v:'1',fresh:true}],active:true}],
expl:{label:'Loop body', text:'count++ increments count from 0 to 1.'} },
{ line:2, tokenRange:[2,3], stack:[{name:'main()',vars:[{n:'count',v:'1',fresh:false}],active:true}],
expl:{label:'Condition: true', text:'Back at the top. 1 < 3 is still true -- another iteration begins.'} },
{ line:3, stack:[{name:'main()',vars:[{n:'count',v:'2',fresh:true}],active:true}],
expl:{label:'Loop body', text:'count++ increments count to 2.'} },
{ line:2, tokenRange:[2,3], stack:[{name:'main()',vars:[{n:'count',v:'2',fresh:false}],active:true}],
expl:{label:'Condition: true', text:'2 < 3 is still true -- one more iteration.'} },
{ line:3, stack:[{name:'main()',vars:[{n:'count',v:'3',fresh:true}],active:true}],
expl:{label:'Loop body', text:'count++ increments count to 3.'} },
{ line:2, tokenRange:[2,3], stack:[{name:'main()',vars:[{n:'count',v:'3',fresh:false}],active:true}],
expl:{label:'Condition: false', text:'3 < 3 is false. The loop exits -- execution jumps past the closing brace.'} },
{ line:5, stack:[{name:'main()',vars:[{n:'count',v:'3',fresh:false}],active:true}],
expl:{label:'After the loop', text:'count retains its value of 3. Its scope continues until main() ends.'} },
{ line:6, stack:[{name:'main()',vars:[{n:'count',v:'3',fresh:false}],active:true}],
expl:{label:'Program ends', text:'main() reaches its closing brace. Its frame is popped and the program finishes.'} },
]
},
/* ------------------------------------------------------------------ */
/* 2. do-while loop */
/* ------------------------------------------------------------------ */
{
label: 'do-while loop',
lines: [
{ code: [['tok-kw','static '],['tok-kw','void '],['tok-meth','main'],['tok-op','(String[] args) {']] },
{ code: [['',' '],['tok-type','int '],['tok-op','n = '],['tok-num','0'],['tok-op',';']] },
{ code: [['',' '],['tok-kw','do '],['tok-op','{']] },
{ code: [['',' '],['tok-op','n++;']] },
{ code: [['',' '],['tok-op','} '],['tok-kw','while '],['tok-op','(n < '],['tok-num','2'],['tok-op',');']] },
{ code: [['',' '],['tok-op','System.out.println('],['tok-str','"Done"'],['tok-op',');']] },
{ code: [['tok-op','}']] },
],
steps: [
{ line:0, stack:[{name:'main()',vars:[],active:true}],
expl:{label:'Program starts', text:'main() begins and a new frame is pushed.'} },
{ line:1, stack:[{name:'main()',vars:[{n:'n',v:'0',fresh:true}],active:true}],
expl:{label:'Variable declared', text:'n is initialized to 0.'} },
{ line:2, stack:[{name:'main()',vars:[{n:'n',v:'0',fresh:false}],active:true}],
expl:{label:'Enter do block', text:'With do-while, the body always executes at least once -- the condition has not been checked yet.'} },
{ line:3, stack:[{name:'main()',vars:[{n:'n',v:'1',fresh:true}],active:true}],
expl:{label:'Loop body', text:'n++ increments n from 0 to 1.'} },
{ line:4, tokenRange:[3,4], stack:[{name:'main()',vars:[{n:'n',v:'1',fresh:false}],active:true}],
expl:{label:'Condition: true', text:'Now the condition is checked: 1 < 2 is true. Execution jumps back to the top of the body.'} },
{ line:3, stack:[{name:'main()',vars:[{n:'n',v:'2',fresh:true}],active:true}],
expl:{label:'Loop body', text:'n++ increments n to 2.'} },
{ line:4, tokenRange:[3,4], stack:[{name:'main()',vars:[{n:'n',v:'2',fresh:false}],active:true}],
expl:{label:'Condition: false', text:'2 < 2 is false. The loop exits. The body ran twice -- the condition was never checked before the first run.'} },
{ line:5, stack:[{name:'main()',vars:[{n:'n',v:'2',fresh:false}],active:true}],
expl:{label:'After the loop', text:'System.out.println("Done") runs.'} },
{ line:6, stack:[{name:'main()',vars:[{n:'n',v:'2',fresh:false}],active:true}],
expl:{label:'Program ends', text:'main() finishes.'} },
]
},
/* ------------------------------------------------------------------ */
/* 3. for loop */
/* ------------------------------------------------------------------ */
{
label: 'for loop',
lines: [
{ code: [['tok-kw','static '],['tok-kw','void '],['tok-meth','main'],['tok-op','(String[] args) {']] },
{ code: [['',' '],['tok-type','int '],['tok-op','sum = '],['tok-num','0'],['tok-op',';']] },
{ code: [['',' '],['tok-kw','for '],['tok-op','('],['tok-type','int '],['tok-op','i = '],['tok-num','0'],['tok-op','; '],['tok-op','i < '],['tok-num','3'],['tok-op','; '],['tok-op','i++'],['tok-op',') {']] },
{ code: [['',' '],['tok-op','sum += i;']] },
{ code: [['',' '],['tok-op','}']] },
{ code: [['',' '],['tok-op','System.out.println(sum);']] },
{ code: [['tok-op','}']] },
],
steps: [
{ line:0, stack:[{name:'main()',vars:[],active:true}],
expl:{label:'Program starts', text:'main() begins.'} },
{ line:1, stack:[{name:'main()',vars:[{n:'sum',v:'0',fresh:true}],active:true}],
expl:{label:'Variable declared', text:'sum starts at 0. It will accumulate the total.'} },
{ line:2, tokenRange:[3,5], stack:[{name:'main()',vars:[{n:'sum',v:'0',fresh:false},{n:'i',v:'0',fresh:true}],active:true}],
expl:{label:'Init', text:'The initializer int i = 0 runs exactly once. i is created and set to 0.'} },
{ line:2, tokenRange:[7,8], stack:[{name:'main()',vars:[{n:'sum',v:'0',fresh:false},{n:'i',v:'0',fresh:false}],active:true}],
expl:{label:'Condition: true', text:'Java checks i < 3. 0 < 3 is true -- the loop body runs.'} },
{ line:3, stack:[{name:'main()',vars:[{n:'sum',v:'0',fresh:false},{n:'i',v:'0',fresh:false}],active:true}],
expl:{label:'Loop body', text:'sum += i adds 0 to sum. sum stays 0 this iteration.'} },
{ line:2, tokenRange:[10,10], stack:[{name:'main()',vars:[{n:'sum',v:'0',fresh:false},{n:'i',v:'1',fresh:true}],active:true}],
expl:{label:'Increment', text:'The update i++ runs. i goes from 0 to 1.'} },
{ line:2, tokenRange:[7,8], stack:[{name:'main()',vars:[{n:'sum',v:'0',fresh:false},{n:'i',v:'1',fresh:false}],active:true}],
expl:{label:'Condition: true', text:'Java checks i < 3. 1 < 3 is true -- another iteration.'} },
{ line:3, stack:[{name:'main()',vars:[{n:'sum',v:'1',fresh:true},{n:'i',v:'1',fresh:false}],active:true}],
expl:{label:'Loop body', text:'sum += i adds 1. sum is now 1.'} },
{ line:2, tokenRange:[10,10], stack:[{name:'main()',vars:[{n:'sum',v:'1',fresh:false},{n:'i',v:'2',fresh:true}],active:true}],
expl:{label:'Increment', text:'i++ runs. i goes from 1 to 2.'} },
{ line:2, tokenRange:[7,8], stack:[{name:'main()',vars:[{n:'sum',v:'1',fresh:false},{n:'i',v:'2',fresh:false}],active:true}],
expl:{label:'Condition: true', text:'Java checks i < 3. 2 < 3 is true -- one more iteration.'} },
{ line:3, stack:[{name:'main()',vars:[{n:'sum',v:'3',fresh:true},{n:'i',v:'2',fresh:false}],active:true}],
expl:{label:'Loop body', text:'sum += i adds 2. sum is now 3.'} },
{ line:2, tokenRange:[10,10], stack:[{name:'main()',vars:[{n:'sum',v:'3',fresh:false},{n:'i',v:'3',fresh:true}],active:true}],
expl:{label:'Increment', text:'i++ runs. i goes from 2 to 3.'} },
{ line:2, tokenRange:[7,8], stack:[{name:'main()',vars:[{n:'sum',v:'3',fresh:false},{n:'i',v:'3',fresh:false}],active:true}],
expl:{label:'Condition: false', text:'Java checks i < 3. 3 < 3 is false -- the loop exits. i goes out of scope.'} },
{ line:5, stack:[{name:'main()',vars:[{n:'sum',v:'3',fresh:false}],active:true}],
expl:{label:'After the loop', text:'i is gone -- it was scoped to the for header. System.out.println(sum) prints 3.'} },
{ line:6, stack:[{name:'main()',vars:[{n:'sum',v:'3',fresh:false}],active:true}],
expl:{label:'Program ends', text:'main() finishes.'} },
]
},
/* ------------------------------------------------------------------ */
/* 4. for-each loop */
/* ------------------------------------------------------------------ */
{
label: 'for-each loop',
lines: [
{ code: [['tok-kw','static '],['tok-kw','void '],['tok-meth','main'],['tok-op','(String[] args) {']] },
{ code: [['',' '],['tok-type','int'],['tok-op','[] nums = {'],['tok-num','10'],['tok-op',', '],['tok-num','20'],['tok-op',', '],['tok-num','30'],['tok-op','};']] },
{ code: [['',' '],['tok-type','int '],['tok-op','total = '],['tok-num','0'],['tok-op',';']] },
{ code: [['',' '],['tok-kw','for '],['tok-op','('],['tok-type','int '],['tok-op','n : nums) {']] },
{ code: [['',' '],['tok-op','total += n;']] },
{ code: [['',' '],['tok-op','}']] },
{ code: [['',' '],['tok-op','System.out.println(total);']] },
{ code: [['tok-op','}']] },
],
steps: [
{ line:0, stack:[{name:'main()',vars:[],active:true}],
expl:{label:'Program starts', text:'main() begins.'} },
{ line:1, stack:[{name:'main()',vars:[{n:'nums',v:'[10, 20, 30]',fresh:true,cls:true}],active:true}],
expl:{label:'Array created', text:'An int array {10, 20, 30} is created. nums holds a reference to it -- arrays are objects in Java.'} },
{ line:2, stack:[{name:'main()',vars:[{n:'nums',v:'[10, 20, 30]',fresh:false,cls:true},{n:'total',v:'0',fresh:true}],active:true}],
expl:{label:'Variable declared', text:'total starts at 0. It will hold the running sum.'} },
{ line:3, stack:[{name:'main()',vars:[{n:'nums',v:'[10, 20, 30]',fresh:false,cls:true},{n:'total',v:'0',fresh:false},{n:'n',v:'10',fresh:true}],active:true}],
expl:{label:'First element', text:'The for-each loop retrieves the first element and assigns it to n. n = 10.'} },
{ line:4, stack:[{name:'main()',vars:[{n:'nums',v:'[10, 20, 30]',fresh:false,cls:true},{n:'total',v:'10',fresh:true},{n:'n',v:'10',fresh:false}],active:true}],
expl:{label:'Loop body', text:'total += n adds 10. total is now 10.'} },
{ line:3, stack:[{name:'main()',vars:[{n:'nums',v:'[10, 20, 30]',fresh:false,cls:true},{n:'total',v:'10',fresh:false},{n:'n',v:'20',fresh:true}],active:true}],
expl:{label:'Next element', text:'The loop advances. n is now 20.'} },
{ line:4, stack:[{name:'main()',vars:[{n:'nums',v:'[10, 20, 30]',fresh:false,cls:true},{n:'total',v:'30',fresh:true},{n:'n',v:'20',fresh:false}],active:true}],
expl:{label:'Loop body', text:'total += n adds 20. total is now 30.'} },
{ line:3, stack:[{name:'main()',vars:[{n:'nums',v:'[10, 20, 30]',fresh:false,cls:true},{n:'total',v:'30',fresh:false},{n:'n',v:'30',fresh:true}],active:true}],
expl:{label:'Last element', text:'n is now 30 -- the final element in the array.'} },
{ line:4, stack:[{name:'main()',vars:[{n:'nums',v:'[10, 20, 30]',fresh:false,cls:true},{n:'total',v:'60',fresh:true},{n:'n',v:'30',fresh:false}],active:true}],
expl:{label:'Loop body', text:'total += n adds 30. total is now 60.'} },
{ line:3, stack:[{name:'main()',vars:[{n:'nums',v:'[10, 20, 30]',fresh:false,cls:true},{n:'total',v:'60',fresh:false}],active:true}],
expl:{label:'No more elements', text:'All elements have been visited. The loop exits and n goes out of scope.'} },
{ line:6, stack:[{name:'main()',vars:[{n:'nums',v:'[10, 20, 30]',fresh:false,cls:true},{n:'total',v:'60',fresh:false}],active:true}],
expl:{label:'After the loop', text:'System.out.println(total) prints 60 -- the sum of all elements.'} },
{ line:7, stack:[{name:'main()',vars:[{n:'nums',v:'[10, 20, 30]',fresh:false,cls:true},{n:'total',v:'60',fresh:false}],active:true}],
expl:{label:'Program ends', text:'main() finishes.'} },
]
},
/* ------------------------------------------------------------------ */
/* 5. Recursion */
/* */
/* Line index (blank lines excluded from count): */
/* 0 static void main(String[] args) { */
/* 1 countdown(3); */
/* 2 } */
/* (blank -- not counted) */
/* 3 static void countdown(int n) { */
/* 4 if (n == 0) { */
/* 5 System.out.println("Go!"); */
/* 6 return; */
/* 7 } */
/* 8 System.out.println(n); */
/* 9 countdown(n - 1); */
/* 10 } */
/* ------------------------------------------------------------------ */
{
label: 'Recursion',
lines: [
{ code: [['tok-kw','static '],['tok-kw','void '],['tok-meth','main'],['tok-op','(String[] args) {']] },
{ code: [['',' '],['tok-meth','countdown'],['tok-op','('],['tok-num','3'],['tok-op',');']] },
{ code: [['tok-op','}']] },
{ blank: true },
{ code: [['tok-kw','static '],['tok-kw','void '],['tok-meth','countdown'],['tok-op','('],['tok-type','int '],['tok-op','n) {']] },
{ code: [['',' '],['tok-kw','if '],['tok-op','(n == '],['tok-num','0'],['tok-op',') {']] },
{ code: [['',' '],['tok-op','System.out.println('],['tok-str','"Go!"'],['tok-op',');']] },
{ code: [['',' '],['tok-kw','return'],['tok-op',';']] },
{ code: [['',' '],['tok-op','}']] },
{ code: [['',' '],['tok-op','System.out.println(n);']] },
{ code: [['',' '],['tok-meth','countdown'],['tok-op','(n - '],['tok-num','1'],['tok-op',');']] },
{ code: [['tok-op','}']] },
],
steps: [
{ line:0, stack:[{name:'main()',vars:[],active:true}],
expl:{label:'Program starts', text:'main() begins. Its frame is at the top of the call stack.'} },
{ line:1, stack:[{name:'main()',vars:[],active:true}],
expl:{label:'Calling countdown(3)', text:'countdown(3) is called. Java will push a new frame for it.'} },
{ line:3, stack:[{name:'countdown(n=3)',vars:[{n:'n',v:'3',fresh:true}],active:true},{name:'main()',vars:[],active:false}],
expl:{label:'Frame created', text:'A new frame for countdown() is pushed. Parameter n is set to 3. main() is now waiting.'} },
{ line:4, stack:[{name:'countdown(n=3)',vars:[{n:'n',v:'3',fresh:false}],active:true},{name:'main()',vars:[],active:false}],
expl:{label:'Base case check', text:'n == 0? No -- 3 is not 0. The if block is skipped.'} },
{ line:8, stack:[{name:'countdown(n=3)',vars:[{n:'n',v:'3',fresh:false}],active:true},{name:'main()',vars:[],active:false}],
expl:{label:'Print n', text:'System.out.println(n) prints 3.'} },
{ line:9, stack:[{name:'countdown(n=3)',vars:[{n:'n',v:'3',fresh:false}],active:true},{name:'main()',vars:[],active:false}],
expl:{label:'Recursive call', text:'countdown(n - 1) calls itself with 2. A new frame is about to be pushed.'} },
{ line:3, stack:[{name:'countdown(n=2)',vars:[{n:'n',v:'2',fresh:true}],active:true},{name:'countdown(n=3)',vars:[{n:'n',v:'3',fresh:false}],active:false},{name:'main()',vars:[],active:false}],
expl:{label:'Stack grows', text:'A second countdown() frame is pushed. Each call has its own n. The first call waits below.'} },
{ line:4, stack:[{name:'countdown(n=2)',vars:[{n:'n',v:'2',fresh:false}],active:true},{name:'countdown(n=3)',vars:[{n:'n',v:'3',fresh:false}],active:false},{name:'main()',vars:[],active:false}],
expl:{label:'Base case check', text:'n == 0? No -- 2 is not 0.'} },
{ line:8, stack:[{name:'countdown(n=2)',vars:[{n:'n',v:'2',fresh:false}],active:true},{name:'countdown(n=3)',vars:[{n:'n',v:'3',fresh:false}],active:false},{name:'main()',vars:[],active:false}],
expl:{label:'Print n', text:'Prints 2.'} },
{ line:9, stack:[{name:'countdown(n=2)',vars:[{n:'n',v:'2',fresh:false}],active:true},{name:'countdown(n=3)',vars:[{n:'n',v:'3',fresh:false}],active:false},{name:'main()',vars:[],active:false}],
expl:{label:'Recursive call', text:'countdown(1) is called. Another frame will be pushed.'} },
{ line:3, stack:[{name:'countdown(n=1)',vars:[{n:'n',v:'1',fresh:true}],active:true},{name:'countdown(n=2)',vars:[{n:'n',v:'2',fresh:false}],active:false},{name:'countdown(n=3)',vars:[{n:'n',v:'3',fresh:false}],active:false},{name:'main()',vars:[],active:false}],
expl:{label:'Stack grows', text:'Three countdown() frames now sit above main(). Each is waiting for the one above it to finish.'} },
{ line:4, stack:[{name:'countdown(n=1)',vars:[{n:'n',v:'1',fresh:false}],active:true},{name:'countdown(n=2)',vars:[{n:'n',v:'2',fresh:false}],active:false},{name:'countdown(n=3)',vars:[{n:'n',v:'3',fresh:false}],active:false},{name:'main()',vars:[],active:false}],
expl:{label:'Base case check', text:'n == 0? No -- 1 is not 0.'} },
{ line:8, stack:[{name:'countdown(n=1)',vars:[{n:'n',v:'1',fresh:false}],active:true},{name:'countdown(n=2)',vars:[{n:'n',v:'2',fresh:false}],active:false},{name:'countdown(n=3)',vars:[{n:'n',v:'3',fresh:false}],active:false},{name:'main()',vars:[],active:false}],
expl:{label:'Print n', text:'Prints 1.'} },
{ line:9, stack:[{name:'countdown(n=1)',vars:[{n:'n',v:'1',fresh:false}],active:true},{name:'countdown(n=2)',vars:[{n:'n',v:'2',fresh:false}],active:false},{name:'countdown(n=3)',vars:[{n:'n',v:'3',fresh:false}],active:false},{name:'main()',vars:[],active:false}],
expl:{label:'Recursive call', text:'countdown(0) is called -- this will trigger the base case.'} },
{ line:3, stack:[{name:'countdown(n=0)',vars:[{n:'n',v:'0',fresh:true}],active:true},{name:'countdown(n=1)',vars:[{n:'n',v:'1',fresh:false}],active:false},{name:'countdown(n=2)',vars:[{n:'n',v:'2',fresh:false}],active:false},{name:'countdown(n=3)',vars:[{n:'n',v:'3',fresh:false}],active:false},{name:'main()',vars:[],active:false}],
expl:{label:'Deepest call', text:'The stack is now at its deepest: five frames. n = 0 in this frame.'} },
{ line:4, stack:[{name:'countdown(n=0)',vars:[{n:'n',v:'0',fresh:false}],active:true},{name:'countdown(n=1)',vars:[{n:'n',v:'1',fresh:false}],active:false},{name:'countdown(n=2)',vars:[{n:'n',v:'2',fresh:false}],active:false},{name:'countdown(n=3)',vars:[{n:'n',v:'3',fresh:false}],active:false},{name:'main()',vars:[],active:false}],
expl:{label:'Base case: true', text:'n == 0 is true. The base case is reached -- the if block executes.'} },
{ line:5, stack:[{name:'countdown(n=0)',vars:[{n:'n',v:'0',fresh:false}],active:true},{name:'countdown(n=1)',vars:[{n:'n',v:'1',fresh:false}],active:false},{name:'countdown(n=2)',vars:[{n:'n',v:'2',fresh:false}],active:false},{name:'countdown(n=3)',vars:[{n:'n',v:'3',fresh:false}],active:false},{name:'main()',vars:[],active:false}],
expl:{label:'Print "Go!"', text:'System.out.println("Go!") runs. The countdown is complete.'} },
{ line:6, stack:[{name:'countdown(n=0)',vars:[{n:'n',v:'0',fresh:false}],active:true},{name:'countdown(n=1)',vars:[{n:'n',v:'1',fresh:false}],active:false},{name:'countdown(n=2)',vars:[{n:'n',v:'2',fresh:false}],active:false},{name:'countdown(n=3)',vars:[{n:'n',v:'3',fresh:false}],active:false},{name:'main()',vars:[],active:false}],
expl:{label:'return', text:'return exits countdown(n=0). Its frame is popped -- the stack begins to unwind.'} },
{ line:10, stack:[{name:'countdown(n=1)',vars:[{n:'n',v:'1',fresh:false}],active:true},{name:'countdown(n=2)',vars:[{n:'n',v:'2',fresh:false}],active:false},{name:'countdown(n=3)',vars:[{n:'n',v:'3',fresh:false}],active:false},{name:'main()',vars:[],active:false}],
expl:{label:'Unwinding', text:'Back in countdown(n=1). It has no more work to do -- it reaches its closing brace and returns.'} },
{ line:10, stack:[{name:'countdown(n=2)',vars:[{n:'n',v:'2',fresh:false}],active:true},{name:'countdown(n=3)',vars:[{n:'n',v:'3',fresh:false}],active:false},{name:'main()',vars:[],active:false}],
expl:{label:'Unwinding', text:'countdown(n=2) also completes and is popped.'} },
{ line:10, stack:[{name:'countdown(n=3)',vars:[{n:'n',v:'3',fresh:false}],active:true},{name:'main()',vars:[],active:false}],
expl:{label:'Unwinding', text:'countdown(n=3) completes and is popped. Only main() remains.'} },
{ line:2, stack:[{name:'main()',vars:[],active:true}],
expl:{label:'Back in main', text:'main() resumes after the original countdown(3) call. The program ends.'} },
]
},
]
});