@@ -13,32 +13,36 @@ Elm.debuggerInit = function(module) {
14Elm.debuggerReset = function() {
14Elm.debuggerReset = function() {
15 staticDebugger.reset();
15 staticDebugger.reset();
18−Elm.debuggerRecord = function() {
19− staticDebugger.startRecording();
22−Elm.debuggerPlayback = function() {
18+Elm.debuggerRestart = function() {
23− staticDebugger.stopRecording();
19+ staticDebugger.restart();
22+Elm.debuggerStep = function() {
23+ staticDebugger.step();
27function debuggerInit(module, elm) {
26function debuggerInit(module, elm) {
28− var State = { OFF: 0, RECORDING: 1, PLAYBACK: 2 };
29− var debuggerState = State.RUNNING;
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 = {
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
41− if (debuggerState == State.RECORDING) {
44+ else {
45+ elm.notify(id, v, timestep);
42 recordEvent(id, v, timestep);
46 recordEvent(id, v, timestep);
@@ -49,37 +53,46 @@ function debuggerInit(module, elm) {
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;
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 });
60 function resetProgram() {
64 function resetProgram() {
61 clearAsyncEvents();
65 clearAsyncEvents();
62− restoreProgramState(allNodes, initialProgramState);
66+ restoreNodeValues(allNodes, initialProgramState.nodeValues);
63 redrawGraphics();
67 redrawGraphics();
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;
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);
87+ // move into stepping mode
88+ programPaused = true;
80 function clearAsyncEvents() {
93 function clearAsyncEvents() {
81− asyncTimers.forEach(function(id) {
94+ asyncTimers.forEach(function(timer) {
82− clearTimeout(id);
95+ clearTimeout(timer.timerId);
@@ -115,13 +128,14 @@ function debuggerInit(module, elm) {
115 moduleRetValue: moduleRetValue,
128 moduleRetValue: moduleRetValue,
117 // debugger functions
130 // debugger functions
118− startRecording: startRecording,
119− stopRecording: stopRecording,
120− reset: resetProgram
131+ reset: resetProgram,
132+ restart: restartProgram,
123 allNodes = flattenNodes(wrappedElm.inputs);
136 allNodes = flattenNodes(wrappedElm.inputs);
124− initialProgramState = saveProgramState(allNodes);
137+ initialProgramState.nodeValues = saveNodeValues(allNodes);
138+ initialProgramState.asyncTimers = asyncTimers.slice();
126 return elmDebugger;
140 return elmDebugger;
@@ -134,7 +148,7 @@ function assert(bool, msg) {
137−function saveProgramState(allNodes) {
151+function saveNodeValues(allNodes) {
138 var nodeValues = [];
152 var nodeValues = [];
140 allNodes.forEach(function(node) {
154 allNodes.forEach(function(node) {
@@ -145,7 +159,7 @@ function saveProgramState(allNodes) {
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];