on master help sign in
Debugger.
commite8846706e26b81dc481dfa1b218a4991cefb424c authorLaszlo Pandy <laszlo.pandy@prezi.com> dateThu 18 Jul 2013, 16:38 (13 years ago) parentcb0183b
1 file changed+161
runtime/Debugger.js+161
runtime/Debugger.jsnew file+161
@@ -0,0 +1,161 @@
1+
2+(function() {
3+'use strict';
4+
5+var staticDebugger = null;
6+
7+Elm.debuggerInit = function(module) {
8+ return function(elm) {
9+ staticDebugger = debuggerInit(module, elm);
10+ return staticDebugger.moduleRetValue;
11+ };
12+};
13+
14+Elm.debuggerReset = function() {
15+ staticDebugger.reset();
16+}
17+
18+Elm.debuggerRecord = function() {
19+ staticDebugger.startRecording();
20+}
21+
22+Elm.debuggerPlayback = function() {
23+ staticDebugger.stopRecording();
24+}
25+
26+
27+function debuggerInit(module, elm) {
28+ var State = { OFF: 0, RECORDING: 1, PLAYBACK: 2 };
29+ var debuggerState = State.RUNNING;
30+
31+ var allNodes = null;
32+ var initialProgramState = null;
33+ var recordedEvents = [];
34+ var asyncTimers = [];
35+
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+ };
45+
46+ function wrapRunDelayed(func, delayMs) {
47+ return safeSetTimeout(func, delayMs);
48+ };
49+
50+ function safeSetTimeout(func, delayMs) {
51+ var timerId = setTimeout(func, delayMs);
52+ asyncTimers.push(timerId);
53+ return timerId;
54+ }
55+
56+ function recordEvent(id, v, timestep) {
57+ recordedEvents.push([id, v, timestep]);
58+ }
59+
60+ function resetProgram() {
61+ clearAsyncEvents();
62+ restoreProgramState(allNodes, initialProgramState);
63+ }
64+
65+ function startRecording() {
66+ clearAsyncEvents();
67+ restoreProgramState(allNodes, initialProgramState);
68+ debuggerState = State.RECORDING;
69+ recordedEvents = [];
70+ }
71+
72+ function stopRecording() {
73+ clearAsyncEvents();
74+ restoreProgramState(allNodes, initialProgramState);
75+ debuggerState = State.PLAYBACK;
76+ doPlayback(recordedEvents);
77+ }
78+
79+ function clearAsyncEvents() {
80+ asyncTimers.forEach(function(id) {
81+ clearTimeout(id);
82+ });
83+ }
84+
85+ function doPlayback(eventList) {
86+ var x = eventList.shift();
87+ var time = x[2];
88+ elm.notify(x[0], x[1], x[2]);
89+
90+ if (eventList.length > 0) {
91+ var delta = eventList[0][2] - time;
92+ setTimeout(function() { doPlayback(eventList); }, delta);
93+ }
94+ }
95+
96+ var moduleRetValue = module(elm);
97+
98+ allNodes = flattenNodes(elm.inputs);
99+ initialProgramState = saveProgramState(allNodes);
100+
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,
112+
113+ // debugger functions
114+ startRecording: startRecording,
115+ stopRecording: stopRecording,
116+ reset: resetProgram
117+ };
118+ return debugElm;
119+};
120+
121+
122+
123+function assert(bool, msg) {
124+ if (!bool) {
125+ throw "Assertion error: " + msg;
126+ }
127+}
128+
129+function saveProgramState(allNodes) {
130+ var nodeValues = [];
131+
132+ allNodes.forEach(function(node) {
133+ nodeValues.push({ value: node.value, id: node.id });
134+ });
135+
136+ return nodeValues;
137+};
138+
139+
140+function 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");
146+
147+ node.value = state.value;
148+ }
149+}
150+
151+function 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+ }
157+
158+ return nodes.reduce(treeReduce, []);
159+};
160+
161+}());