on master help sign in
Add basics of properly handling ports
71bb1c8Evan Czaplicki
compiler/Generate/JavaScript.hs+9−3
@@ -299,7 +299,8 @@ generate unsafeModule =
299 , [ IfSingleStmt () thisModule (ReturnStmt () (Just thisModule)) ]
299 , [ IfSingleStmt () thisModule (ReturnStmt () (Just thisModule)) ]
300 , [ internalImports (List.intercalate "." (names modul)) ]
300 , [ internalImports (List.intercalate "." (names modul)) ]
301 , concatMap jsImport (imports modul)
301 , concatMap jsImport (imports modul)
302+ , checkInPorts (ports modul)
302− , concatMap jsPort (ports modul)
303+ , map jsPort (ports modul)
303 , [ assign ["_op"] (ObjectLit () []) ]
304 , [ assign ["_op"] (ObjectLit () []) ]
304 , concat $ evalState (mapM definition . fst . SD.flattenLets [] $ program modul) 0
305 , concat $ evalState (mapM definition . fst . SD.flattenLets [] $ program modul) 0
305 , [ jsExports ]
306 , [ jsExports ]
@@ -331,10 +332,15 @@ generate unsafeModule =
331
332
332 addId js = InfixExpr () OpAdd (string (js++"_")) (obj "_elm.id")
333 addId js = InfixExpr () OpAdd (string (js++"_")) (obj "_elm.id")
333
334
335+ checkInPorts ports =
336+ [ ExprStmt () $ obj "_N.checkPorts" `call` [ref "$moduleName", names] ]
337+ where
338+ names = ArrayLit () [ string name | (name, _, Nothing) <- ports ]
339+
334 jsPort (name, _, maybe) =
340 jsPort (name, _, maybe) =
335 case maybe of
341 case maybe of
336− Nothing -> error "in-ports are not defined yet"
342+ Nothing -> assign [name] $ dotSep ["_elm","ports_in",name]
337− Just expr -> error "out-ports are not defined yet"
343+ Just expr -> assign ["_elm","ports_out",name] $ evalState (expression expr) 0
338
344
339binop span op e1 e2 =
345binop span op e1 e2 =
340 case op of
346 case op of
compiler/Transform/Optimize.hs+1−1
@@ -19,7 +19,7 @@ class Simplify a where
19
19
20instance Simplify (Declaration t v) where
20instance Simplify (Declaration t v) where
21 simp (Definition def) = Definition (simp def)
21 simp (Definition def) = Definition (simp def)
22− simp (ImportEvent js b elm t) = ImportEvent js (simp b) elm t
22+ simp (Port name tipe maybe) = Port name tipe (simp `fmap` maybe)
23 simp stmt = stmt
23 simp stmt = stmt
24
24
25instance Simplify (Def t v) where
25instance Simplify (Def t v) where
libraries/Native/Utils.js+26−1
@@ -207,6 +207,30 @@ Elm.Native.Utils.make = function(elm) {
207 return Tuple2(posx, posy);
207 return Tuple2(posx, posy);
208 }
208 }
209
209
210+ function checkPorts(moduleName, ports) {
211+ var expected = {};
212+ for (var i = ports.length; i--; ) {
213+ expected[ports[i]] = 1;
214+ }
215+ for (var key in elm.ports_in) {
216+ expected[key] = expected[key] || 0;
217+ expected[key] -= 1;
218+ }
219+ var missing = [];
220+ var extra = [];
221+ for (var key in expected) {
222+ var result = expected[key];
223+ if (result > 0) missing.push(key);
224+ if (result < 0) extra.push(key);
225+ }
226+ if (missing.length > 0) {
227+ throw new Error("Module " + moduleName + " requires inputs for these ports: " + missing.join(', '));
228+ }
229+ if (extra.length > 0) {
230+ throw new Error("Module " + moduleName + " has been given ports that do not exist: " + extra.join(', '));
231+ }
232+ }
233+
210 return elm.Native.Utils.values = {
234 return elm.Native.Utils.values = {
211 eq:eq,
235 eq:eq,
212 cmp:cmp,
236 cmp:cmp,
@@ -226,6 +250,7 @@ Elm.Native.Utils.make = function(elm) {
226 mod : F2(mod),
250 mod : F2(mod),
227 htmlHeight: F2(htmlHeight),
251 htmlHeight: F2(htmlHeight),
228 getXY: getXY,
252 getXY: getXY,
229− toFloat: function(x) { return +x; }
253+ toFloat: function(x) { return +x; },
254+ checkPorts: checkPorts
230 };
255 };
231};
256};
runtime/Init.js+10−9
@@ -2,7 +2,7 @@
2(function() {
2(function() {
3'use strict';
3'use strict';
4
4
5−Elm.fullscreen = function(module) {
5+Elm.fullscreen = function(module, ports) {
6 var style = document.createElement('style');
6 var style = document.createElement('style');
7 style.type = 'text/css';
7 style.type = 'text/css';
8 style.innerHTML = "html,head,body { padding:0; margin:0; }" +
8 style.innerHTML = "html,head,body { padding:0; margin:0; }" +
@@ -10,24 +10,24 @@ Elm.fullscreen = function(module) {
10 document.head.appendChild(style);
10 document.head.appendChild(style);
11 var container = document.createElement('div');
11 var container = document.createElement('div');
12 document.body.appendChild(container);
12 document.body.appendChild(container);
13− return init(ElmRuntime.Display.FULLSCREEN, container, module);
13+ return init(ElmRuntime.Display.FULLSCREEN, container, module, ports);
14};
14};
15
15
16−Elm.embed = function(module, container) {
16+Elm.embed = function(module, container, ports) {
17 var tag = container.tagName;
17 var tag = container.tagName;
18 if (tag !== 'DIV') {
18 if (tag !== 'DIV') {
19 throw new Error('Elm.node must be given a DIV, not a ' + tag + '.');
19 throw new Error('Elm.node must be given a DIV, not a ' + tag + '.');
20 } else if (container.hasChildNodes()) {
20 } else if (container.hasChildNodes()) {
21 throw new Error('Elm.node must be given an empty DIV. No children allowed!');
21 throw new Error('Elm.node must be given an empty DIV. No children allowed!');
22 }
22 }
23− return init(ElmRuntime.Display.COMPONENT, container, module);
23+ return init(ElmRuntime.Display.COMPONENT, container, module, ports);
24};
24};
25
25
26−Elm.worker = function(module) {
26+Elm.worker = function(module, ports) {
27− return init(ElmRuntime.Display.NONE, {}, module);
27+ return init(ElmRuntime.Display.NONE, {}, module, ports);
28};
28};
29
29
30−function init(display, container, module, moduleToReplace) {
30+function init(display, container, module, moduleToReplace, ports) {
31 // defining state needed for an instance of the Elm RTS
31 // defining state needed for an instance of the Elm RTS
32 var inputs = [];
32 var inputs = [];
33
33
@@ -67,7 +67,8 @@ function init(display, container, module, moduleToReplace) {
67 display:display,
67 display:display,
68 id:ElmRuntime.guid(),
68 id:ElmRuntime.guid(),
69 addListener:addListener,
69 addListener:addListener,
70− inputs:inputs
70+ inputs:inputs,
71+ ports_in:ports
71 };
72 };
72
73
73 // Set up methods to communicate with Elm program from JS.
74 // Set up methods to communicate with Elm program from JS.
@@ -123,7 +124,7 @@ function init(display, container, module, moduleToReplace) {
123 }
124 }
124
125
125 reportAnyErrors();
126 reportAnyErrors();
126− return { send:send, recv:recv, swap:swap };
127+ return { send:send, recv:recv, swap:swap, ports:elm.ports_out };
127};
128};
128
129
129function filterListeners(inputs, listeners) {
130function filterListeners(inputs, listeners) {