@@ -2,24 +2,27 @@
22module Parse.Declaration where
33
44import Control.Applicative ((<$>), (<*>))
5−import Data.List (foldl')
5+import qualified Data.List as List
66import Text.Parsec hiding (newline,spaces)
77import Text.Parsec.Indent
88import qualified Text.Pandoc as Pan
99
1010import Parse.Helpers
1111import qualified Parse.Expression as Expr
12+import qualified SourceSyntax.Type as T
1213import qualified Parse.Type as Type
1314
1415import SourceSyntax.Declaration (Declaration(..))
1516
1617import Unique
1718
19+declaration :: IParser (Declaration t v)
20+declaration = definition <|> alias <|> datatype <|> foreignDef
1821
1922definition :: IParser (Declaration t v)
2023definition = Definition <$> Expr.def
2124
22−alias :: IParser [Declaration t v]
25+alias :: IParser (Declaration t v)
2326alias = do
2427 start <- getPosition
2528 reserved "type" <?> "type alias (type Point = {x:Int, y:Int})"
@@ -29,4 +32,95 @@ alias = do
2932 whitespace ; string "=" ; whitespace
3033 tipe <- Type.expr
3134 end <- getPosition
32− return [TypeAlias alias args tipe]
35+ return (TypeAlias alias args tipe)
36+
37+datatype :: IParser (Declaration t v)
38+datatype = do
39+ reserved "data" <?> "datatype definition (data T = A | B | ...)"
40+ forcedWS
41+ name <- capVar <?> "name of data-type"
42+ args <- spacePrefix lowVar
43+ whitespace ; string "=" ; whitespace
44+ tcs <- pipeSep1 Type.constructor
45+ return $ Datatype name args tcs
46+
47+
48+foreignDef :: IParser (Declaration t v)
49+foreignDef = do
50+ try (reserved "foreign")
51+ whitespace
52+ importEvent <|> exportEvent
53+
54+exportEvent :: IParser (Declaration t v)
55+exportEvent = do
56+ try (reserved "export") >> whitespace >> reserved "jsevent" >> whitespace
57+ eventName <- jsVar
58+ whitespace
59+ elmVar <- lowVar
60+ whitespace ; hasType ; whitespace
61+ tipe <- Type.expr
62+ case tipe of
63+ T.Data "Signal" [t] ->
64+ case isExportable t of
65+ Nothing -> return (ExportEvent eventName elmVar tipe)
66+ Just err -> error err
67+ _ -> error "When importing foreign events, the imported value must have type Signal."
68+
69+importEvent :: IParser (Declaration t v)
70+importEvent = do
71+ try (reserved "import") >> whitespace >> reserved "jsevent" >> whitespace
72+ eventName <- jsVar
73+ whitespace
74+ baseValue <- Expr.term <?> "Base case for imported signal (signals cannot be undefined)"
75+ whitespace
76+ elmVar <- lowVar <?> "Name of imported signal"
77+ whitespace ; hasType ; whitespace
78+ tipe <- Type.expr
79+ case tipe of
80+ T.Data "Signal" [t] ->
81+ case isExportable t of
82+ Nothing -> return (ImportEvent eventName baseValue elmVar tipe)
83+ Just err -> error err
84+ _ -> error "When importing foreign events, the imported value must have type Signal."
85+
86+jsVar :: IParser String
87+jsVar = betwixt '"' '"' $ do
88+ v <- (:) <$> (letter <|> char '_') <*> many (alphaNum <|> char '_')
89+ if v `notElem` jsReserveds then return v else
90+ error $ "'" ++ v ++
91+ "' is not a good name for a importing or exporting JS values."
92+
93+jsReserveds :: [String]
94+jsReserveds =
95+ [ "null", "undefined", "Nan", "Infinity", "true", "false", "eval"
96+ , "arguments", "int", "byte", "char", "goto", "long", "final", "float"
97+ , "short", "double", "native", "throws", "boolean", "abstract", "volatile"
98+ , "transient", "synchronized", "function", "break", "case", "catch"
99+ , "continue", "debugger", "default", "delete", "do", "else", "finally"
100+ , "for", "function", "if", "in", "instanceof", "new", "return", "switch"
101+ , "this", "throw", "try", "typeof", "var", "void", "while", "with", "class"
102+ , "const", "enum", "export", "extends", "import", "super", "implements"
103+ , "interface", "let", "package", "private", "protected", "public"
104+ , "static", "yield"
105+ ]
106+
107+isExportable tipe =
108+ case tipe of
109+ T.Lambda _ _ ->
110+ Just $ "Elm's JavaScript event interface does not yet handle functions. " ++
111+ "Only simple values can be imported and exported in this release."
112+
113+ T.Data "JSArray" [t] -> isExportable t
114+
115+ T.Data name []
116+ | name `elem` jsTypes -> Nothing
117+ | otherwise -> Just $ "'" ++ name ++ "' is not an exportable type." ++ msg
118+
119+ T.Data name _ ->
120+ Just $ "'" ++ name ++ "' is not an exportable type " ++
121+ "constructor. Only 'JSArray' is an exportable container."
122+
123+ T.Var _ -> Just $ "Cannot export type variables." ++ msg
124+ where
125+ msg = " The following types are exportable: " ++ List.intercalate ", " jsTypes
126+ jsTypes = ["JSString","JSNumber","JSDomNode","JSBool","JSObject"]