@@ -0,0 +1,161 @@
5+var staticDebugger = null;
7+Elm.debuggerInit = function(module) {
8+ return function(elm) {
9+ staticDebugger = debuggerInit(module, elm);
10+ return staticDebugger.moduleRetValue;
14+Elm.debuggerReset = function() {
15+ staticDebugger.reset();
18+Elm.debuggerRecord = function() {
19+ staticDebugger.startRecording();
22+Elm.debuggerPlayback = function() {
23+ staticDebugger.stopRecording();
27+function debuggerInit(module, elm) {
28+ var State = { OFF: 0, RECORDING: 1, PLAYBACK: 2 };
29+ var debuggerState = State.RUNNING;
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);
41+ if (debuggerState == State.RECORDING) {
42+ recordEvent(id, v, timestep);
46+ function wrapRunDelayed(func, delayMs) {
47+ return safeSetTimeout(func, delayMs);
50+ function safeSetTimeout(func, delayMs) {
51+ var timerId = setTimeout(func, delayMs);
52+ asyncTimers.push(timerId);
56+ function recordEvent(id, v, timestep) {
57+ recordedEvents.push([id, v, timestep]);
60+ function resetProgram() {
62+ restoreProgramState(allNodes, initialProgramState);
65+ function startRecording() {
67+ restoreProgramState(allNodes, initialProgramState);
68+ debuggerState = State.RECORDING;
72+ function stopRecording() {
74+ restoreProgramState(allNodes, initialProgramState);
75+ debuggerState = State.PLAYBACK;
76+ doPlayback(recordedEvents);
79+ function clearAsyncEvents() {
80+ asyncTimers.forEach(function(id) {
85+ function doPlayback(eventList) {
86+ var x = eventList.shift();
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);
96+ var moduleRetValue = module(elm);
98+ allNodes = flattenNodes(elm.inputs);
99+ initialProgramState = saveProgramState(allNodes);
104+ runDelayed: wrapRunDelayed,
106+ display: elm.display,
108+ addListener: elm.addListener,
111+ moduleRetValue: moduleRetValue,
113+ // debugger functions
114+ startRecording: startRecording,
115+ stopRecording: stopRecording,
123+function assert(bool, msg) {
125+ throw "Assertion error: " + msg;
129+function saveProgramState(allNodes) {
130+ var nodeValues = [];
132+ allNodes.forEach(function(node) {
133+ nodeValues.push({ value: node.value, id: node.id });
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");
147+ node.value = state.value;
151+function flattenNodes(nodes) {
152+ var treeReduce = function(prev, cur, i, arr) {
153+ var flatKids = cur.kids.reduce(treeReduce, []);
155+ return prev.concat(flatKids);
158+ return nodes.reduce(treeReduce, []);