on e884670 help sign in
elk/runtime/Debugger.js
161 lines 3.6 kB history raw
2(function() {
3'use strict';
5var staticDebugger = null;
7Elm.debuggerInit = function(module) {
8 return function(elm) {
9 staticDebugger = debuggerInit(module, elm);
10 return staticDebugger.moduleRetValue;
11 };
12};
14Elm.debuggerReset = function() {
15 staticDebugger.reset();
18Elm.debuggerRecord = function() {
19 staticDebugger.startRecording();
22Elm.debuggerPlayback = function() {
23 staticDebugger.stopRecording();
27function debuggerInit(module, elm) {
28 var State = { OFF: 0, RECORDING: 1, PLAYBACK: 2 };
29 var debuggerState = State.RUNNING;
31 var allNodes = null;
32 var initialProgramState = null;
33 var recordedEvents = [];
34 var asyncTimers = [];
36 function wrapNotify(id, v) {
37 var timestep = Date.now();
38 if (debuggerState != State.PLAYBACK) {
39 elm.notify(id, v, timestep);
40 }
41 if (debuggerState == State.RECORDING) {
42 recordEvent(id, v, timestep);
43 }
44 };
46 function wrapRunDelayed(func, delayMs) {
47 return safeSetTimeout(func, delayMs);
48 };
50 function safeSetTimeout(func, delayMs) {
51 var timerId = setTimeout(func, delayMs);
52 asyncTimers.push(timerId);
53 return timerId;
54 }
56 function recordEvent(id, v, timestep) {
57 recordedEvents.push([id, v, timestep]);
58 }
60 function resetProgram() {
61 clearAsyncEvents();
62 restoreProgramState(allNodes, initialProgramState);
63 }
65 function startRecording() {
66 clearAsyncEvents();
67 restoreProgramState(allNodes, initialProgramState);
68 debuggerState = State.RECORDING;
69 recordedEvents = [];
70 }
72 function stopRecording() {
73 clearAsyncEvents();
74 restoreProgramState(allNodes, initialProgramState);
75 debuggerState = State.PLAYBACK;
76 doPlayback(recordedEvents);
77 }
79 function clearAsyncEvents() {
80 asyncTimers.forEach(function(id) {
81 clearTimeout(id);
82 });
83 }
85 function doPlayback(eventList) {
86 var x = eventList.shift();
87 var time = x[2];
88 elm.notify(x[0], x[1], x[2]);
90 if (eventList.length > 0) {
91 var delta = eventList[0][2] - time;
92 setTimeout(function() { doPlayback(eventList); }, delta);
93 }
94 }
96 var moduleRetValue = module(elm);
98 allNodes = flattenNodes(elm.inputs);
99 initialProgramState = saveProgramState(allNodes);
101 var debugElm = {
102 elm: {
103 notify: wrapNotify,
104 runDelayed: wrapRunDelayed,
105 node: elm.node,
106 display: elm.display,
107 id: elm.id,
108 addListener: elm.addListener,
109 inputs: elm.inputs
110 },
111 moduleRetValue: moduleRetValue,
113 // debugger functions
114 startRecording: startRecording,
115 stopRecording: stopRecording,
116 reset: resetProgram
117 };
118 return debugElm;
119};
123function assert(bool, msg) {
124 if (!bool) {
125 throw "Assertion error: " + msg;
126 }
129function saveProgramState(allNodes) {
130 var nodeValues = [];
132 allNodes.forEach(function(node) {
133 nodeValues.push({ value: node.value, id: node.id });
134 });
136 return nodeValues;
137};
140function restoreProgramState(allNodes, nodeStates) {
141 assert(allNodes.length == nodeStates.length, "saved program state has wrong length");
142 for (var i=0; i < allNodes.length; i++) {
143 var node = allNodes[i];
144 var state = nodeStates[i];
145 assert(node.id == state.id, "the nodes moved position");
147 node.value = state.value;
148 }
151function flattenNodes(nodes) {
152 var treeReduce = function(prev, cur, i, arr) {
153 var flatKids = cur.kids.reduce(treeReduce, []);
154 flatKids.push(cur);
155 return prev.concat(flatKids);
156 }
158 return nodes.reduce(treeReduce, []);
159};
161}());