on master help sign in
Add basics of properly handling ports
commit71bb1c8bf9cd8333218e612cddbcd741ed9c26ed authorEvan Czaplicki <info@elm-lang.org> dateTue 24 Dec 2013, 10:13 (13 years ago) parent740702c
4 files changed+46−14
compiler/Generate/JavaScript.hs+9−3 compiler/Transform/Optimize.hs+1−1 libraries/Native/Utils.js+26−1 runtime/Init.js+10−9
compiler/Generate/JavaScript.hs+9−3
@@ -299,7 +299,8 @@ generate unsafeModule =
299299 , [ IfSingleStmt () thisModule (ReturnStmt () (Just thisModule)) ]
300300 , [ internalImports (List.intercalate "." (names modul)) ]
301301 , concatMap jsImport (imports modul)
302− , concatMap jsPort (ports modul)
302+ , checkInPorts (ports modul)
303+ , map jsPort (ports modul)
303304 , [ assign ["_op"] (ObjectLit () []) ]
304305 , concat $ evalState (mapM definition . fst . SD.flattenLets [] $ program modul) 0
305306 , [ jsExports ]
@@ -331,10 +332,15 @@ generate unsafeModule =
331332
332333 addId js = InfixExpr () OpAdd (string (js++"_")) (obj "_elm.id")
333334
335+ checkInPorts ports =
336+ [ ExprStmt () $ obj "_N.checkPorts" `call` [ref "$moduleName", names] ]
337+ where
338+ names = ArrayLit () [ string name | (name, _, Nothing) <- ports ]
339+
334340 jsPort (name, _, maybe) =
335341 case maybe of
336− Nothing -> error "in-ports are not defined yet"
337− Just expr -> error "out-ports are not defined yet"
342+ Nothing -> assign [name] $ dotSep ["_elm","ports_in",name]
343+ Just expr -> assign ["_elm","ports_out",name] $ evalState (expression expr) 0
338344
339345binop span op e1 e2 =
340346 case op of
compiler/Transform/Optimize.hs+1−1
@@ -19,7 +19,7 @@ class Simplify a where
1919
2020instance Simplify (Declaration t v) where
2121 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)
2323 simp stmt = stmt
2424
2525instance Simplify (Def t v) where
libraries/Native/Utils.js+26−1
@@ -207,6 +207,30 @@ Elm.Native.Utils.make = function(elm) {
207207 return Tuple2(posx, posy);
208208 }
209209
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+
210234 return elm.Native.Utils.values = {
211235 eq:eq,
212236 cmp:cmp,
@@ -226,6 +250,7 @@ Elm.Native.Utils.make = function(elm) {
226250 mod : F2(mod),
227251 htmlHeight: F2(htmlHeight),
228252 getXY: getXY,
229− toFloat: function(x) { return +x; }
253+ toFloat: function(x) { return +x; },
254+ checkPorts: checkPorts
230255 };
231256};
runtime/Init.js+10−9
@@ -2,7 +2,7 @@
22(function() {
33'use strict';
44
5−Elm.fullscreen = function(module) {
5+Elm.fullscreen = function(module, ports) {
66 var style = document.createElement('style');
77 style.type = 'text/css';
88 style.innerHTML = "html,head,body { padding:0; margin:0; }" +
@@ -10,24 +10,24 @@ Elm.fullscreen = function(module) {
1010 document.head.appendChild(style);
1111 var container = document.createElement('div');
1212 document.body.appendChild(container);
13− return init(ElmRuntime.Display.FULLSCREEN, container, module);
13+ return init(ElmRuntime.Display.FULLSCREEN, container, module, ports);
1414};
1515
16−Elm.embed = function(module, container) {
16+Elm.embed = function(module, container, ports) {
1717 var tag = container.tagName;
1818 if (tag !== 'DIV') {
1919 throw new Error('Elm.node must be given a DIV, not a ' + tag + '.');
2020 } else if (container.hasChildNodes()) {
2121 throw new Error('Elm.node must be given an empty DIV. No children allowed!');
2222 }
23− return init(ElmRuntime.Display.COMPONENT, container, module);
23+ return init(ElmRuntime.Display.COMPONENT, container, module, ports);
2424};
2525
26−Elm.worker = function(module) {
27− return init(ElmRuntime.Display.NONE, {}, module);
26+Elm.worker = function(module, ports) {
27+ return init(ElmRuntime.Display.NONE, {}, module, ports);
2828};
2929
30−function init(display, container, module, moduleToReplace) {
30+function init(display, container, module, moduleToReplace, ports) {
3131 // defining state needed for an instance of the Elm RTS
3232 var inputs = [];
3333
@@ -67,7 +67,8 @@ function init(display, container, module, moduleToReplace) {
6767 display:display,
6868 id:ElmRuntime.guid(),
6969 addListener:addListener,
70− inputs:inputs
70+ inputs:inputs,
71+ ports_in:ports
7172 };
7273
7374 // Set up methods to communicate with Elm program from JS.
@@ -123,7 +124,7 @@ function init(display, container, module, moduleToReplace) {
123124 }
124125
125126 reportAnyErrors();
126− return { send:send, recv:recv, swap:swap };
127+ return { send:send, recv:recv, swap:swap, ports:elm.ports_out };
127128};
128129
129130function filterListeners(inputs, listeners) {