Add basics of properly handling ports

This commit is contained in:
Evan Czaplicki 2013-12-24 10:13:19 -08:00
parent 740702c0d7
commit 71bb1c8bf9
4 changed files with 46 additions and 14 deletions

View file

@ -299,7 +299,8 @@ generate unsafeModule =
, [ IfSingleStmt () thisModule (ReturnStmt () (Just thisModule)) ]
, [ internalImports (List.intercalate "." (names modul)) ]
, concatMap jsImport (imports modul)
, concatMap jsPort (ports modul)
, checkInPorts (ports modul)
, map jsPort (ports modul)
, [ assign ["_op"] (ObjectLit () []) ]
, concat $ evalState (mapM definition . fst . SD.flattenLets [] $ program modul) 0
, [ jsExports ]
@ -331,10 +332,15 @@ generate unsafeModule =
addId js = InfixExpr () OpAdd (string (js++"_")) (obj "_elm.id")
checkInPorts ports =
[ ExprStmt () $ obj "_N.checkPorts" `call` [ref "$moduleName", names] ]
where
names = ArrayLit () [ string name | (name, _, Nothing) <- ports ]
jsPort (name, _, maybe) =
case maybe of
Nothing -> error "in-ports are not defined yet"
Just expr -> error "out-ports are not defined yet"
Nothing -> assign [name] $ dotSep ["_elm","ports_in",name]
Just expr -> assign ["_elm","ports_out",name] $ evalState (expression expr) 0
binop span op e1 e2 =
case op of

View file

@ -19,7 +19,7 @@ class Simplify a where
instance Simplify (Declaration t v) where
simp (Definition def) = Definition (simp def)
simp (ImportEvent js b elm t) = ImportEvent js (simp b) elm t
simp (Port name tipe maybe) = Port name tipe (simp `fmap` maybe)
simp stmt = stmt
instance Simplify (Def t v) where

View file

@ -207,6 +207,30 @@ Elm.Native.Utils.make = function(elm) {
return Tuple2(posx, posy);
}
function checkPorts(moduleName, ports) {
var expected = {};
for (var i = ports.length; i--; ) {
expected[ports[i]] = 1;
}
for (var key in elm.ports_in) {
expected[key] = expected[key] || 0;
expected[key] -= 1;
}
var missing = [];
var extra = [];
for (var key in expected) {
var result = expected[key];
if (result > 0) missing.push(key);
if (result < 0) extra.push(key);
}
if (missing.length > 0) {
throw new Error("Module " + moduleName + " requires inputs for these ports: " + missing.join(', '));
}
if (extra.length > 0) {
throw new Error("Module " + moduleName + " has been given ports that do not exist: " + extra.join(', '));
}
}
return elm.Native.Utils.values = {
eq:eq,
cmp:cmp,
@ -226,6 +250,7 @@ Elm.Native.Utils.make = function(elm) {
mod : F2(mod),
htmlHeight: F2(htmlHeight),
getXY: getXY,
toFloat: function(x) { return +x; }
toFloat: function(x) { return +x; },
checkPorts: checkPorts
};
};

View file

@ -2,7 +2,7 @@
(function() {
'use strict';
Elm.fullscreen = function(module) {
Elm.fullscreen = function(module, ports) {
var style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = "html,head,body { padding:0; margin:0; }" +
@ -10,24 +10,24 @@ Elm.fullscreen = function(module) {
document.head.appendChild(style);
var container = document.createElement('div');
document.body.appendChild(container);
return init(ElmRuntime.Display.FULLSCREEN, container, module);
return init(ElmRuntime.Display.FULLSCREEN, container, module, ports);
};
Elm.embed = function(module, container) {
Elm.embed = function(module, container, ports) {
var tag = container.tagName;
if (tag !== 'DIV') {
throw new Error('Elm.node must be given a DIV, not a ' + tag + '.');
} else if (container.hasChildNodes()) {
throw new Error('Elm.node must be given an empty DIV. No children allowed!');
}
return init(ElmRuntime.Display.COMPONENT, container, module);
return init(ElmRuntime.Display.COMPONENT, container, module, ports);
};
Elm.worker = function(module) {
return init(ElmRuntime.Display.NONE, {}, module);
Elm.worker = function(module, ports) {
return init(ElmRuntime.Display.NONE, {}, module, ports);
};
function init(display, container, module, moduleToReplace) {
function init(display, container, module, moduleToReplace, ports) {
// defining state needed for an instance of the Elm RTS
var inputs = [];
@ -67,7 +67,8 @@ function init(display, container, module, moduleToReplace) {
display:display,
id:ElmRuntime.guid(),
addListener:addListener,
inputs:inputs
inputs:inputs,
ports_in:ports
};
// Set up methods to communicate with Elm program from JS.
@ -123,7 +124,7 @@ function init(display, container, module, moduleToReplace) {
}
reportAnyErrors();
return { send:send, recv:recv, swap:swap };
return { send:send, recv:recv, swap:swap, ports:elm.ports_out };
};
function filterListeners(inputs, listeners) {