on master help sign in
Debugger with forward stepping.
73e6bc2Laszlo Pandy
runtime/Debugger.js+48−34
@@ -13,32 +13,36 @@ Elm.debuggerInit = function(module) {
13
13
14Elm.debuggerReset = function() {
14Elm.debuggerReset = function() {
15 staticDebugger.reset();
15 staticDebugger.reset();
16−}
16+};
17−
18−Elm.debuggerRecord = function() {
19− staticDebugger.startRecording();
20−}
21
17
22−Elm.debuggerPlayback = function() {
18+Elm.debuggerRestart = function() {
23− staticDebugger.stopRecording();
19+ staticDebugger.restart();
24−}
20+};
25
21
22+Elm.debuggerStep = function() {
23+ staticDebugger.step();
24+};
26
25
27function debuggerInit(module, elm) {
26function debuggerInit(module, elm) {
28− var State = { OFF: 0, RECORDING: 1, PLAYBACK: 2 };
29− var debuggerState = State.RUNNING;
30
27
28+ var programPaused = false;
31 var allNodes = null;
29 var allNodes = null;
32− var initialProgramState = null;
30+
33 var recordedEvents = [];
31 var recordedEvents = [];
34 var asyncTimers = [];
32 var asyncTimers = [];
33+ var initialProgramState = {
34+ nodeValues: [],
35+ asyncTimers: []
36+ };
35
37
36 function wrapNotify(id, v) {
38 function wrapNotify(id, v) {
37 var timestep = Date.now();
39 var timestep = Date.now();
38− if (debuggerState != State.PLAYBACK) {
40+
39− elm.notify(id, v, timestep);
41+ if (programPaused) {
42+ // ignore notify because we are stepping
40 }
43 }
41− if (debuggerState == State.RECORDING) {
44+ else {
45+ elm.notify(id, v, timestep);
42 recordEvent(id, v, timestep);
46 recordEvent(id, v, timestep);
43 }
47 }
44 };
48 };
@@ -49,37 +53,46 @@ function debuggerInit(module, elm) {
49
53
50 function safeSetTimeout(func, delayMs) {
54 function safeSetTimeout(func, delayMs) {
51 var timerId = setTimeout(func, delayMs);
55 var timerId = setTimeout(func, delayMs);
52− asyncTimers.push(timerId);
56+ asyncTimers.push({ func:func, delayMs:delayMs, timerId:timerId });
53 return timerId;
57 return timerId;
54 }
58 }
55
59
56 function recordEvent(id, v, timestep) {
60 function recordEvent(id, v, timestep) {
57− recordedEvents.push([id, v, timestep]);
61+ recordedEvents.push({ id:id, value:v, timestep:timestep });
58 }
62 }
59
63
60 function resetProgram() {
64 function resetProgram() {
61 clearAsyncEvents();
65 clearAsyncEvents();
62− restoreProgramState(allNodes, initialProgramState);
66+ restoreNodeValues(allNodes, initialProgramState.nodeValues);
63 redrawGraphics();
67 redrawGraphics();
64 }
68 }
65
69
66− function startRecording() {
70+ function restartProgram() {
67− clearAsyncEvents();
71+ resetProgram();
68− restoreProgramState(allNodes, initialProgramState);
69− debuggerState = State.RECORDING;
70 recordedEvents = [];
72 recordedEvents = [];
73+ initialProgramState.asyncTimers.forEach(function(timer) {
74+ var func = timer.func;
75+ func();
76+ });
71 }
77 }
72
78
73− function stopRecording() {
79+ function stepRecording() {
74− clearAsyncEvents();
80+ if (programPaused) {
75− restoreProgramState(allNodes, initialProgramState);
81+ if (recordedEvents.length > 0) {
76− debuggerState = State.PLAYBACK;
82+ var nextEvent = recordedEvents.shift();
77− doPlayback(recordedEvents);
83+ elm.notify(nextEvent.id, nextEvent.value, nextEvent.timestep);
84+ }
85+ }
86+ else {
87+ // move into stepping mode
88+ programPaused = true;
89+ resetProgram();
90+ }
78 }
91 }
79
92
80 function clearAsyncEvents() {
93 function clearAsyncEvents() {
81− asyncTimers.forEach(function(id) {
94+ asyncTimers.forEach(function(timer) {
82− clearTimeout(id);
95+ clearTimeout(timer.timerId);
83 });
96 });
84 }
97 }
85
98
@@ -115,13 +128,14 @@ function debuggerInit(module, elm) {
115 moduleRetValue: moduleRetValue,
128 moduleRetValue: moduleRetValue,
116
129
117 // debugger functions
130 // debugger functions
118− startRecording: startRecording,
119− stopRecording: stopRecording,
120− reset: resetProgram
131+ reset: resetProgram,
132+ restart: restartProgram,
133+ step: stepRecording
121 };
134 };
122
135
123 allNodes = flattenNodes(wrappedElm.inputs);
136 allNodes = flattenNodes(wrappedElm.inputs);
124− initialProgramState = saveProgramState(allNodes);
137+ initialProgramState.nodeValues = saveNodeValues(allNodes);
138+ initialProgramState.asyncTimers = asyncTimers.slice();
125
139
126 return elmDebugger;
140 return elmDebugger;
127};
141};
@@ -134,7 +148,7 @@ function assert(bool, msg) {
134 }
148 }
135}
149}
136
150
137−function saveProgramState(allNodes) {
151+function saveNodeValues(allNodes) {
138 var nodeValues = [];
152 var nodeValues = [];
139
153
140 allNodes.forEach(function(node) {
154 allNodes.forEach(function(node) {
@@ -145,7 +159,7 @@ function saveProgramState(allNodes) {
145};
159};
146
160
147
161
148−function restoreProgramState(allNodes, nodeStates) {
162+function restoreNodeValues(allNodes, nodeStates) {
149 assert(allNodes.length == nodeStates.length, "saved program state has wrong length");
163 assert(allNodes.length == nodeStates.length, "saved program state has wrong length");
150 for (var i=0; i < allNodes.length; i++) {
164 for (var i=0; i < allNodes.length; i++) {
151 var node = allNodes[i];
165 var node = allNodes[i];