on master help sign in
Migrate runtime/debug.js to elm-reactor
b0596f7Evan Czaplicki
elm-compiler.cabal−3
@@ -27,9 +27,6 @@ Extra-source-files: changelog.md
27Cabal-version: >=1.9
27Cabal-version: >=1.9
28Build-type: Simple
28Build-type: Simple
29
29
30−Data-files:
31− runtime/debug.js
32−
33source-repository head
30source-repository head
34 type: git
31 type: git
35 location: git://github.com/elm-lang/elm-compiler.git
32 location: git://github.com/elm-lang/elm-compiler.git
runtime/debug.jsdeleted−604
@@ -1,604 +0,0 @@
1−(function() {
2−'use strict';
3−
4−if (typeof window != 'undefined' && !window.location.origin) {
5− window.location.origin =
6− window.location.protocol + "//" +
7− window.location.hostname +
8− (window.location.port ? (':' + window.location.port) : '');
9−}
10−
11−Elm.fullscreenDebugHooks = function(elmModule, debuggerHistory /* =undefined */) {
12− var exposedDebugger = {};
13− function debuggerAttach(elmModule, debuggerHistory) {
14− return {
15− make: function(runtime) {
16− var wrappedModule = debugModule(elmModule, runtime);
17− exposedDebugger = debuggerInit(wrappedModule, runtime, debuggerHistory);
18− return wrappedModule.debuggedModule;
19− }
20− }
21− }
22− var mainHandle = Elm.fullscreen(debuggerAttach(elmModule, debuggerHistory));
23− mainHandle.debugger = exposedDebugger;
24− return mainHandle;
25−};
26−
27−var EVENTS_PER_SAVE = 100;
28−
29−function debugModule(module, runtime) {
30− var programPaused = false;
31− var recordedEvents = [];
32− var asyncCallbacks = [];
33− var snapshots = [];
34− var watchTracker = Elm.Native.Debug.make(runtime).watchTracker;
35− var pauseTime = 0;
36− var eventsUntilSnapshot = EVENTS_PER_SAVE;
37− runtime.debuggerStatus = runtime.debuggerStatus || {};
38− runtime.debuggerStatus.eventCounter = runtime.debuggerStatus.eventCounter || 0;
39−
40− // runtime is the prototype of wrappedRuntime
41− // so we can access all runtime properties too
42− var wrappedRuntime = Object.create(runtime);
43− wrappedRuntime.notify = notifyWrapper;
44− wrappedRuntime.setTimeout = setTimeoutWrapper;
45−
46− // make a copy of the wrappedRuntime
47− var assignedPropTracker = Object.create(wrappedRuntime);
48− var debuggedModule = module.make(assignedPropTracker);
49−
50− // make sure the signal graph is actually a signal & extract the visual model
51− if ( !('recv' in debuggedModule.main) ) {
52− debuggedModule.main = Elm.Signal.make(runtime).constant(debuggedModule.main);
53− }
54−
55− // The main module stores imported modules onto the runtime.
56− // To ensure only one instance of each module is created,
57− // we assign them back on the original runtime object.
58− Object.keys(assignedPropTracker).forEach(function(key) {
59− runtime[key] = assignedPropTracker[key];
60− });
61−
62− var signalGraphNodes = flattenSignalGraph(wrappedRuntime.inputs);
63− var tracePath = tracePathInit(runtime, debuggedModule.main);
64−
65− snapshots.push(snapshotSignalGraph(signalGraphNodes));
66−
67− function notifyWrapper(id, v) {
68− var timestep = runtime.timer.now();
69−
70− if (programPaused) {
71− // ignore async events generated while playing back
72− // or user events while program is paused
73− return false;
74− }
75− else {
76− recordEvent(id, v, timestep);
77− var changed = runtime.notify(id, v, timestep);
78− snapshotOnCheckpoint();
79− if (parent.window) {
80− parent.window.postMessage("elmNotify", window.location.origin);
81− }
82− return changed;
83− }
84− };
85−
86− function setTimeoutWrapper(func, delayMs) {
87− if (programPaused) {
88− // Don't push timers and such to the callback stack while we're paused.
89− // It causes too many callbacks to be fired during unpausing.
90− return 0;
91− }
92− var cbObj = { func:func, delayMs:delayMs, timerId:0, executed:false };
93− var timerId = setTimeout(function() {
94− cbObj.executed = true;
95− func();
96− }, delayMs);
97− cbObj.timerId = timerId;
98− asyncCallbacks.push(cbObj);
99− return timerId;
100− }
101−
102− function recordEvent(id, v, timestep) {
103− watchTracker.pushFrame();
104− recordedEvents.push({ id:id, value:v, timestep:timestep });
105− runtime.debuggerStatus.eventCounter += 1;
106− }
107−
108− function clearAsyncCallbacks() {
109− asyncCallbacks.forEach(function(timer) {
110− if (!timer.executed) {
111− clearTimeout(timer.timerId);
112− }
113− });
114− }
115−
116− function clearRecordedEvents() {
117− recordedEvents = [];
118− runtime.debuggerStatus.eventCounter = 0;
119− }
120−
121− function getRecordedEventsLength() {
122− return recordedEvents.length;
123− }
124−
125− function getRecordedEventAt(i) {
126− return recordedEvents[i];
127− }
128−
129− function copyRecordedEvents() {
130− return recordedEvents.slice();
131− }
132−
133− function loadRecordedEvents(events) {
134− recordedEvents = events.slice();
135− }
136−
137− function clearSnapshots() {
138− snapshots = [snapshotSignalGraph(signalGraphNodes)];
139− }
140−
141− function getSnapshotAt(i) {
142− var snapshotEvent = Math.floor(i / EVENTS_PER_SAVE);
143− assert(snapshotEvent < snapshots.length && snapshotEvent >= 0,
144− "Out of bounds index: " + snapshotEvent);
145− return snapshots[snapshotEvent];
146− }
147−
148− function snapshotOnCheckpoint() {
149− if (eventsUntilSnapshot === 1) {
150− snapshots.push(snapshotSignalGraph(signalGraphNodes));
151− eventsUntilSnapshot = EVENTS_PER_SAVE;
152− } else {
153− eventsUntilSnapshot -= 1;
154− }
155− }
156−
157− function setPaused() {
158− programPaused = true;
159− clearAsyncCallbacks();
160− pauseTime = Date.now();
161− tracePath.stopRecording();
162− preventInputEvents();
163− }
164−
165− function setContinue(position) {
166− var pauseDelay = Date.now() - pauseTime;
167− runtime.timer.addDelay(pauseDelay);
168− programPaused = false;
169−
170− // we need to dump the events that are ahead of where we're continuing.
171− var lastSnapshotPosition = Math.floor(position / EVENTS_PER_SAVE);
172− eventsUntilSnapshot = EVENTS_PER_SAVE - (position % EVENTS_PER_SAVE);
173− snapshots = snapshots.slice(0, lastSnapshotPosition + 1);
174−
175− if (position < getRecordedEventsLength()) {
176− var lastEventTime = recordedEvents[position].timestep;
177− var scrubTime = runtime.timer.now() - lastEventTime;
178− runtime.timer.addDelay(scrubTime);
179− }
180−
181− recordedEvents = recordedEvents.slice(0, position);
182− tracePath.clearTracesAfter(position);
183− runtime.debuggerStatus.eventCounter = position;
184− executeCallbacks(asyncCallbacks);
185− permitInputEvents();
186−
187− tracePath.startRecording();
188− }
189−
190− function getPaused() {
191− return programPaused;
192− }
193−
194− function preventInputEvents(){
195− var events =
196− [ "click", "mousemove", "mouseup", "mousedown", "mouseclick"
197− , "keydown", "keypress", "keyup", "touchstart", "touchend"
198− , "touchcancel", "touchleave", "touchmove", "pointermove"
199− , "pointerdown", "pointerup", "pointerover", "pointerout"
200− , "pointerenter", "pointerleave", "pointercancel"
201− ];
202−
203− var ignore = function(e) {
204− var evt = e ? e : window.event;
205− if (evt.stopPropagation) {
206− evt.stopPropagation();
207− }
208− if (evt.cancelBubble !== null) {
209− evt.cancelBubble = true;
210− }
211− if (evt.preventDefault) {
212− evt.preventDefault();
213− }
214− return false;
215− };
216−
217− var ignoringDiv = document.getElementById("elmEventIgnorer");
218− if (!ignoringDiv) {
219− ignoringDiv = document.createElement("div");
220− ignoringDiv.id = "elmEventIgnorer";
221− ignoringDiv.style.position = "absolute";
222− ignoringDiv.style.top = "0px";
223− ignoringDiv.style.left = "0px";
224− ignoringDiv.style.width = "100%";
225− ignoringDiv.style.height = "100%";
226−
227− for (var i = events.length; i-- ;) {
228− ignoringDiv.addEventListener(events[i], ignore, true);
229− }
230− runtime.node.appendChild(ignoringDiv);
231− }
232− }
233−
234− function permitInputEvents(){
235− var ignoringDiv = document.getElementById("elmEventIgnorer");
236− ignoringDiv.parentNode.removeChild(ignoringDiv);
237− }
238−
239− return {
240− debuggedModule: debuggedModule,
241− signalGraphNodes: signalGraphNodes,
242− initialSnapshot: snapshotSignalGraph(signalGraphNodes),
243− initialAsyncCallbacks: asyncCallbacks.slice(),
244− // API functions
245− clearAsyncCallbacks: clearAsyncCallbacks,
246− clearRecordedEvents: clearRecordedEvents,
247− getRecordedEventsLength: getRecordedEventsLength,
248− getRecordedEventAt: getRecordedEventAt,
249− copyRecordedEvents: copyRecordedEvents,
250− loadRecordedEvents: loadRecordedEvents,
251− clearSnapshots: clearSnapshots,
252− getSnapshotAt: getSnapshotAt,
253− snapshotOnCheckpoint: snapshotOnCheckpoint,
254− getPaused: getPaused,
255− setPaused: setPaused,
256− setContinue: setContinue,
257− tracePath: tracePath,
258− watchTracker: watchTracker
259− };
260−}
261−
262−// The debuggerHistory variable is passed in on swap. It represents
263−// the a state of the debugger for it to assume during init. It contains
264−// the paused state of the debugger, the recorded events, and the current
265−// event being processed.
266−function debuggerInit(debugModule, runtime, debuggerHistory /* =undefined */) {
267− var currentEventIndex = 0;
268−
269− function resetProgram(position) {
270− var closestSnapshot = debugModule.getSnapshotAt(position);
271− debugModule.clearAsyncCallbacks();
272− restoreSnapshot(debugModule.signalGraphNodes, closestSnapshot);
273− redrawGraphics();
274− }
275−
276− function restartProgram() {
277− pauseProgram();
278− resetProgram(0);
279− debugModule.watchTracker.clear();
280− debugModule.tracePath.clearTraces();
281− debugModule.setContinue(0);
282− debugModule.clearRecordedEvents();
283− debugModule.clearSnapshots();
284− executeCallbacks(debugModule.initialAsyncCallbacks);
285− }
286−
287− function pauseProgram() {
288− debugModule.setPaused();
289− currentEventIndex = debugModule.getRecordedEventsLength();
290− }
291−
292− function continueProgram() {
293− if (debugModule.getPaused())
294− {
295− var closestSnapshotIndex =
296− Math.floor(currentEventIndex / EVENTS_PER_SAVE) * EVENTS_PER_SAVE;
297− resetProgram(currentEventIndex);
298− var continueIndex = currentEventIndex;
299− currentEventIndex = closestSnapshotIndex;
300− stepTo(continueIndex);
301− debugModule.setContinue(currentEventIndex);
302− }
303− }
304−
305− function stepTo(index) {
306− if (!debugModule.getPaused()) {
307− debugModule.setPaused();
308− resetProgram();
309− }
310−
311− if (index < 0 || index > getMaxSteps()) {
312− throw "Index out of bounds: " + index;
313− }
314−
315− if (index < currentEventIndex) {
316− var closestSnapshotIndex = Math.floor(index / EVENTS_PER_SAVE) * EVENTS_PER_SAVE;
317− resetProgram(index);
318− currentEventIndex = closestSnapshotIndex;
319− }
320−
321− while (currentEventIndex < index) {
322− var nextEvent = debugModule.getRecordedEventAt(currentEventIndex);
323− runtime.notify(nextEvent.id, nextEvent.value, nextEvent.timestep);
324−
325− currentEventIndex += 1;
326− }
327− }
328−
329− function getMaxSteps() {
330− return debugModule.getRecordedEventsLength();
331− }
332−
333− function redrawGraphics() {
334− var main = debugModule.debuggedModule.main
335− for (var i = main.kids.length ; i-- ; ) {
336− main.kids[i].recv(runtime.timer.now(), true, main.id);
337− }
338− }
339−
340− function getSwapState() {
341− var continueIndex = currentEventIndex;
342− if (!debugModule.getPaused()) {
343− continueIndex = getMaxSteps();
344− }
345− return {
346− paused: debugModule.getPaused(),
347− recordedEvents: debugModule.copyRecordedEvents(),
348− currentEventIndex: continueIndex
349− };
350− }
351−
352− function dispose() {
353− var parentNode = runtime.node.parentNode;
354− parentNode.removeChild(debugModule.tracePath.canvas);
355− parentNode.removeChild(runtime.node);
356− }
357−
358− if (debuggerHistory) {
359− // The problem is that we want to previous paused state. But
360− // by the time JS reaches here, the old code has been swapped out
361− // and the new modules are being generated. So we can ask the
362− // debugging console what it thinks the pause state is and go
363− // from there.
364− var paused = debuggerHistory.paused;
365− debugModule.setPaused();
366− debugModule.loadRecordedEvents(debuggerHistory.recordedEvents);
367− var index = getMaxSteps();
368− runtime.debuggerStatus.eventCounter = 0;
369− debugModule.tracePath.clearTraces();
370−
371− // draw new trace path
372− debugModule.tracePath.startRecording();
373− while(currentEventIndex < index) {
374− var nextEvent = debugModule.getRecordedEventAt(currentEventIndex);
375− runtime.debuggerStatus.eventCounter += 1;
376− runtime.notify(nextEvent.id, nextEvent.value, nextEvent.timestep);
377− debugModule.snapshotOnCheckpoint();
378− currentEventIndex += 1;
379− }
380− debugModule.tracePath.stopRecording();
381−
382− stepTo(debuggerHistory.currentEventIndex);
383− if (!paused) {
384− debugModule.setContinue(debuggerHistory.currentEventIndex);
385− }
386− }
387−
388− runtime.node.parentNode.appendChild(debugModule.tracePath.canvas);
389−
390− var elmDebugger = {
391− restart: restartProgram,
392− pause: pauseProgram,
393− kontinue: continueProgram,
394− getMaxSteps: getMaxSteps,
395− stepTo: stepTo,
396− getPaused: debugModule.getPaused,
397− getSwapState: getSwapState,
398− dispose: dispose,
399− allNodes: debugModule.signalGraphNodes,
400− watchTracker: debugModule.watchTracker
401− };
402−
403− return elmDebugger;
404−}
405−
406−function Point(x, y) {
407− this.x = x;
408− this.y = y;
409−
410− this.translate = function(x, y) {
411− return new Point(this.x + x, this.y + y);
412− }
413−
414− this.equals = function(p) {
415− return this.x == p.x && this.y == p.y;
416− }
417−}
418−
419−function tracePathInit(runtime, signalGraphMain) {
420− var List = Elm.List.make(runtime);
421− var Signal = Elm.Signal.make(runtime);
422− var tracePathNode = A2(Signal.map, graphicsUpdate, signalGraphMain);
423− var tracePathCanvas = createCanvas();
424− var tracePositions = {};
425− var recordingTraces = true;
426−
427− function findPositions(currentScene) {
428− var positions = {};
429− function processElement(elem, offset) {
430− if (elem.element.ctor == "Custom" && elem.element.type == "Collage")
431− {
432− List.map(F2(processForm)(offset))(elem.element.model.forms);
433− }
434− }
435−
436− function processForm(offset, form) {
437− if (form.form.ctor == "FElement")
438− {
439− processElement(form.form._0, offset.translate(form.x, -form.y));
440− }
441− if (form.form.ctor == "FGroup")
442− {
443− var newOffset = offset.translate(form.x, -form.y);
444− List.map(F2(processForm)(newOffset))(form.form._1);
445− }
446− if (form.debugTracePathId)
447− {
448− positions[form.debugTracePathId] = new Point(form.x + offset.x, -form.y + offset.y);
449− }
450− }
451−
452− processElement(currentScene, new Point(0, 0));
453− return positions;
454− }
455−
456− function appendPositions(positions) {
457− for (var id in positions) {
458− var pos = positions[id];
459− if (tracePositions.hasOwnProperty(id)) {
460− tracePositions[id].push(pos);
461− }
462− else {
463− tracePositions[id] = [pos];
464− }
465− if (tracePositions[id].length < runtime.debuggerStatus.eventCounter) {
466− var padCount = runtime.debuggerStatus.eventCounter - tracePositions[id].length;
467− var lastTracePosition = tracePositions[id][tracePositions[id].length - 1];
468− for (var i = padCount; i--;) {
469− tracePositions[id].push(lastTracePosition)
470− }
471− }
472− assert(tracePositions[id].length === runtime.debuggerStatus.eventCounter,
473− "We don't have a 1-1 mapping of trace positions to events");
474− }
475− }
476−
477− function graphicsUpdate(currentScene) {
478− if (!recordingTraces) {
479− return;
480− }
481−
482− var ctx = tracePathCanvas.getContext('2d');
483− ctx.clearRect(0, 0, tracePathCanvas.width, tracePathCanvas.height);
484−
485− ctx.save();
486− ctx.translate(ctx.canvas.width/2, ctx.canvas.height/2);
487− appendPositions(findPositions(currentScene));
488− for (var id in tracePositions)
489− {
490− ctx.beginPath();
491− var points = tracePositions[id];
492− for (var i=0; i < points.length; i++)
493− {
494− var p = points[i];
495− if (i == 0) {
496− ctx.moveTo(p.x, p.y);
497− }
498− else {
499− ctx.lineTo(p.x, p.y);
500− }
501− }
502− ctx.lineWidth = 1;
503− ctx.strokeStyle = "rgba(50, 50, 50, 0.4)";
504− ctx.stroke();
505− }
506−
507− ctx.restore();
508− }
509−
510− function clearTraces() {
511− tracePositions = {};
512− }
513−
514− function stopRecording() {
515− recordingTraces = false;
516− }
517−
518− function startRecording() {
519− recordingTraces = true;
520− }
521−
522− function clearTracesAfter(position) {
523− var newTraces = {};
524− for (var id in tracePositions) {
525− newTraces[id] = tracePositions[id].slice(0,position);
526− }
527− tracePositions = newTraces;
528− }
529−
530− return {
531− graphicsUpdate: graphicsUpdate,
532− canvas: tracePathCanvas,
533− clearTraces: clearTraces,
534− clearTracesAfter: clearTracesAfter,
535− stopRecording: stopRecording,
536− startRecording: startRecording
537− }
538−}
539−
540−function executeCallbacks(callbacks) {
541− callbacks.forEach(function(timer) {
542− if (!timer.executed) {
543− var func = timer.func;
544− timer.executed = true;
545− func();
546− }
547− });
548−}
549−
550−function createCanvas() {
551− var c = document.createElement('canvas');
552− c.width = window.innerWidth;
553− c.height = window.innerHeight;
554− c.style.position = "absolute";
555− c.style.top = "0";
556− c.style.left = "0";
557− c.style.pointerEvents = "none";
558− return c;
559−}
560−
561−function assert(bool, msg) {
562− if (!bool) {
563− throw "Assertion error: " + msg;
564− }
565−}
566−
567−function snapshotSignalGraph(signalGraphNodes) {
568− var nodeValues = [];
569−
570− signalGraphNodes.forEach(function(node) {
571− nodeValues.push({ value: node.value, id: node.id });
572− });
573−
574− return nodeValues;
575−};
576−
577−function restoreSnapshot(signalGraphNodes, snapshot) {
578− assert(signalGraphNodes.length == snapshot.length,
579− "saved program state has wrong length");
580− for (var i=0; i < signalGraphNodes.length; i++) {
581− var node = signalGraphNodes[i];
582− var state = snapshot[i];
583− assert(node.id == state.id, "the nodes moved position");
584−
585− node.value = state.value;
586− }
587−}
588−
589−function flattenSignalGraph(nodes) {
590− var nodesById = {};
591−
592− function addAllToDict(node) {
593− nodesById[node.id] = node;
594− node.kids.forEach(addAllToDict);
595− }
596− nodes.forEach(addAllToDict);
597−
598− var allNodes = Object.keys(nodesById).sort().map(function(key) {
599− return nodesById[key];
600− });
601− return allNodes;
602−};
603−
604−}());
src/Elm/Compiler.hs−12
@@ -3,7 +3,6 @@
3module Elm.Compiler
3module Elm.Compiler
4 ( version
4 ( version
5 , parseDependencies, compile
5 , parseDependencies, compile
6− , runtimeDebugPath
7 ) where
6 ) where
8
7
9import Control.Monad.Error (MonadError, throwError)
8import Control.Monad.Error (MonadError, throwError)
@@ -16,11 +15,9 @@ import qualified Compile
16import qualified Elm.Compiler.Module as PublicModule
15import qualified Elm.Compiler.Module as PublicModule
17import qualified Elm.Compiler.Version as Version
16import qualified Elm.Compiler.Version as Version
18import Elm.Utils ((|>))
17import Elm.Utils ((|>))
19−import qualified Elm.Utils as Utils
20import qualified Generate.JavaScript as JS
18import qualified Generate.JavaScript as JS
21import qualified Parse.Helpers as Help
19import qualified Parse.Helpers as Help
22import qualified Parse.Module as Parse
20import qualified Parse.Module as Parse
23−import qualified Paths_elm_compiler as Paths
24
21
25
22
26-- VERSION
23-- VERSION
@@ -70,12 +67,3 @@ compile user packageName source interfaces =
70 |> List.intersperse ""
67 |> List.intersperse ""
71 |> unlines
68 |> unlines
72 |> Left
69 |> Left
73−
74−
75−-- DATA FILES
76−
77−{-| Path to the debugger runtime.
78−-}
79−runtimeDebugPath :: IO FilePath
80−runtimeDebugPath =
81− Utils.getAsset "compiler" Paths.getDataFileName "runtime/debug.js"