on master help sign in
Switch to "port" syntax for Ports

Thank you @laszlopandy for the key insight on this one! :D

commitcbe557dc3d7ac06f627bf94c86a4f4c95dfcee46 authorEvan Czaplicki <info@elm-lang.org> dateFri 20 Mar 2015, 13:28 (12 years ago) parenta378254
20 files changed+265−614
elm-compiler.cabal+2−2 src/AST/Declaration.hs+9−103 src/AST/Expression/General.hs+4−22 src/AST/Type.hs+33−2 src/AST/Variable.hs−25 src/Docs.hs+1−1 src/Generate/JavaScript.hs+10−17 src/Generate/JavaScript/Foreign.hs → src/Generate/JavaScript/Port.hs+22−36 src/Parse/Declaration.hs+6−37 src/Parse/Helpers.hs+1−2 src/Transform/Canonicalize.hs+12−40 src/Transform/Canonicalize/Port.hs+144 src/Transform/Canonicalize/Setup.hs+7−17 src/Transform/Canonicalize/Wire.hs−207 src/Transform/Check.hs+3−9 src/Transform/Declaration.hs+5−52 src/Transform/Expression.hs+2−11 src/Transform/SortDefinitions.hs+2−11 src/Transform/Substitute.hs+1−10 src/Type/Constrain/Expression.hs+1−10
elm-compiler.cabal+2−2
@@ -63,17 +63,17 @@ Library
6363 Elm.Compiler.Type.Extract,
6464 Elm.Compiler.Version,
6565 Generate.JavaScript,
66− Generate.JavaScript.Foreign,
6766 Generate.JavaScript.Helpers,
67+ Generate.JavaScript.Port,
6868 Generate.JavaScript.Variable,
6969 Generate.Cases,
7070 Transform.AddDefaultImports,
7171 Transform.Canonicalize,
7272 Transform.Canonicalize.Environment,
73+ Transform.Canonicalize.Port,
7374 Transform.Canonicalize.Setup,
7475 Transform.Canonicalize.Type,
7576 Transform.Canonicalize.Variable,
76− Transform.Canonicalize.Wire,
7777 Transform.Check,
7878 Transform.Expression,
7979 Transform.Declaration,
src/AST/Declaration.hs+9−103
@@ -13,11 +13,11 @@ import Text.PrettyPrint as P
1313
1414-- DECLARATIONS
1515
16−data Declaration' wire def var
16+data Declaration' portType def var
1717 = Definition def
1818 | Datatype String [String] [(String, [T.Type var])]
1919 | TypeAlias String [String] (T.Type var)
20− | Wire wire
20+ | Port String portType
2121 | Fixity Assoc Int String
2222
2323
@@ -28,48 +28,15 @@ data Assoc = L | N | R
2828-- DECLARATION PHASES
2929
3030type SourceDecl =
31− Declaration' RawWire Source.Def Var.Raw
31+ Declaration' T.RawType Source.Def Var.Raw
3232
3333
3434type ValidDecl =
35− Declaration' ValidWire Valid.Def Var.Raw
35+ Declaration' T.RawType Valid.Def Var.Raw
3636
3737
3838type CanonicalDecl =
39− Declaration' CanonicalWire Canonical.Def Var.Canonical
40−
41−
42−-- WIRES
43−
44−data RawWire
45− = InputAnnotation String T.RawType
46− | OutputAnnotation String T.RawType
47− | OutputDefinition String Source.Expr
48− | LoopbackAnnotation String T.RawType
49− | LoopbackDefinition String Source.Expr
50−
51−
52−data Wire expr var input
53− = Input String (T.Type var)
54− | Output String expr (T.Type var)
55− | Loopback input
56−
57−
58−data ValidLoopback =
59− ValidLoopback String (Maybe Valid.Expr) T.RawType
60−
61−
62−data CanonicalLoopback
63− = Address String T.CanonicalType
64− | Task String T.CanonicalType Canonical.Expr T.CanonicalType
65−
66−
67−type ValidWire =
68− Wire Valid.Expr Var.Raw ValidLoopback
69−
70−
71−type CanonicalWire =
72− Wire Canonical.Expr Var.Canonical CanonicalLoopback
39+ Declaration' (T.PortType Var.Canonical) Canonical.Def Var.Canonical
7340
7441
7542-- BINARY CONVERSION
@@ -101,8 +68,8 @@ assocToString assoc =
10168 R -> "right"
10269
10370
104−instance (Pretty wire, Pretty def, Pretty var, Var.ToString var) =>
105− Pretty (Declaration' wire def var) where
71+instance (Pretty portType, Pretty def, Pretty var, Var.ToString var) =>
72+ Pretty (Declaration' portType def var) where
10673 pretty decl =
10774 case decl of
10875 Definition def -> pretty def
@@ -128,7 +95,8 @@ instance (Pretty wire, Pretty def, Pretty var, Var.ToString var) =>
12895 name' =
12996 P.text name <+> P.hsep (map P.text tvars)
13097
131− Wire wire -> pretty wire
98+ Port name tipe ->
99+ P.text "port" <+> P.text name <+> P.colon <+> pretty tipe
132100
133101 Fixity assoc prec op ->
134102 P.text "infix" <> assoc' <+> P.int prec <+> P.text op
@@ -138,65 +106,3 @@ instance (Pretty wire, Pretty def, Pretty var, Var.ToString var) =>
138106 L -> P.text "l"
139107 N -> P.empty
140108 R -> P.text "r"
141−
142−
143−instance Pretty RawWire where
144− pretty wire =
145− case wire of
146− InputAnnotation name tipe ->
147− prettyWire "foreign input" name ":" tipe
148−
149− OutputAnnotation name tipe ->
150− prettyWire "foreign output" name ":" tipe
151−
152− OutputDefinition name expr ->
153− prettyWire "foreign output" name "=" expr
154−
155− LoopbackAnnotation name tipe ->
156− prettyWire "input" name ":" tipe
157−
158− LoopbackDefinition name expr ->
159− prettyWire "input" name "from" expr
160−
161−
162−instance (Pretty expr, Pretty var, Var.ToString var, Pretty input) =>
163− Pretty (Wire expr var input) where
164− pretty wire =
165− case wire of
166− Input name tipe ->
167− prettyWire "foreign input" name ":" tipe
168−
169− Output name expr tipe ->
170− P.vcat
171− [ prettyWire "foreign output" name ":" tipe
172− , prettyWire "foreign output" name "=" expr
173− ]
174−
175− Loopback input ->
176− pretty input
177−
178−
179−instance Pretty ValidLoopback where
180− pretty (ValidLoopback name maybeExpr tipe) =
181− P.vcat
182− [ prettyWire "input" name ":" tipe
183− , maybe P.empty (prettyWire "input" name "with") maybeExpr
184− ]
185−
186−
187−instance Pretty CanonicalLoopback where
188− pretty input =
189− case input of
190− Address name tipe ->
191− prettyWire "input" name ":" tipe
192−
193− Task name _taskType expr resultType ->
194− P.vcat
195− [ prettyWire "input" name ":" resultType
196− , prettyWire "input" name "with" expr
197− ]
198−
199−
200−prettyWire :: (Pretty a) => String -> String -> String -> a -> Doc
201−prettyWire keyword name op e =
202− P.text keyword <+> P.text name <+> P.text op <+> pretty e
src/AST/Expression/General.hs+4−22
@@ -10,7 +10,7 @@ module AST.Expression.General where
1010
1111import AST.PrettyPrint
1212import Text.PrettyPrint as P
13−import AST.Type (Type)
13+import AST.Type (Type, PortType)
1414
1515import qualified AST.Annotation as Annotation
1616import qualified AST.Helpers as Help
@@ -58,20 +58,11 @@ data Expr' ann def var
5858 | Modify (Expr ann def var) [(String, Expr ann def var)]
5959 | Record [(String, Expr ann def var)]
6060 -- for type checking and code gen only
61− | Input String (Type var)
62− | Output String (Type var) (Expr ann def var)
63− | LoopbackIn String Source
64− | LoopbackOut String (Expr ann def var)
61+ | Port String (PortType var)
6562 | GLShader String String Literal.GLShaderTipe
6663 deriving (Show)
6764
6865
69−data Source
70− = Address
71− | TaskStream
72− deriving (Show)
73−
74−
7566---- UTILITIES ----
7667
7768rawVar :: String -> Expr' ann def Var.Raw
@@ -202,17 +193,8 @@ instance (Pretty def, Pretty var, Var.ToString var) => Pretty (Expr' ann def var
202193 GLShader _ _ _ ->
203194 P.text "[glsl| ... |]"
204195
205− Input name _ ->
206− P.text ("<input:" ++ name ++ ">")
207−
208− Output name _ _ ->
209− P.text ("<output:" ++ name ++ ">")
210−
211− LoopbackIn name _ ->
212− P.text ("<loopback-in:" ++ name ++ ">")
213−
214− LoopbackOut name _ ->
215− P.text ("<loopback-out:" ++ name ++ ">")
196+ Port name _ ->
197+ P.text ("<port:" ++ name ++ ">")
216198
217199
218200collectApps :: Expr ann def var -> [Expr ann def var]
src/AST/Type.hs+33−2
@@ -1,6 +1,6 @@
11module AST.Type
2− ( Type(..), RawType, CanonicalType
3− , fieldMap, recordOf, listOf, tupleOf
2+ ( Type(..), RawType, CanonicalType, PortType(..)
3+ , portTypeToType, fieldMap, recordOf, listOf, tupleOf
44 , deepDealias, dealias
55 , collectLambdas
66 , prettyParens
@@ -37,6 +37,24 @@ type CanonicalType =
3737 Type Var.Canonical
3838
3939
40+data PortType var
41+ = Inbound (Type var)
42+ | Internal (Type var)
43+ | Outbound (Type var)
44+ deriving (Show)
45+
46+
47+portTypeToType :: PortType Var.Canonical -> CanonicalType
48+portTypeToType portType =
49+ let makeType name tipe =
50+ App (Type (Var.fromModule ["Port"] name)) [tipe]
51+ in
52+ case portType of
53+ Inbound tipe -> makeType "InboundPort" tipe
54+ Internal tipe -> makeType "Port" tipe
55+ Outbound tipe -> makeType "OutboundPort" tipe
56+
57+
4058fieldMap :: [(String,a)] -> Map.Map String [a]
4159fieldMap fields =
4260 let add r (field,tipe) =
@@ -119,6 +137,19 @@ replace typeTable t =
119137
120138-- PRETTY PRINTING
121139
140+instance (Pretty var, Var.ToString var) => Pretty (PortType var) where
141+ pretty portType =
142+ case portType of
143+ Inbound tipe ->
144+ P.text "InboundPort" <+> pretty tipe
145+
146+ Internal tipe ->
147+ P.text "Port" <+> pretty tipe
148+
149+ Outbound tipe ->
150+ P.text "OutboundPort" <+> pretty tipe
151+
152+
122153instance (Var.ToString var, Pretty var) => Pretty (Type var) where
123154 pretty tipe =
124155 case tipe of
src/AST/Variable.hs−25
@@ -63,31 +63,6 @@ isArray =
6363 is ["Array"] "Array"
6464
6565
66−isStream :: Canonical -> Bool
67−isStream =
68− is ["Signal"] "Stream"
69−
70−
71−isAddress :: Canonical -> Bool
72−isAddress =
73− is ["Stream"] "Address"
74−
75−
76−isVarying :: Canonical -> Bool
77−isVarying =
78− is ["Signal"] "Varying"
79−
80−
81−isTask :: Canonical -> Bool
82−isTask =
83− is ["Task"] "Task"
84−
85−
86−isResult :: Canonical -> Bool
87−isResult =
88− is ["Result"] "Result"
89−
90−
9166isList :: Canonical -> Bool
9267isList v =
9368 v == Canonical BuiltIn "List"
src/Docs.hs+1−1
@@ -211,7 +211,7 @@ collectInfo (comment, decl) info =
211211 in
212212 info { infixes = Map.insert name infixInfo (infixes info) }
213213
214− Decl.Wire _ ->
214+ Decl.Port _ _ ->
215215 error errorMessage
216216
217217
src/Generate/JavaScript.hs+10−17
@@ -11,7 +11,7 @@ import Language.ECMAScript3.Syntax
1111
1212import Generate.JavaScript.Helpers as Help
1313import qualified Generate.Cases as Case
14−import qualified Generate.JavaScript.Foreign as Foreign
14+import qualified Generate.JavaScript.Port as Port
1515import qualified Generate.JavaScript.Variable as Var
1616
1717import AST.Annotation
@@ -22,6 +22,7 @@ import qualified AST.Module as Module
2222import qualified AST.Helpers as Help
2323import AST.Literal
2424import qualified AST.Pattern as P
25+import qualified AST.Type as T
2526import qualified AST.Variable as Var
2627
2728
@@ -30,7 +31,6 @@ internalImports name =
3031 [ varDecl "_N" (obj ["Elm","Native"])
3132 , include "_U" "Utils"
3233 , include "_L" "List"
33− , include "_P" "Ports"
3434 , varDecl Help.localModuleName (string (Module.nameToString name))
3535 ]
3636 where
@@ -207,24 +207,17 @@ expression (A region expr) =
207207 GLShader _uid src _tipe ->
208208 return $ ObjectLit () [(PropString () "src", literal (Str src))]
209209
210− Input name tipe ->
211− return (Foreign.input name tipe)
210+ Port name portType ->
211+ case portType of
212+ T.Inbound tipe ->
213+ return (Port.inbound name tipe)
212214
213− Output name tipe value ->
214− do value' <- expression value
215− return (Foreign.output name tipe value')
216−
217− LoopbackIn name source ->
218− case source of
219− Address ->
220− return $ obj ["_P","input"] `call` [ string name ]
215+ T.Internal _ ->
216+ return (Port.internal name)
221217
222− TaskStream ->
223− return $ obj ["_P","loopbackIn"] `call` [ string name ]
218+ T.Outbound tipe ->
219+ return (Port.outbound name tipe)
224220
225− LoopbackOut name expr ->
226− do expr' <- expression expr
227− return $ obj ["_P","loopbackOut"] `call` [ string name, expr' ]
228221
229222
230223definition :: Canonical.Def -> State Int [Statement ()]
src/Generate/JavaScript/Foreign.hs → src/Generate/JavaScript/Port.hsrenamed+22−36
@@ -1,4 +1,4 @@
1−module Generate.JavaScript.Foreign (input, output) where
1+module Generate.JavaScript.Port (inbound, internal, outbound) where
22
33import qualified Data.List as List
44import Generate.JavaScript.Helpers
@@ -42,6 +42,11 @@ _Maybe functionName =
4242 useLazy ["Elm","Maybe"] functionName
4343
4444
45+_Port :: String -> Expression ()
46+_Port functionName =
47+ useLazy ["Elm","Native","Port"] functionName
48+
49+
4550check :: Expression () -> JSType -> Expression () -> Expression ()
4651check x jsType continue =
4752 CondExpr () (jsFold OpLOr checks x) continue throw
@@ -62,26 +67,22 @@ check x jsType continue =
6267 [jsFold OpLAnd (typeof "object" : map member fields)]
6368
6469
65−-- INPUT
70+-- INTERNAL
6671
67−input :: String -> CanonicalType -> Expression ()
68−input name tipe =
69− let args t =
70− [ string name, string (show (pretty t)), toTypeFunction t ]
71− in
72− case tipe of
73− Aliased _ args t ->
74− input name (dealias args t)
72+internal :: String -> Expression ()
73+internal name =
74+ _Port "port" `call` [ string name ]
7575
76− App (Type signal) [t]
77− | Var.isStream signal ->
78− obj ["_P","inputStream"] `call` args t
7976
80− | Var.isVarying signal ->
81− obj ["_P","inputVarying"] `call` args t
77+-- INBOUND
8278
83− _ ->
84− obj ["_P","inputValue"] `call` args tipe
79+inbound :: String -> CanonicalType -> Expression ()
80+inbound name tipe =
81+ _Port "inbound" `call`
82+ [ string name
83+ , string (show (pretty tipe))
84+ , toTypeFunction tipe
85+ ]
8586
8687
8788toTypeFunction :: CanonicalType -> Expression ()
@@ -169,26 +170,11 @@ toTuple types x =
169170 )
170171
171172
172−-- OUTPUT
173−
174−output :: String -> CanonicalType -> Expression () -> Expression ()
175−output name tipe value =
176− let args t =
177− [ string name, fromTypeFunction t, value ]
178− in
179− case tipe of
180− Aliased _ args t ->
181− output name (dealias args t) value
182−
183− App (Type signal) [t]
184− | Var.isStream signal ->
185− obj ["_P","outputStream"] `call` args t
186−
187− | Var.isVarying signal ->
188− obj ["_P","outputVarying"] `call` args t
173+-- OUTBOUND
189174
190− _ ->
191− obj ["_P","outputValue"] `call` args tipe
175+outbound :: String -> CanonicalType -> Expression ()
176+outbound name tipe =
177+ _Port "outbound" `call` [ string name, fromTypeFunction tipe ]
192178
193179
194180fromTypeFunction :: CanonicalType -> Expression ()
src/Parse/Declaration.hs+6−37
@@ -12,7 +12,7 @@ import qualified Parse.Type as Type
1212
1313declaration :: IParser D.SourceDecl
1414declaration =
15− typeDecl <|> infixDecl <|> foreign <|> input <|> definition
15+ typeDecl <|> infixDecl <|> port <|> definition
1616
1717
1818definition :: IParser D.SourceDecl
@@ -54,42 +54,11 @@ infixDecl =
5454 D.Fixity assoc (read [n]) <$> anyOp
5555
5656
57−foreign :: IParser D.SourceDecl
58−foreign =
59− do try (reserved "foreign")
60− whitespace
61− choice
62− [ do name <- wireBegining "input"
63− wireEnding (D.InputAnnotation name) hasType Type.expr
64− , do name <- wireBegining "output"
65− choice
66− [ wireEnding (D.OutputAnnotation name) hasType Type.expr
67− , wireEnding (D.OutputDefinition name) equals Expr.expr
68− ]
69− ]
70−
71−
72−input :: IParser D.SourceDecl
73−input =
74− do name <- wireBegining "input"
75− choice
76− [ wireEnding (D.LoopbackAnnotation name) hasType Type.expr
77− , wireEnding (D.LoopbackDefinition name) (string "from") Expr.expr
78− ]
79−
80−
81−wireBegining :: String -> IParser String
82−wireBegining keyword =
83− do try (reserved keyword)
57+port :: IParser D.SourceDecl
58+port =
59+ do try (reserved "port")
8460 whitespace
8561 name <- lowVar
8662 whitespace
87− return name
88−
89−
90−wireEnding :: (a -> D.RawWire) -> IParser String -> IParser a -> IParser D.SourceDecl
91−wireEnding makeWire op valueParser =
92− do op
93− whitespace
94− value <- valueParser
95− return (D.Wire (makeWire value))
63+ tipe <- Type.expr <?> "a type"
64+ return (D.Port name tipe)
src/Parse/Helpers.hs+1−2
@@ -31,9 +31,8 @@ reserveds =
3131 , "type"
3232 , "module", "where"
3333 , "import", "as", "hiding", "exposing"
34− , "export"
34+ , "port", "export", "foreign"
3535 , "deriving"
36− , "input", "output", "foreign"
3736 ]
3837
3938
src/Transform/Canonicalize.hs+12−40
@@ -26,7 +26,7 @@ import qualified Transform.Canonicalize.Environment as Env
2626import qualified Transform.Canonicalize.Setup as Setup
2727import qualified Transform.Canonicalize.Type as Canonicalize
2828import qualified Transform.Canonicalize.Variable as Canonicalize
29−import qualified Transform.Canonicalize.Wire as Wire
29+import qualified Transform.Canonicalize.Port as Port
3030import qualified Transform.SortDefinitions as Transform
3131import qualified Transform.Declaration as Transform
3232
@@ -77,17 +77,9 @@ moduleHelp interfaces modul@(Module.Module _ _ exports _ decls) =
7777 , aliases =
7878 Map.fromList [ (name,(tvs,alias)) | D.TypeAlias name tvs alias <- decls ]
7979 , ports =
80− [ wireName wire | D.Wire wire <- decls ]
80+ [ name | D.Port name _ <- decls ]
8181 }
8282
83− wireName :: D.CanonicalWire -> String
84− wireName wire =
85− case wire of
86− D.Input name _ -> name
87− D.Output name _ _ -> name
88− D.Loopback (D.Address name _) -> name
89− D.Loopback (D.Task name _ _ _) -> name
90−
9183
9284resolveExports
9385 :: [Var.Value]
@@ -210,27 +202,12 @@ declaration env decl =
210202 do expanded' <- canonicalize Canonicalize.tipe "type alias" name env expanded
211203 return (D.TypeAlias name tvars expanded')
212204
213− D.Wire wire ->
205+ D.Port name tipe ->
214206 do Env.uses ["Native","Ports"]
215207 Env.uses ["Native","Json"]
216− D.Wire <$>
217− case wire of
218− D.Input name tipe ->
219− do tipe' <- canonicalize Canonicalize.tipe "foreign input" name env tipe
220− Wire.checkForeignInput name tipe'
221− return (D.Input name tipe')
222−
223− D.Output name expr tipe ->
224− do expr' <- expression env expr
225− tipe' <- canonicalize Canonicalize.tipe "foreign output" name env tipe
226− Wire.checkForeignOutput name tipe'
227− return (D.Output name expr' tipe')
228−
229− D.Loopback (D.ValidLoopback name maybeExpr tipe) ->
230− do maybeExpr' <- T.traverse (expression env) maybeExpr
231− tipe' <- canonicalize Canonicalize.tipe "input" name env tipe
232− input' <- Wire.input name maybeExpr' tipe'
233− return (D.Loopback input')
208+ tipe' <- canonicalize Canonicalize.tipe "port" name env tipe
209+ portType <- Port.check name tipe'
210+ return $ D.Port name portType
234211
235212 D.Fixity assoc prec op ->
236213 return $ D.Fixity assoc prec op
@@ -322,17 +299,12 @@ expression env (A.A ann validExpr) =
322299 (,) <$> format (pattern env p)
323300 <*> expression (Env.addPattern p env) b
324301
325− Input name tipe ->
326− Input name <$> tipe' env tipe
327−
328− Output name tipe expr ->
329− Output name <$> tipe' env tipe <*> go expr
330−
331− LoopbackIn name source ->
332− return (LoopbackIn name source)
333−
334− LoopbackOut name expr ->
335− LoopbackOut name <$> go expr
302+ Port name portType ->
303+ Port name <$>
304+ case portType of
305+ Type.Inbound tipe -> Type.Inbound <$> tipe' env tipe
306+ Type.Internal tipe -> Type.Internal <$> tipe' env tipe
307+ Type.Outbound tipe -> Type.Outbound <$> tipe' env tipe
336308
337309 GLShader uid src tipe ->
338310 return (GLShader uid src tipe)
src/Transform/Canonicalize/Port.hsnew file+144
@@ -0,0 +1,144 @@
1+module Transform.Canonicalize.Port (check) where
2+
3+import Control.Applicative ((<$>))
4+import Control.Monad.Error (throwError)
5+import Text.PrettyPrint as P
6+
7+import qualified AST.PrettyPrint as PP
8+import qualified AST.Type as T
9+import qualified AST.Variable as Var
10+import qualified Transform.Canonicalize.Environment as Env
11+
12+
13+throw :: [Doc] -> Env.Canonicalizer [P.Doc] a
14+throw err =
15+ throwError [ P.vcat err ]
16+
17+
18+-- CHECK FOR PORT
19+
20+check
21+ :: String
22+ -> T.CanonicalType
23+ -> Env.Canonicalizer [P.Doc] (T.PortType Var.Canonical)
24+check name tipe =
25+ checkHelp name tipe tipe
26+
27+
28+checkHelp
29+ :: String
30+ -> T.CanonicalType
31+ -> T.CanonicalType
32+ -> Env.Canonicalizer [P.Doc] (T.PortType Var.Canonical)
33+checkHelp name rootType tipe =
34+ case tipe of
35+ T.Aliased alias _ arg
36+ | Var.is ["Port"] "Port" alias ->
37+ return (T.Internal arg)
38+
39+ | Var.is ["Port"] "InboundPort" alias ->
40+ do validForeignType name In arg arg
41+ return (T.Inbound arg)
42+
43+ | Var.is ["Port"] "OutboundPort" alias ->
44+ do validForeignType name Out arg arg
45+ return (T.Outbound arg)
46+
47+ | otherwise ->
48+ checkHelp name rootType arg
49+
50+ _ ->
51+ throw $
52+ [ P.text "Port Error:"
53+ , P.nest 4 $
54+ P.vcat $
55+ [ P.text ("The port named '" ++ name ++ "' has an invalid type.\n")
56+ , P.nest 4 (PP.pretty tipe) <> P.text "\n"
57+ , P.text "It must be a Port, InboundPort, or OutboundPort."
58+ , P.text "See the Port module for more details:"
59+ , P.text "<http://package.elm-lang.org/packages/elm-lang/core/latest/Port>"
60+ ]
61+ ]
62+
63+
64+-- CHECK INBOUND AND OUTBOUND TYPES
65+
66+data Direction = In | Out
67+
68+
69+validForeignType
70+ :: String
71+ -> Direction
72+ -> T.CanonicalType
73+ -> T.CanonicalType
74+ -> Env.Canonicalizer [P.Doc] ()
75+validForeignType name portKind rootType tipe =
76+ let valid localType =
77+ validForeignType name portKind rootType localType
78+
79+ err hint =
80+ throw (foreignError name portKind rootType tipe hint)
81+ in
82+ case tipe of
83+ T.Aliased _ args t ->
84+ valid (T.dealias args t)
85+
86+ T.Type v ->
87+ case any ($ v) [ Var.isJson, Var.isPrimitive, Var.isTuple ] of
88+ True -> return ()
89+ False -> err "It contains an unsupported type"
90+
91+ T.App t [] ->
92+ valid t
93+
94+ T.App (T.Type v) [t]
95+ | Var.isMaybe v -> valid t
96+ | Var.isArray v -> valid t
97+ | Var.isList v -> valid t
98+
99+ T.App (T.Type v) ts
100+ | Var.isTuple v -> mapM_ valid ts
101+
102+ T.App _ _ ->
103+ err "It contains an unsupported type"
104+
105+ T.Var _ ->
106+ err "It contains a free type variable"
107+
108+ T.Lambda _ _ ->
109+ err "It contains functions"
110+
111+ T.Record _ (Just _) ->
112+ err "It contains extended records with free type variables"
113+
114+ T.Record fields Nothing ->
115+ mapM_ (\(k,v) -> (,) k <$> valid v) fields
116+
117+
118+foreignError
119+ :: String
120+ -> Direction
121+ -> T.CanonicalType
122+ -> T.CanonicalType
123+ -> String
124+ -> [P.Doc]
125+foreignError name portKind rootType localType problemMessage =
126+ [ P.text ("Port Error:")
127+ , P.nest 4 $
128+ P.vcat
129+ [ txt [ "The ", port, " named '", name, "' has an invalid type.\n" ]
130+ , P.nest 4 (PP.pretty rootType) <> P.text "\n"
131+ , txt [ problemMessage, ":\n" ]
132+ , P.nest 4 (PP.pretty localType) <> P.text "\n"
133+ , txt [ "Acceptable values for ", port, "s include:" ]
134+ , txt [ " Ints, Floats, Bools, Strings, Maybes, Lists, Arrays," ]
135+ , txt [ " Tuples, unit values, Json.Values, and concrete records." ]
136+ ]
137+ ]
138+ where
139+ port =
140+ case portKind of
141+ In -> "inbound port"
142+ Out -> "outbound port"
143+
144+ txt = P.text . concat
src/Transform/Canonicalize/Setup.hs+7−17
@@ -245,16 +245,12 @@ addTypeAlias moduleName env scc =
245245 ]
246246
247247
248−typeAlias
249− :: (String, [String], Type.Type var)
250− -> D.Declaration' wire def var
248+typeAlias :: (String, [String], Type.Type var) -> D.Declaration' pk def var
251249typeAlias (n,ts,t) =
252250 D.TypeAlias n ts t
253251
254252
255−datatype
256− :: (String, [String], Type.Type var)
257− -> D.Declaration' wire def var
253+datatype :: (String, [String], Type.Type var) -> D.Declaration' pk def var
258254datatype (n,ts,t) =
259255 D.Datatype n ts [(n,[t])]
260256
@@ -326,17 +322,11 @@ addDecl moduleName info@(nodes,env) decl =
326322 _values env
327323 }
328324
329− D.Wire wire ->
330− let wireName =
331− case wire of
332− D.Input name _ -> name
333− D.Output name _ _ -> name
334− D.Loopback (D.ValidLoopback name _ _) -> name
335− in
336− (,) nodes $ env
337− { _values =
338− addLocal wireName (_values env)
339− }
325+ D.Port name _ ->
326+ (,) nodes $ env
327+ { _values =
328+ addLocal name (_values env)
329+ }
340330
341331 D.Fixity _ _ _ ->
342332 info
src/Transform/Canonicalize/Wire.hsdeleted−207
@@ -1,207 +0,0 @@
1−module Transform.Canonicalize.Wire (checkForeignInput, checkForeignOutput, input) where
2−
3−import Control.Applicative ((<$>))
4−import Control.Monad.Error (forM_, throwError)
5−import Text.PrettyPrint as P
6−
7−import qualified AST.Declaration as D
8−import qualified AST.Expression.Canonical as Canonical
9−import qualified AST.PrettyPrint as PP
10−import qualified AST.Type as ST
11−import qualified AST.Variable as Var
12−import qualified Transform.Canonicalize.Environment as Env
13−
14−
15−throw :: [Doc] -> Env.Canonicalizer [P.Doc] a
16−throw err =
17− throwError [ P.vcat err ]
18−
19−
20−checkForeignInput :: String -> ST.CanonicalType -> Env.Canonicalizer [P.Doc] ()
21−checkForeignInput name tipe =
22− checkForeign In name tipe tipe
23−
24−
25−checkForeignOutput :: String -> ST.CanonicalType -> Env.Canonicalizer [P.Doc] ()
26−checkForeignOutput name tipe =
27− checkForeign Out name tipe tipe
28−
29−
30−data Direction = In | Out
31−
32−
33−checkForeign
34− :: Direction
35− -> String
36− -> ST.CanonicalType
37− -> ST.CanonicalType
38− -> Env.Canonicalizer [P.Doc] ()
39−checkForeign direction name rootType tipe =
40− case tipe of
41− ST.Aliased _ args t ->
42− checkForeign direction name rootType (ST.dealias args t)
43−
44− ST.App (ST.Type signal) [t]
45− | Var.isStream signal ->
46− validForeignType False (Just Stream) direction name rootType t
47−
48− | Var.isVarying signal ->
49− validForeignType False (Just Varying) direction name rootType t
50−
51− _ ->
52− validForeignType False Nothing direction name rootType tipe
53−
54−
55−data Signal = Stream | Varying
56−
57−
58−validForeignType
59− :: Bool
60− -> Maybe Signal
61− -> Direction
62− -> String
63− -> ST.CanonicalType
64− -> ST.CanonicalType
65− -> Env.Canonicalizer [P.Doc] ()
66−validForeignType seenFunc seenSignal direction name rootType tipe =
67− let valid localType =
68− validForeignType seenFunc seenSignal direction name rootType localType
69−
70− err kind =
71− throw (foreignError name direction rootType tipe kind)
72− in
73− case tipe of
74− ST.Aliased _ args t ->
75− valid (ST.dealias args t)
76−
77− ST.Type v ->
78− case any ($ v) [ Var.isJson, Var.isPrimitive, Var.isTuple ] of
79− True -> return ()
80− False -> err "It contains an unsupported type"
81−
82− ST.App t [] ->
83− valid t
84−
85− ST.App (ST.Type v) [t]
86− | Var.isMaybe v -> valid t
87− | Var.isArray v -> valid t
88− | Var.isList v -> valid t
89−
90− ST.App (ST.Type v) ts
91− | Var.isTuple v -> mapM_ valid ts
92−
93− ST.App _ _ ->
94− err "It contains an unsupported type"
95−
96− ST.Var _ ->
97− err "It contains a free type variable"
98−
99− ST.Lambda _ _ ->
100− case direction of
101− In -> err "It contains functions"
102− Out ->
103− if seenFunc
104− then err "It contains higher-order functions"
105− else
106− case seenSignal of
107− Just Stream ->
108− err "It is a streams that contains a function"
109−
110− Just Varying ->
111− err "It is a varying value that contains a function"
112−
113− Nothing ->
114− forM_ (ST.collectLambdas tipe)
115− (validForeignType True seenSignal direction name rootType)
116−
117− ST.Record _ (Just _) ->
118− err "It contains extended records with free type variables"
119−
120− ST.Record fields Nothing ->
121− mapM_ (\(k,v) -> (,) k <$> valid v) fields
122−
123−
124−foreignError
125− :: String
126− -> Direction
127− -> ST.CanonicalType
128− -> ST.CanonicalType
129− -> String
130− -> [P.Doc]
131−foreignError name direction rootType localType problemMessage =
132− [ P.text ("Foreign " ++ dir "Input" "Output" ++ " Error:")
133− , P.nest 4 $
134− P.vcat
135− [ txt [ "The foreign ", wire, " named '", name, "' has an invalid type.\n" ]
136− , P.nest 4 (PP.pretty rootType) <> P.text "\n"
137− , txt [ problemMessage, ":\n" ]
138− , P.nest 4 (PP.pretty localType) <> P.text "\n"
139− , txt [ "Acceptable values for foreign ", wire, "s include:" ]
140− , txt [ " Ints, Floats, Bools, Strings, Maybes, Lists, Arrays, Tuples, unit values," ]
141− , txt [ " Json.Values, ", dir "" "first-order functions, tasks, ", "and concrete records." ]
142− ]
143− ]
144− where
145− dir inMsg outMsg =
146− case direction of
147− In -> inMsg
148− Out -> outMsg
149−
150− txt = P.text . concat
151−
152− wire =
153− dir "input" "output"
154−
155−
156−input
157− :: String
158− -> Maybe Canonical.Expr
159− -> ST.CanonicalType
160− -> Env.Canonicalizer [P.Doc] D.CanonicalLoopback
161−input name maybeExpr tipe =
162− case maybeExpr of
163− Nothing ->
164− case ST.deepDealias tipe of
165− ST.Record
166− [ ("address", ST.App (ST.Type address) [a])
167− , ("stream", ST.App (ST.Type stream) [b])
168− ]
169− Nothing
170− | Var.isStream stream && Var.isAddress address && a == b ->
171− return (D.Address name tipe)
172−
173−
174− _ ->
175− throw $ inputError name tipe $
176− [ P.text "An input like this must be a Stream.Input" ]
177−
178− Just expr ->
179− case ST.deepDealias tipe of
180− ST.App (ST.Type signal) [ ST.App (ST.Type result) [failure,success] ]
181− | Var.isStream signal && Var.isResult result ->
182− let task =
183− Var.fromModule ["Task"] "Task"
184− taskType =
185− ST.App (ST.Type signal) [ ST.App (ST.Type task) [failure,success] ]
186− in
187− return (D.Task name taskType expr tipe)
188−
189− _ ->
190− throw $ inputError name tipe $
191− [ P.text "An input that runs tasks must be a stream of results."
192− , P.text "Something like the following:\n"
193− , P.text " Stream (Result Http.Error String)"
194− , P.text " Stream (Result x ())"
195− ]
196−
197−
198−inputError :: String -> ST.CanonicalType -> [Doc] -> [Doc]
199−inputError name tipe message =
200− [ P.text "Input Error:"
201− , P.nest 4 $
202− P.vcat $
203− [ P.text ("The input named '" ++ name ++ "' has an invalid type.\n")
204− , P.nest 4 (PP.pretty tipe) <> P.text "\n"
205− ]
206− ++ message
207− ]
src/Transform/Check.hs+3−9
@@ -1,7 +1,6 @@
11{-# OPTIONS_GHC -Wall #-}
22module Transform.Check (mistakes) where
33
4−import qualified Control.Arrow as Arrow
54import qualified Data.List as List
65import qualified Data.Maybe as Maybe
76import qualified Data.Set as Set
@@ -42,7 +41,7 @@ dups names =
4241duplicateValues :: [D.ValidDecl] -> [String]
4342duplicateValues decls =
4443 map msg (dups (portNames ++ concatMap Pattern.boundVarList defPatterns)) ++
45− case mapM exprDups (portExprs ++ defExprs) of
44+ case mapM exprDups defExprs of
4645 Left name -> [msg name]
4746 Right _ -> []
4847
@@ -53,13 +52,8 @@ duplicateValues decls =
5352 (defPatterns, defExprs) =
5453 unzip [ (pat,expr) | D.Definition (Valid.Definition pat expr _) <- decls ]
5554
56− (portNames, portExprs) =
57− Arrow.second Maybe.catMaybes $ unzip $
58− flip map [ wire | D.Wire wire <- decls ] $ \wire ->
59− case wire of
60− D.Input name _ -> (name, Nothing)
61− D.Output name expr _ -> (name, Just expr)
62− D.Loopback (D.ValidLoopback name maybeExpr _) -> (name, maybeExpr)
55+ portNames =
56+ [ name | D.Port name _ <- decls ]
6357
6458 exprDups :: Valid.Expr -> Either String Valid.Expr
6559 exprDups expr =
src/Transform/Declaration.hs+5−52
@@ -44,6 +44,9 @@ combineAnnotations =
4444 D.Fixity assoc prec op : rest ->
4545 (:) (D.Fixity assoc prec op) <$> go rest
4646
47+ D.Port name tipe : rest ->
48+ (:) (D.Port name tipe) <$> go rest
49+
4750 -- combine definitions
4851 D.Definition def : defRest ->
4952 case def of
@@ -62,38 +65,6 @@ combineAnnotations =
6265
6366 _ -> Left (errorMessage "value" name)
6467
65− -- combine wires
66− D.Wire wire : wireRest ->
67− case wire of
68− D.InputAnnotation name tipe ->
69− (:) (D.Wire (D.Input name tipe)) <$> go wireRest
70−
71− D.OutputDefinition name _ ->
72− Left (errorMessage "foreign output" name)
73−
74− D.OutputAnnotation name tipe ->
75− case wireRest of
76− D.Wire (D.OutputDefinition name' expr) : rest | name == name' ->
77− do expr' <- exprCombineAnnotations expr
78− (:) (D.Wire (D.Output name expr' tipe)) <$> go rest
79−
80− _ ->
81− Left (errorMessage "foreign output" name)
82−
83− D.LoopbackDefinition name _tipe ->
84− Left (errorMessage "input" name)
85−
86− D.LoopbackAnnotation name tipe ->
87− case wireRest of
88− D.Wire (D.LoopbackDefinition name' expr) : rest | name == name' ->
89− do expr' <- exprCombineAnnotations expr
90− let loop = D.ValidLoopback name (Just expr') tipe
91− (:) (D.Wire (D.Loopback loop)) <$> go rest
92−
93− _ ->
94− do let loop = D.ValidLoopback name Nothing tipe
95− (:) (D.Wire (D.Loopback loop)) <$> go wireRest
96−
9768
9869toExpr :: Module.Name -> [D.CanonicalDecl] -> [Canonical.Def]
9970toExpr moduleName =
@@ -141,26 +112,8 @@ toDefs moduleName decl =
141112 D.TypeAlias _ _ _ ->
142113 []
143114
144− D.Wire wire ->
145− case wire of
146− D.Output name expr@(A.A s _) tipe ->
147− [ definition name (A.A s $ E.Output name tipe expr) tipe ]
148−
149− D.Input name tipe ->
150− [ definition name (A.none $ E.Input name tipe) tipe ]
151−
152− D.Loopback input ->
153− case input of
154− D.Address name tipe ->
155− [ definition name (A.none $ E.LoopbackIn name E.Address) tipe ]
156−
157− D.Task name taskType expr resultType ->
158− let dummyName =
159− "$" ++ name ++ "$effect"
160− in
161− [ definition name (A.none $ E.LoopbackIn name E.TaskStream) resultType
162− , definition dummyName (A.none $ E.LoopbackOut name expr) taskType
163− ]
115+ D.Port name tipe ->
116+ [ definition name (A.none $ E.Port name tipe) (T.portTypeToType tipe) ]
164117
165118 -- no constraints are needed for fixity declarations
166119 D.Fixity _ _ _ ->
src/Transform/Expression.hs+2−11
@@ -69,14 +69,5 @@ crawlLet defsTransform annotatedExpression =
6969 GLShader uid src gltipe ->
7070 return $ GLShader uid src gltipe
7171
72− Input name tipe ->
73− return $ Input name tipe
74−
75− Output name tipe expr ->
76− Output name tipe <$> go expr
77−
78− LoopbackIn name source ->
79− return (LoopbackIn name source)
80−
81− LoopbackOut name expr ->
82− LoopbackOut name <$> go expr
72+ Port name tipe ->
73+ return $ Port name tipe
src/Transform/SortDefinitions.hs+2−11
@@ -115,17 +115,8 @@ reorder (A ann expression) =
115115 GLShader _ _ _ ->
116116 return expression
117117
118− Input name tipe ->
119− return $ Input name tipe
120−
121− Output name tipe signal ->
122− Output name tipe <$> reorder signal
123−
124− LoopbackIn name source ->
125− return $ LoopbackIn name source
126−
127− LoopbackOut name expr ->
128− LoopbackOut name <$> reorder expr
118+ Port name tipe ->
119+ return $ Port name tipe
129120
130121 -- Actually do some reordering
131122 Let defs body ->
src/Transform/Substitute.hs+1−10
@@ -83,14 +83,5 @@ subst old new expression =
8383 GLShader _ _ _ ->
8484 expression
8585
86− Input _ _ ->
86+ Port _ _ ->
8787 expression
88−
89− Output name tipe expr ->
90− Output name tipe (f expr)
91−
92− LoopbackIn _ _ ->
93− expression
94−
95− LoopbackOut name expr ->
96− LoopbackOut name (f expr)
src/Type/Constrain/Expression.hs+1−10
@@ -165,18 +165,9 @@ constrain env (A region expr) tipe =
165165 (clet [Scheme rqs fqs (clet [monoscheme header] c2) header ]
166166 (c1 /\ c))
167167
168− Input _ _ ->
168+ Port _ _ ->
169169 return true
170170
171− Output _ _ signal ->
172− constrain env signal tipe
173−
174− LoopbackIn _ _ ->
175− return true
176−
177− LoopbackOut _ expr ->
178− constrain env expr tipe
179−
180171
181172constrainDef env info (Canonical.Definition pattern expr maybeTipe) =
182173 let qs = [] -- should come from the def, but I'm not sure what would live there...