on master help sign in
Merge branch 'dev'
b65bf8cEvan Czaplicki
Elm.cabal+14−13
@@ -1,5 +1,5 @@
1Name: Elm
1Name: Elm
2−Version: 0.11
2+Version: 0.12
3Synopsis: The Elm language module.
3Synopsis: The Elm language module.
4Description: Elm aims to make client-side web-development more pleasant.
4Description: Elm aims to make client-side web-development more pleasant.
5 It is a statically/strongly typed, functional reactive
5 It is a statically/strongly typed, functional reactive
@@ -14,7 +14,7 @@ License-file: LICENSE
14
14
15Author: Evan Czaplicki
15Author: Evan Czaplicki
16Maintainer: info@elm-lang.org
16Maintainer: info@elm-lang.org
17−Copyright: Copyright: (c) 2011-2013 Evan Czaplicki
17+Copyright: Copyright: (c) 2011-2014 Evan Czaplicki
18
18
19Category: Compiler, Language
19Category: Compiler, Language
20
20
@@ -37,19 +37,19 @@ Library
37 Elm.Internal.Utils,
37 Elm.Internal.Utils,
38 Elm.Internal.Version
38 Elm.Internal.Version
39 Hs-Source-Dirs: compiler
39 Hs-Source-Dirs: compiler
40− other-modules: SourceSyntax.Declaration,
40+ other-modules: SourceSyntax.Annotation,
41+ SourceSyntax.Declaration,
41 SourceSyntax.Expression,
42 SourceSyntax.Expression,
42 SourceSyntax.Helpers,
43 SourceSyntax.Helpers,
43 SourceSyntax.Literal,
44 SourceSyntax.Literal,
44− SourceSyntax.Location,
45 SourceSyntax.Module,
45 SourceSyntax.Module,
46 SourceSyntax.Pattern,
46 SourceSyntax.Pattern,
47 SourceSyntax.PrettyPrint,
47 SourceSyntax.PrettyPrint,
48 SourceSyntax.Type,
48 SourceSyntax.Type,
49+ SourceSyntax.Variable,
49 Generate.JavaScript,
50 Generate.JavaScript,
50 Generate.JavaScript.Helpers,
51 Generate.JavaScript.Helpers,
51 Generate.JavaScript.Ports,
52 Generate.JavaScript.Ports,
52− Generate.Noscript,
53 Generate.Markdown,
53 Generate.Markdown,
54 Generate.Html,
54 Generate.Html,
55 Generate.Cases,
55 Generate.Cases,
@@ -97,7 +97,7 @@ Library
97 Build-depends: aeson,
97 Build-depends: aeson,
98 base >=4.2 && <5,
98 base >=4.2 && <5,
99 binary >= 0.6.4.0,
99 binary >= 0.6.4.0,
100− blaze-html == 0.5.* || == 0.6.*,
100+ blaze-html >= 0.5 && < 0.8,
101 blaze-markup,
101 blaze-markup,
102 bytestring,
102 bytestring,
103 cmdargs,
103 cmdargs,
@@ -119,19 +119,19 @@ Executable elm
119 Main-is: Compiler.hs
119 Main-is: Compiler.hs
120 ghc-options: -threaded -O2
120 ghc-options: -threaded -O2
121 Hs-Source-Dirs: compiler
121 Hs-Source-Dirs: compiler
122− other-modules: SourceSyntax.Declaration,
122+ other-modules: SourceSyntax.Annotation,
123+ SourceSyntax.Declaration,
123 SourceSyntax.Expression,
124 SourceSyntax.Expression,
124 SourceSyntax.Helpers,
125 SourceSyntax.Helpers,
125 SourceSyntax.Literal,
126 SourceSyntax.Literal,
126− SourceSyntax.Location,
127 SourceSyntax.Module,
127 SourceSyntax.Module,
128 SourceSyntax.Pattern,
128 SourceSyntax.Pattern,
129 SourceSyntax.PrettyPrint,
129 SourceSyntax.PrettyPrint,
130 SourceSyntax.Type,
130 SourceSyntax.Type,
131+ SourceSyntax.Variable,
131 Generate.JavaScript,
132 Generate.JavaScript,
132 Generate.JavaScript.Helpers,
133 Generate.JavaScript.Helpers,
133 Generate.JavaScript.Ports,
134 Generate.JavaScript.Ports,
134− Generate.Noscript,
135 Generate.Markdown,
135 Generate.Markdown,
136 Generate.Html,
136 Generate.Html,
137 Generate.Cases,
137 Generate.Cases,
@@ -179,8 +179,8 @@ Executable elm
179 Build-depends: aeson,
179 Build-depends: aeson,
180 base >=4.2 && <5,
180 base >=4.2 && <5,
181 binary >= 0.6.4.0,
181 binary >= 0.6.4.0,
182− blaze-html == 0.5.* || == 0.6.*,
182+ blaze-html >= 0.5 && < 0.8,
183− blaze-markup == 0.5.1.*,
183+ blaze-markup,
184 bytestring,
184 bytestring,
185 cmdargs,
185 cmdargs,
186 containers >= 0.3,
186 containers >= 0.3,
@@ -200,15 +200,16 @@ Executable elm
200Executable elm-doc
200Executable elm-doc
201 Main-is: Docs.hs
201 Main-is: Docs.hs
202 Hs-Source-Dirs: compiler
202 Hs-Source-Dirs: compiler
203− other-modules: SourceSyntax.Declaration,
203+ other-modules: SourceSyntax.Annotation,
204+ SourceSyntax.Declaration,
204 SourceSyntax.Expression,
205 SourceSyntax.Expression,
205 SourceSyntax.Helpers,
206 SourceSyntax.Helpers,
206 SourceSyntax.Literal,
207 SourceSyntax.Literal,
207− SourceSyntax.Location,
208 SourceSyntax.Module,
208 SourceSyntax.Module,
209 SourceSyntax.Pattern,
209 SourceSyntax.Pattern,
210 SourceSyntax.PrettyPrint,
210 SourceSyntax.PrettyPrint,
211 SourceSyntax.Type,
211 SourceSyntax.Type,
212+ SourceSyntax.Variable,
212 Parse.Binop,
213 Parse.Binop,
213 Parse.Declaration,
214 Parse.Declaration,
214 Parse.Expression,
215 Parse.Expression,
Setup.hs+2−1
@@ -148,7 +148,8 @@ buildRuntime :: LocalBuildInfo -> [FilePath] -> IO ()
148buildRuntime lbi elmos = do
148buildRuntime lbi elmos = do
149 createDirectoryIfMissing True (rtsDir lbi)
149 createDirectoryIfMissing True (rtsDir lbi)
150 let rts' = rts lbi
150 let rts' = rts lbi
151+ writeFile rts' "'use strict';\n\
151− writeFile rts' "var Elm = {}; Elm.Native = {}; Elm.Native.Graphics = {};\n\
152+ \var Elm = {}; Elm.Native = {}; Elm.Native.Graphics = {};\n\
152 \var ElmRuntime = {}; ElmRuntime.Render = {};\n"
153 \var ElmRuntime = {}; ElmRuntime.Render = {};\n"
153 mapM_ (appendTo rts') =<< getFiles ".js" "libraries"
154 mapM_ (appendTo rts') =<< getFiles ".js" "libraries"
154 mapM_ (appendTo rts') elmos
155 mapM_ (appendTo rts') elmos
changelog.txt → changelog.mdrenamed+31−3
@@ -1,10 +1,38 @@
1
1
2+## 0.12
3+
4+#### Breaking Changes:
5+
6+ * Overhaul Graphics.Input library (inspired by Spiros Eliopoulos and Jeff Smitts)
7+ * Overhaul Text library to accomodate new Graphics.Input.Field
8+ library and make the API more consistent overall
9+ * Overhaul Regex library (inspired by Attila Gazso)
10+ * Change syntax for "import open List" to "import List (..)"
11+ * Improved JSON format for types generated by elm-doc
12+ * Remove problematic Mouse.isClicked signal
13+ * Revise the semantics of keepWhen and dropWhen to only update when
14+ the filtered signal changes (thanks Max New and Janis Voigtländer)
15+
16+#### Improvements:
17+
18+ * Add Graphics.Input.Field for customizable text fields
19+ * Add Trampoline library (thanks to @maxsnew and @timthelion)
20+ * Add Debug library (inspired by @timthelion)
21+ * Drastically improved performance on markdown parsing (thanks to @Dandandan)
22+ * Add Date.fromTime function
23+ * Use pointer-events to detect hovers on layered elements (thanks to @Xashili)
24+ * Fix bugs in Bitwise library
25+ * Fix bug when exporting Maybe values through ports
26+
2## 0.11
27## 0.11
3
28
29+ * Ports, a new FFI that is more general and much nicer to use
4− * Lazy and Lazy.Stream (thanks to Max New)
30+ * Basic compiler tests (thanks to Max New)
31+
32+## 0.10.1
33+
5− * sortBy, sortWith (thanks to Max Goldstein)
34+ * sort, sortBy, sortWith (thanks to Max Goldstein)
6 * elm-repl
35 * elm-repl
7− * Markdown interpolation
8 * Bitwise library
36 * Bitwise library
9 * Regex library
37 * Regex library
10 * Improve Transform2D library (thanks to Michael Søndergaard)
38 * Improve Transform2D library (thanks to Michael Søndergaard)
compiler/Build/Dependencies.hs+30−22
@@ -29,10 +29,7 @@ getSortedDependencies srcDirs builtIns root =
29 result <- runErrorT $ readAllDeps allSrcDirs builtIns root
29 result <- runErrorT $ readAllDeps allSrcDirs builtIns root
30 case result of
30 case result of
31 Right deps -> sortDeps deps
31 Right deps -> sortDeps deps
32− Left err -> failure $ err ++ if Maybe.isJust extras then "" else msg
32+ Left err -> failure err
33− where msg = "\nYou may need to create a " ++
34− Path.dependencyFile ++
35− " file if you\nare trying to use a 3rd party library."
36
33
37extraDependencies :: IO (Maybe [FilePath])
34extraDependencies :: IO (Maybe [FilePath])
38extraDependencies =
35extraDependencies =
@@ -75,20 +72,22 @@ sortDeps depends =
75 msg = "A cyclical module dependency or was detected in:\n"
72 msg = "A cyclical module dependency or was detected in:\n"
76
73
77readAllDeps :: [FilePath] -> Module.Interfaces -> FilePath -> ErrorT String IO [Deps]
74readAllDeps :: [FilePath] -> Module.Interfaces -> FilePath -> ErrorT String IO [Deps]
78−readAllDeps srcDirs builtIns root =
75+readAllDeps srcDirs rawBuiltIns filePath =
79− do let ifaces = (Set.fromList . Map.keys) builtIns
80− State.evalStateT (go ifaces root) Set.empty
76+ State.evalStateT (go Nothing filePath) Set.empty
81 where
77 where
78+ builtIns :: Set.Set String
79+ builtIns = Set.fromList $ Map.keys rawBuiltIns
80+
82− go :: Set.Set String -> FilePath -> State.StateT (Set.Set String) (ErrorT String IO) [Deps]
81+ go :: Maybe String -> FilePath -> State.StateT (Set.Set String) (ErrorT String IO) [Deps]
83− go builtIns root = do
82+ go parentModuleName filePath = do
84− root' <- lift $ findSrcFile srcDirs root
83+ filePath' <- lift $ findSrcFile parentModuleName srcDirs filePath
85− (name, deps) <- lift $ readDeps root'
84+ (moduleName, deps) <- lift $ readDeps filePath'
86 seen <- State.get
85 seen <- State.get
87 let realDeps = Set.difference (Set.fromList deps) builtIns
86 let realDeps = Set.difference (Set.fromList deps) builtIns
88 newDeps = Set.difference (Set.filter (not . isNative) realDeps) seen
87 newDeps = Set.difference (Set.filter (not . isNative) realDeps) seen
89− State.put (Set.insert name (Set.union newDeps seen))
88+ State.put (Set.insert moduleName (Set.union newDeps seen))
90− rest <- mapM (go builtIns . toFilePath) (Set.toList newDeps)
89+ rest <- mapM (go (Just moduleName) . toFilePath) (Set.toList newDeps)
91− return ((makeRelative "." root', name, Set.toList realDeps) : concat rest)
90+ return ((makeRelative "." filePath', moduleName, Set.toList realDeps) : concat rest)
92
91
93readDeps :: FilePath -> ErrorT String IO (String, [String])
92readDeps :: FilePath -> ErrorT String IO (String, [String])
94readDeps path = do
93readDeps path = do
@@ -98,15 +97,10 @@ readDeps path = do
98 where msg = "Error resolving dependencies in " ++ path ++ ":\n"
97 where msg = "Error resolving dependencies in " ++ path ++ ":\n"
99 Right o -> return o
98 Right o -> return o
100
99
101−findSrcFile :: [FilePath] -> FilePath -> ErrorT String IO FilePath
100+findSrcFile :: Maybe String -> [FilePath] -> FilePath -> ErrorT String IO FilePath
101+findSrcFile parentModuleName dirs path =
102−findSrcFile dirs path = foldr tryDir notFound dirs
102+ foldr tryDir notFound dirs
103 where
103 where
104− notFound = throwError $ unlines
105− [ "Could not find file: " ++ path
106− , " If it is not in the root directory of your project, use"
107− , " --src-dir to declare additional locations for source files."
108− , " If it is part of a 3rd party library, it needs to be declared"
109− , " as a dependency in the " ++ Path.dependencyFile ++ " file." ]
110 tryDir dir next = do
104 tryDir dir next = do
111 let path' = dir </> path
105 let path' = dir </> path
112 exists <- liftIO $ doesFileExist path'
106 exists <- liftIO $ doesFileExist path'
@@ -114,6 +108,20 @@ findSrcFile dirs path = foldr tryDir notFound dirs
114 then return path'
108 then return path'
115 else next
109 else next
116
110
111+ parentModuleName' =
112+ case parentModuleName of
113+ Just name -> "module '" ++ name ++ "'"
114+ Nothing -> "the main module"
115+
116+ notFound = throwError $ unlines
117+ [ "When finding the imports declared in " ++ parentModuleName' ++ ", could not find file: " ++ path
118+ , " If you created this module, but it is in a subdirectory that does not"
119+ , " exactly match the module name, you may need to use the --src-dir flag."
120+ , ""
121+ , " If it is part of a 3rd party library, it needs to be declared"
122+ , " as a dependency in your project's " ++ Path.dependencyFile ++ " file."
123+ ]
124+
117isNative :: String -> Bool
125isNative :: String -> Bool
118isNative name = List.isPrefixOf "Native." name
126isNative name = List.isPrefixOf "Native." name
119
127
compiler/Build/Source.hs+1−2
@@ -2,7 +2,6 @@
2module Build.Source (build) where
2module Build.Source (build) where
3
3
4import qualified Data.Map as Map
4import qualified Data.Map as Map
5−import qualified Data.Set as Set
6import System.FilePath as FP
5import System.FilePath as FP
7import Text.PrettyPrint (Doc)
6import Text.PrettyPrint (Doc)
8
7
@@ -33,7 +32,7 @@ build noPrelude interfaces source =
33
32
34 let exports'
33 let exports'
35 | null exs =
34 | null exs =
36− let get = Set.toList . Pattern.boundVars in
35+ let get = Pattern.boundVarList in
37 concat [ get pattern | Definition (Expr.Definition pattern _ _) <- decls ] ++
36 concat [ get pattern | Definition (Expr.Definition pattern _ _) <- decls ] ++
38 concat [ map fst ctors | Datatype _ _ ctors <- decls ] ++
37 concat [ map fst ctors | Datatype _ _ ctors <- decls ] ++
39 [ name | TypeAlias name _ (Type.Record _ _) <- decls ]
38 [ name | TypeAlias name _ (Type.Record _ _) <- decls ]
compiler/Build/Utils.hs+14
@@ -1,8 +1,11 @@
1{-# OPTIONS_GHC -W #-}
1{-# OPTIONS_GHC -W #-}
2module Build.Utils where
2module Build.Utils where
3
3
4+import System.Directory (doesFileExist)
5+import System.Environment (getEnv)
4import System.FilePath ((</>), replaceExtension)
6import System.FilePath ((</>), replaceExtension)
5import qualified Build.Flags as Flag
7import qualified Build.Flags as Flag
8+import qualified Paths_Elm as This
6
9
7buildPath :: Flag.Flags -> FilePath -> String -> FilePath
10buildPath :: Flag.Flags -> FilePath -> String -> FilePath
8buildPath flags filePath ext =
11buildPath flags filePath ext =
@@ -19,3 +22,14 @@ elmo flags filePath =
19elmi :: Flag.Flags -> FilePath -> FilePath
22elmi :: Flag.Flags -> FilePath -> FilePath
20elmi flags filePath =
23elmi flags filePath =
21 cachePath flags filePath "elmi"
24 cachePath flags filePath "elmi"
25+
26+-- |The absolute path to a data file
27+getDataFile :: FilePath -> IO FilePath
28+getDataFile name = do
29+ path <- This.getDataFileName name
30+ exists <- doesFileExist path
31+ if exists
32+ then return path
33+ else do
34+ env <- getEnv "ELM_HOME"
35+ return (env </> name)
compiler/Docs.hs+42−18
@@ -8,6 +8,7 @@ import System.Exit
8import System.IO
8import System.IO
9
9
10import Control.Applicative ((<$>))
10import Control.Applicative ((<$>))
11+import Control.Arrow (second)
11import Data.Aeson
12import Data.Aeson
12import Data.Aeson.Encode.Pretty
13import Data.Aeson.Encode.Pretty
13import qualified Data.List as List
14import qualified Data.List as List
@@ -15,8 +16,8 @@ import qualified Data.Map as Map
15import qualified Data.ByteString.Lazy as BS
16import qualified Data.ByteString.Lazy as BS
16import qualified Data.Text as Text
17import qualified Data.Text as Text
17
18
18−import SourceSyntax.Helpers (isSymbol)
19+import qualified SourceSyntax.Helpers as Help
19−import SourceSyntax.Type (Type(..))
20+import qualified SourceSyntax.Type as T
20import qualified SourceSyntax.Expression as E
21import qualified SourceSyntax.Expression as E
21import qualified SourceSyntax.Declaration as D
22import qualified SourceSyntax.Declaration as D
22
23
@@ -30,20 +31,24 @@ data Flags = Flags
30 { files :: [FilePath] }
31 { files :: [FilePath] }
31 deriving (Data,Typeable,Show,Eq)
32 deriving (Data,Typeable,Show,Eq)
32
33
34+defaultFlags :: Flags
33defaultFlags = Flags
35defaultFlags = Flags
34 { files = def &= args &= typ "FILES"
36 { files = def &= args &= typ "FILES"
35 } &= help "Generate documentation for Elm"
37 } &= help "Generate documentation for Elm"
36 &= summary ("Generate documentation for Elm, (c) Evan Czaplicki")
38 &= summary ("Generate documentation for Elm, (c) Evan Czaplicki")
37
39
40+main :: IO ()
38main = do
41main = do
39 flags <- cmdArgs defaultFlags
42 flags <- cmdArgs defaultFlags
40− mapM parseFile (files flags)
43+ mapM_ parseFile (files flags)
41
44
45+config :: Config
42config = Config { confIndent = 2, confCompare = keyOrder keys }
46config = Config { confIndent = 2, confCompare = keyOrder keys }
43 where
47 where
44− keys = ["name","document","comment","raw","aliases","datatypes"
48+ keys = ["tag","name","document","comment","raw","aliases","datatypes"
45 ,"values","typeVariables","type","constructors"]
49 ,"values","typeVariables","type","constructors"]
46
50
51+parseFile :: FilePath -> IO ()
47parseFile path = do
52parseFile path = do
48 source <- readFile path
53 source <- readFile path
49 case iParse docs source of
54 case iParse docs source of
@@ -69,6 +74,7 @@ docComment = do
69 let reversed = dropWhile (`elem` " \n\r") . drop 2 $ reverse contents
74 let reversed = dropWhile (`elem` " \n\r") . drop 2 $ reverse contents
70 return $ dropWhile (==' ') (reverse reversed)
75 return $ dropWhile (==' ') (reverse reversed)
71
76
77+moduleDocs :: IParser (String, [String], String)
72moduleDocs = do
78moduleDocs = do
73 optional freshLine
79 optional freshLine
74 (names,exports) <- moduleDef
80 (names,exports) <- moduleDef
@@ -121,7 +127,7 @@ collect infixes types aliases adts things =
121 where
127 where
122 nonCustomOps = Map.mapWithKey addDefaultInfix $ Map.difference types infixes
128 nonCustomOps = Map.mapWithKey addDefaultInfix $ Map.difference types infixes
123 addDefaultInfix name pairs
129 addDefaultInfix name pairs
124− | all isSymbol name = addInfix (D.L, 9 :: Int) pairs
130+ | all Help.isSymbol name = addInfix (D.L, 9 :: Int) pairs
125 | otherwise = pairs
131 | otherwise = pairs
126
132
127 customOps = Map.intersectionWith addInfix infixes types
133 customOps = Map.intersectionWith addInfix infixes types
@@ -138,7 +144,7 @@ collect infixes types aliases adts things =
138 let fields = ["typeVariables" .= vars, "type" .= tipe ]
144 let fields = ["typeVariables" .= vars, "type" .= tipe ]
139 in collect infixes types (insert name fields aliases) adts rest
145 in collect infixes types (insert name fields aliases) adts rest
140 D.Datatype name vars ctors ->
146 D.Datatype name vars ctors ->
141− let tipe = Data name (map Var vars)
147+ let tipe = T.Data name (map T.Var vars)
142 fields = ["typeVariables" .= vars
148 fields = ["typeVariables" .= vars
143 , "constructors" .= map (ctorToJson tipe) ctors ]
149 , "constructors" .= map (ctorToJson tipe) ctors ]
144 in collect infixes types aliases (insert name fields adts) rest
150 in collect infixes types aliases (insert name fields adts) rest
@@ -147,17 +153,35 @@ collect infixes types aliases adts things =
147 obj name fields =
153 obj name fields =
148 [ "name" .= name, "raw" .= source, "comment" .= comment ] ++ fields
154 [ "name" .= name, "raw" .= source, "comment" .= comment ] ++ fields
149
155
150−instance ToJSON Type where
156+instance ToJSON T.Type where
151− toJSON tipe =
157+ toJSON tipe =
158+ object $
152− case tipe of
159+ case tipe of
153− Lambda t1 t2 -> toJSON [ "->", toJSON t1, toJSON t2 ]
160+ T.Lambda _ _ ->
161+ let tipes = T.collectLambdas tipe in
162+ [ "tag" .= ("function" :: Text.Text)
163+ , "args" .= toJSON (init tipes)
164+ , "result" .= toJSON (last tipes)
165+ ]
166+
167+ T.Var x ->
168+ [ "tag" .= ("var" :: Text.Text)
154− Var x -> toJSON x
169+ , "name" .= toJSON x
170+ ]
171+
172+ T.Data name ts ->
173+ [ "tag" .= ("adt" :: Text.Text)
174+ , "name" .= toJSON name
155− Data name ts -> toJSON (toJSON name : map toJSON ts)
175+ , "args" .= map toJSON ts
176+ ]
177+
156− Record fields ext -> object $ map (\(n,t) -> Text.pack n .= toJSON t) fields'
178+ T.Record fields ext ->
157− where fields' = case ext of
179+ [ "tag" .= ("record" :: Text.Text)
158− Nothing -> fields
180+ , "fields" .= toJSON (map (toJSON . second toJSON) fields)
159− Just x -> ("_", Var x) : fields
181+ , "extension" .= toJSON ext
160−
182+ ]
183+
184+ctorToJson :: T.Type -> (String, [T.Type]) -> Value
161ctorToJson tipe (ctor, tipes) =
185ctorToJson tipe (ctor, tipes) =
162 object [ "name" .= ctor
186 object [ "name" .= ctor
163− , "type" .= foldr Lambda tipe tipes ]
187+ , "type" .= foldr T.Lambda tipe tipes ]
compiler/Elm/Internal/Paths.hs+5−4
@@ -1,7 +1,8 @@
1+{-# OPTIONS_GHC -Wall #-}
1module Elm.Internal.Paths where
2module Elm.Internal.Paths where
2
3
4+import Build.Utils (getDataFile)
3−import System.IO.Unsafe
5+import System.IO.Unsafe (unsafePerformIO)
4−import qualified Paths_Elm as This
5
6
6-- |Name of directory for all of a project's dependencies.
7-- |Name of directory for all of a project's dependencies.
7dependencyDirectory :: FilePath
8dependencyDirectory :: FilePath
@@ -15,9 +16,9 @@ dependencyFile = "elm_dependencies.json"
15{-# NOINLINE runtime #-}
16{-# NOINLINE runtime #-}
16-- |The absolute path to Elm's runtime system.
17-- |The absolute path to Elm's runtime system.
17runtime :: FilePath
18runtime :: FilePath
18−runtime = unsafePerformIO $ This.getDataFileName "elm-runtime.js"
19+runtime = unsafePerformIO $ getDataFile "elm-runtime.js"
19
20
20{-# NOINLINE docs #-}
21{-# NOINLINE docs #-}
21-- |The absolute path to Elm's core library documentation.
22-- |The absolute path to Elm's core library documentation.
22docs :: FilePath
23docs :: FilePath
23−docs = unsafePerformIO $ This.getDataFileName "docs.json"
24+docs = unsafePerformIO $ getDataFile "docs.json"
compiler/Generate/Cases.hs+32−31
@@ -6,14 +6,15 @@ import Control.Monad.State
6import Data.List (groupBy,sortBy)
6import Data.List (groupBy,sortBy)
7import Data.Maybe (fromMaybe)
7import Data.Maybe (fromMaybe)
8
8
9−import SourceSyntax.Location
9+import SourceSyntax.Annotation
10−import SourceSyntax.Literal
11−import SourceSyntax.Pattern
12import SourceSyntax.Expression
10import SourceSyntax.Expression
11+import SourceSyntax.Literal
12+import qualified SourceSyntax.Pattern as P
13+import qualified SourceSyntax.Variable as V
13import Transform.Substitute
14import Transform.Substitute
14
15
15
16
16−toMatch :: [(Pattern, LExpr)] -> State Int (String, Match)
17+toMatch :: [(P.Pattern, Expr)] -> State Int (String, Match)
17toMatch patterns = do
18toMatch patterns = do
18 v <- newVar
19 v <- newVar
19 (,) v <$> match [v] (map (first (:[])) patterns) Fail
20 (,) v <$> match [v] (map (first (:[])) patterns) Fail
@@ -27,7 +28,7 @@ data Match
27 = Match String [Clause] Match
28 = Match String [Clause] Match
28 | Break
29 | Break
29 | Fail
30 | Fail
30− | Other LExpr
31+ | Other Expr
31 | Seq [Match]
32 | Seq [Match]
32 deriving Show
33 deriving Show
33
34
@@ -39,8 +40,8 @@ matchSubst :: [(String,String)] -> Match -> Match
39matchSubst _ Break = Break
40matchSubst _ Break = Break
40matchSubst _ Fail = Fail
41matchSubst _ Fail = Fail
41matchSubst pairs (Seq ms) = Seq (map (matchSubst pairs) ms)
42matchSubst pairs (Seq ms) = Seq (map (matchSubst pairs) ms)
42−matchSubst pairs (Other (L s e)) =
43+matchSubst pairs (Other (A a e)) =
43− Other . L s $ foldr ($) e $ map (\(x,y) -> subst x (Var y)) pairs
44+ Other . A a $ foldr ($) e $ map (\(x,y) -> subst x (rawVar y)) pairs
44matchSubst pairs (Match n cs m) =
45matchSubst pairs (Match n cs m) =
45 Match (varSubst n) (map clauseSubst cs) (matchSubst pairs m)
46 Match (varSubst n) (map clauseSubst cs) (matchSubst pairs m)
46 where varSubst v = fromMaybe v (lookup v pairs)
47 where varSubst v = fromMaybe v (lookup v pairs)
@@ -49,13 +50,13 @@ matchSubst pairs (Match n cs m) =
49
50
50isCon (p:_, _) =
51isCon (p:_, _) =
51 case p of
52 case p of
52− PData _ _ -> True
53+ P.Data _ _ -> True
53− PLiteral _ -> True
54+ P.Literal _ -> True
54− _ -> False
55+ _ -> False
55
56
56isVar p = not (isCon p)
57isVar p = not (isCon p)
57
58
58−match :: [String] -> [([Pattern],LExpr)] -> Match -> State Int Match
59+match :: [String] -> [([P.Pattern],Expr)] -> Match -> State Int Match
59match [] [] def = return def
60match [] [] def = return def
60match [] [([],e)] Fail = return $ Other e
61match [] [([],e)] Fail = return $ Other e
61match [] [([],e)] Break = return $ Other e
62match [] [([],e)] Break = return $ Other e
@@ -67,46 +68,46 @@ match vs@(v:_) cs def
67 where
68 where
68 cs' = map (dealias v) cs
69 cs' = map (dealias v) cs
69
70
70−dealias v c@(p:ps, L s e) =
71+dealias v c@(p:ps, A a e) =
71 case p of
72 case p of
72− PAlias x pattern -> (pattern:ps, L s $ subst x (Var v) e)
73+ P.Alias x pattern -> (pattern:ps, A a $ subst x (rawVar v) e)
73 _ -> c
74 _ -> c
74
75
75−matchVar :: [String] -> [([Pattern],LExpr)] -> Match -> State Int Match
76+matchVar :: [String] -> [([P.Pattern],Expr)] -> Match -> State Int Match
76matchVar (v:vs) cs def = match vs (map subVar cs) def
77matchVar (v:vs) cs def = match vs (map subVar cs) def
77 where
78 where
78− subVar (p:ps, (L s e)) = (ps, L s $ subOnePattern p e)
79+ subVar (p:ps, (A a e)) = (ps, A a $ subOnePattern p e)
79 where
80 where
80 subOnePattern pattern e =
81 subOnePattern pattern e =
81 case pattern of
82 case pattern of
82− PVar x -> subst x (Var v) e
83+ P.Var x -> subst x (rawVar v) e
83− PAnything -> e
84+ P.Anything -> e
84− PRecord fs ->
85+ P.Record fs ->
85− foldr (\x -> subst x (Access (L s (Var v)) x)) e fs
86+ foldr (\x -> subst x (Access (A a (rawVar v)) x)) e fs
86
87
87−matchCon :: [String] -> [([Pattern],LExpr)] -> Match -> State Int Match
88+matchCon :: [String] -> [([P.Pattern],Expr)] -> Match -> State Int Match
88matchCon (v:vs) cs def = (flip (Match v) def) <$> mapM toClause css
89matchCon (v:vs) cs def = (flip (Match v) def) <$> mapM toClause css
89 where
90 where
90 css = groupBy eq (sortBy cmp cs)
91 css = groupBy eq (sortBy cmp cs)
91
92
92 cmp (p1:_,_) (p2:_,_) =
93 cmp (p1:_,_) (p2:_,_) =
93 case (p1,p2) of
94 case (p1,p2) of
94− (PData n1 _, PData n2 _) -> compare n1 n2
95+ (P.Data n1 _, P.Data n2 _) -> compare n1 n2
95 _ -> compare p1 p2
96 _ -> compare p1 p2
96
97
97 eq (p1:_,_) (p2:_,_) =
98 eq (p1:_,_) (p2:_,_) =
98 case (p1,p2) of
99 case (p1,p2) of
99− (PData n1 _, PData n2 _) -> n1 == n2
100+ (P.Data n1 _, P.Data n2 _) -> n1 == n2
100 _ -> p1 == p2
101 _ -> p1 == p2
101
102
102 toClause cs =
103 toClause cs =
103 case head cs of
104 case head cs of
104− (PData name _ : _, _) -> matchClause (Left name) (v:vs) cs Break
105+ (P.Data name _ : _, _) -> matchClause (Left name) (v:vs) cs Break
105− (PLiteral lit : _, _) -> matchClause (Right lit) (v:vs) cs Break
106+ (P.Literal lit : _, _) -> matchClause (Right lit) (v:vs) cs Break
106
107
107matchClause :: Either String Literal
108matchClause :: Either String Literal
108 -> [String]
109 -> [String]
109− -> [([Pattern],LExpr)]
110+ -> [([P.Pattern],Expr)]
110 -> Match
111 -> Match
111 -> State Int Clause
112 -> State Int Clause
112matchClause c (_:vs) cs def =
113matchClause c (_:vs) cs def =
@@ -116,14 +117,14 @@ matchClause c (_:vs) cs def =
116
117
117 flatten (p:ps, e) =
118 flatten (p:ps, e) =
118 case p of
119 case p of
119− PData _ ps' -> (ps' ++ ps, e)
120+ P.Data _ ps' -> (ps' ++ ps, e)
120− PLiteral _ -> (ps, e)
121+ P.Literal _ -> (ps, e)
121
122
122 getVars =
123 getVars =
123 case head cs of
124 case head cs of
124− (PData _ ps : _, _) -> forM ps (const newVar)
125+ (P.Data _ ps : _, _) -> forM ps (const newVar)
125− (PLiteral _ : _, _) -> return []
126+ (P.Literal _ : _, _) -> return []
126
127
127−matchMix :: [String] -> [([Pattern],LExpr)] -> Match -> State Int Match
128+matchMix :: [String] -> [([P.Pattern],Expr)] -> Match -> State Int Match
128matchMix vs cs def = foldM (flip $ match vs) def (reverse css)
129matchMix vs cs def = foldM (flip $ match vs) def (reverse css)
129− where css = groupBy (\p1 p2 -> isCon p1 == isCon p2) cs
130+ where css = groupBy (\p1 p2 -> isCon p1 == isCon p2) cs
compiler/Generate/JavaScript.hs+63−54
@@ -1,25 +1,27 @@
1{-# OPTIONS_GHC -W #-}
1{-# OPTIONS_GHC -W #-}
2module Generate.JavaScript (generate) where
2module Generate.JavaScript (generate) where
3
3
4−import Control.Arrow (first,(***))
5import Control.Applicative ((<$>),(<*>))
4import Control.Applicative ((<$>),(<*>))
5+import Control.Arrow (first,(***))
6import Control.Monad.State
6import Control.Monad.State
7import qualified Data.List as List
7import qualified Data.List as List
8import qualified Data.Map as Map
8import qualified Data.Map as Map
9import qualified Data.Set as Set
9import qualified Data.Set as Set
10+import Language.ECMAScript3.PrettyPrint
11+import Language.ECMAScript3.Syntax
10
12
11import Generate.JavaScript.Helpers
13import Generate.JavaScript.Helpers
12import qualified Generate.Cases as Case
14import qualified Generate.Cases as Case
13import qualified Generate.JavaScript.Ports as Port
15import qualified Generate.JavaScript.Ports as Port
14import qualified Generate.Markdown as MD
16import qualified Generate.Markdown as MD
17+import SourceSyntax.Annotation
18+import SourceSyntax.Expression
15import qualified SourceSyntax.Helpers as Help
19import qualified SourceSyntax.Helpers as Help
16import SourceSyntax.Literal
20import SourceSyntax.Literal
17−import SourceSyntax.Pattern as Pattern
18−import SourceSyntax.Location
19−import SourceSyntax.Expression
20import SourceSyntax.Module
21import SourceSyntax.Module
21−import Language.ECMAScript3.Syntax
22+import qualified SourceSyntax.Pattern as P
22−import Language.ECMAScript3.PrettyPrint
23+import SourceSyntax.PrettyPrint (renderPretty)
24+import qualified SourceSyntax.Variable as V
23import qualified Transform.SafeNames as MakeSafe
25import qualified Transform.SafeNames as MakeSafe
24
26
25varDecl :: String -> Expression () -> VarDecl ()
27varDecl :: String -> Expression () -> VarDecl ()
@@ -50,10 +52,10 @@ literal lit =
50 FloatNum n -> NumLit () n
52 FloatNum n -> NumLit () n
51 Boolean b -> BoolLit () b
53 Boolean b -> BoolLit () b
52
54
53−expression :: LExpr -> State Int (Expression ())
55+expression :: Expr -> State Int (Expression ())
54−expression (L span expr) =
56+expression (A region expr) =
55 case expr of
57 case expr of
56− Var x -> return $ ref x
58+ Var (V.Raw x) -> return $ obj x
57 Literal lit -> return $ literal lit
59 Literal lit -> return $ literal lit
58
60
59 Range lo hi ->
61 Range lo hi ->
@@ -85,17 +87,16 @@ expression (L span expr) =
85 do fields' <- forM fields $ \(f,e) -> do
87 do fields' <- forM fields $ \(f,e) -> do
86 (,) f <$> expression e
88 (,) f <$> expression e
87 let fieldMap = List.foldl' combine Map.empty fields'
89 let fieldMap = List.foldl' combine Map.empty fields'
88− return $ ObjectLit () $ (PropId () (var "_"), hidden fieldMap) : visible fieldMap
90+ return $ ObjectLit () $ (prop "_", hidden fieldMap) : visible fieldMap
89 where
91 where
90 combine r (k,v) = Map.insertWith (++) k [v] r
92 combine r (k,v) = Map.insertWith (++) k [v] r
91− prop = PropId () . var
92 hidden fs = ObjectLit () . map (prop *** ArrayLit ()) .
93 hidden fs = ObjectLit () . map (prop *** ArrayLit ()) .
93 Map.toList . Map.filter (not . null) $ Map.map tail fs
94 Map.toList . Map.filter (not . null) $ Map.map tail fs
94 visible fs = map (first prop) . Map.toList $ Map.map head fs
95 visible fs = map (first prop) . Map.toList $ Map.map head fs
95
96
96− Binop op e1 e2 -> binop span op e1 e2
97+ Binop op e1 e2 -> binop region op e1 e2
97
98
98− Lambda p e@(L s _) ->
99+ Lambda p e@(A ann _) ->
99 do (args, body) <- foldM depattern ([], innerBody) (reverse patterns)
100 do (args, body) <- foldM depattern ([], innerBody) (reverse patterns)
100 body' <- expression body
101 body' <- expression body
101 return $ case length args < 2 || length args > 9 of
102 return $ case length args < 2 || length args > 9 of
@@ -104,13 +105,14 @@ expression (L span expr) =
104 where
105 where
105 depattern (args, body) pattern =
106 depattern (args, body) pattern =
106 case pattern of
107 case pattern of
107− PVar x -> return (args ++ [x], body)
108+ P.Var x -> return (args ++ [x], body)
108 _ -> do arg <- Case.newVar
109 _ -> do arg <- Case.newVar
110+ return ( args ++ [arg]
109− return (args ++ [arg], L s (Case (L s (Var arg)) [(pattern, body)]))
111+ , A ann (Case (A ann (rawVar arg)) [(pattern, body)]))
110
112
111 (patterns, innerBody) = collect [p] e
113 (patterns, innerBody) = collect [p] e
112
114
113− collect patterns lexpr@(L _ expr) =
115+ collect patterns lexpr@(A _ expr) =
114 case expr of
116 case expr of
115 Lambda p e -> collect (p:patterns) e
117 Lambda p e -> collect (p:patterns) e
116 _ -> (patterns, lexpr)
118 _ -> (patterns, lexpr)
@@ -127,7 +129,7 @@ expression (L span expr) =
127 (func, args) = getArgs e1 [e2]
129 (func, args) = getArgs e1 [e2]
128 getArgs func args =
130 getArgs func args =
129 case func of
131 case func of
130− (L _ (App f arg)) -> getArgs f (arg : args)
132+ (A _ (App f arg)) -> getArgs f (arg : args)
131 _ -> (func, args)
133 _ -> (func, args)
132
134
133 Let defs e ->
135 Let defs e ->
@@ -139,9 +141,9 @@ expression (L span expr) =
139 MultiIf branches ->
141 MultiIf branches ->
140 do branches' <- forM branches $ \(b,e) -> (,) <$> expression b <*> expression e
142 do branches' <- forM branches $ \(b,e) -> (,) <$> expression b <*> expression e
141 return $ case last branches of
143 return $ case last branches of
142− (L _ (Var "Basics.otherwise"), _) -> safeIfs branches'
144+ (A _ (Var (V.Raw "Basics.otherwise")), _) -> safeIfs branches'
143− (L _ (Literal (Boolean True)), _) -> safeIfs branches'
145+ (A _ (Literal (Boolean True)), _) -> safeIfs branches'
144− _ -> ifs branches' (obj "_E.If" `call` [ ref "$moduleName", string (show span) ])
146+ _ -> ifs branches' (obj "_E.If" `call` [ ref "$moduleName", string (renderPretty region) ])
145 where
147 where
146 safeIfs branches = ifs (init branches) (snd (last branches))
148 safeIfs branches = ifs (init branches) (snd (last branches))
147 ifs branches finally = foldr iff finally branches
149 ifs branches finally = foldr iff finally branches
@@ -151,10 +153,12 @@ expression (L span expr) =
151 do (tempVar,initialMatch) <- Case.toMatch cases
153 do (tempVar,initialMatch) <- Case.toMatch cases
152 (revisedMatch, stmt) <-
154 (revisedMatch, stmt) <-
153 case e of
155 case e of
156+ A _ (Var (V.Raw x)) ->
154− L _ (Var x) -> return (Case.matchSubst [(tempVar,x)] initialMatch, [])
157+ return (Case.matchSubst [(tempVar,x)] initialMatch, [])
158+ _ ->
155− _ -> do e' <- expression e
159+ do e' <- expression e
156− return (initialMatch, [VarDeclStmt () [varDecl tempVar e']])
160+ return (initialMatch, [VarDeclStmt () [varDecl tempVar e']])
157− match' <- match span revisedMatch
161+ match' <- match region revisedMatch
158 return (function [] (stmt ++ match') `call` [])
162 return (function [] (stmt ++ match') `call` [])
159
163
160 ExplicitList es ->
164 ExplicitList es ->
@@ -184,28 +188,28 @@ expression (L span expr) =
184 [ string name, Port.outgoing tipe, value' ]
188 [ string name, Port.outgoing tipe, value' ]
185
189
186definition :: Def -> State Int [Statement ()]
190definition :: Def -> State Int [Statement ()]
187−definition (Definition pattern expr@(L span _) _) = do
191+definition (Definition pattern expr@(A region _) _) = do
188 expr' <- expression expr
192 expr' <- expression expr
189 let assign x = varDecl x expr'
193 let assign x = varDecl x expr'
190 case pattern of
194 case pattern of
191− PVar x
195+ P.Var x
192 | Help.isOp x ->
196 | Help.isOp x ->
193 let op = LBracket () (ref "_op") (string x) in
197 let op = LBracket () (ref "_op") (string x) in
194 return [ ExprStmt () $ AssignExpr () OpAssign op expr' ]
198 return [ ExprStmt () $ AssignExpr () OpAssign op expr' ]
195 | otherwise ->
199 | otherwise ->
196 return [ VarDeclStmt () [ assign x ] ]
200 return [ VarDeclStmt () [ assign x ] ]
197
201
198− PRecord fields ->
202+ P.Record fields ->
199 let setField f = varDecl f (dotSep ["$",f]) in
203 let setField f = varDecl f (dotSep ["$",f]) in
200 return [ VarDeclStmt () (assign "$" : map setField fields) ]
204 return [ VarDeclStmt () (assign "$" : map setField fields) ]
201
205
202− PData name patterns | vars /= Nothing ->
206+ P.Data name patterns | vars /= Nothing ->
203 return [ VarDeclStmt () (setup (zipWith decl (maybe [] id vars) [0..])) ]
207 return [ VarDeclStmt () (setup (zipWith decl (maybe [] id vars) [0..])) ]
204 where
208 where
205 vars = getVars patterns
209 vars = getVars patterns
206 getVars patterns =
210 getVars patterns =
207 case patterns of
211 case patterns of
208− PVar x : rest -> (x:) `fmap` getVars rest
212+ P.Var x : rest -> (x:) `fmap` getVars rest
209 [] -> Just []
213 [] -> Just []
210 _ -> Nothing
214 _ -> Nothing
211
215
@@ -216,41 +220,45 @@ definition (Definition pattern expr@(L span _) _) = do
216
220
217 safeAssign = varDecl "$" (CondExpr () if' (obj "$raw") exception)
221 safeAssign = varDecl "$" (CondExpr () if' (obj "$raw") exception)
218 if' = InfixExpr () OpStrictEq (obj "$raw.ctor") (string name)
222 if' = InfixExpr () OpStrictEq (obj "$raw.ctor") (string name)
219− exception = obj "_E.Case" `call` [ref "$moduleName", string (show span)]
223+ exception = obj "_E.Case" `call` [ref "$moduleName", string (renderPretty region)]
220
224
221 _ ->
225 _ ->
222 do defs' <- concat <$> mapM toDef vars
226 do defs' <- concat <$> mapM toDef vars
223 return (VarDeclStmt () [assign "$"] : defs')
227 return (VarDeclStmt () [assign "$"] : defs')
224 where
228 where
225− vars = Set.toList $ Pattern.boundVars pattern
229+ vars = P.boundVarList pattern
226− mkVar = L span . Var
230+ mkVar = A region . rawVar
227− toDef y = let expr = L span $ Case (mkVar "$") [(pattern, mkVar y)]
231+ toDef y = let expr = A region $ Case (mkVar "$") [(pattern, mkVar y)]
228− in definition $ Definition (PVar y) expr Nothing
232+ in definition $ Definition (P.Var y) expr Nothing
229
233
230−match :: SrcSpan -> Case.Match -> State Int [Statement ()]
234+match :: Region -> Case.Match -> State Int [Statement ()]
231−match span mtch =
235+match region mtch =
232 case mtch of
236 case mtch of
233 Case.Match name clauses mtch' ->
237 Case.Match name clauses mtch' ->
234− do (isChars, clauses') <- unzip <$> mapM (clause span name) clauses
238+ do (isChars, clauses') <- unzip <$> mapM (clause region name) clauses
235− mtch'' <- match span mtch'
239+ mtch'' <- match region mtch'
236 return (SwitchStmt () (format isChars (access name)) clauses' : mtch'')
240 return (SwitchStmt () (format isChars (access name)) clauses' : mtch'')
237 where
241 where
238 isLiteral p = case p of
242 isLiteral p = case p of
239 Case.Clause (Right _) _ _ -> True
243 Case.Clause (Right _) _ _ -> True
240 _ -> False
244 _ -> False
245+
246+ access name
241− access name = if any isLiteral clauses then ref name else dotSep [name,"ctor"]
247+ | any isLiteral clauses = obj name
248+ | otherwise = dotSep (split name ++ ["ctor"])
249+
242 format isChars e
250 format isChars e
243 | or isChars = InfixExpr () OpAdd e (string "")
251 | or isChars = InfixExpr () OpAdd e (string "")
244 | otherwise = e
252 | otherwise = e
245
253
246 Case.Fail ->
254 Case.Fail ->
247− return [ ExprStmt () (obj "_E.Case" `call` [ref "$moduleName", string (show span)]) ]
255+ return [ ExprStmt () (obj "_E.Case" `call` [ref "$moduleName", string (renderPretty region)]) ]
248
256
249 Case.Break -> return [BreakStmt () Nothing]
257 Case.Break -> return [BreakStmt () Nothing]
250 Case.Other e ->
258 Case.Other e ->
251 do e' <- expression e
259 do e' <- expression e
252 return [ ret e' ]
260 return [ ret e' ]
253− Case.Seq ms -> concat <$> mapM (match span) (dropEnd [] ms)
261+ Case.Seq ms -> concat <$> mapM (match region) (dropEnd [] ms)
254 where
262 where
255 dropEnd acc [] = acc
263 dropEnd acc [] = acc
256 dropEnd acc (m:ms) =
264 dropEnd acc (m:ms) =
@@ -258,9 +266,9 @@ match span mtch =
258 Case.Other _ -> acc ++ [m]
266 Case.Other _ -> acc ++ [m]
259 _ -> dropEnd (acc ++ [m]) ms
267 _ -> dropEnd (acc ++ [m]) ms
260
268
261−clause :: SrcSpan -> String -> Case.Clause -> State Int (Bool, CaseClause ())
269+clause :: Region -> String -> Case.Clause -> State Int (Bool, CaseClause ())
262−clause span variable (Case.Clause value vars mtch) =
270+clause region variable (Case.Clause value vars mtch) =
263− (,) isChar . CaseClause () pattern <$> match span (Case.matchSubst (zip vars vars') mtch)
271+ (,) isChar . CaseClause () pattern <$> match region (Case.matchSubst (zip vars vars') mtch)
264 where
272 where
265 vars' = map (\n -> variable ++ "._" ++ show n) [0..]
273 vars' = map (\n -> variable ++ "._" ++ show n) [0..]
266 (isChar, pattern) =
274 (isChar, pattern) =
@@ -273,8 +281,8 @@ clause span variable (Case.Clause value vars mtch) =
273 [] -> name
281 [] -> name
274 is -> drop (last is + 1) name
282 is -> drop (last is + 1) name
275
283
276−flattenLets :: [Def] -> LExpr -> ([Def], LExpr)
284+flattenLets :: [Def] -> Expr -> ([Def], Expr)
277−flattenLets defs lexpr@(L _ expr) =
285+flattenLets defs lexpr@(A _ expr) =
278 case expr of
286 case expr of
279 Let ds body -> flattenLets (defs ++ ds) body
287 Let ds body -> flattenLets (defs ++ ds) body
280 _ -> (defs, lexpr)
288 _ -> (defs, lexpr)
@@ -288,7 +296,8 @@ generate unsafeModule =
288 thisModule = dotSep ("_elm" : names modul ++ ["values"])
296 thisModule = dotSep ("_elm" : names modul ++ ["values"])
289 programStmts =
297 programStmts =
290 concat
298 concat
299+ [ [ ExprStmt () $ string "use strict" ]
291− [ setup (Just "_elm") (names modul ++ ["values"])
300+ , setup (Just "_elm") (names modul ++ ["values"])
292 , [ IfSingleStmt () thisModule (ret thisModule) ]
301 , [ IfSingleStmt () thisModule (ret thisModule) ]
293 , [ internalImports (List.intercalate "." (names modul)) ]
302 , [ internalImports (List.intercalate "." (names modul)) ]
294 , concatMap jsImport . Set.toList . Set.fromList . map fst $ imports modul
303 , concatMap jsImport . Set.toList . Set.fromList . map fst $ imports modul
@@ -301,7 +310,7 @@ generate unsafeModule =
301 jsExports = assign ("_elm" : names modul ++ ["values"]) (ObjectLit () exs)
310 jsExports = assign ("_elm" : names modul ++ ["values"]) (ObjectLit () exs)
302 where
311 where
303 exs = map entry . filter (not . Help.isOp) $ "_op" : exports modul
312 exs = map entry . filter (not . Help.isOp) $ "_op" : exports modul
304− entry x = (PropId () (var x), ref x)
313+ entry x = (prop x, ref x)
305
314
306 assign path expr =
315 assign path expr =
307 case path of
316 case path of
@@ -311,7 +320,7 @@ generate unsafeModule =
311
320
312 jsImport modul = setup Nothing path ++ [ include ]
321 jsImport modul = setup Nothing path ++ [ include ]
313 where
322 where
314− path = split modul
323+ path = Help.splitDots modul
315 include = assign path $ dotSep ("Elm" : path ++ ["make"]) <| ref "_elm"
324 include = assign path $ dotSep ("Elm" : path ++ ["make"]) <| ref "_elm"
316
325
317 setup namespace path = map create paths
326 setup namespace path = map create paths
@@ -321,8 +330,8 @@ generate unsafeModule =
321 Nothing -> tail . init $ List.inits path
330 Nothing -> tail . init $ List.inits path
322 Just nmspc -> drop 2 . init . List.inits $ nmspc : path
331 Just nmspc -> drop 2 . init . List.inits $ nmspc : path
323
332
324−binop :: SrcSpan -> String -> LExpr -> LExpr -> State Int (Expression ())
333+binop :: Region -> String -> Expr -> Expr -> State Int (Expression ())
325−binop span op e1 e2 =
334+binop region op e1 e2 =
326 case op of
335 case op of
327 "Basics.." ->
336 "Basics.." ->
328 do es <- mapM expression (e1 : collect [] e2)
337 do es <- mapM expression (e1 : collect [] e2)
@@ -335,7 +344,7 @@ binop span op e1 e2 =
335 do e1' <- expression e1
344 do e1' <- expression e1
336 e2' <- expression e2
345 e2' <- expression e2
337 return $ obj "_L.append" `call` [e1', e2']
346 return $ obj "_L.append" `call` [e1', e2']
338− "::" -> expression (L span (Data "::" [e1,e2]))
347+ "::" -> expression (A region (Data "::" [e1,e2]))
339 _ ->
348 _ ->
340 do e1' <- expression e1
349 do e1' <- expression e1
341 e2' <- expression e2
350 e2' <- expression e2
@@ -345,13 +354,13 @@ binop span op e1 e2 =
345 where
354 where
346 collect es e =
355 collect es e =
347 case e of
356 case e of
348− L _ (Binop op e1 e2) | op == "Basics.." -> collect (es ++ [e1]) e2
357+ A _ (Binop op e1 e2) | op == "Basics.." -> collect (es ++ [e1]) e2
349 _ -> es ++ [e]
358 _ -> es ++ [e]
350
359
351 func | Help.isOp operator = BracketRef () (dotSep (init parts ++ ["_op"])) (string operator)
360 func | Help.isOp operator = BracketRef () (dotSep (init parts ++ ["_op"])) (string operator)
352 | otherwise = dotSep parts
361 | otherwise = dotSep parts
353 where
362 where
354− parts = split op
363+ parts = Help.splitDots op
355 operator = last parts
364 operator = last parts
356
365
357 opDict = Map.fromList (infixOps ++ specialOps)
366 opDict = Map.fromList (infixOps ++ specialOps)
compiler/Generate/JavaScript/Ports.hs+23−17
@@ -32,7 +32,7 @@ incoming tipe =
32
32
33inc :: Type -> Expression () -> Expression ()
33inc :: Type -> Expression () -> Expression ()
34inc tipe x =
34inc tipe x =
35− case tipe of
35+ case tipe of
36 Lambda _ _ -> error "functions should not be allowed through input ports"
36 Lambda _ _ -> error "functions should not be allowed through input ports"
37 Var _ -> error "type variables should not be allowed through input ports"
37 Var _ -> error "type variables should not be allowed through input ports"
38 Data ctor []
38 Data ctor []
@@ -58,22 +58,26 @@ inc tipe x =
58 where
58 where
59 array = DotRef () x (var "map") <| incoming t
59 array = DotRef () x (var "map") <| incoming t
60
60
61+ Data ctor ts
61− Data ctor ts | Help.isTuple ctor -> check x JSArray tuple
62+ | Help.isTuple ctor -> check x JSArray tuple
62 where
63 where
63− tuple = ObjectLit () $ (PropId () (var "ctor"), string ctor) : values
64+ tuple = ObjectLit () $ (prop "ctor", string ctor) : values
64 values = zipWith convert [0..] ts
65 values = zipWith convert [0..] ts
65− convert n t = ( PropId () $ var ('_':show n)
66+ convert n t = ( prop ('_':show n)
66 , inc t (BracketRef () x (IntLit () n)))
67 , inc t (BracketRef () x (IntLit () n)))
67
68
69+ Data _ _ ->
68− Data _ _ -> error "bad ADT got to port generation code"
70+ error "bad ADT got to port generation code"
69
71
72+ Record _ (Just _) ->
70− Record _ (Just _) -> error "bad record got to port generation code"
73+ error "bad record got to port generation code"
71
74
75+ Record fields Nothing ->
72− Record fields Nothing -> check x (JSObject (map fst fields)) object
76+ check x (JSObject (map fst fields)) object
73 where
77 where
74− object = ObjectLit () $ (PropId () (var "_"), ObjectLit () []) : keys
78+ object = ObjectLit () $ (prop "_", ObjectLit () []) : keys
75 keys = map convert fields
79 keys = map convert fields
76− convert (f,t) = (PropId () (var f), inc t (DotRef () x (var f)))
80+ convert (f,t) = (prop f, inc t (DotRef () x (var f)))
77
81
78outgoing tipe =
82outgoing tipe =
79 case tipe of
83 case tipe of
@@ -109,19 +113,21 @@ out tipe x =
109 | ctor == "Maybe.Maybe" ->
113 | ctor == "Maybe.Maybe" ->
110 CondExpr () (equal (DotRef () x (var "ctor")) (string "Nothing"))
114 CondExpr () (equal (DotRef () x (var "ctor")) (string "Nothing"))
111 (NullLit ())
115 (NullLit ())
112− (DotRef () x (var "_0"))
116+ (out t (DotRef () x (var "_0")))
113
117
114 | ctor == "_List" ->
118 | ctor == "_List" ->
115 DotRef () (obj "_J.fromList" <| x) (var "map") <| outgoing t
119 DotRef () (obj "_J.fromList" <| x) (var "map") <| outgoing t
116
120
121+ Data ctor ts
117− Data ctor ts | Help.isTuple ctor ->
122+ | Help.isTuple ctor ->
118− ArrayLit () $ zipWith convert [0..] ts
119− where
120− convert n t = out t $ DotRef () x $ var ('_':show n)
123+ let convert n t = out t $ DotRef () x $ var ('_':show n)
121−
124+ in ArrayLit () $ zipWith convert [0..] ts
125+
126+ Data _ _ ->
122− Data _ _ -> error "bad ADT got to port generation code"
127+ error "bad ADT got to port generation code"
123
128
129+ Record _ (Just _) ->
124− Record _ (Just _) -> error "bad record got to port generation code"
130+ error "bad record got to port generation code"
125
131
126 Record fields Nothing ->
132 Record fields Nothing ->
127 ObjectLit () keys
133 ObjectLit () keys
compiler/Generate/Noscript.hsdeleted−68
@@ -1,68 +0,0 @@
1−module Generate.Noscript (noscript) where
2−
3−import Data.List (isInfixOf)
4−import qualified SourceSyntax.Declaration as D
5−import SourceSyntax.Expression
6−import SourceSyntax.Literal
7−import SourceSyntax.Location
8−import SourceSyntax.Module
9−import qualified Generate.Markdown as MD
10−
11−noscript :: Extract def => Module def -> String
12−noscript modul = concat (extract modul)
13−
14−class Extract a where
15− extract :: a -> [String]
16−
17−instance Extract def => Extract (Module def) where
18− extract (Module _ _ _ stmts) =
19− map (\s -> "<p>" ++ s ++ "</p>") (concatMap extract stmts)
20−
21−instance Extract def => Extract (D.Declaration' port def) where
22− extract (D.Definition d) = extract d
23− extract _ = []
24−
25−instance Extract Def where
26− extract (Definition _ e _) = extract e
27−
28−instance Extract e => Extract (Located e) where
29− extract (L _ e) = extract e
30−
31−instance Extract def => Extract (Expr' def) where
32− extract expr =
33− let f = extract in
34− case expr of
35− Literal (Str s) -> [s]
36− Binop op e1 e2 -> case (op, f e1, f e2) of
37− ("++", [s1], [s2]) -> [s1 ++ s2]
38− (_ , ss1 , ss2 ) -> ss1 ++ ss2
39− Lambda v e -> f e
40− App (L _ (App (L _ (App (L _ (Var func)) w)) h)) src
41− | "image" `isInfixOf` func -> extractImage src
42− App (L _ (App (L _ (Var func)) src)) txt
43− | "link" `isInfixOf` func -> extractLink src txt
44− App (L _ (Var func)) e
45− | "header" `isInfixOf` func -> tag "h1" e
46− | "bold" `isInfixOf` func -> tag "b" e
47− | "italic" `isInfixOf` func -> tag "i" e
48− | "monospace" `isInfixOf` func -> tag "code" e
49− App e1 e2 -> f e1 ++ f e2
50− Let defs e -> concatMap extract defs ++ f e
51− Var _ -> []
52− Case e cases -> concatMap (f . snd) cases
53− Data _ es -> concatMap f es
54− MultiIf es -> concatMap (f . snd) es
55− Markdown _ md _ -> [ MD.toHtml md ]
56− _ -> []
57−
58−extractLink src txt =
59− case (extract src, extract txt) of
60− ([s1],[s2]) -> [ "<a href=\"" ++ s1 ++ "\">" ++ s2 ++ "</a>" ]
61− ( ss1, ss2) -> ss1 ++ ss2
62−
63−extractImage src =
64− case extract src of
65− [s] -> ["<img src=\"" ++ s ++ "\">"]
66− ss -> ss
67−
68−tag t e = map (\s -> concat [ "<", t, ">", s, "</", t, ">" ]) (extract e)
compiler/Metadata/Prelude.hs+7−7
@@ -3,11 +3,11 @@ module Metadata.Prelude (interfaces, add) where
3
3
4import qualified Data.Map as Map
4import qualified Data.Map as Map
5import qualified Control.Exception as E
5import qualified Control.Exception as E
6−import qualified Paths_Elm as Path
7import System.Exit
6import System.Exit
8import System.IO
7import System.IO
9import SourceSyntax.Module
8import SourceSyntax.Module
10import qualified Build.Interface as Interface
9import qualified Build.Interface as Interface
10+import Build.Utils (getDataFile)
11
11
12add :: Bool -> Module def -> Module def
12add :: Bool -> Module def -> Module def
13add noPrelude (Module name exs ims decls) = Module name exs (customIms ++ ims) decls
13add noPrelude (Module name exs ims decls) = Module name exs (customIms ++ ims) decls
@@ -20,18 +20,18 @@ add noPrelude (Module name exs ims decls) = Module name exs (customIms ++ ims) d
20 Just _ -> []
20 Just _ -> []
21
21
22prelude :: [(String, ImportMethod)]
22prelude :: [(String, ImportMethod)]
23−prelude = string : text ++ map (\n -> (n, Hiding [])) modules
23+prelude = string ++ text ++ map (\n -> (n, Hiding [])) modules
24 where
24 where
25 text = map ((,) "Text") [ As "Text", Hiding ["link", "color", "height"] ]
25 text = map ((,) "Text") [ As "Text", Hiding ["link", "color", "height"] ]
26− string = ("String", As "String")
26+ string = map ((,) "String") [ As "String", Importing ["show"] ]
27− modules = [ "Basics", "Signal", "List", "Maybe", "Time", "Prelude"
27+ modules = [ "Basics", "Signal", "List", "Maybe", "Time", "Color"
28− , "Graphics.Element", "Color", "Graphics.Collage", "Native.Ports" ]
28+ , "Graphics.Element", "Graphics.Collage", "Native.Ports" ]
29
29
30interfaces :: Bool -> IO Interfaces
30interfaces :: Bool -> IO Interfaces
31interfaces noPrelude =
31interfaces noPrelude =
32 if noPrelude
32 if noPrelude
33− then return $ Map.empty
33+ then return Map.empty
34− else safeReadDocs =<< Path.getDataFileName "interfaces.data"
34+ else safeReadDocs =<< getDataFile "interfaces.data"
35
35
36safeReadDocs :: FilePath -> IO Interfaces
36safeReadDocs :: FilePath -> IO Interfaces
37safeReadDocs name =
37safeReadDocs name =
compiler/Parse/Binop.hs+17−16
@@ -1,10 +1,11 @@
1+{-# OPTIONS_GHC -W #-}
1module Parse.Binop (binops, OpTable) where
2module Parse.Binop (binops, OpTable) where
2
3
3import Control.Applicative ((<$>))
4import Control.Applicative ((<$>))
4−import Data.List (intercalate)
5+import qualified Data.List as List
5import qualified Data.Map as Map
6import qualified Data.Map as Map
6
7
7−import SourceSyntax.Location (merge)
8+import SourceSyntax.Annotation (merge)
8import qualified SourceSyntax.Expression as E
9import qualified SourceSyntax.Expression as E
9import SourceSyntax.Declaration (Assoc(..))
10import SourceSyntax.Declaration (Assoc(..))
10import Text.Parsec
11import Text.Parsec
@@ -16,13 +17,13 @@ opLevel table op = fst $ Map.findWithDefault (9,L) op table
16opAssoc :: OpTable -> String -> Assoc
17opAssoc :: OpTable -> String -> Assoc
17opAssoc table op = snd $ Map.findWithDefault (9,L) op table
18opAssoc table op = snd $ Map.findWithDefault (9,L) op table
18
19
19−hasLevel :: OpTable -> Int -> (String, E.LParseExpr) -> Bool
20+hasLevel :: OpTable -> Int -> (String, E.ParseExpr) -> Bool
20hasLevel table n (op,_) = opLevel table op == n
21hasLevel table n (op,_) = opLevel table op == n
21
22
22−binops :: IParser E.LParseExpr
23+binops :: IParser E.ParseExpr
23− -> IParser E.LParseExpr
24+ -> IParser E.ParseExpr
24 -> IParser String
25 -> IParser String
25− -> IParser E.LParseExpr
26+ -> IParser E.ParseExpr
26binops term last anyOp =
27binops term last anyOp =
27 do e <- term
28 do e <- term
28 table <- getState
29 table <- getState
@@ -38,9 +39,9 @@ binops term last anyOp =
38
39
39split :: OpTable
40split :: OpTable
40 -> Int
41 -> Int
41− -> E.LParseExpr
42+ -> E.ParseExpr
42− -> [(String, E.LParseExpr)]
43+ -> [(String, E.ParseExpr)]
43− -> IParser E.LParseExpr
44+ -> IParser E.ParseExpr
44split _ _ e [] = return e
45split _ _ e [] = return e
45split table n e eops = do
46split table n e eops = do
46 assoc <- getAssoc table n eops
47 assoc <- getAssoc table n eops
@@ -49,26 +50,26 @@ split table n e eops = do
49 case assoc of R -> joinR es ops
50 case assoc of R -> joinR es ops
50 _ -> joinL es ops
51 _ -> joinL es ops
51
52
52−splitLevel :: OpTable -> Int -> E.LParseExpr -> [(String, E.LParseExpr)]
53+splitLevel :: OpTable -> Int -> E.ParseExpr -> [(String, E.ParseExpr)]
53− -> [IParser E.LParseExpr]
54+ -> [IParser E.ParseExpr]
54splitLevel table n e eops =
55splitLevel table n e eops =
55 case break (hasLevel table n) eops of
56 case break (hasLevel table n) eops of
56− (lops, (op,e'):rops) ->
57+ (lops, (_op,e'):rops) ->
57 split table (n+1) e lops : splitLevel table n e' rops
58 split table (n+1) e lops : splitLevel table n e' rops
58 (lops, []) -> [ split table (n+1) e lops ]
59 (lops, []) -> [ split table (n+1) e lops ]
59
60
60−joinL :: [E.LParseExpr] -> [String] -> IParser E.LParseExpr
61+joinL :: [E.ParseExpr] -> [String] -> IParser E.ParseExpr
61joinL [e] [] = return e
62joinL [e] [] = return e
62joinL (a:b:es) (op:ops) = joinL (merge a b (E.Binop op a b) : es) ops
63joinL (a:b:es) (op:ops) = joinL (merge a b (E.Binop op a b) : es) ops
63joinL _ _ = failure "Ill-formed binary expression. Report a compiler bug."
64joinL _ _ = failure "Ill-formed binary expression. Report a compiler bug."
64
65
65−joinR :: [E.LParseExpr] -> [String] -> IParser E.LParseExpr
66+joinR :: [E.ParseExpr] -> [String] -> IParser E.ParseExpr
66joinR [e] [] = return e
67joinR [e] [] = return e
67joinR (a:b:es) (op:ops) = do e <- joinR (b:es) ops
68joinR (a:b:es) (op:ops) = do e <- joinR (b:es) ops
68 return (merge a e (E.Binop op a e))
69 return (merge a e (E.Binop op a e))
69joinR _ _ = failure "Ill-formed binary expression. Report a compiler bug."
70joinR _ _ = failure "Ill-formed binary expression. Report a compiler bug."
70
71
71−getAssoc :: OpTable -> Int -> [(String,E.LParseExpr)] -> IParser Assoc
72+getAssoc :: OpTable -> Int -> [(String,E.ParseExpr)] -> IParser Assoc
72getAssoc table n eops
73getAssoc table n eops
73 | all (==L) assocs = return L
74 | all (==L) assocs = return L
74 | all (==R) assocs = return R
75 | all (==R) assocs = return R
@@ -79,5 +80,5 @@ getAssoc table n eops
79 assocs = map (opAssoc table . fst) levelOps
80 assocs = map (opAssoc table . fst) levelOps
80 msg problem =
81 msg problem =
81 concat [ "Conflicting " ++ problem ++ " for binary operators ("
82 concat [ "Conflicting " ++ problem ++ " for binary operators ("
82− , intercalate ", " (map fst eops), "). "
83+ , List.intercalate ", " (map fst eops), "). "
83 , "Consider adding parentheses to disambiguate." ]
84 , "Consider adding parentheses to disambiguate." ]
compiler/Parse/Expression.hs+69−68
@@ -5,45 +5,45 @@ import Data.List (foldl')
5import Text.Parsec hiding (newline,spaces)
5import Text.Parsec hiding (newline,spaces)
6import Text.Parsec.Indent
6import Text.Parsec.Indent
7
7
8+import Parse.Binop
8import Parse.Helpers
9import Parse.Helpers
10+import Parse.Literal
9import qualified Parse.Pattern as Pattern
11import qualified Parse.Pattern as Pattern
10import qualified Parse.Type as Type
12import qualified Parse.Type as Type
11−import Parse.Binop
12−import Parse.Literal
13
13
14−import SourceSyntax.Location as Location
14+import SourceSyntax.Annotation as Annotation
15−import SourceSyntax.Pattern hiding (tuple,list)
15+import qualified SourceSyntax.Pattern as P
16−import qualified SourceSyntax.Literal as Literal
16+import qualified SourceSyntax.Literal as L
17import SourceSyntax.Expression
17import SourceSyntax.Expression
18
18
19
19
20-------- Basic Terms --------
20-------- Basic Terms --------
21
21
22−varTerm :: IParser ParseExpr
22+varTerm :: IParser ParseExpr'
23varTerm = toVar <$> var <?> "variable"
23varTerm = toVar <$> var <?> "variable"
24
24
25−toVar :: String -> ParseExpr
25+toVar :: String -> ParseExpr'
26−toVar v = case v of "True" -> Literal (Literal.Boolean True)
26+toVar v = case v of "True" -> Literal (L.Boolean True)
27− "False" -> Literal (Literal.Boolean False)
27+ "False" -> Literal (L.Boolean False)
28− _ -> Var v
28+ _ -> rawVar v
29
29
30−accessor :: IParser ParseExpr
30+accessor :: IParser ParseExpr'
31accessor = do
31accessor = do
32 (start, lbl, end) <- located (try (string "." >> rLabel))
32 (start, lbl, end) <- located (try (string "." >> rLabel))
33− let loc e = Location.at start end e
33+ let loc e = Annotation.at start end e
34− return (Lambda (PVar "_") (loc $ Access (loc $ Var "_") lbl))
34+ return (Lambda (P.Var "_") (loc $ Access (loc $ rawVar "_") lbl))
35
35
36−negative :: IParser ParseExpr
36+negative :: IParser ParseExpr'
37negative = do
37negative = do
38 (start, nTerm, end) <-
38 (start, nTerm, end) <-
39 located (try (char '-' >> notFollowedBy (char '.' <|> char '-')) >> term)
39 located (try (char '-' >> notFollowedBy (char '.' <|> char '-')) >> term)
40− let loc e = Location.at start end e
40+ let loc e = Annotation.at start end e
41− return (Binop "-" (loc $ Literal (Literal.IntNum 0)) nTerm)
41+ return (Binop "-" (loc $ Literal (L.IntNum 0)) nTerm)
42
42
43
43
44-------- Complex Terms --------
44-------- Complex Terms --------
45
45
46−listTerm :: IParser ParseExpr
46+listTerm :: IParser ParseExpr'
47listTerm = markdown' <|> braces (try range <|> ExplicitList <$> commaSep expr)
47listTerm = markdown' <|> braces (try range <|> ExplicitList <$> commaSep expr)
48 where
48 where
49 range = do
49 range = do
@@ -60,92 +60,93 @@ listTerm = markdown' <|> braces (try range <|> ExplicitList <$> commaSep expr)
60 span uid index =
60 span uid index =
61 "<span id=\"md-" ++ uid ++ "-" ++ show index ++ "\">{{ markdown interpolation is in the pipeline, but still needs more testing }}</span>"
61 "<span id=\"md-" ++ uid ++ "-" ++ show index ++ "\">{{ markdown interpolation is in the pipeline, but still needs more testing }}</span>"
62
62
63− interpolation uid md exprs = do
63+ interpolation uid exprs = do
64 try (string "{{")
64 try (string "{{")
65 e <- padded expr
65 e <- padded expr
66 string "}}"
66 string "}}"
67− return (md ++ span uid (length exprs), exprs ++ [e])
67+ return (span uid (length exprs), exprs ++ [e])
68
68
69−parensTerm :: IParser LParseExpr
69+parensTerm :: IParser ParseExpr
70parensTerm = try (parens opFn) <|> parens (tupleFn <|> parened)
70parensTerm = try (parens opFn) <|> parens (tupleFn <|> parened)
71 where
71 where
72 opFn = do
72 opFn = do
73 (start, op, end) <- located anyOp
73 (start, op, end) <- located anyOp
74− let loc = Location.at start end
74+ let loc = Annotation.at start end
75− return . loc . Lambda (PVar "x") . loc . Lambda (PVar "y") . loc $
75+ return . loc . Lambda (P.Var "x") . loc . Lambda (P.Var "y") . loc $
76− Binop op (loc $ Var "x") (loc $ Var "y")
76+ Binop op (loc $ rawVar "x") (loc $ rawVar "y")
77
77
78 tupleFn = do
78 tupleFn = do
79 let comma = char ',' <?> "comma ','"
79 let comma = char ',' <?> "comma ','"
80 (start, commas, end) <- located (comma >> many (whitespace >> comma))
80 (start, commas, end) <- located (comma >> many (whitespace >> comma))
81 let vars = map (('v':) . show) [ 0 .. length commas + 1 ]
81 let vars = map (('v':) . show) [ 0 .. length commas + 1 ]
82− loc = Location.at start end
82+ loc = Annotation.at start end
83 return $ foldr (\x e -> loc $ Lambda x e)
83 return $ foldr (\x e -> loc $ Lambda x e)
84− (loc . tuple $ map (loc . Var) vars) (map PVar vars)
84+ (loc . tuple $ map (loc . rawVar) vars) (map P.Var vars)
85
85
86 parened = do
86 parened = do
87 (start, es, end) <- located (commaSep expr)
87 (start, es, end) <- located (commaSep expr)
88 return $ case es of
88 return $ case es of
89 [e] -> e
89 [e] -> e
90− _ -> Location.at start end (tuple es)
90+ _ -> Annotation.at start end (tuple es)
91
91
92−recordTerm :: IParser LParseExpr
92+recordTerm :: IParser ParseExpr
93recordTerm = brackets $ choice [ misc, addLocation record ]
93recordTerm = brackets $ choice [ misc, addLocation record ]
94+ where
94− where field = do
95+ field = do
95− label <- rLabel
96+ label <- rLabel
96− patterns <- spacePrefix Pattern.term
97+ patterns <- spacePrefix Pattern.term
97− padded equals
98+ padded equals
98− body <- expr
99+ body <- expr
99− return (label, makeFunction patterns body)
100+ return (label, makeFunction patterns body)
100
101
101− record = Record <$> commaSep field
102+ record = Record <$> commaSep field
102
103
103− change = do
104+ change = do
104− lbl <- rLabel
105+ lbl <- rLabel
105− padded (string "<-")
106+ padded (string "<-")
106− (,) lbl <$> expr
107+ (,) lbl <$> expr
107
108
108− remove r = addLocation (string "-" >> whitespace >> Remove r <$> rLabel)
109+ remove r = addLocation (string "-" >> whitespace >> Remove r <$> rLabel)
109
110
110− insert r = addLocation $ do
111+ insert r = addLocation $ do
111− string "|" >> whitespace
112+ string "|" >> whitespace
112− Insert r <$> rLabel <*> (padded equals >> expr)
113+ Insert r <$> rLabel <*> (padded equals >> expr)
113
114
114− modify r = addLocation
115+ modify r =
115− (string "|" >> whitespace >> Modify r <$> commaSep1 change)
116+ addLocation (string "|" >> whitespace >> Modify r <$> commaSep1 change)
116
117
117− misc = try $ do
118+ misc = try $ do
118− record <- addLocation (Var <$> rLabel)
119+ record <- addLocation (rawVar <$> rLabel)
119− opt <- padded (optionMaybe (remove record))
120+ opt <- padded (optionMaybe (remove record))
120− case opt of
121+ case opt of
121− Just e -> try (insert e) <|> return e
122+ Just e -> try (insert e) <|> return e
122− Nothing -> try (insert record) <|> try (modify record)
123+ Nothing -> try (insert record) <|> try (modify record)
123
124
124
125
125−term :: IParser LParseExpr
126+term :: IParser ParseExpr
126term = addLocation (choice [ Literal <$> literal, listTerm, accessor, negative ])
127term = addLocation (choice [ Literal <$> literal, listTerm, accessor, negative ])
127 <|> accessible (addLocation varTerm <|> parensTerm <|> recordTerm)
128 <|> accessible (addLocation varTerm <|> parensTerm <|> recordTerm)
128 <?> "basic term (4, x, 'c', etc.)"
129 <?> "basic term (4, x, 'c', etc.)"
129
130
130-------- Applications --------
131-------- Applications --------
131
132
132−appExpr :: IParser LParseExpr
133+appExpr :: IParser ParseExpr
133appExpr = do
134appExpr = do
134 t <- term
135 t <- term
135 ts <- constrainedSpacePrefix term $ \str ->
136 ts <- constrainedSpacePrefix term $ \str ->
136 if null str then notFollowedBy (char '-') else return ()
137 if null str then notFollowedBy (char '-') else return ()
137 return $ case ts of
138 return $ case ts of
138 [] -> t
139 [] -> t
139− _ -> foldl' (\f x -> Location.merge f x $ App f x) t ts
140+ _ -> foldl' (\f x -> Annotation.merge f x $ App f x) t ts
140
141
141-------- Normal Expressions --------
142-------- Normal Expressions --------
142
143
143−binaryExpr :: IParser LParseExpr
144+binaryExpr :: IParser ParseExpr
144binaryExpr = binops appExpr lastExpr anyOp
145binaryExpr = binops appExpr lastExpr anyOp
145 where lastExpr = addLocation (choice [ ifExpr, letExpr, caseExpr ])
146 where lastExpr = addLocation (choice [ ifExpr, letExpr, caseExpr ])
146 <|> lambdaExpr
147 <|> lambdaExpr
147
148
148−ifExpr :: IParser ParseExpr
149+ifExpr :: IParser ParseExpr'
149ifExpr = reserved "if" >> whitespace >> (normal <|> multiIf)
150ifExpr = reserved "if" >> whitespace >> (normal <|> multiIf)
150 where
151 where
151 normal = do
152 normal = do
@@ -155,13 +156,13 @@ ifExpr = reserved "if" >> whitespace >> (normal <|> multiIf)
155 whitespace <?> "an 'else' branch" ; reserved "else" <?> "an 'else' branch" ; whitespace
156 whitespace <?> "an 'else' branch" ; reserved "else" <?> "an 'else' branch" ; whitespace
156 elseBranch <- expr
157 elseBranch <- expr
157 return $ MultiIf [(bool, thenBranch),
158 return $ MultiIf [(bool, thenBranch),
158− (Location.sameAs elseBranch (Literal . Literal.Boolean $ True), elseBranch)]
159+ (Annotation.sameAs elseBranch (Literal . L.Boolean $ True), elseBranch)]
159 multiIf = MultiIf <$> spaceSep1 iff
160 multiIf = MultiIf <$> spaceSep1 iff
160 where iff = do string "|" ; whitespace
161 where iff = do string "|" ; whitespace
161 b <- expr ; padded arrow
162 b <- expr ; padded arrow
162 (,) b <$> expr
163 (,) b <$> expr
163
164
164−lambdaExpr :: IParser LParseExpr
165+lambdaExpr :: IParser ParseExpr
165lambdaExpr = do char '\\' <|> char '\x03BB' <?> "anonymous function"
166lambdaExpr = do char '\\' <|> char '\x03BB' <?> "anonymous function"
166 whitespace
167 whitespace
167 args <- spaceSep1 Pattern.term
168 args <- spaceSep1 Pattern.term
@@ -172,14 +173,14 @@ lambdaExpr = do char '\\' <|> char '\x03BB' <?> "anonymous function"
172defSet :: IParser [ParseDef]
173defSet :: IParser [ParseDef]
173defSet = block (do d <- def ; whitespace ; return d)
174defSet = block (do d <- def ; whitespace ; return d)
174
175
175−letExpr :: IParser ParseExpr
176+letExpr :: IParser ParseExpr'
176letExpr = do
177letExpr = do
177 reserved "let" ; whitespace
178 reserved "let" ; whitespace
178 defs <- defSet
179 defs <- defSet
179 padded (reserved "in")
180 padded (reserved "in")
180 Let defs <$> expr
181 Let defs <$> expr
181
182
182−caseExpr :: IParser ParseExpr
183+caseExpr :: IParser ParseExpr'
183caseExpr = do
184caseExpr = do
184 reserved "case"; e <- padded expr; reserved "of"; whitespace
185 reserved "case"; e <- padded expr; reserved "of"; whitespace
185 Case e <$> (with <|> without)
186 Case e <$> (with <|> without)
@@ -189,35 +190,35 @@ caseExpr = do
189 with = brackets (semiSep1 (case_ <?> "cases { x -> ... }"))
190 with = brackets (semiSep1 (case_ <?> "cases { x -> ... }"))
190 without = block (do c <- case_ ; whitespace ; return c)
191 without = block (do c <- case_ ; whitespace ; return c)
191
192
192−expr :: IParser LParseExpr
193+expr :: IParser ParseExpr
193expr = addLocation (choice [ ifExpr, letExpr, caseExpr ])
194expr = addLocation (choice [ ifExpr, letExpr, caseExpr ])
194 <|> lambdaExpr
195 <|> lambdaExpr
195 <|> binaryExpr
196 <|> binaryExpr
196 <?> "an expression"
197 <?> "an expression"
197
198
198−defStart :: IParser [Pattern]
199+defStart :: IParser [P.Pattern]
199defStart =
200defStart =
200 choice [ do p1 <- try Pattern.term
201 choice [ do p1 <- try Pattern.term
201 infics p1 <|> func p1
202 infics p1 <|> func p1
202− , func =<< (PVar <$> parens symOp)
203+ , func =<< (P.Var <$> parens symOp)
203 , (:[]) <$> Pattern.expr
204 , (:[]) <$> Pattern.expr
204 ] <?> "the definition of a variable (x = ...)"
205 ] <?> "the definition of a variable (x = ...)"
205 where
206 where
206 func pattern =
207 func pattern =
207 case pattern of
208 case pattern of
208− PVar _ -> (pattern:) <$> spacePrefix Pattern.term
209+ P.Var _ -> (pattern:) <$> spacePrefix Pattern.term
209 _ -> do try (lookAhead (whitespace >> string "="))
210 _ -> do try (lookAhead (whitespace >> string "="))
210 return [pattern]
211 return [pattern]
211
212
212 infics p1 = do
213 infics p1 = do
213 o:p <- try (whitespace >> anyOp)
214 o:p <- try (whitespace >> anyOp)
214 p2 <- (whitespace >> Pattern.term)
215 p2 <- (whitespace >> Pattern.term)
215− return $ if o == '`' then [ PVar $ takeWhile (/='`') p, p1, p2 ]
216+ return $ if o == '`' then [ P.Var $ takeWhile (/='`') p, p1, p2 ]
216− else [ PVar (o:p), p1, p2 ]
217+ else [ P.Var (o:p), p1, p2 ]
217
218
218−makeFunction :: [Pattern] -> LParseExpr -> LParseExpr
219+makeFunction :: [P.Pattern] -> ParseExpr -> ParseExpr
219−makeFunction args body@(L s _) =
220+makeFunction args body@(A ann _) =
220− foldr (\arg body' -> L s $ Lambda arg body') body args
221+ foldr (\arg body' -> A ann $ Lambda arg body') body args
221
222
222definition :: IParser ParseDef
223definition :: IParser ParseDef
223definition = withPos $ do
224definition = withPos $ do
compiler/Parse/Helpers.hs+22−18
@@ -12,11 +12,12 @@ import Text.Parsec hiding (newline,spaces,State)
12import Text.Parsec.Indent
12import Text.Parsec.Indent
13import qualified Text.Parsec.Token as T
13import qualified Text.Parsec.Token as T
14
14
15−import SourceSyntax.Helpers as Help
15+import SourceSyntax.Annotation as Annotation
16−import SourceSyntax.Location as Location
16+import SourceSyntax.Declaration (Assoc)
17import SourceSyntax.Expression
17import SourceSyntax.Expression
18+import SourceSyntax.Helpers as Help
18import SourceSyntax.PrettyPrint
19import SourceSyntax.PrettyPrint
19−import SourceSyntax.Declaration (Assoc)
20+import SourceSyntax.Variable as Variable
20
21
21reserveds = [ "if", "then", "else"
22reserveds = [ "if", "then", "else"
22 , "case", "of"
23 , "case", "of"
@@ -168,7 +169,8 @@ betwixt a b c = do char a ; out <- c
168 char b <?> "closing '" ++ [b] ++ "'" ; return out
169 char b <?> "closing '" ++ [b] ++ "'" ; return out
169
170
170surround a z name p = do
171surround a z name p = do
172+ char a
171− char a ; v <- padded p
173+ v <- padded p
172 char z <?> unwords ["closing", name, show z]
174 char z <?> unwords ["closing", name, show z]
173 return v
175 return v
174
176
@@ -181,10 +183,10 @@ parens = surround '(' ')' "paren"
181brackets :: IParser a -> IParser a
183brackets :: IParser a -> IParser a
182brackets = surround '{' '}' "bracket"
184brackets = surround '{' '}' "bracket"
183
185
184−addLocation :: (Pretty a) => IParser a -> IParser (Location.Located a)
186+addLocation :: (Pretty a) => IParser a -> IParser (Annotation.Located a)
185addLocation expr = do
187addLocation expr = do
186 (start, e, end) <- located expr
188 (start, e, end) <- located expr
187− return (Location.at start end e)
189+ return (Annotation.at start end e)
188
190
189located :: IParser a -> IParser (SourcePos, a, SourcePos)
191located :: IParser a -> IParser (SourcePos, a, SourcePos)
190located p = do
192located p = do
@@ -193,10 +195,10 @@ located p = do
193 end <- getPosition
195 end <- getPosition
194 return (start, e, end)
196 return (start, e, end)
195
197
196−accessible :: IParser LParseExpr -> IParser LParseExpr
198+accessible :: IParser ParseExpr -> IParser ParseExpr
197accessible expr = do
199accessible expr = do
198 start <- getPosition
200 start <- getPosition
199− ce@(L _ e) <- expr
201+ ce@(A _ e) <- expr
200 let rest f = do
202 let rest f = do
201 let dot = char '.' >> notFollowedBy (char '.')
203 let dot = char '.' >> notFollowedBy (char '.')
202 access <- optionMaybe (try dot <?> "field access (e.g. List.map)")
204 access <- optionMaybe (try dot <?> "field access (e.g. List.map)")
@@ -205,10 +207,12 @@ accessible expr = do
205 Just _ -> accessible $ do
207 Just _ -> accessible $ do
206 v <- var <?> "field access (e.g. List.map)"
208 v <- var <?> "field access (e.g. List.map)"
207 end <- getPosition
209 end <- getPosition
208− return (Location.at start end (f v))
210+ return (Annotation.at start end (f v))
211+ case e of
212+ Var (Variable.Raw (c:cs))
209− case e of Var (c:cs) | isUpper c -> rest (\v -> Var (c:cs ++ '.':v))
213+ | isUpper c -> rest (\v -> rawVar (c:cs ++ '.':v))
210− | otherwise -> rest (Access ce)
214+ | otherwise -> rest (Access ce)
211− _ -> rest (Access ce)
215+ _ -> rest (Access ce)
212
216
213
217
214spaces :: IParser String
218spaces :: IParser String
@@ -268,7 +272,7 @@ ignoreUntil end = go
268 ignore p = const () <$> p
272 ignore p = const () <$> p
269 filler = choice [ try (ignore chr) <|> ignore str
273 filler = choice [ try (ignore chr) <|> ignore str
270 , ignore multiComment
274 , ignore multiComment
271− , ignore (markdown (\_ _ -> mzero))
275+ , ignore (markdown (\_ -> mzero))
272 , ignore anyChar
276 , ignore anyChar
273 ]
277 ]
274 go = choice [ Just <$> end
278 go = choice [ Just <$> end
@@ -301,15 +305,15 @@ anyUntilPos pos = go
301 True -> return []
305 True -> return []
302 False -> (:) <$> anyChar <*> go
306 False -> (:) <$> anyChar <*> go
303
307
304−markdown :: (String -> [a] -> IParser (String, [a])) -> IParser (String, [a])
308+markdown :: ([a] -> IParser (String, [a])) -> IParser (String, [a])
305−markdown interpolation = try (string "[markdown|") >> closeMarkdown "" []
309+markdown interpolation = try (string "[markdown|") >> closeMarkdown (++ "") []
306 where
310 where
307 closeMarkdown md stuff =
311 closeMarkdown md stuff =
308 choice [ do try (string "|]")
312 choice [ do try (string "|]")
309− return (md, stuff)
313+ return (md "", stuff)
310− , uncurry closeMarkdown =<< interpolation md stuff
314+ , (\(m,s) -> closeMarkdown (md . (m ++)) s) =<< interpolation stuff
311 , do c <- anyChar
315 , do c <- anyChar
312− closeMarkdown (md ++ [c]) stuff
316+ closeMarkdown (md . ([c]++)) stuff
313 ]
317 ]
314
318
315--str :: IParser String
319--str :: IParser String
compiler/Parse/Literal.hs+30−12
@@ -1,4 +1,4 @@
1−{-# OPTIONS_GHC -Wall -fno-warn-unused-do-bind #-}
1+{-# OPTIONS_GHC -W #-}
2module Parse.Literal (literal) where
2module Parse.Literal (literal) where
3
3
4import Control.Applicative ((<$>))
4import Control.Applicative ((<$>))
@@ -7,16 +7,34 @@ import Parse.Helpers
7import SourceSyntax.Literal
7import SourceSyntax.Literal
8
8
9literal :: IParser Literal
9literal :: IParser Literal
10−literal = num <|> (Str <$> str) <|> (Chr <$> chr)
10+literal = num <|> (Str <$> str) <|> (Chr <$> chr) <?> "literal"
11
11
12num :: IParser Literal
12num :: IParser Literal
13−num = fmap toLit (preNum <?> "number")
13+num = toLit <$> (number <?> "number")
14+ where
15+ toLit n
14− where toLit n | '.' `elem` n = FloatNum (read n)
16+ | any (`elem` ".eE") n = FloatNum (read n)
15− | otherwise = IntNum (read n)
17+ | otherwise = IntNum (read n)
16− preNum = concat <$> sequence [ option "" minus, many1 digit, option "" postNum ]
18+
19+ number = concat <$> sequence
20+ [ option "" minus
21+ , many1 digit
22+ , option "" decimals
23+ , option "" exponent ]
24+
25+ minus = try $ do
26+ string "-"
27+ lookAhead digit
28+ return "-"
29+
30+ decimals = do
17− postNum = do try $ lookAhead (string "." >> digit)
31+ try $ lookAhead (string "." >> digit)
18− string "."
32+ string "."
19− ('.':) <$> many1 digit
33+ n <- many1 digit
20− minus = try $ do string "-"
34+ return ('.' : n)
35+
36+ exponent = do
37+ string "e" <|> string "E"
38+ op <- option "" (string "+" <|> string "-")
21− lookAhead digit
39+ n <- many1 digit
22− return "-"
40+ return ('e' : op ++ n)
compiler/Parse/Module.hs+15−10
@@ -8,7 +8,7 @@ import Parse.Helpers
8import SourceSyntax.Module (ImportMethod(..), Imports)
8import SourceSyntax.Module (ImportMethod(..), Imports)
9
9
10varList :: IParser [String]
10varList :: IParser [String]
11−varList = parens $ commaSep1 (var <|> parens symOp)
11+varList = commaSep1 (var <|> parens symOp)
12
12
13getModuleName :: String -> Maybe String
13getModuleName :: String -> Maybe String
14getModuleName source =
14getModuleName source =
@@ -27,7 +27,7 @@ moduleDef = do
27 whitespace
27 whitespace
28 names <- dotSep1 capVar <?> "name of module"
28 names <- dotSep1 capVar <?> "name of module"
29 whitespace
29 whitespace
30− exports <- option [] varList
30+ exports <- option [] (parens varList)
31 whitespace <?> "reserved word 'where'"
31 whitespace <?> "reserved word 'where'"
32 reserved "where"
32 reserved "where"
33 return (names, exports)
33 return (names, exports)
@@ -38,17 +38,22 @@ imports = option [] ((:) <$> import' <*> many (try (freshLine >> import')))
38import' :: IParser (String, ImportMethod)
38import' :: IParser (String, ImportMethod)
39import' =
39import' =
40 do reserved "import"
40 do reserved "import"
41− whitespace
42− open <- optionMaybe (reserved "open")
43 whitespace
41 whitespace
44 name <- intercalate "." <$> dotSep1 capVar
42 name <- intercalate "." <$> dotSep1 capVar
45− case open of
46− Just _ -> return (name, Hiding [])
47− Nothing -> let how = try (whitespace >> (as' <|> importing'))
48− in (,) name <$> option (As name) how
43+ (,) name <$> option (As name) method
49 where
44 where
45+ method :: IParser ImportMethod
46+ method = try $ do whitespace
47+ as' <|> importing'
48+
50 as' :: IParser ImportMethod
49 as' :: IParser ImportMethod
50+ as' = do
51+ reserved "as"
52+ whitespace
51− as' = reserved "as" >> whitespace >> As <$> capVar <?> "alias for module"
53+ As <$> capVar <?> "alias for module"
52
54
53 importing' :: IParser ImportMethod
55 importing' :: IParser ImportMethod
56+ importing' =
57+ parens (choice [ const (Hiding []) <$> string ".."
58+ , Importing <$> varList
54− importing' = Importing <$> varList <?> "listing of imported values (x,y,z)"
59+ ] <?> "listing of imported values (x,y,z)")
compiler/Parse/Pattern.hs+29−27
@@ -3,57 +3,59 @@ module Parse.Pattern (term, expr) where
3
3
4import Control.Applicative ((<$>))
4import Control.Applicative ((<$>))
5import Data.Char (isUpper)
5import Data.Char (isUpper)
6−import Data.List (intercalate)
6+import qualified Data.List as List
7import Text.Parsec hiding (newline,spaces,State)
7import Text.Parsec hiding (newline,spaces,State)
8
8
9import Parse.Helpers
9import Parse.Helpers
10import Parse.Literal
10import Parse.Literal
11import SourceSyntax.Literal
11import SourceSyntax.Literal
12−import SourceSyntax.Pattern hiding (tuple, list)
13−import qualified SourceSyntax.Pattern as Pattern
12+import qualified SourceSyntax.Pattern as P
14
13
15−basic :: IParser Pattern
14+basic :: IParser P.Pattern
16basic = choice
15basic = choice
17− [ char '_' >> return PAnything
16+ [ char '_' >> return P.Anything
18 , do v <- var
17 , do v <- var
19 return $ case v of
18 return $ case v of
20− "True" -> PLiteral (Boolean True)
19+ "True" -> P.Literal (Boolean True)
21− "False" -> PLiteral (Boolean False)
20+ "False" -> P.Literal (Boolean False)
22− c:_ | isUpper c -> PData v []
21+ c:_ | isUpper c -> P.Data v []
23− _ -> PVar v
22+ _ -> P.Var v
24− , PLiteral <$> literal
23+ , P.Literal <$> literal
25 ]
24 ]
26
25
27−asPattern :: Pattern -> IParser Pattern
26+asPattern :: P.Pattern -> IParser P.Pattern
28asPattern pattern = do
27asPattern pattern = do
29 var <- optionMaybe (try (whitespace >> reserved "as" >> whitespace >> lowVar))
28 var <- optionMaybe (try (whitespace >> reserved "as" >> whitespace >> lowVar))
30 return $ case var of
29 return $ case var of
31− Just v -> PAlias v pattern
30+ Just v -> P.Alias v pattern
32 Nothing -> pattern
31 Nothing -> pattern
33
32
34−record :: IParser Pattern
33+record :: IParser P.Pattern
35−record = PRecord <$> brackets (commaSep1 lowVar)
34+record = P.Record <$> brackets (commaSep1 lowVar)
36
35
37−tuple :: IParser Pattern
36+tuple :: IParser P.Pattern
37+tuple = do
38−tuple = do ps <- parens (commaSep expr)
38+ ps <- parens (commaSep expr)
39− return $ case ps of { [p] -> p; _ -> Pattern.tuple ps }
39+ return $ case ps of
40+ [p] -> p
41+ _ -> P.tuple ps
40
42
41−list :: IParser Pattern
43+list :: IParser P.Pattern
42−list = Pattern.list <$> braces (commaSep expr)
44+list = P.list <$> braces (commaSep expr)
43
45
44−term :: IParser Pattern
46+term :: IParser P.Pattern
45term =
47term =
46 (choice [ record, tuple, list, basic ]) <?> "pattern"
48 (choice [ record, tuple, list, basic ]) <?> "pattern"
47
49
48−patternConstructor :: IParser Pattern
50+patternConstructor :: IParser P.Pattern
49patternConstructor = do
51patternConstructor = do
50− v <- intercalate "." <$> dotSep1 capVar
52+ v <- List.intercalate "." <$> dotSep1 capVar
51 case v of
53 case v of
52− "True" -> return $ PLiteral (Boolean True)
54+ "True" -> return $ P.Literal (Boolean True)
53− "False" -> return $ PLiteral (Boolean False)
55+ "False" -> return $ P.Literal (Boolean False)
54− _ -> PData v <$> spacePrefix term
56+ _ -> P.Data v <$> spacePrefix term
55
57
56−expr :: IParser Pattern
58+expr :: IParser P.Pattern
57expr = do
59expr = do
58 patterns <- consSep1 (patternConstructor <|> term)
60 patterns <- consSep1 (patternConstructor <|> term)
59− asPattern (foldr1 Pattern.cons patterns) <?> "pattern"
61+ asPattern (foldr1 P.cons patterns) <?> "pattern"
compiler/SourceSyntax/Annotation.hsnew file+74
@@ -0,0 +1,74 @@
1+{-# OPTIONS_GHC -W #-}
2+module SourceSyntax.Annotation where
3+
4+import qualified Text.Parsec.Pos as Parsec
5+import qualified Text.PrettyPrint as P
6+import SourceSyntax.PrettyPrint
7+
8+data Annotated annotation expr = A annotation expr
9+ deriving (Show)
10+
11+data Region
12+ = Span Position Position P.Doc
13+ | None P.Doc
14+ deriving (Show)
15+
16+data Position = Position
17+ { line :: Int
18+ , column :: Int
19+ } deriving (Show)
20+
21+type Located expr = Annotated Region expr
22+
23+none e = A (None (pretty e)) e
24+noneNoDocs e = A (None P.empty) e
25+
26+at :: (Pretty expr) => Parsec.SourcePos -> Parsec.SourcePos -> expr
27+ -> Annotated Region expr
28+at start end e =
29+ A (Span (position start) (position end) (pretty e)) e
30+ where
31+ position loc = Position (Parsec.sourceLine loc) (Parsec.sourceColumn loc)
32+
33+merge (A s1 _) (A s2 _) e =
34+ A (span (pretty e)) e
35+ where
36+ span = case (s1,s2) of
37+ (Span start _ _, Span _ end _) -> Span start end
38+ (Span start end _, _) -> Span start end
39+ (_, Span start end _) -> Span start end
40+ (_, _) -> None
41+
42+mergeOldDocs (A s1 _) (A s2 _) e =
43+ A span e
44+ where
45+ span = case (s1,s2) of
46+ (Span start _ d1, Span _ end d2) ->
47+ Span start end (P.vcat [d1, P.text "\n", d2])
48+
49+ (Span _ _ _, _) -> s1
50+ (_, Span _ _ _) -> s2
51+ (_, _) -> None P.empty
52+
53+sameAs :: Annotated a expr -> expr' -> Annotated a expr'
54+sameAs (A annotation _) expr = A annotation expr
55+
56+getRegionDocs region =
57+ case region of
58+ Span _ _ doc -> doc
59+ None doc -> doc
60+
61+instance Pretty Region where
62+ pretty span =
63+ case span of
64+ None _ -> P.empty
65+ Span start end _ ->
66+ P.text $
67+ case line start == line end of
68+ False -> "between lines " ++ show (line start) ++ " and " ++ show (line end)
69+ True -> "on line " ++ show (line end) ++ ", column " ++
70+ show (column start) ++ " to " ++ show (column end)
71+
72+instance Pretty e => Pretty (Annotated a e) where
73+ pretty (A _ e) = pretty e
74+
compiler/SourceSyntax/Declaration.hs+2−2
@@ -20,11 +20,11 @@ data Assoc = L | N | R
20
20
21data ParsePort
21data ParsePort
22 = PPAnnotation String T.Type
22 = PPAnnotation String T.Type
23− | PPDef String Expr.LParseExpr
23+ | PPDef String Expr.ParseExpr
24 deriving (Show)
24 deriving (Show)
25
25
26data Port
26data Port
27− = Out String Expr.LExpr T.Type
27+ = Out String Expr.Expr T.Type
28 | In String T.Type
28 | In String T.Type
29 deriving (Show)
29 deriving (Show)
30
30
compiler/SourceSyntax/Expression.hs+88−62
@@ -11,49 +11,54 @@ module SourceSyntax.Expression where
11import SourceSyntax.PrettyPrint
11import SourceSyntax.PrettyPrint
12import Text.PrettyPrint as P
12import Text.PrettyPrint as P
13import qualified SourceSyntax.Helpers as Help
13import qualified SourceSyntax.Helpers as Help
14−import qualified SourceSyntax.Location as Location
14+import qualified SourceSyntax.Annotation as Annotation
15import qualified SourceSyntax.Pattern as Pattern
15import qualified SourceSyntax.Pattern as Pattern
16import qualified SourceSyntax.Type as SrcType
16import qualified SourceSyntax.Type as SrcType
17import qualified SourceSyntax.Literal as Literal
17import qualified SourceSyntax.Literal as Literal
18+import qualified SourceSyntax.Variable as Variable
18
19
19---- GENERAL AST ----
20---- GENERAL AST ----
20
21
21−{-| This is a located expression, meaning it is tagged with info about where it
22−came from in the source code. Expr' is defined in terms of LExpr' so that the
23−location information does not need to be an extra field on every constructor.
24−-}
25−type LExpr' def = Location.Located (Expr' def)
26−
27{-| This is a fully general Abstract Syntax Tree (AST) for expressions. It has
22{-| This is a fully general Abstract Syntax Tree (AST) for expressions. It has
28"type holes" that allow us to enrich the AST with additional information as we
23"type holes" that allow us to enrich the AST with additional information as we
29−move through the compilation process. The type holes let us show these
24+move through the compilation process. The type holes are used to represent:
30−structural changes in the types. The only type hole right now is:
25+
26+ ann: Annotations for arbitrary expressions. Allows you to add information
27+ to the AST like position in source code or inferred types.
28+
29+ def: Definition style. The source syntax separates type annotations and
30+ definitions, but after parsing we check that they are well formed and
31+ collapse them.
31
32
32− def: Parsing allows two kinds of definitions (type annotations or definitions),
33+ var: Representation of variables. Starts as strings, but is later enriched
33− but later checks will see that they are well formed and combine them.
34+ with information about what module a variable came from.
34
35
35-}
36-}
37+type GeneralExpr annotation definition variable =
38+ Annotation.Annotated annotation (GeneralExpr' annotation definition variable)
39+
36−data Expr' def
40+data GeneralExpr' ann def var
37 = Literal Literal.Literal
41 = Literal Literal.Literal
38− | Var String
42+ | Var var
39− | Range (LExpr' def) (LExpr' def)
43+ | Range (GeneralExpr ann def var) (GeneralExpr ann def var)
40− | ExplicitList [LExpr' def]
44+ | ExplicitList [GeneralExpr ann def var]
41− | Binop String (LExpr' def) (LExpr' def)
45+ | Binop String (GeneralExpr ann def var) (GeneralExpr ann def var)
42− | Lambda Pattern.Pattern (LExpr' def)
46+ | Lambda Pattern.Pattern (GeneralExpr ann def var)
43− | App (LExpr' def) (LExpr' def)
47+ | App (GeneralExpr ann def var) (GeneralExpr ann def var)
44− | MultiIf [(LExpr' def,LExpr' def)]
48+ | MultiIf [(GeneralExpr ann def var,GeneralExpr ann def var)]
45− | Let [def] (LExpr' def)
49+ | Let [def] (GeneralExpr ann def var)
46− | Case (LExpr' def) [(Pattern.Pattern, LExpr' def)]
50+ | Case (GeneralExpr ann def var) [(Pattern.Pattern, GeneralExpr ann def var)]
47− | Data String [LExpr' def]
51+ | Data String [GeneralExpr ann def var]
48− | Access (LExpr' def) String
52+ | Access (GeneralExpr ann def var) String
49− | Remove (LExpr' def) String
53+ | Remove (GeneralExpr ann def var) String
50− | Insert (LExpr' def) String (LExpr' def)
54+ | Insert (GeneralExpr ann def var) String (GeneralExpr ann def var)
51− | Modify (LExpr' def) [(String, LExpr' def)]
55+ | Modify (GeneralExpr ann def var) [(String, GeneralExpr ann def var)]
52− | Record [(String, LExpr' def)]
56+ | Record [(String, GeneralExpr ann def var)]
53− | Markdown String String [LExpr' def]
57+ | Markdown String String [GeneralExpr ann def var]
54 -- for type checking and code gen only
58 -- for type checking and code gen only
55 | PortIn String SrcType.Type
59 | PortIn String SrcType.Type
56− | PortOut String SrcType.Type (LExpr' def)
60+ | PortOut String SrcType.Type (GeneralExpr ann def var)
61+ deriving (Show)
57
62
58
63
59---- SPECIALIZED ASTs ----
64---- SPECIALIZED ASTs ----
@@ -62,81 +67,100 @@ data Expr' def
62annotations and definitions, which is how they appear in source code and how
67annotations and definitions, which is how they appear in source code and how
63they are parsed.
68they are parsed.
64-}
69-}
65−type ParseExpr = Expr' ParseDef
70+type ParseExpr = GeneralExpr Annotation.Region ParseDef Variable.Raw
66−type LParseExpr = LExpr' ParseDef
71+type ParseExpr' = GeneralExpr' Annotation.Region ParseDef Variable.Raw
67
72
68data ParseDef
73data ParseDef
69− = Def Pattern.Pattern LParseExpr
74+ = Def Pattern.Pattern ParseExpr
70 | TypeAnnotation String SrcType.Type
75 | TypeAnnotation String SrcType.Type
71− deriving (Show)
76+ deriving (Show)
72
77
73{-| "Normal" expressions. When the compiler checks that type annotations and
78{-| "Normal" expressions. When the compiler checks that type annotations and
74ports are all paired with definitions in the appropriate order, it collapses
79ports are all paired with definitions in the appropriate order, it collapses
75them into a Def that is easier to work with in later phases of compilation.
80them into a Def that is easier to work with in later phases of compilation.
76-}
81-}
77−type LExpr = LExpr' Def
82+type Expr = GeneralExpr Annotation.Region Def Variable.Raw
78−type Expr = Expr' Def
83+type Expr' = GeneralExpr' Annotation.Region Def Variable.Raw
79
84
80−data Def = Definition Pattern.Pattern LExpr (Maybe SrcType.Type)
85+data Def = Definition Pattern.Pattern Expr (Maybe SrcType.Type)
81 deriving (Show)
86 deriving (Show)
82
87
83
88
89+
84---- UTILITIES ----
90---- UTILITIES ----
85
91
86−tuple :: [LExpr' def] -> Expr' def
92+rawVar :: String -> GeneralExpr' ann def Variable.Raw
93+rawVar x = Var (Variable.Raw x)
94+
95+tuple :: [GeneralExpr ann def var] -> GeneralExpr' ann def var
87tuple es = Data ("_Tuple" ++ show (length es)) es
96tuple es = Data ("_Tuple" ++ show (length es)) es
88
97
89−delist :: LExpr' def -> [LExpr' def]
98+delist :: GeneralExpr ann def var -> [GeneralExpr ann def var]
90−delist (Location.L _ (Data "::" [h,t])) = h : delist t
99+delist (Annotation.A _ (Data "::" [h,t])) = h : delist t
91delist _ = []
100delist _ = []
92
101
93saveEnvName :: String
102saveEnvName :: String
94saveEnvName = "_save_the_environment!!!"
103saveEnvName = "_save_the_environment!!!"
95
104
96−dummyLet :: Pretty def => [def] -> LExpr' def
105+dummyLet :: (Pretty def) => [def] -> GeneralExpr Annotation.Region def Variable.Raw
97dummyLet defs =
106dummyLet defs =
98− Location.none $ Let defs (Location.none $ Var saveEnvName)
107+ Annotation.none $ Let defs (Annotation.none $ rawVar saveEnvName)
99
108
100−instance Pretty def => Show (Expr' def) where
109+instance (Pretty def, Pretty var) => Pretty (GeneralExpr' ann def var) where
101− show = render . pretty
102−
103−instance Pretty def => Pretty (Expr' def) where
104 pretty expr =
110 pretty expr =
105 case expr of
111 case expr of
106 Literal lit -> pretty lit
112 Literal lit -> pretty lit
113+
107− Var x -> variable x
114+ Var x -> pretty x
115+
108 Range e1 e2 -> P.brackets (pretty e1 <> P.text ".." <> pretty e2)
116 Range e1 e2 -> P.brackets (pretty e1 <> P.text ".." <> pretty e2)
117+
109 ExplicitList es -> P.brackets (commaCat (map pretty es))
118 ExplicitList es -> P.brackets (commaCat (map pretty es))
119+
110− Binop "-" (Location.L _ (Literal (Literal.IntNum 0))) e ->
120+ Binop "-" (Annotation.A _ (Literal (Literal.IntNum 0))) e ->
111 P.text "-" <> prettyParens e
121 P.text "-" <> prettyParens e
122+
112 Binop op e1 e2 -> P.sep [ prettyParens e1 <+> P.text op', prettyParens e2 ]
123 Binop op e1 e2 -> P.sep [ prettyParens e1 <+> P.text op', prettyParens e2 ]
124+ where
113− where op' = if Help.isOp op then op else "`" ++ op ++ "`"
125+ op' = if Help.isOp op then op else "`" ++ op ++ "`"
126+
114 Lambda p e -> P.text "\\" <> args <+> P.text "->" <+> pretty body
127 Lambda p e -> P.text "\\" <> args <+> P.text "->" <+> pretty body
115 where
128 where
116− (ps,body) = collectLambdas (Location.none $ Lambda p e)
129+ (ps,body) = collectLambdas (Annotation.A undefined $ Lambda p e)
117 args = P.sep (map Pattern.prettyParens ps)
130 args = P.sep (map Pattern.prettyParens ps)
131+
118 App _ _ -> P.hang func 2 (P.sep args)
132 App _ _ -> P.hang func 2 (P.sep args)
133+ where
119− where func:args = map prettyParens (collectApps (Location.none expr))
134+ func:args = map prettyParens (collectApps (Annotation.A undefined expr))
135+
120− MultiIf branches -> P.text "if" $$ nest 3 (vcat $ map iff branches)
136+ MultiIf branches -> P.text "if" $$ nest 3 (vcat $ map iff branches)
121 where
137 where
122 iff (b,e) = P.text "|" <+> P.hang (pretty b <+> P.text "->") 2 (pretty e)
138 iff (b,e) = P.text "|" <+> P.hang (pretty b <+> P.text "->") 2 (pretty e)
139+
123 Let defs e ->
140 Let defs e ->
124 P.sep [ P.hang (P.text "let") 4 (P.vcat (map pretty defs))
141 P.sep [ P.hang (P.text "let") 4 (P.vcat (map pretty defs))
125 , P.text "in" <+> pretty e ]
142 , P.text "in" <+> pretty e ]
143+
126 Case e pats ->
144 Case e pats ->
127 P.hang pexpr 2 (P.vcat (map pretty' pats))
145 P.hang pexpr 2 (P.vcat (map pretty' pats))
128 where
146 where
129 pexpr = P.sep [ P.text "case" <+> pretty e, P.text "of" ]
147 pexpr = P.sep [ P.text "case" <+> pretty e, P.text "of" ]
130 pretty' (p,b) = pretty p <+> P.text "->" <+> pretty b
148 pretty' (p,b) = pretty p <+> P.text "->" <+> pretty b
149+
131 Data "::" [hd,tl] -> pretty hd <+> P.text "::" <+> pretty tl
150 Data "::" [hd,tl] -> pretty hd <+> P.text "::" <+> pretty tl
132 Data "[]" [] -> P.text "[]"
151 Data "[]" [] -> P.text "[]"
133 Data name es
152 Data name es
134 | Help.isTuple name -> P.parens (commaCat (map pretty es))
153 | Help.isTuple name -> P.parens (commaCat (map pretty es))
135 | otherwise -> P.hang (P.text name) 2 (P.sep (map prettyParens es))
154 | otherwise -> P.hang (P.text name) 2 (P.sep (map prettyParens es))
155+
136 Access e x -> prettyParens e <> P.text "." <> variable x
156 Access e x -> prettyParens e <> P.text "." <> variable x
157+
137 Remove e x -> P.braces (pretty e <+> P.text "-" <+> variable x)
158 Remove e x -> P.braces (pretty e <+> P.text "-" <+> variable x)
159+
138− Insert (Location.L _ (Remove e y)) x v ->
160+ Insert (Annotation.A _ (Remove e y)) x v ->
139− P.braces (pretty e <+> P.text "-" <+> variable y <+> P.text "|" <+> variable x <+> P.equals <+> pretty v)
161+ P.braces $ P.hsep [ pretty e, P.text "-", variable y, P.text "|"
162+ , variable x, P.equals, pretty v ]
163+
140 Insert e x v ->
164 Insert e x v ->
141 P.braces (pretty e <+> P.text "|" <+> variable x <+> P.equals <+> pretty v)
165 P.braces (pretty e <+> P.text "|" <+> variable x <+> P.equals <+> pretty v)
142
166
@@ -175,21 +199,23 @@ instance Pretty Def where
175 Nothing -> P.empty
199 Nothing -> P.empty
176 Just tipe -> pretty pattern <+> P.colon <+> pretty tipe
200 Just tipe -> pretty pattern <+> P.colon <+> pretty tipe
177
201
178−collectApps :: LExpr' def -> [LExpr' def]
202+collectApps :: GeneralExpr ann def var -> [GeneralExpr ann def var]
179−collectApps lexpr@(Location.L _ expr) =
203+collectApps annExpr@(Annotation.A _ expr) =
180 case expr of
204 case expr of
181 App a b -> collectApps a ++ [b]
205 App a b -> collectApps a ++ [b]
182− _ -> [lexpr]
206+ _ -> [annExpr]
183
207
184−collectLambdas :: LExpr' def -> ([Pattern.Pattern], LExpr' def)
208+collectLambdas :: GeneralExpr ann def var -> ([Pattern.Pattern], GeneralExpr ann def var)
185−collectLambdas lexpr@(Location.L _ expr) =
209+collectLambdas lexpr@(Annotation.A _ expr) =
186 case expr of
210 case expr of
187− Lambda pattern body -> (pattern : ps, body')
211+ Lambda pattern body ->
188− where (ps, body') = collectLambdas body
212+ let (ps, body') = collectLambdas body
213+ in (pattern : ps, body')
214+
189 _ -> ([], lexpr)
215 _ -> ([], lexpr)
190
216
191−prettyParens :: (Pretty def) => LExpr' def -> Doc
217+prettyParens :: (Pretty def, Pretty var) => GeneralExpr ann def var -> Doc
192−prettyParens (Location.L _ expr) = parensIf needed (pretty expr)
218+prettyParens (Annotation.A _ expr) = parensIf needed (pretty expr)
193 where
219 where
194 needed =
220 needed =
195 case expr of
221 case expr of
compiler/SourceSyntax/Helpers.hs+9
@@ -3,6 +3,15 @@ module SourceSyntax.Helpers where
3
3
4import qualified Data.Char as Char
4import qualified Data.Char as Char
5
5
6+splitDots :: String -> [String]
7+splitDots = go []
8+ where
9+ go vars str =
10+ case break (=='.') str of
11+ (x,_:rest) | isOp x -> vars ++ [x ++ '.' : rest]
12+ | otherwise -> go (vars ++ [x]) rest
13+ (x,[]) -> vars ++ [x]
14+
6brkt :: String -> String
15brkt :: String -> String
7brkt s = "{ " ++ s ++ " }"
16brkt s = "{ " ++ s ++ " }"
8
17
compiler/SourceSyntax/Location.hsdeleted−58
@@ -1,58 +0,0 @@
1−module SourceSyntax.Location where
2−
3−import Text.PrettyPrint
4−import SourceSyntax.PrettyPrint
5−import qualified Text.Parsec.Pos as Parsec
6−
7−data SrcPos = Pos { line :: Int, column :: Int }
8− deriving (Eq, Ord)
9−
10−data SrcSpan = Span SrcPos SrcPos String | NoSpan String
11− deriving (Eq, Ord)
12−
13−data Located e = L SrcSpan e
14− deriving (Eq, Ord)
15−
16−none e = L (NoSpan (render $ pretty e)) e
17−noneNoDocs = L (NoSpan "")
18−
19−at start end e = L (Span (Pos (Parsec.sourceLine start) (Parsec.sourceColumn start))
20− (Pos (Parsec.sourceLine end ) (Parsec.sourceColumn end ))
21− (render $ pretty e)) e
22−
23−merge (L s1 _) (L s2 _) e = L (span (render $ pretty e)) e
24− where span = case (s1,s2) of
25− (Span start _ _, Span _ end _) -> Span start end
26− (Span start end _, _) -> Span start end
27− (_, Span start end _) -> Span start end
28− (_, _) -> NoSpan
29−
30−mergeOldDocs (L s1 _) (L s2 _) e = L span e
31− where span = case (s1,s2) of
32− (Span start _ d1, Span _ end d2) -> Span start end (d1 ++ "\n\n" ++ d2)
33− (Span _ _ _, _) -> s1
34− (_, Span _ _ _) -> s2
35− (_, _) -> NoSpan ""
36−
37−sameAs (L s _) = L s
38−
39−
40−instance Show SrcPos where
41− show (Pos r c) = show r ++ "," ++ show c
42−
43−instance Show SrcSpan where
44− show span =
45− case span of
46− NoSpan _ -> ""
47− Span start end _ ->
48− case line start == line end of
49− False -> "between lines " ++ show (line start) ++ " and " ++ show (line end)
50− True -> "on line " ++ show (line end) ++ ", column " ++
51− show (column start) ++ " to " ++ show (column end)
52−
53−instance Show e => Show (Located e) where
54− show (L _ e) = show e
55−
56−instance Pretty a => Pretty (Located a) where
57− pretty (L _ e) = pretty e
58−
compiler/SourceSyntax/Module.hs+33−3
@@ -1,12 +1,15 @@
1−{-# OPTIONS_GHC -Wall #-}
1+{-# OPTIONS_GHC -W #-}
2module SourceSyntax.Module where
2module SourceSyntax.Module where
3
3
4import Data.Binary
4import Data.Binary
5+import qualified Data.List as List
5import qualified Data.Map as Map
6import qualified Data.Map as Map
6import Control.Applicative ((<$>), (<*>))
7import Control.Applicative ((<$>), (<*>))
8+import Text.PrettyPrint as P
7
9
8−import SourceSyntax.Expression (LExpr)
10+import SourceSyntax.Expression (Expr)
9import SourceSyntax.Declaration
11import SourceSyntax.Declaration
12+import SourceSyntax.PrettyPrint
10import SourceSyntax.Type
13import SourceSyntax.Type
11
14
12import qualified Elm.Internal.Version as Version
15import qualified Elm.Internal.Version as Version
@@ -21,6 +24,33 @@ type Imports = [(String, ImportMethod)]
21data ImportMethod = As String | Importing [String] | Hiding [String]
24data ImportMethod = As String | Importing [String] | Hiding [String]
22 deriving (Eq, Ord, Show)
25 deriving (Eq, Ord, Show)
23
26
27+instance (Pretty def) => Pretty (Module def) where
28+ pretty (Module modNames exports imports decls) =
29+ P.vcat [modul, P.text "", prettyImports, P.text "", prettyDecls]
30+ where
31+ prettyDecls = P.sep $ map pretty decls
32+
33+ modul = P.text "module" <+> moduleName <+> prettyExports <+> P.text "where"
34+ moduleName = P.text $ List.intercalate "." modNames
35+ prettyExports =
36+ case exports of
37+ [] -> P.empty
38+ _ -> P.parens . commaCat $ map P.text exports
39+
40+ prettyImports = P.vcat $ map prettyImport imports
41+
42+ prettyImport (name, method) =
43+ P.text "import" <+>
44+ case method of
45+ As alias ->
46+ P.text $ name ++ (if name == alias then "" else " as " ++ alias)
47+
48+ Importing values ->
49+ P.text name <+> P.parens (commaCat (map P.text values))
50+
51+ Hiding [] -> P.text ("open " ++ name)
52+ Hiding _ -> error "invalid import declaration"
53+
24instance Binary ImportMethod where
54instance Binary ImportMethod where
25 put method =
55 put method =
26 let put' n info = putWord8 n >> put info in
56 let put' n info = putWord8 n >> put info in
@@ -42,7 +72,7 @@ data MetadataModule =
42 , path :: FilePath
72 , path :: FilePath
43 , exports :: [String]
73 , exports :: [String]
44 , imports :: [(String, ImportMethod)]
74 , imports :: [(String, ImportMethod)]
45− , program :: LExpr
75+ , program :: Expr
46 , types :: Map.Map String Type
76 , types :: Map.Map String Type
47 , fixities :: [(Assoc, Int, String)]
77 , fixities :: [(Assoc, Int, String)]
48 , aliases :: [Alias]
78 , aliases :: [Alias]
compiler/SourceSyntax/Pattern.hs+30−26
@@ -7,50 +7,54 @@ import Text.PrettyPrint as PP
7import qualified Data.Set as Set
7import qualified Data.Set as Set
8import SourceSyntax.Literal as Literal
8import SourceSyntax.Literal as Literal
9
9
10+data Pattern
10−data Pattern = PData String [Pattern]
11+ = Data String [Pattern]
11− | PRecord [String]
12+ | Record [String]
12− | PAlias String Pattern
13+ | Alias String Pattern
13− | PVar String
14+ | Var String
14− | PAnything
15+ | Anything
15− | PLiteral Literal.Literal
16+ | Literal Literal.Literal
16− deriving (Eq, Ord, Show)
17+ deriving (Eq, Ord, Show)
17
18
18cons :: Pattern -> Pattern -> Pattern
19cons :: Pattern -> Pattern -> Pattern
19−cons h t = PData "::" [h,t]
20+cons h t = Data "::" [h,t]
20
21
21nil :: Pattern
22nil :: Pattern
22−nil = PData "[]" []
23+nil = Data "[]" []
23
24
24list :: [Pattern] -> Pattern
25list :: [Pattern] -> Pattern
25list = foldr cons nil
26list = foldr cons nil
26
27
27tuple :: [Pattern] -> Pattern
28tuple :: [Pattern] -> Pattern
28−tuple es = PData ("_Tuple" ++ show (length es)) es
29+tuple es = Data ("_Tuple" ++ show (length es)) es
30+
31+boundVarList :: Pattern -> [String]
32+boundVarList = Set.toList . boundVars
29
33
30boundVars :: Pattern -> Set.Set String
34boundVars :: Pattern -> Set.Set String
31boundVars pattern =
35boundVars pattern =
32 case pattern of
36 case pattern of
33− PVar x -> Set.singleton x
37+ Var x -> Set.singleton x
34− PAlias x p -> Set.insert x (boundVars p)
38+ Alias x p -> Set.insert x (boundVars p)
35− PData _ ps -> Set.unions (map boundVars ps)
39+ Data _ ps -> Set.unions (map boundVars ps)
36− PRecord fields -> Set.fromList fields
40+ Record fields -> Set.fromList fields
37− PAnything -> Set.empty
41+ Anything -> Set.empty
38− PLiteral _ -> Set.empty
42+ Literal _ -> Set.empty
39
43
40
44
41instance Pretty Pattern where
45instance Pretty Pattern where
42 pretty pattern =
46 pretty pattern =
43 case pattern of
47 case pattern of
44− PVar x -> variable x
48+ Var x -> variable x
45− PLiteral lit -> pretty lit
49+ Literal lit -> pretty lit
46− PRecord fs -> PP.braces (commaCat $ map variable fs)
50+ Record fs -> PP.braces (commaCat $ map variable fs)
47− PAlias x p -> prettyParens p <+> PP.text "as" <+> variable x
51+ Alias x p -> prettyParens p <+> PP.text "as" <+> variable x
48− PAnything -> PP.text "_"
52+ Anything -> PP.text "_"
49− PData "::" [hd,tl] -> parensIf isCons (pretty hd) <+> PP.text "::" <+> pretty tl
53+ Data "::" [hd,tl] -> parensIf isCons (pretty hd) <+> PP.text "::" <+> pretty tl
50 where isCons = case hd of
54 where isCons = case hd of
51− PData "::" _ -> True
55+ Data "::" _ -> True
52 _ -> False
56 _ -> False
53− PData name ps ->
57+ Data name ps ->
54 if Help.isTuple name then
58 if Help.isTuple name then
55 PP.parens . commaCat $ map pretty ps
59 PP.parens . commaCat $ map pretty ps
56 else hsep (PP.text name : map prettyParens ps)
60 else hsep (PP.text name : map prettyParens ps)
@@ -60,6 +64,6 @@ prettyParens pattern = parensIf needsThem (pretty pattern)
60 where
64 where
61 needsThem =
65 needsThem =
62 case pattern of
66 case pattern of
63− PData name (_:_) | not (Help.isTuple name) -> True
67+ Data name (_:_) | not (Help.isTuple name) -> True
64− PAlias _ _ -> True
68+ Alias _ _ -> True
65 _ -> False
69 _ -> False
compiler/SourceSyntax/PrettyPrint.hs+5
@@ -10,11 +10,16 @@ class Pretty a where
10instance Pretty () where
10instance Pretty () where
11 pretty () = empty
11 pretty () = empty
12
12
13+renderPretty :: (Pretty a) => a -> String
14+renderPretty e = render (pretty e)
15+
13commaCat docs = cat (punctuate comma docs)
16commaCat docs = cat (punctuate comma docs)
14commaSep docs = sep (punctuate comma docs)
17commaSep docs = sep (punctuate comma docs)
15
18
19+parensIf :: Bool -> Doc -> Doc
16parensIf bool doc = if bool then parens doc else doc
20parensIf bool doc = if bool then parens doc else doc
17
21
22+variable :: String -> Doc
18variable x =
23variable x =
19 if Help.isOp x then parens (text x)
24 if Help.isOp x then parens (text x)
20 else text (reprime x)
25 else text (reprime x)
compiler/SourceSyntax/Type.hs+3−6
@@ -1,18 +1,18 @@
1{-# OPTIONS_GHC -W #-}
1{-# OPTIONS_GHC -W #-}
2module SourceSyntax.Type where
2module SourceSyntax.Type where
3
3
4+import Control.Applicative ((<$>), (<*>))
4import Data.Binary
5import Data.Binary
5import qualified Data.Map as Map
6import qualified Data.Map as Map
6−import qualified SourceSyntax.Helpers as Help
7−import Control.Applicative ((<$>), (<*>))
8import SourceSyntax.PrettyPrint
7import SourceSyntax.PrettyPrint
8+import qualified SourceSyntax.Helpers as Help
9import Text.PrettyPrint as P
9import Text.PrettyPrint as P
10
10
11data Type = Lambda Type Type
11data Type = Lambda Type Type
12 | Var String
12 | Var String
13 | Data String [Type]
13 | Data String [Type]
14 | Record [(String,Type)] (Maybe String)
14 | Record [(String,Type)] (Maybe String)
15− deriving (Eq)
15+ deriving (Eq,Show)
16
16
17fieldMap :: [(String,a)] -> Map.Map String [a]
17fieldMap :: [(String,a)] -> Map.Map String [a]
18fieldMap fields =
18fieldMap fields =
@@ -27,9 +27,6 @@ listOf t = Data "_List" [t]
27tupleOf :: [Type] -> Type
27tupleOf :: [Type] -> Type
28tupleOf ts = Data ("_Tuple" ++ show (length ts)) ts
28tupleOf ts = Data ("_Tuple" ++ show (length ts)) ts
29
29
30−instance Show Type where
31− show = render . pretty
32−
33instance Pretty Type where
30instance Pretty Type where
34 pretty tipe =
31 pretty tipe =
35 case tipe of
32 case tipe of
compiler/SourceSyntax/Variable.hsnew file+11
@@ -0,0 +1,11 @@
1+
2+module SourceSyntax.Variable where
3+
4+import qualified Text.PrettyPrint as P
5+import SourceSyntax.PrettyPrint
6+
7+newtype Raw = Raw String
8+ deriving (Eq,Ord,Show)
9+
10+instance Pretty Raw where
11+ pretty (Raw var) = variable var
compiler/Transform/Canonicalize.hs+30−22
@@ -1,19 +1,21 @@
1−{-# OPTIONS_GHC -W #-}
1+{-# OPTIONS_GHC -Wall #-}
2module Transform.Canonicalize (interface, metadataModule) where
2module Transform.Canonicalize (interface, metadataModule) where
3
3
4import Control.Arrow ((***))
4import Control.Arrow ((***))
5import Control.Applicative (Applicative,(<$>),(<*>))
5import Control.Applicative (Applicative,(<$>),(<*>))
6import Control.Monad.Identity
6import Control.Monad.Identity
7−import qualified Data.Traversable as T
7+import qualified Data.Either as Either
8+import qualified Data.List as List
8import qualified Data.Map as Map
9import qualified Data.Map as Map
9import qualified Data.Set as Set
10import qualified Data.Set as Set
10−import qualified Data.List as List
11+import qualified Data.Traversable as T
11−import qualified Data.Either as Either
12−import SourceSyntax.Module
12+import SourceSyntax.Annotation as A
13import SourceSyntax.Expression
13import SourceSyntax.Expression
14−import SourceSyntax.Location as Loc
14+import SourceSyntax.Module
15+import SourceSyntax.PrettyPrint (pretty)
15import qualified SourceSyntax.Pattern as P
16import qualified SourceSyntax.Pattern as P
16import qualified SourceSyntax.Type as Type
17import qualified SourceSyntax.Type as Type
18+import qualified SourceSyntax.Variable as Var
17import Text.PrettyPrint as P
19import Text.PrettyPrint as P
18
20
19interface :: String -> ModuleInterface -> ModuleInterface
21interface :: String -> ModuleInterface -> ModuleInterface
@@ -55,7 +57,9 @@ metadataModule :: Interfaces -> MetadataModule -> Either [Doc] MetadataModule
55metadataModule ifaces modul =
57metadataModule ifaces modul =
56 do case filter (\m -> Map.notMember m ifaces) (map fst realImports) of
58 do case filter (\m -> Map.notMember m ifaces) (map fst realImports) of
57 [] -> Right ()
59 [] -> Right ()
58− missings -> Left [ P.text $ "The following imports were not found: " ++ List.intercalate ", " missings ]
60+ missings -> Left [ P.text $ "The following imports were not found: " ++ List.intercalate ", " missings ++
61+ "\n You may need to compile with the --make flag to detect modules you have written."
62+ ]
59 program' <- rename initialEnv (program modul)
63 program' <- rename initialEnv (program modul)
60 aliases' <- mapM (three3 renameType') (aliases modul)
64 aliases' <- mapM (three3 renameType') (aliases modul)
61 datatypes' <- mapM (three3 (mapM (two2 (mapM renameType')))) (datatypes modul)
65 datatypes' <- mapM (three3 (mapM (two2 (mapM renameType')))) (datatypes modul)
@@ -94,8 +98,7 @@ type Env = Map.Map String String
94
98
95extend :: Env -> P.Pattern -> Env
99extend :: Env -> P.Pattern -> Env
96extend env pattern = Map.union (Map.fromList (zip xs xs)) env
100extend env pattern = Map.union (Map.fromList (zip xs xs)) env
97− where xs = Set.toList (P.boundVars pattern)
101+ where xs = P.boundVarList pattern
98−
99
102
100replace :: String -> Env -> String -> Either String String
103replace :: String -> Env -> String -> Either String String
101replace variable env v =
104replace variable env v =
@@ -108,14 +111,18 @@ replace variable env v =
108 msg = if null matches then "" else
111 msg = if null matches then "" else
109 "\nClose matches include: " ++ List.intercalate ", " matches
112 "\nClose matches include: " ++ List.intercalate ", " matches
110
113
114+-- TODO: Var.Raw -> Var.Canonical
111−rename :: Env -> LExpr -> Either [Doc] LExpr
115+rename :: Env -> Expr -> Either [Doc] Expr
112−rename env (L s expr) =
116+rename env (A ann expr) =
113 let rnm = rename env
117 let rnm = rename env
114− throw err = Left [ P.text $ "Error " ++ show s ++ "\n" ++ err ]
118+ throw err = Left [ P.vcat [ P.text "Error" <+> pretty ann <> P.colon
119+ , P.text err
120+ ]
121+ ]
115 format = Either.either throw return
122 format = Either.either throw return
116− renameType' env = renameType (format . replace "variable" env)
123+ renameType' environ = renameType (format . replace "variable" environ)
117 in
124 in
118− L s <$>
125+ A ann <$>
119 case expr of
126 case expr of
120 Literal _ -> return expr
127 Literal _ -> return expr
121
128
@@ -153,7 +160,8 @@ rename env (L s expr) =
153 <*> rename env' body
160 <*> rename env' body
154 <*> T.traverse (renameType' env') mtipe
161 <*> T.traverse (renameType' env') mtipe
155
162
163+ -- TODO: Raw -> Canonical
156− Var x -> Var <$> format (replace "variable" env x)
164+ Var (Var.Raw x) -> rawVar <$> format (replace "variable" env x)
157
165
158 Data name es -> Data name <$> mapM rnm es
166 Data name es -> Data name <$> mapM rnm es
159
167
@@ -174,10 +182,10 @@ rename env (L s expr) =
174renamePattern :: Env -> P.Pattern -> Either String P.Pattern
182renamePattern :: Env -> P.Pattern -> Either String P.Pattern
175renamePattern env pattern =
183renamePattern env pattern =
176 case pattern of
184 case pattern of
177− P.PVar _ -> return pattern
185+ P.Var _ -> return pattern
178− P.PLiteral _ -> return pattern
186+ P.Literal _ -> return pattern
179− P.PRecord _ -> return pattern
187+ P.Record _ -> return pattern
180− P.PAnything -> return pattern
188+ P.Anything -> return pattern
181− P.PAlias x p -> P.PAlias x <$> renamePattern env p
189+ P.Alias x p -> P.Alias x <$> renamePattern env p
182− P.PData name ps -> P.PData <$> replace "pattern" env name
190+ P.Data name ps -> P.Data <$> replace "pattern" env name
183− <*> mapM (renamePattern env) ps
191+ <*> mapM (renamePattern env) ps
compiler/Transform/Check.hs+4−5
@@ -32,7 +32,7 @@ dupErr err x =
32
32
33duplicates :: [D.Declaration] -> [String]
33duplicates :: [D.Declaration] -> [String]
34duplicates decls =
34duplicates decls =
35− map msg (dups (portNames ++ concatMap getNames defPatterns)) ++
35+ map msg (dups (portNames ++ concatMap Pattern.boundVarList defPatterns)) ++
36 case mapM exprDups (portExprs ++ defExprs) of
36 case mapM exprDups (portExprs ++ defExprs) of
37 Left name -> [msg name]
37 Left name -> [msg name]
38 Right _ -> []
38 Right _ -> []
@@ -50,14 +50,13 @@ duplicates decls =
50 D.Out name expr _ -> (name, [expr])
50 D.Out name expr _ -> (name, [expr])
51 D.In name _ -> (name, [])
51 D.In name _ -> (name, [])
52
52
53− getNames = Set.toList . Pattern.boundVars
54−
55− exprDups :: E.LExpr -> Either String E.LExpr
53+ exprDups :: E.Expr -> Either String E.Expr
56 exprDups expr = Expr.crawlLet defsDups expr
54 exprDups expr = Expr.crawlLet defsDups expr
57
55
58 defsDups :: [E.Def] -> Either String [E.Def]
56 defsDups :: [E.Def] -> Either String [E.Def]
59 defsDups defs =
57 defsDups defs =
58+ let varsIn (E.Definition pattern _ _) = Pattern.boundVarList pattern in
60− case dups $ concatMap (\(E.Definition name _ _) -> getNames name) defs of
59+ case dups $ concatMap varsIn defs of
61 [] -> Right defs
60 [] -> Right defs
62 name:_ -> Left name
61 name:_ -> Left name
63
62
compiler/Transform/Declaration.hs+1−1
@@ -42,7 +42,7 @@ combineAnnotations = go
42
42
43 TypeAnnotation name tipe ->
43 TypeAnnotation name tipe ->
44 case defRest of
44 case defRest of
45− D.Definition (Def pat@(P.PVar name') expr) : rest | name == name' ->
45+ D.Definition (Def pat@(P.Var name') expr) : rest | name == name' ->
46 do expr' <- exprCombineAnnotations expr
46 do expr' <- exprCombineAnnotations expr
47 let def' = E.Definition pat expr' (Just tipe)
47 let def' = E.Definition pat expr' (Just tipe)
48 (:) (D.Definition def') <$> go rest
48 (:) (D.Definition def') <$> go rest
compiler/Transform/Definition.hs+1−1
@@ -16,7 +16,7 @@ combineAnnotations = go
16
16
17 go defs =
17 go defs =
18 case defs of
18 case defs of
19− TypeAnnotation name tipe : Def pat@(P.PVar name') expr : rest | name == name' ->
19+ TypeAnnotation name tipe : Def pat@(P.Var name') expr : rest | name == name' ->
20 do expr' <- exprCombineAnnotations expr
20 do expr' <- exprCombineAnnotations expr
21 let def = Definition pat expr' (Just tipe)
21 let def = Definition pat expr' (Just tipe)
22 (:) def <$> go rest
22 (:) def <$> go rest
compiler/Transform/Expression.hs+15−13
@@ -2,17 +2,19 @@
2module Transform.Expression (crawlLet, checkPorts) where
2module Transform.Expression (crawlLet, checkPorts) where
3
3
4import Control.Applicative ((<$>),(<*>))
4import Control.Applicative ((<$>),(<*>))
5+import SourceSyntax.Annotation ( Annotated(A) )
5import SourceSyntax.Expression
6import SourceSyntax.Expression
6−import SourceSyntax.Location
7+import SourceSyntax.Type (Type)
7−import qualified SourceSyntax.Type as ST
8
8
9−crawlLet :: ([def] -> Either a [def']) -> LExpr' def -> Either a (LExpr' def')
9+crawlLet :: ([def] -> Either a [def'])
10+ -> GeneralExpr ann def var
11+ -> Either a (GeneralExpr ann def' var)
10crawlLet = crawl (\_ _ -> return ()) (\_ _ -> return ())
12crawlLet = crawl (\_ _ -> return ()) (\_ _ -> return ())
11
13
12−checkPorts :: (String -> ST.Type -> Either a ())
14+checkPorts :: (String -> Type -> Either a ())
13− -> (String -> ST.Type -> Either a ())
15+ -> (String -> Type -> Either a ())
14− -> LExpr
16+ -> Expr
15− -> Either a LExpr
17+ -> Either a Expr
16checkPorts inCheck outCheck expr =
18checkPorts inCheck outCheck expr =
17 crawl inCheck outCheck (mapM checkDef) expr
19 crawl inCheck outCheck (mapM checkDef) expr
18 where
20 where
@@ -20,15 +22,15 @@ checkPorts inCheck outCheck expr =
20 do _ <- checkPorts inCheck outCheck body
22 do _ <- checkPorts inCheck outCheck body
21 return def
23 return def
22
24
23−crawl :: (String -> ST.Type -> Either a ())
25+crawl :: (String -> Type -> Either a ())
24− -> (String -> ST.Type -> Either a ())
26+ -> (String -> Type -> Either a ())
25 -> ([def] -> Either a [def'])
27 -> ([def] -> Either a [def'])
26− -> LExpr' def
28+ -> GeneralExpr ann def var
27− -> Either a (LExpr' def')
29+ -> Either a (GeneralExpr ann def' var)
28crawl portInCheck portOutCheck defsTransform = go
30crawl portInCheck portOutCheck defsTransform = go
29 where
31 where
30− go (L srcSpan expr) =
32+ go (A srcSpan expr) =
31− L srcSpan <$>
33+ A srcSpan <$>
32 case expr of
34 case expr of
33 Var x -> return (Var x)
35 Var x -> return (Var x)
34 Lambda p e -> Lambda p <$> go e
36 Lambda p e -> Lambda p <$> go e
compiler/Transform/SafeNames.hs+21−16
@@ -2,38 +2,43 @@
2module Transform.SafeNames (metadataModule) where
2module Transform.SafeNames (metadataModule) where
3
3
4import Control.Arrow (first, (***))
4import Control.Arrow (first, (***))
5−import SourceSyntax.Expression
5+import qualified Data.List as List
6−import SourceSyntax.Location
7−import SourceSyntax.Module
8−import SourceSyntax.Pattern
9import qualified Data.Set as Set
6import qualified Data.Set as Set
7+
10import qualified Parse.Helpers as PHelp
8import qualified Parse.Helpers as PHelp
9+import SourceSyntax.Annotation
10+import SourceSyntax.Expression
11+import qualified SourceSyntax.Helpers as SHelp
12+import SourceSyntax.Module
13+import qualified SourceSyntax.Pattern as P
14+import qualified SourceSyntax.Variable as Variable
11
15
12var :: String -> String
16var :: String -> String
13−var = dereserve . deprime
17+var = List.intercalate "." . map (dereserve . deprime) . SHelp.splitDots
14 where
18 where
15 deprime = map (\c -> if c == '\'' then '$' else c)
19 deprime = map (\c -> if c == '\'' then '$' else c)
16 dereserve x = case Set.member x PHelp.jsReserveds of
20 dereserve x = case Set.member x PHelp.jsReserveds of
17 False -> x
21 False -> x
18 True -> "$" ++ x
22 True -> "$" ++ x
19
23
20−pattern :: Pattern -> Pattern
24+pattern :: P.Pattern -> P.Pattern
21pattern pat =
25pattern pat =
22 case pat of
26 case pat of
23− PVar x -> PVar (var x)
27+ P.Var x -> P.Var (var x)
24− PLiteral _ -> pat
28+ P.Literal _ -> pat
25− PRecord fs -> PRecord (map var fs)
29+ P.Record fs -> P.Record (map var fs)
26− PAnything -> pat
30+ P.Anything -> pat
27− PAlias x p -> PAlias (var x) (pattern p)
31+ P.Alias x p -> P.Alias (var x) (pattern p)
28− PData name ps -> PData name (map pattern ps)
32+ P.Data name ps -> P.Data name (map pattern ps)
29
33
34+-- TODO: should be "normal expression" -> "expression for JS generation"
30−expression :: LExpr -> LExpr
35+expression :: Expr -> Expr
31−expression (L loc expr) =
36+expression (A ann expr) =
32 let f = expression in
37 let f = expression in
33− L loc $
38+ A ann $
34 case expr of
39 case expr of
35 Literal _ -> expr
40 Literal _ -> expr
36− Var x -> Var (var x)
41+ Var (Variable.Raw x) -> rawVar (var x)
37 Range e1 e2 -> Range (f e1) (f e2)
42 Range e1 e2 -> Range (f e1) (f e2)
38 ExplicitList es -> ExplicitList (map f es)
43 ExplicitList es -> ExplicitList (map f es)
39 Binop op e1 e2 -> Binop op (f e1) (f e2)
44 Binop op e1 e2 -> Binop op (f e1) (f e2)
compiler/Transform/SortDefinitions.hs+18−17
@@ -3,23 +3,24 @@ module Transform.SortDefinitions (sortDefs) where
3
3
4import Control.Monad.State
4import Control.Monad.State
5import Control.Applicative ((<$>),(<*>))
5import Control.Applicative ((<$>),(<*>))
6+import qualified Data.Graph as Graph
6import qualified Data.Map as Map
7import qualified Data.Map as Map
8+import qualified Data.Maybe as Maybe
9+import qualified Data.Set as Set
10+import SourceSyntax.Annotation
7import SourceSyntax.Expression
11import SourceSyntax.Expression
8−import SourceSyntax.Location
9import qualified SourceSyntax.Pattern as P
12import qualified SourceSyntax.Pattern as P
10−import qualified Data.Graph as Graph
13+import qualified SourceSyntax.Variable as V
11−import qualified Data.Set as Set
12−import qualified Data.Maybe as Maybe
13
14
14ctors :: P.Pattern -> [String]
15ctors :: P.Pattern -> [String]
15ctors pattern =
16ctors pattern =
16 case pattern of
17 case pattern of
17− P.PVar _ -> []
18+ P.Var _ -> []
18− P.PAlias _ p -> ctors p
19+ P.Alias _ p -> ctors p
19− P.PData ctor ps -> ctor : concatMap ctors ps
20+ P.Data ctor ps -> ctor : concatMap ctors ps
20− P.PRecord _ -> []
21+ P.Record _ -> []
21− P.PAnything -> []
22+ P.Anything -> []
22− P.PLiteral _ -> []
23+ P.Literal _ -> []
23
24
24free :: String -> State (Set.Set String) ()
25free :: String -> State (Set.Set String) ()
25free x = modify (Set.insert x)
26free x = modify (Set.insert x)
@@ -27,15 +28,15 @@ free x = modify (Set.insert x)
27bound :: Set.Set String -> State (Set.Set String) ()
28bound :: Set.Set String -> State (Set.Set String) ()
28bound boundVars = modify (\freeVars -> Set.difference freeVars boundVars)
29bound boundVars = modify (\freeVars -> Set.difference freeVars boundVars)
29
30
30−sortDefs :: LExpr -> LExpr
31+sortDefs :: Expr -> Expr
31sortDefs expr = evalState (reorder expr) Set.empty
32sortDefs expr = evalState (reorder expr) Set.empty
32
33
33−reorder :: LExpr -> State (Set.Set String) LExpr
34+reorder :: Expr -> State (Set.Set String) Expr
34−reorder (L s expr) =
35+reorder (A ann expr) =
35− L s <$>
36+ A ann <$>
36 case expr of
37 case expr of
37 -- Be careful adding and restricting freeVars
38 -- Be careful adding and restricting freeVars
38− Var x -> free x >> return expr
39+ Var (V.Raw x) -> free x >> return expr
39
40
40 Lambda p e ->
41 Lambda p e ->
41 uncurry Lambda <$> bindingReorder (p,e)
42 uncurry Lambda <$> bindingReorder (p,e)
@@ -103,11 +104,11 @@ reorder (L s expr) =
103 bound (P.boundVars pattern)
104 bound (P.boundVars pattern)
104 mapM free (ctors pattern)
105 mapM free (ctors pattern)
105
106
106− let L _ let' = foldr (\ds bod -> L s (Let ds bod)) body' defss
107+ let A _ let' = foldr (\ds bod -> A ann (Let ds bod)) body' defss
107
108
108 return let'
109 return let'
109
110
110−bindingReorder :: (P.Pattern, LExpr) -> State (Set.Set String) (P.Pattern, LExpr)
111+bindingReorder :: (P.Pattern, Expr) -> State (Set.Set String) (P.Pattern, Expr)
111bindingReorder (pattern,expr) =
112bindingReorder (pattern,expr) =
112 do expr' <- reorder expr
113 do expr' <- reorder expr
113 bound (P.boundVars pattern)
114 bound (P.boundVars pattern)
compiler/Transform/Substitute.hs+8−6
@@ -2,14 +2,16 @@
2module Transform.Substitute (subst) where
2module Transform.Substitute (subst) where
3
3
4import Control.Arrow (second, (***))
4import Control.Arrow (second, (***))
5+import qualified Data.Set as Set
6+
7+import SourceSyntax.Annotation
5import SourceSyntax.Expression
8import SourceSyntax.Expression
6−import SourceSyntax.Location
7import qualified SourceSyntax.Pattern as Pattern
9import qualified SourceSyntax.Pattern as Pattern
8−import qualified Data.Set as Set
10+import qualified SourceSyntax.Variable as V
9
11
10−subst :: String -> Expr -> Expr -> Expr
12+subst :: String -> Expr' -> Expr' -> Expr'
11subst old new expr =
13subst old new expr =
12− let f (L s e) = L s (subst old new e) in
14+ let f (A a e) = A a (subst old new e) in
13 case expr of
15 case expr of
14 Range e1 e2 -> Range (f e1) (f e2)
16 Range e1 e2 -> Range (f e1) (f e2)
15 ExplicitList es -> ExplicitList (map f es)
17 ExplicitList es -> ExplicitList (map f es)
@@ -28,7 +30,7 @@ subst old new expr =
28 anyShadow =
30 anyShadow =
29 any (Set.member old . Pattern.boundVars) [ p | Definition p _ _ <- defs ]
31 any (Set.member old . Pattern.boundVars) [ p | Definition p _ _ <- defs ]
30
32
31− Var x -> if x == old then new else expr
33+ Var (V.Raw x) -> if x == old then new else expr
32 Case e cases -> Case (f e) $ map (second f) cases
34 Case e cases -> Case (f e) $ map (second f) cases
33 Data name es -> Data name (map f es)
35 Data name es -> Data name (map f es)
34 Access e x -> Access (f e) x
36 Access e x -> Access (f e) x
@@ -39,4 +41,4 @@ subst old new expr =
39 Literal _ -> expr
41 Literal _ -> expr
40 Markdown uid md es -> Markdown uid md (map f es)
42 Markdown uid md es -> Markdown uid md (map f es)
41 PortIn name st -> PortIn name st
43 PortIn name st -> PortIn name st
42− PortOut name st signal -> PortOut name st (f signal)
44+ PortOut name st signal -> PortOut name st (f signal)
compiler/Type/Constrain/Declaration.hs+23−23
@@ -1,62 +1,62 @@
1{-# OPTIONS_GHC -Wall #-}
1{-# OPTIONS_GHC -Wall #-}
2module Type.Constrain.Declaration where
2module Type.Constrain.Declaration where
3
3
4+import qualified SourceSyntax.Annotation as A
4−import SourceSyntax.Declaration
5+import qualified SourceSyntax.Declaration as D
5import qualified SourceSyntax.Expression as E
6import qualified SourceSyntax.Expression as E
6−import qualified SourceSyntax.Location as L
7import qualified SourceSyntax.Pattern as P
7import qualified SourceSyntax.Pattern as P
8import qualified SourceSyntax.Type as T
8import qualified SourceSyntax.Type as T
9
9
10−toExpr :: [Declaration] -> [E.Def]
10+toExpr :: [D.Declaration] -> [E.Def]
11toExpr = concatMap toDefs
11toExpr = concatMap toDefs
12
12
13−toDefs :: Declaration -> [E.Def]
13+toDefs :: D.Declaration -> [E.Def]
14toDefs decl =
14toDefs decl =
15 case decl of
15 case decl of
16− Definition def -> [def]
16+ D.Definition def -> [def]
17
17
18− Datatype name tvars constructors -> concatMap toDefs' constructors
18+ D.Datatype name tvars constructors -> concatMap toDefs' constructors
19 where
19 where
20 toDefs' (ctor, tipes) =
20 toDefs' (ctor, tipes) =
21 let vars = take (length tipes) arguments
21 let vars = take (length tipes) arguments
22 tbody = T.Data name $ map T.Var tvars
22 tbody = T.Data name $ map T.Var tvars
23− body = L.none . E.Data ctor $ map (L.none . E.Var) vars
23+ body = A.none . E.Data ctor $ map (A.none . E.rawVar) vars
24 in [ definition ctor (buildFunction body vars) (foldr T.Lambda tbody tipes) ]
24 in [ definition ctor (buildFunction body vars) (foldr T.Lambda tbody tipes) ]
25
25
26− TypeAlias name _ tipe@(T.Record fields ext) ->
26+ D.TypeAlias name _ tipe@(T.Record fields ext) ->
27 [ definition name (buildFunction record vars) (foldr T.Lambda tipe args) ]
27 [ definition name (buildFunction record vars) (foldr T.Lambda tipe args) ]
28 where
28 where
29 args = map snd fields ++ maybe [] (\x -> [T.Var x]) ext
29 args = map snd fields ++ maybe [] (\x -> [T.Var x]) ext
30
30
31− var = L.none . E.Var
31+ var = A.none . E.rawVar
32 vars = take (length args) arguments
32 vars = take (length args) arguments
33
33
34 efields = zip (map fst fields) (map var vars)
34 efields = zip (map fst fields) (map var vars)
35 record = case ext of
35 record = case ext of
36− Nothing -> L.none $ E.Record efields
36+ Nothing -> A.none $ E.Record efields
37− Just _ -> foldl (\r (f,v) -> L.none $ E.Insert r f v) (var $ last vars) efields
37+ Just _ -> foldl (\r (f,v) -> A.none $ E.Insert r f v) (var $ last vars) efields
38
38
39 -- Type aliases must be added to an extended equality dictionary,
39 -- Type aliases must be added to an extended equality dictionary,
40 -- but they do not require any basic constraints.
40 -- but they do not require any basic constraints.
41− TypeAlias _ _ _ -> []
41+ D.TypeAlias _ _ _ -> []
42
42
43− Port port ->
43+ D.Port port ->
44 case port of
44 case port of
45− Out name expr@(L.L s _) tipe ->
45+ D.Out name expr@(A.A s _) tipe ->
46− [ definition name (L.L s $ E.PortOut name tipe expr) tipe ]
46+ [ definition name (A.A s $ E.PortOut name tipe expr) tipe ]
47− In name tipe ->
47+ D.In name tipe ->
48− [ definition name (L.none $ E.PortIn name tipe) tipe ]
48+ [ definition name (A.none $ E.PortIn name tipe) tipe ]
49
49
50 -- no constraints are needed for fixity declarations
50 -- no constraints are needed for fixity declarations
51− Fixity _ _ _ -> []
51+ D.Fixity _ _ _ -> []
52
52
53
53
54arguments :: [String]
54arguments :: [String]
55arguments = map (:[]) ['a'..'z'] ++ map (\n -> "_" ++ show (n :: Int)) [1..]
55arguments = map (:[]) ['a'..'z'] ++ map (\n -> "_" ++ show (n :: Int)) [1..]
56
56
57−buildFunction :: E.LExpr -> [String] -> E.LExpr
57+buildFunction :: E.Expr -> [String] -> E.Expr
58−buildFunction body@(L.L s _) vars =
58+buildFunction body@(A.A s _) vars =
59− foldr (\p e -> L.L s (E.Lambda p e)) body (map P.PVar vars)
59+ foldr (\p e -> A.A s (E.Lambda p e)) body (map P.Var vars)
60
60
61−definition :: String -> E.LExpr -> T.Type -> E.Def
61+definition :: String -> E.Expr -> T.Type -> E.Def
62−definition name expr tipe = E.Definition (P.PVar name) expr (Just tipe)
62+definition name expr tipe = E.Definition (P.Var name) expr (Just tipe)
compiler/Type/Constrain/Expression.hs+38−37
@@ -1,44 +1,45 @@
1{-# OPTIONS_GHC -W #-}
1{-# OPTIONS_GHC -W #-}
2module Type.Constrain.Expression where
2module Type.Constrain.Expression where
3
3
4−import qualified Data.List as List
5−import qualified Data.Map as Map
6−import qualified Data.Set as Set
7import Control.Applicative ((<$>))
4import Control.Applicative ((<$>))
8import qualified Control.Monad as Monad
5import qualified Control.Monad as Monad
9import Control.Monad.Error
6import Control.Monad.Error
7+import qualified Data.List as List
8+import qualified Data.Map as Map
10import qualified Text.PrettyPrint as PP
9import qualified Text.PrettyPrint as PP
11
10
12−import SourceSyntax.Location as Loc
11+import SourceSyntax.Annotation as Ann
13−import SourceSyntax.Pattern (Pattern(PVar), boundVars)
14import SourceSyntax.Expression
12import SourceSyntax.Expression
15−import qualified SourceSyntax.Type as SrcT
13+import qualified SourceSyntax.Pattern as P
14+import qualified SourceSyntax.Type as ST
15+import qualified SourceSyntax.Variable as V
16import Type.Type hiding (Descriptor(..))
16import Type.Type hiding (Descriptor(..))
17import Type.Fragment
17import Type.Fragment
18import qualified Type.Environment as Env
18import qualified Type.Environment as Env
19import qualified Type.Constrain.Literal as Literal
19import qualified Type.Constrain.Literal as Literal
20import qualified Type.Constrain.Pattern as Pattern
20import qualified Type.Constrain.Pattern as Pattern
21
21
22−constrain :: Env.Environment -> LExpr -> Type -> ErrorT [PP.Doc] IO TypeConstraint
22+constrain :: Env.Environment -> Expr -> Type -> ErrorT [PP.Doc] IO TypeConstraint
23−constrain env (L span expr) tipe =
23+constrain env (A region expr) tipe =
24 let list t = Env.get env Env.types "_List" <| t
24 let list t = Env.get env Env.types "_List" <| t
25− and = L span . CAnd
25+ and = A region . CAnd
26− true = L span CTrue
26+ true = A region CTrue
27− t1 === t2 = L span (CEqual t1 t2)
27+ t1 === t2 = A region (CEqual t1 t2)
28− x <? t = L span (CInstance x t)
28+ x <? t = A region (CInstance x t)
29− clet schemes c = L span (CLet schemes c)
29+ clet schemes c = A region (CLet schemes c)
30 in
30 in
31 case expr of
31 case expr of
32− Literal lit -> liftIO $ Literal.constrain env span lit tipe
32+ Literal lit -> liftIO $ Literal.constrain env region lit tipe
33
33
34+ Var (V.Raw name)
34− Var name | name == saveEnvName -> return (L span CSaveEnv)
35+ | name == saveEnvName -> return (A region CSaveEnv)
35− | otherwise -> return (name <? tipe)
36+ | otherwise -> return (name <? tipe)
36
37
37 Range lo hi ->
38 Range lo hi ->
38− exists $ \x -> do
39+ existsNumber $ \n -> do
39− clo <- constrain env lo x
40+ clo <- constrain env lo n
40− chi <- constrain env hi x
41+ chi <- constrain env hi n
41− return $ and [clo, chi, list x === tipe]
42+ return $ and [clo, chi, list n === tipe]
42
43
43 ExplicitList exprs ->
44 ExplicitList exprs ->
44 exists $ \x -> do
45 exists $ \x -> do
@@ -55,7 +56,7 @@ constrain env (L span expr) tipe =
55 Lambda p e ->
56 Lambda p e ->
56 exists $ \t1 ->
57 exists $ \t1 ->
57 exists $ \t2 -> do
58 exists $ \t2 -> do
58− fragment <- try span $ Pattern.constrain env p t1
59+ fragment <- try region $ Pattern.constrain env p t1
59 c2 <- constrain env e t2
60 c2 <- constrain env e t2
60 let c = ex (vars fragment) (clet [monoscheme (typeEnv fragment)]
61 let c = ex (vars fragment) (clet [monoscheme (typeEnv fragment)]
61 (typeConstraint fragment /\ c2 ))
62 (typeConstraint fragment /\ c2 ))
@@ -79,7 +80,7 @@ constrain env (L span expr) tipe =
79 exists $ \t -> do
80 exists $ \t -> do
80 ce <- constrain env exp t
81 ce <- constrain env exp t
81 let branch (p,e) = do
82 let branch (p,e) = do
82− fragment <- try span $ Pattern.constrain env p t
83+ fragment <- try region $ Pattern.constrain env p t
83 clet [toScheme fragment] <$> constrain env e tipe
84 clet [toScheme fragment] <$> constrain env e tipe
84 and . (:) ce <$> mapM branch branches
85 and . (:) ce <$> mapM branch branches
85
86
@@ -112,11 +113,11 @@ constrain env (L span expr) tipe =
112 Modify e fields ->
113 Modify e fields ->
113 exists $ \t -> do
114 exists $ \t -> do
114 oldVars <- forM fields $ \_ -> liftIO (var Flexible)
115 oldVars <- forM fields $ \_ -> liftIO (var Flexible)
115− let oldFields = SrcT.fieldMap (zip (map fst fields) (map VarN oldVars))
116+ let oldFields = ST.fieldMap (zip (map fst fields) (map VarN oldVars))
116 cOld <- ex oldVars <$> constrain env e (record oldFields t)
117 cOld <- ex oldVars <$> constrain env e (record oldFields t)
117
118
118 newVars <- forM fields $ \_ -> liftIO (var Flexible)
119 newVars <- forM fields $ \_ -> liftIO (var Flexible)
119− let newFields = SrcT.fieldMap (zip (map fst fields) (map VarN newVars))
120+ let newFields = ST.fieldMap (zip (map fst fields) (map VarN newVars))
120 let cNew = tipe === record newFields t
121 let cNew = tipe === record newFields t
121
122
122 cs <- zipWithM (constrain env) (map snd fields) (map VarN newVars)
123 cs <- zipWithM (constrain env) (map snd fields) (map VarN newVars)
@@ -126,7 +127,7 @@ constrain env (L span expr) tipe =
126 Record fields ->
127 Record fields ->
127 do vars <- forM fields $ \_ -> liftIO (var Flexible)
128 do vars <- forM fields $ \_ -> liftIO (var Flexible)
128 cs <- zipWithM (constrain env) (map snd fields) (map VarN vars)
129 cs <- zipWithM (constrain env) (map snd fields) (map VarN vars)
129− let fields' = SrcT.fieldMap (zip (map fst fields) (map VarN vars))
130+ let fields' = ST.fieldMap (zip (map fst fields) (map VarN vars))
130 recordType = record fields' (TermN EmptyRecord1)
131 recordType = record fields' (TermN EmptyRecord1)
131 return . ex vars . and $ tipe === recordType : cs
132 return . ex vars . and $ tipe === recordType : cs
132
133
@@ -158,14 +159,14 @@ constrainDef env info (Definition pattern expr maybeTipe) =
158 do rigidVars <- forM qs (\_ -> liftIO $ var Rigid) -- Some mistake may be happening here.
159 do rigidVars <- forM qs (\_ -> liftIO $ var Rigid) -- Some mistake may be happening here.
159 -- Currently, qs is always [].
160 -- Currently, qs is always [].
160 case (pattern, maybeTipe) of
161 case (pattern, maybeTipe) of
161− (PVar name, Just tipe) -> do
162+ (P.Var name, Just tipe) -> do
162 flexiVars <- forM qs (\_ -> liftIO $ var Flexible)
163 flexiVars <- forM qs (\_ -> liftIO $ var Flexible)
163 let inserts = zipWith (\arg typ -> Map.insert arg (VarN typ)) qs flexiVars
164 let inserts = zipWith (\arg typ -> Map.insert arg (VarN typ)) qs flexiVars
164 env' = env { Env.value = List.foldl' (\x f -> f x) (Env.value env) inserts }
165 env' = env { Env.value = List.foldl' (\x f -> f x) (Env.value env) inserts }
165 (vars, typ) <- Env.instantiateType env tipe Map.empty
166 (vars, typ) <- Env.instantiateType env tipe Map.empty
166 let scheme = Scheme { rigidQuantifiers = [],
167 let scheme = Scheme { rigidQuantifiers = [],
167 flexibleQuantifiers = flexiVars ++ vars,
168 flexibleQuantifiers = flexiVars ++ vars,
168− constraint = Loc.noneNoDocs CTrue,
169+ constraint = Ann.noneNoDocs CTrue,
169 header = Map.singleton name typ }
170 header = Map.singleton name typ }
170 c <- constrain env' expr typ
171 c <- constrain env' expr typ
171 return ( scheme : schemes
172 return ( scheme : schemes
@@ -175,7 +176,7 @@ constrainDef env info (Definition pattern expr maybeTipe) =
175 , c2
176 , c2
176 , fl rigidVars c /\ c1 )
177 , fl rigidVars c /\ c1 )
177
178
178− (PVar name, Nothing) -> do
179+ (P.Var name, Nothing) -> do
179 v <- liftIO $ var Flexible
180 v <- liftIO $ var Flexible
180 let tipe = VarN v
181 let tipe = VarN v
181 inserts = zipWith (\arg typ -> Map.insert arg (VarN typ)) qs rigidVars
182 inserts = zipWith (\arg typ -> Map.insert arg (VarN typ)) qs rigidVars
@@ -191,19 +192,19 @@ constrainDef env info (Definition pattern expr maybeTipe) =
191 _ -> error (show pattern)
192 _ -> error (show pattern)
192
193
193expandPattern :: Def -> [Def]
194expandPattern :: Def -> [Def]
194−expandPattern def@(Definition pattern lexpr@(L s _) maybeType) =
195+expandPattern def@(Definition pattern lexpr@(A r _) maybeType) =
195 case pattern of
196 case pattern of
196− PVar _ -> [def]
197+ P.Var _ -> [def]
197− _ -> Definition (PVar x) lexpr maybeType : map toDef vars
198+ _ -> Definition (P.Var x) lexpr maybeType : map toDef vars
198 where
199 where
199− vars = Set.toList $ boundVars pattern
200+ vars = P.boundVarList pattern
200 x = "$" ++ concat vars
201 x = "$" ++ concat vars
201− mkVar = L s . Var
202+ mkVar = A r . rawVar
202− toDef y = Definition (PVar y) (L s $ Case (mkVar x) [(pattern, mkVar y)]) Nothing
203+ toDef y = Definition (P.Var y) (A r $ Case (mkVar x) [(pattern, mkVar y)]) Nothing
203
204
204−try :: SrcSpan -> ErrorT (SrcSpan -> PP.Doc) IO a -> ErrorT [PP.Doc] IO a
205+try :: Region -> ErrorT (Region -> PP.Doc) IO a -> ErrorT [PP.Doc] IO a
205−try span computation = do
206+try region computation = do
206 result <- liftIO $ runErrorT computation
207 result <- liftIO $ runErrorT computation
207 case result of
208 case result of
208− Left err -> throwError [err span]
209+ Left err -> throwError [err region]
209 Right value -> return value
210 Right value -> return value
compiler/Type/Constrain/Literal.hs+5−4
@@ -1,14 +1,15 @@
1+{-# OPTIONS_GHC -W #-}
1module Type.Constrain.Literal where
2module Type.Constrain.Literal where
2
3
4+import SourceSyntax.Annotation
3import SourceSyntax.Literal
5import SourceSyntax.Literal
4−import SourceSyntax.Location
5import Type.Type
6import Type.Type
6import Type.Environment as Env
7import Type.Environment as Env
7
8
8−constrain :: Environment -> SrcSpan -> Literal -> Type -> IO TypeConstraint
9+constrain :: Environment -> Region -> Literal -> Type -> IO TypeConstraint
9−constrain env span literal tipe =
10+constrain env region literal tipe =
10 do tipe' <- litType
11 do tipe' <- litType
11− return . L span $ CEqual tipe tipe'
12+ return . A region $ CEqual tipe tipe'
12 where
13 where
13 prim name = return (Env.get env Env.types name)
14 prim name = return (Env.get env Env.types name)
14
15
compiler/Type/Constrain/Pattern.hs+17−18
@@ -1,3 +1,4 @@
1+{-# OPTIONS_GHC -W #-}
1{-# LANGUAGE FlexibleInstances #-}
2{-# LANGUAGE FlexibleInstances #-}
2module Type.Constrain.Pattern where
3module Type.Constrain.Pattern where
3
4
@@ -8,31 +9,29 @@ import Control.Monad.Error
8import qualified Data.Map as Map
9import qualified Data.Map as Map
9import qualified Text.PrettyPrint as PP
10import qualified Text.PrettyPrint as PP
10
11
12+import qualified SourceSyntax.Annotation as A
11−import SourceSyntax.Pattern
13+import qualified SourceSyntax.Pattern as P
12−import SourceSyntax.Location
13−import SourceSyntax.PrettyPrint
14+import SourceSyntax.PrettyPrint (pretty)
14−import Text.PrettyPrint (render)
15−import qualified SourceSyntax.Location as Loc
16import Type.Type
15import Type.Type
17import Type.Fragment
16import Type.Fragment
18import Type.Environment as Env
17import Type.Environment as Env
19import qualified Type.Constrain.Literal as Literal
18import qualified Type.Constrain.Literal as Literal
20
19
21
20
22−constrain :: Environment -> Pattern -> Type -> ErrorT (SrcSpan -> PP.Doc) IO Fragment
21+constrain :: Environment -> P.Pattern -> Type -> ErrorT (A.Region -> PP.Doc) IO Fragment
23constrain env pattern tipe =
22constrain env pattern tipe =
24− let span = Loc.NoSpan (render $ pretty pattern)
23+ let region = A.None (pretty pattern)
25− t1 === t2 = Loc.L span (CEqual t1 t2)
24+ t1 === t2 = A.A region (CEqual t1 t2)
26− x <? t = Loc.L span (CInstance x t)
25+ x <? t = A.A region (CInstance x t)
27 in
26 in
28 case pattern of
27 case pattern of
29− PAnything -> return emptyFragment
28+ P.Anything -> return emptyFragment
30
29
31− PLiteral lit -> do
30+ P.Literal lit -> do
32− c <- liftIO $ Literal.constrain env span lit tipe
31+ c <- liftIO $ Literal.constrain env region lit tipe
33 return $ emptyFragment { typeConstraint = c }
32 return $ emptyFragment { typeConstraint = c }
34
33
35− PVar name -> do
34+ P.Var name -> do
36 v <- liftIO $ var Flexible
35 v <- liftIO $ var Flexible
37 return $ Fragment {
36 return $ Fragment {
38 typeEnv = Map.singleton name (VarN v),
37 typeEnv = Map.singleton name (VarN v),
@@ -40,14 +39,14 @@ constrain env pattern tipe =
40 typeConstraint = VarN v === tipe
39 typeConstraint = VarN v === tipe
41 }
40 }
42
41
43− PAlias name p -> do
42+ P.Alias name p -> do
44 fragment <- constrain env p tipe
43 fragment <- constrain env p tipe
45 return $ fragment {
44 return $ fragment {
46 typeEnv = Map.insert name tipe (typeEnv fragment),
45 typeEnv = Map.insert name tipe (typeEnv fragment),
47 typeConstraint = name <? tipe /\ typeConstraint fragment
46 typeConstraint = name <? tipe /\ typeConstraint fragment
48 }
47 }
49
48
50− PData name patterns -> do
49+ P.Data name patterns -> do
51 (kind, cvars, args, result) <- liftIO $ freshDataScheme env name
50 (kind, cvars, args, result) <- liftIO $ freshDataScheme env name
52 let msg = concat [ "Constructor '", name, "' expects ", show kind
51 let msg = concat [ "Constructor '", name, "' expects ", show kind
53 , " argument", if kind == 1 then "" else "s"
52 , " argument", if kind == 1 then "" else "s"
@@ -63,7 +62,7 @@ constrain env pattern tipe =
63 vars = cvars ++ vars fragment
62 vars = cvars ++ vars fragment
64 }
63 }
65
64
66− PRecord fields -> do
65+ P.Record fields -> do
67 pairs <- liftIO $ mapM (\name -> (,) name <$> var Flexible) fields
66 pairs <- liftIO $ mapM (\name -> (,) name <$> var Flexible) fields
68 let tenv = Map.fromList (map (second VarN) pairs)
67 let tenv = Map.fromList (map (second VarN) pairs)
69 c <- exists $ \t -> return (tipe === record (Map.map (:[]) tenv) t)
68 c <- exists $ \t -> return (tipe === record (Map.map (:[]) tenv) t)
@@ -73,8 +72,8 @@ constrain env pattern tipe =
73 typeConstraint = c
72 typeConstraint = c
74 }
73 }
75
74
76−instance Error (SrcSpan -> PP.Doc) where
75+instance Error (A.Region -> PP.Doc) where
77 noMsg _ = PP.empty
76 noMsg _ = PP.empty
78 strMsg str span =
77 strMsg str span =
79 PP.vcat [ PP.text $ "Type error " ++ show span
78 PP.vcat [ PP.text $ "Type error " ++ show span
80− , PP.text str ]
79+ , PP.text str ]
compiler/Type/ExtraChecks.hs+39−36
@@ -1,32 +1,35 @@
1{-# OPTIONS_GHC -W #-}
1{-# OPTIONS_GHC -W #-}
2+
3+{-| This module contains checks to be run *after* type inference has completed
4+successfully. At that point we still need to do occurs checks and ensure that
5+`main` has an acceptable type.
6+-}
2module Type.ExtraChecks (mainType, occurs, portTypes) where
7module Type.ExtraChecks (mainType, occurs, portTypes) where
3−-- This module contains checks to be run *after* type inference has
4−-- completed successfully. At that point we still need to do occurs
5−-- checks and ensure that `main` has an acceptable type.
6
8
7import Control.Applicative ((<$>),(<*>))
9import Control.Applicative ((<$>),(<*>))
8import Control.Monad.State
10import Control.Monad.State
9import qualified Data.List as List
11import qualified Data.List as List
10import qualified Data.Map as Map
12import qualified Data.Map as Map
13+import qualified Data.Traversable as Traverse
11import qualified Data.UnionFind.IO as UF
14import qualified Data.UnionFind.IO as UF
12−import Type.Type ( Variable, structure, Term1(..), toSrcType )
13−import qualified Type.State as TS
14−import qualified Type.Alias as Alias
15import Text.PrettyPrint as P
15import Text.PrettyPrint as P
16−import SourceSyntax.PrettyPrint (pretty)
16+
17−import qualified SourceSyntax.Helpers as Help
17+import qualified SourceSyntax.Annotation as A
18−import qualified SourceSyntax.Type as T
19import qualified SourceSyntax.Expression as E
18import qualified SourceSyntax.Expression as E
20−import qualified SourceSyntax.Location as L
19+import qualified SourceSyntax.Helpers as Help
20+import qualified SourceSyntax.PrettyPrint as SPP
21+import qualified SourceSyntax.Type as ST
21import qualified Transform.Expression as Expr
22import qualified Transform.Expression as Expr
22−import qualified Data.Traversable as Traverse
23+import qualified Type.Type as TT
24+import qualified Type.State as TS
25+import qualified Type.Alias as Alias
23
26
24throw err = Left [ P.vcat err ]
27throw err = Left [ P.vcat err ]
25
28
26−mainType :: Alias.Rules -> TS.Env -> IO (Either [P.Doc] (Map.Map String T.Type))
29+mainType :: Alias.Rules -> TS.Env -> IO (Either [P.Doc] (Map.Map String ST.Type))
27−mainType rules env = mainCheck rules <$> Traverse.traverse toSrcType env
30+mainType rules env = mainCheck rules <$> Traverse.traverse TT.toSrcType env
28 where
31 where
29− mainCheck :: Alias.Rules -> Map.Map String T.Type -> Either [P.Doc] (Map.Map String T.Type)
32+ mainCheck :: Alias.Rules -> Map.Map String ST.Type -> Either [P.Doc] (Map.Map String ST.Type)
30 mainCheck rules env =
33 mainCheck rules env =
31 case Map.lookup "main" env of
34 case Map.lookup "main" env of
32 Nothing -> Right env
35 Nothing -> Right env
@@ -37,40 +40,40 @@ mainType rules env = mainCheck rules <$> Traverse.traverse toSrcType env
37 acceptable = [ "Graphics.Element.Element"
40 acceptable = [ "Graphics.Element.Element"
38 , "Signal.Signal Graphics.Element.Element" ]
41 , "Signal.Signal Graphics.Element.Element" ]
39
42
40− tipe = P.render . pretty $ Alias.canonicalRealias (fst rules) mainType
43+ tipe = SPP.renderPretty $ Alias.canonicalRealias (fst rules) mainType
41 err = [ P.text "Type Error: 'main' must have type Element or (Signal Element)."
44 err = [ P.text "Type Error: 'main' must have type Element or (Signal Element)."
42 , P.text "Instead 'main' has type:\n"
45 , P.text "Instead 'main' has type:\n"
43− , P.nest 4 . pretty $ Alias.realias rules mainType
46+ , P.nest 4 . SPP.pretty $ Alias.realias rules mainType
44 , P.text " " ]
47 , P.text " " ]
45
48
46data Direction = In | Out
49data Direction = In | Out
47
50
48−portTypes :: Alias.Rules -> E.LExpr -> Either [P.Doc] ()
51+portTypes :: Alias.Rules -> E.Expr -> Either [P.Doc] ()
49portTypes rules expr =
52portTypes rules expr =
50 const () <$> Expr.checkPorts (check In) (check Out) expr
53 const () <$> Expr.checkPorts (check In) (check Out) expr
51 where
54 where
52 check = isValid True False False
55 check = isValid True False False
53 isValid isTopLevel seenFunc seenSignal direction name tipe =
56 isValid isTopLevel seenFunc seenSignal direction name tipe =
54 case tipe of
57 case tipe of
55− T.Data ctor ts
58+ ST.Data ctor ts
56 | isJs ctor || isElm ctor -> mapM_ valid ts
59 | isJs ctor || isElm ctor -> mapM_ valid ts
57 | ctor == "Signal.Signal" -> handleSignal ts
60 | ctor == "Signal.Signal" -> handleSignal ts
58 | otherwise -> err' True "an unsupported type"
61 | otherwise -> err' True "an unsupported type"
59
62
60− T.Var _ -> err "free type variables"
63+ ST.Var _ -> err "free type variables"
61
64
62− T.Lambda _ _ ->
65+ ST.Lambda _ _ ->
63 case direction of
66 case direction of
64 In -> err "functions"
67 In -> err "functions"
65 Out | seenFunc -> err "higher-order functions"
68 Out | seenFunc -> err "higher-order functions"
66 | seenSignal -> err "signals that contain functions"
69 | seenSignal -> err "signals that contain functions"
67 | otherwise ->
70 | otherwise ->
68− forM_ (T.collectLambdas tipe)
71+ forM_ (ST.collectLambdas tipe)
69 (isValid' True seenSignal direction name)
72 (isValid' True seenSignal direction name)
70
73
71− T.Record _ (Just _) -> err "extended records with free type variables"
74+ ST.Record _ (Just _) -> err "extended records with free type variables"
72
75
73− T.Record fields Nothing ->
76+ ST.Record fields Nothing ->
74 mapM_ (\(k,v) -> (,) k <$> valid v) fields
77 mapM_ (\(k,v) -> (,) k <$> valid v) fields
75
78
76 where
79 where
@@ -100,7 +103,7 @@ portTypes rules expr =
100 [ txt [ "Type Error: the value ", dir "coming in" "sent out"
103 [ txt [ "Type Error: the value ", dir "coming in" "sent out"
101 , " through port '", name, "' is invalid." ]
104 , " through port '", name, "' is invalid." ]
102 , txt [ "It contains ", kind, ":\n" ]
105 , txt [ "It contains ", kind, ":\n" ]
103− , (P.nest 4 . pretty $ Alias.realias rules tipe) <> P.text "\n"
106+ , (P.nest 4 . SPP.pretty $ Alias.realias rules tipe) <> P.text "\n"
104 , txt [ "Acceptable values for ", dir "incoming" "outgoing"
107 , txt [ "Acceptable values for ", dir "incoming" "outgoing"
105 , " ports include JavaScript values and" ]
108 , " ports include JavaScript values and" ]
106 , txt [ "the following Elm values: Ints, Floats, Bools, Strings, Maybes," ]
109 , txt [ "the following Elm values: Ints, Floats, Bools, Strings, Maybes," ]
@@ -112,37 +115,37 @@ portTypes rules expr =
112 , txt [ "manually for now (e.g. {x:Int,y:Int} instead of a type alias of that type)." ]
115 , txt [ "manually for now (e.g. {x:Int,y:Int} instead of a type alias of that type)." ]
113 ]
116 ]
114
117
115−occurs :: (String, Variable) -> StateT TS.SolverState IO ()
118+occurs :: (String, TT.Variable) -> StateT TS.SolverState IO ()
116occurs (name, variable) =
119occurs (name, variable) =
117 do vars <- liftIO $ infiniteVars [] variable
120 do vars <- liftIO $ infiniteVars [] variable
118 case vars of
121 case vars of
119 [] -> return ()
122 [] -> return ()
120 var:_ -> do
123 var:_ -> do
121 desc <- liftIO $ UF.descriptor var
124 desc <- liftIO $ UF.descriptor var
122− case structure desc of
125+ case TT.structure desc of
123 Nothing ->
126 Nothing ->
124 modify $ \state -> state { TS.sErrors = fallback : TS.sErrors state }
127 modify $ \state -> state { TS.sErrors = fallback : TS.sErrors state }
125 Just _ ->
128 Just _ ->
126− do liftIO $ UF.setDescriptor var (desc { structure = Nothing })
129+ do liftIO $ UF.setDescriptor var (desc { TT.structure = Nothing })
127 var' <- liftIO $ UF.fresh desc
130 var' <- liftIO $ UF.fresh desc
128− TS.addError (L.NoSpan name) (Just msg) var var'
131+ TS.addError (A.None (P.text name)) (Just msg) var var'
129 where
132 where
130 msg = "Infinite types are not allowed"
133 msg = "Infinite types are not allowed"
131 fallback _ = return $ P.text msg
134 fallback _ = return $ P.text msg
132
135
133− infiniteVars :: [Variable] -> Variable -> IO [Variable]
136+ infiniteVars :: [TT.Variable] -> TT.Variable -> IO [TT.Variable]
134− infiniteVars seen var =
137+ infiniteVars seen var =
135 let go = infiniteVars (var:seen) in
138 let go = infiniteVars (var:seen) in
136 if var `elem` seen
139 if var `elem` seen
137 then return [var]
140 then return [var]
138 else do
141 else do
139 desc <- UF.descriptor var
142 desc <- UF.descriptor var
140− case structure desc of
143+ case TT.structure desc of
141 Nothing -> return []
144 Nothing -> return []
142 Just struct ->
145 Just struct ->
143 case struct of
146 case struct of
144− App1 a b -> (++) <$> go a <*> go b
147+ TT.App1 a b -> (++) <$> go a <*> go b
145− Fun1 a b -> (++) <$> go a <*> go b
148+ TT.Fun1 a b -> (++) <$> go a <*> go b
146− Var1 a -> go a
149+ TT.Var1 a -> go a
147− EmptyRecord1 -> return []
150+ TT.EmptyRecord1 -> return []
148− Record1 fields ext -> concat <$> mapM go (ext : concat (Map.elems fields))
151+ TT.Record1 fields ext -> concat <$> mapM go (ext : concat (Map.elems fields))
compiler/Type/Fragment.hs+12−13
@@ -5,24 +5,23 @@ import qualified Data.Map as Map
5
5
6import Type.Type
6import Type.Type
7import SourceSyntax.Pattern
7import SourceSyntax.Pattern
8−import SourceSyntax.Location (noneNoDocs)
8+import SourceSyntax.Annotation (noneNoDocs)
9
9
10−data Fragment = Fragment {
10+data Fragment = Fragment
11− typeEnv :: Map.Map String Type,
11+ { typeEnv :: Map.Map String Type
12− vars :: [Variable],
12+ , vars :: [Variable]
13− typeConstraint :: TypeConstraint
13+ , typeConstraint :: TypeConstraint
14−} deriving Show
14+ } deriving Show
15
15
16emptyFragment = Fragment Map.empty [] (noneNoDocs CTrue)
16emptyFragment = Fragment Map.empty [] (noneNoDocs CTrue)
17
17
18−joinFragment f1 f2 = Fragment {
18+joinFragment f1 f2 = Fragment
19− typeEnv = Map.union (typeEnv f1) (typeEnv f2),
19+ { typeEnv = Map.union (typeEnv f1) (typeEnv f2)
20− vars = vars f1 ++ vars f2,
20+ , vars = vars f1 ++ vars f2
21− typeConstraint = typeConstraint f1 /\ typeConstraint f2
21+ , typeConstraint = typeConstraint f1 /\ typeConstraint f2
22−}
22+ }
23
23
24joinFragments = List.foldl' (flip joinFragment) emptyFragment
24joinFragments = List.foldl' (flip joinFragment) emptyFragment
25
25
26−
27toScheme fragment =
26toScheme fragment =
28− Scheme [] (vars fragment) (typeConstraint fragment) (typeEnv fragment)
27+ Scheme [] (vars fragment) (typeConstraint fragment) (typeEnv fragment)
compiler/Type/Inference.hs+1−1
@@ -9,7 +9,7 @@ import qualified Type.Constrain.Expression as TcExpr
9import qualified Type.Solve as Solve
9import qualified Type.Solve as Solve
10
10
11import SourceSyntax.Module as Module
11import SourceSyntax.Module as Module
12−import SourceSyntax.Location (noneNoDocs)
12+import SourceSyntax.Annotation (noneNoDocs)
13import SourceSyntax.Type (Type)
13import SourceSyntax.Type (Type)
14import Text.PrettyPrint
14import Text.PrettyPrint
15import qualified Type.State as TS
15import qualified Type.State as TS
compiler/Type/Solve.hs+19−19
@@ -3,15 +3,15 @@ module Type.Solve (solve) where
3
3
4import Control.Monad
4import Control.Monad
5import Control.Monad.State
5import Control.Monad.State
6−import qualified Data.UnionFind.IO as UF
6+import qualified Data.List as List
7import qualified Data.Map as Map
7import qualified Data.Map as Map
8import qualified Data.Traversable as Traversable
8import qualified Data.Traversable as Traversable
9−import qualified Data.List as List
9+import qualified Data.UnionFind.IO as UF
10import Type.Type
10import Type.Type
11import Type.Unify
11import Type.Unify
12import qualified Type.ExtraChecks as Check
12import qualified Type.ExtraChecks as Check
13import qualified Type.State as TS
13import qualified Type.State as TS
14−import SourceSyntax.Location (Located(L), SrcSpan)
14+import qualified SourceSyntax.Annotation as A
15
15
16
16
17-- | Every variable has rank less than or equal to the maxRank of the pool.
17-- | Every variable has rank less than or equal to the maxRank of the pool.
@@ -96,7 +96,7 @@ adjustRank youngMark visitedMark groupRank variable =
96
96
97
97
98solve :: TypeConstraint -> StateT TS.SolverState IO ()
98solve :: TypeConstraint -> StateT TS.SolverState IO ()
99−solve (L span constraint) =
99+solve (A.A region constraint) =
100 case constraint of
100 case constraint of
101 CTrue -> return ()
101 CTrue -> return ()
102
102
@@ -105,11 +105,11 @@ solve (L span constraint) =
105 CEqual term1 term2 -> do
105 CEqual term1 term2 -> do
106 t1 <- TS.flatten term1
106 t1 <- TS.flatten term1
107 t2 <- TS.flatten term2
107 t2 <- TS.flatten term2
108− unify span t1 t2
108+ unify region t1 t2
109
109
110 CAnd cs -> mapM_ solve cs
110 CAnd cs -> mapM_ solve cs
111
111
112− CLet [Scheme [] fqs constraint' _] (L _ CTrue) -> do
112+ CLet [Scheme [] fqs constraint' _] (A.A _ CTrue) -> do
113 oldEnv <- TS.getEnv
113 oldEnv <- TS.getEnv
114 mapM TS.introduce fqs
114 mapM TS.introduce fqs
115 solve constraint'
115 solve constraint'
@@ -117,7 +117,7 @@ solve (L span constraint) =
117
117
118 CLet schemes constraint' -> do
118 CLet schemes constraint' -> do
119 oldEnv <- TS.getEnv
119 oldEnv <- TS.getEnv
120− headers <- Map.unions `fmap` mapM (solveScheme span) schemes
120+ headers <- Map.unions `fmap` mapM (solveScheme region) schemes
121 TS.modifyEnv $ \env -> Map.union headers env
121 TS.modifyEnv $ \env -> Map.union headers env
122 solve constraint'
122 solve constraint'
123 mapM Check.occurs $ Map.toList headers
123 mapM Check.occurs $ Map.toList headers
@@ -134,10 +134,10 @@ solve (L span constraint) =
134 error ("Could not find '" ++ name ++ "' when solving type constraints.")
134 error ("Could not find '" ++ name ++ "' when solving type constraints.")
135
135
136 t <- TS.flatten term
136 t <- TS.flatten term
137− unify span freshCopy t
137+ unify region freshCopy t
138
138
139−solveScheme :: SrcSpan -> TypeScheme -> StateT TS.SolverState IO (Map.Map String Variable)
139+solveScheme :: A.Region -> TypeScheme -> StateT TS.SolverState IO (Map.Map String Variable)
140−solveScheme span scheme =
140+solveScheme region scheme =
141 case scheme of
141 case scheme of
142 Scheme [] [] constraint header -> do
142 Scheme [] [] constraint header -> do
143 solve constraint
143 solve constraint
@@ -154,39 +154,39 @@ solveScheme span scheme =
154 header' <- Traversable.traverse TS.flatten header
154 header' <- Traversable.traverse TS.flatten header
155 solve constraint
155 solve constraint
156
156
157− allDistinct span rigidQuantifiers
157+ allDistinct region rigidQuantifiers
158 youngPool <- TS.getPool
158 youngPool <- TS.getPool
159 TS.switchToPool oldPool
159 TS.switchToPool oldPool
160 generalize youngPool
160 generalize youngPool
161− mapM (isGeneric span) rigidQuantifiers
161+ mapM (isGeneric region) rigidQuantifiers
162 return header'
162 return header'
163
163
164
164
165-- Checks that all of the given variables belong to distinct equivalence classes.
165-- Checks that all of the given variables belong to distinct equivalence classes.
166-- Also checks that their structure is Nothing, so they represent a variable, not
166-- Also checks that their structure is Nothing, so they represent a variable, not
167-- a more complex term.
167-- a more complex term.
168−allDistinct :: SrcSpan -> [Variable] -> StateT TS.SolverState IO ()
168+allDistinct :: A.Region -> [Variable] -> StateT TS.SolverState IO ()
169−allDistinct span vars = do
169+allDistinct region vars = do
170 seen <- TS.uniqueMark
170 seen <- TS.uniqueMark
171 let check var = do
171 let check var = do
172 desc <- liftIO $ UF.descriptor var
172 desc <- liftIO $ UF.descriptor var
173 case structure desc of
173 case structure desc of
174− Just _ -> TS.addError span (Just msg) var var
174+ Just _ -> TS.addError region (Just msg) var var
175 where msg = "Cannot generalize something that is not a type variable."
175 where msg = "Cannot generalize something that is not a type variable."
176
176
177 Nothing -> do
177 Nothing -> do
178 if mark desc == seen
178 if mark desc == seen
179 then let msg = "Duplicate variable during generalization."
179 then let msg = "Duplicate variable during generalization."
180− in TS.addError span (Just msg) var var
180+ in TS.addError region (Just msg) var var
181 else return ()
181 else return ()
182 liftIO $ UF.setDescriptor var (desc { mark = seen })
182 liftIO $ UF.setDescriptor var (desc { mark = seen })
183 mapM_ check vars
183 mapM_ check vars
184
184
185-- Check that a variable has rank == noRank, meaning that it can be generalized.
185-- Check that a variable has rank == noRank, meaning that it can be generalized.
186−isGeneric :: SrcSpan -> Variable -> StateT TS.SolverState IO ()
186+isGeneric :: A.Region -> Variable -> StateT TS.SolverState IO ()
187−isGeneric span var = do
187+isGeneric region var = do
188 desc <- liftIO $ UF.descriptor var
188 desc <- liftIO $ UF.descriptor var
189 if rank desc == noRank
189 if rank desc == noRank
190 then return ()
190 then return ()
191 else let msg = "Unable to generalize a type variable. It is not unranked."
191 else let msg = "Unable to generalize a type variable. It is not unranked."
192− in TS.addError span (Just msg) var var
192+ in TS.addError region (Just msg) var var
compiler/Type/State.hs+12−20
@@ -1,16 +1,17 @@
1{-# OPTIONS_GHC -W #-}
1{-# OPTIONS_GHC -W #-}
2module Type.State where
2module Type.State where
3
3
4−import Type.Type
5−import qualified Data.Map as Map
6−import qualified Data.UnionFind.IO as UF
7−import Control.Monad.State
8import Control.Applicative ((<$>),(<*>), Applicative)
4import Control.Applicative ((<$>),(<*>), Applicative)
5+import Control.Monad.State
6+import qualified Data.Map as Map
9import qualified Data.Traversable as Traversable
7import qualified Data.Traversable as Traversable
10−import Text.PrettyPrint as P
8+import qualified Data.UnionFind.IO as UF
9+
10+import qualified SourceSyntax.Annotation as A
11import SourceSyntax.PrettyPrint
11import SourceSyntax.PrettyPrint
12−import SourceSyntax.Location
12+import Text.PrettyPrint as P
13import qualified Type.Alias as Alias
13import qualified Type.Alias as Alias
14+import Type.Type
14
15
15-- Pool
16-- Pool
16-- Holds a bunch of variables
17-- Holds a bunch of variables
@@ -46,7 +47,7 @@ initialState = SS {
46modifyEnv f = modify $ \state -> state { sEnv = f (sEnv state) }
47modifyEnv f = modify $ \state -> state { sEnv = f (sEnv state) }
47modifyPool f = modify $ \state -> state { sPool = f (sPool state) }
48modifyPool f = modify $ \state -> state { sPool = f (sPool state) }
48
49
49−addError span hint t1 t2 =
50+addError region hint t1 t2 =
50 modify $ \state -> state { sErrors = makeError : sErrors state }
51 modify $ \state -> state { sErrors = makeError : sErrors state }
51 where
52 where
52 makeError rules = do
53 makeError rules = do
@@ -54,24 +55,15 @@ addError span hint t1 t2 =
54 t1' <- prettiest <$> toSrcType t1
55 t1' <- prettiest <$> toSrcType t1
55 t2' <- prettiest <$> toSrcType t2
56 t2' <- prettiest <$> toSrcType t2
56 return . P.vcat $
57 return . P.vcat $
57− [ P.text $ "Type error" ++ location ++ ":"
58+ [ P.text "Type error" <+> pretty region <> P.colon
58 , maybe P.empty P.text hint
59 , maybe P.empty P.text hint
59− , display $ case span of { NoSpan msg -> msg ; Span _ _ msg -> msg }
60+ , P.text ""
61+ , P.nest 8 $ A.getRegionDocs region
62+ , P.text ""
60 , P.text " Expected Type:" <+> t1'
63 , P.text " Expected Type:" <+> t1'
61 , P.text " Actual Type:" <+> t2'
64 , P.text " Actual Type:" <+> t2'
62 ]
65 ]
63
66
64− location = case span of
65− NoSpan _ -> ""
66− Span p1 p2 _ ->
67− if line p1 == line p2 then " on line " ++ show (line p1)
68− else " between lines " ++ show (line p1) ++ " and " ++ show (line p2)
69−
70− display msg =
71− P.vcat [ P.text $ concatMap ("\n "++) (lines msg)
72− , P.text " " ]
73−
74−
75switchToPool pool = modifyPool (\_ -> pool)
67switchToPool pool = modifyPool (\_ -> pool)
76
68
77getPool :: StateT SolverState IO Pool
69getPool :: StateT SolverState IO Pool
compiler/Type/Type.hs+19−12
@@ -11,7 +11,7 @@ import Control.Applicative ((<$>),(<*>))
11import Control.Monad.State
11import Control.Monad.State
12import Control.Monad.Error
12import Control.Monad.Error
13import Data.Traversable (traverse)
13import Data.Traversable (traverse)
14−import SourceSyntax.Location
14+import SourceSyntax.Annotation
15import SourceSyntax.Helpers (isTuple)
15import SourceSyntax.Helpers (isTuple)
16import qualified SourceSyntax.Type as Src
16import qualified SourceSyntax.Type as Src
17
17
@@ -62,7 +62,7 @@ monoscheme headers = Scheme [] [] (noneNoDocs CTrue) headers
62infixl 8 /\
62infixl 8 /\
63
63
64(/\) :: Constraint a b -> Constraint a b -> Constraint a b
64(/\) :: Constraint a b -> Constraint a b -> Constraint a b
65−a@(L _ c1) /\ b@(L _ c2) =
65+a@(A _ c1) /\ b@(A _ c2) =
66 case (c1, c2) of
66 case (c1, c2) of
67 (CTrue, _) -> b
67 (CTrue, _) -> b
68 (_, CTrue) -> a
68 (_, CTrue) -> a
@@ -128,17 +128,24 @@ structuredVar structure = UF.fresh $ Descriptor {
128
128
129-- ex qs constraint == exists qs. constraint
129-- ex qs constraint == exists qs. constraint
130ex :: [Variable] -> TypeConstraint -> TypeConstraint
130ex :: [Variable] -> TypeConstraint -> TypeConstraint
131+ex fqs constraint@(A ann _) =
131−ex fqs constraint@(L s _) = L s $ CLet [Scheme [] fqs constraint Map.empty] (L s CTrue)
132+ A ann $ CLet [Scheme [] fqs constraint Map.empty] (A ann CTrue)
132
133
133-- fl qs constraint == forall qs. constraint
134-- fl qs constraint == forall qs. constraint
134fl :: [Variable] -> TypeConstraint -> TypeConstraint
135fl :: [Variable] -> TypeConstraint -> TypeConstraint
136+fl rqs constraint@(A ann _) =
135−fl rqs constraint@(L s _) = L s $ CLet [Scheme rqs [] constraint Map.empty] (L s CTrue)
137+ A ann $ CLet [Scheme rqs [] constraint Map.empty] (A ann CTrue)
136
138
137exists :: Error e => (Type -> ErrorT e IO TypeConstraint) -> ErrorT e IO TypeConstraint
139exists :: Error e => (Type -> ErrorT e IO TypeConstraint) -> ErrorT e IO TypeConstraint
138exists f = do
140exists f = do
139 v <- liftIO $ var Flexible
141 v <- liftIO $ var Flexible
140 ex [v] <$> f (VarN v)
142 ex [v] <$> f (VarN v)
141
143
144+existsNumber :: Error e => (Type -> ErrorT e IO TypeConstraint) -> ErrorT e IO TypeConstraint
145+existsNumber f = do
146+ v <- liftIO $ var (Is Number)
147+ ex [v] <$> f (VarN v)
148+
142
149
143instance Show a => Show (UF.Point a) where
150instance Show a => Show (UF.Point a) where
144 show point = unsafePerformIO $ fmap show (UF.descriptor point)
151 show point = unsafePerformIO $ fmap show (UF.descriptor point)
@@ -148,8 +155,8 @@ instance PrettyType a => PrettyType (UF.Point a) where
148 pretty when point = unsafePerformIO $ fmap (pretty when) (UF.descriptor point)
155 pretty when point = unsafePerformIO $ fmap (pretty when) (UF.descriptor point)
149
156
150
157
151−instance PrettyType a => PrettyType (Located a) where
158+instance PrettyType t => PrettyType (Annotated a t) where
152− pretty when (L _ e) = pretty when e
159+ pretty when (A _ e) = pretty when e
153
160
154
161
155instance PrettyType a => PrettyType (Term1 a) where
162instance PrettyType a => PrettyType (Term1 a) where
@@ -212,12 +219,12 @@ instance (PrettyType a, PrettyType b) => PrettyType (BasicConstraint a b) where
212 CAnd cs ->
219 CAnd cs ->
213 P.parens . P.sep $ P.punctuate (P.text " and") (map (pretty Never) cs)
220 P.parens . P.sep $ P.punctuate (P.text " and") (map (pretty Never) cs)
214
221
215− CLet [Scheme [] fqs constraint header] (L _ CTrue) | Map.null header ->
222+ CLet [Scheme [] fqs constraint header] (A _ CTrue) | Map.null header ->
216 P.sep [ binder, pretty Never c ]
223 P.sep [ binder, pretty Never c ]
217 where
224 where
218− mergeExists vs (L _ c) =
225+ mergeExists vs (A _ c) =
219 case c of
226 case c of
220− CLet [Scheme [] fqs' c' _] (L _ CTrue) -> mergeExists (vs ++ fqs') c'
227+ CLet [Scheme [] fqs' c' _] (A _ CTrue) -> mergeExists (vs ++ fqs') c'
221 _ -> (vs, c)
228 _ -> (vs, c)
222
229
223 (fqs', c) = mergeExists fqs constraint
230 (fqs', c) = mergeExists fqs constraint
@@ -233,7 +240,7 @@ instance (PrettyType a, PrettyType b) => PrettyType (BasicConstraint a b) where
233 P.text name <+> P.text "<" <+> prty tipe
240 P.text name <+> P.text "<" <+> prty tipe
234
241
235instance (PrettyType a, PrettyType b) => PrettyType (Scheme a b) where
242instance (PrettyType a, PrettyType b) => PrettyType (Scheme a b) where
236− pretty _ (Scheme rqs fqs (L _ constraint) headers) =
243+ pretty _ (Scheme rqs fqs (A _ constraint) headers) =
237 P.sep [ forall, cs, headers' ]
244 P.sep [ forall, cs, headers' ]
238 where
245 where
239 prty = pretty Never
246 prty = pretty Never
@@ -297,8 +304,8 @@ class Crawl t where
297 -> t
304 -> t
298 -> StateT CrawlState IO t
305 -> StateT CrawlState IO t
299
306
300−instance Crawl a => Crawl (Located a) where
307+instance Crawl e => Crawl (Annotated a e) where
301− crawl nextState (L s e) = L s <$> crawl nextState e
308+ crawl nextState (A ann e) = A ann <$> crawl nextState e
302
309
303instance (Crawl t, Crawl v) => Crawl (BasicConstraint t v) where
310instance (Crawl t, Crawl v) => Crawl (BasicConstraint t v) where
304 crawl nextState constraint =
311 crawl nextState constraint =
compiler/Type/Unify.hs+15−15
@@ -1,27 +1,27 @@
1{-# OPTIONS_GHC -W #-}
1{-# OPTIONS_GHC -W #-}
2module Type.Unify (unify) where
2module Type.Unify (unify) where
3
3
4−import Type.Type
4+import Control.Monad.State
5−import qualified Data.UnionFind.IO as UF
6import qualified Data.Map as Map
5import qualified Data.Map as Map
7import qualified Data.Maybe as Maybe
6import qualified Data.Maybe as Maybe
7+import qualified Data.UnionFind.IO as UF
8+import qualified SourceSyntax.Annotation as A
8import qualified Type.State as TS
9import qualified Type.State as TS
9−import Control.Monad.State
10+import Type.Type
10−import SourceSyntax.Location
11import Type.PrettyPrint
11import Type.PrettyPrint
12import Text.PrettyPrint (render)
12import Text.PrettyPrint (render)
13
13
14−unify :: SrcSpan -> Variable -> Variable -> StateT TS.SolverState IO ()
14+unify :: A.Region -> Variable -> Variable -> StateT TS.SolverState IO ()
15−unify span variable1 variable2 = do
15+unify region variable1 variable2 = do
16 equivalent <- liftIO $ UF.equivalent variable1 variable2
16 equivalent <- liftIO $ UF.equivalent variable1 variable2
17 if equivalent then return ()
17 if equivalent then return ()
18− else actuallyUnify span variable1 variable2
18+ else actuallyUnify region variable1 variable2
19
19
20−actuallyUnify :: SrcSpan -> Variable -> Variable -> StateT TS.SolverState IO ()
20+actuallyUnify :: A.Region -> Variable -> Variable -> StateT TS.SolverState IO ()
21−actuallyUnify span variable1 variable2 = do
21+actuallyUnify region variable1 variable2 = do
22 desc1 <- liftIO $ UF.descriptor variable1
22 desc1 <- liftIO $ UF.descriptor variable1
23 desc2 <- liftIO $ UF.descriptor variable2
23 desc2 <- liftIO $ UF.descriptor variable2
24− let unify' = unify span
24+ let unify' = unify region
25
25
26 name' :: Maybe String
26 name' :: Maybe String
27 name' = case (name desc1, name desc2) of
27 name' = case (name desc1, name desc2) of
@@ -79,11 +79,11 @@ actuallyUnify span variable1 variable2 = do
79
79
80 unifyNumber svar name
80 unifyNumber svar name
81 | name `elem` ["Int","Float","number"] = flexAndUnify svar
81 | name `elem` ["Int","Float","number"] = flexAndUnify svar
82− | otherwise = TS.addError span (Just hint) variable1 variable2
82+ | otherwise = TS.addError region (Just hint) variable1 variable2
83 where hint = "A number must be an Int or Float."
83 where hint = "A number must be an Int or Float."
84
84
85 comparableError maybe =
85 comparableError maybe =
86− TS.addError span (Just $ Maybe.fromMaybe msg maybe) variable1 variable2
86+ TS.addError region (Just $ Maybe.fromMaybe msg maybe) variable1 variable2
87 where msg = "A comparable must be an Int, Float, Char, String, list, or tuple."
87 where msg = "A comparable must be an Int, Float, Char, String, list, or tuple."
88
88
89 unifyComparable var name
89 unifyComparable var name
@@ -110,7 +110,7 @@ actuallyUnify span variable1 variable2 = do
110 List _ -> flexAndUnify varSuper
110 List _ -> flexAndUnify varSuper
111 _ -> comparableError Nothing
111 _ -> comparableError Nothing
112
112
113− rigidError variable = TS.addError span (Just hint) variable1 variable2
113+ rigidError variable = TS.addError region (Just hint) variable1 variable2
114 where
114 where
115 var = "'" ++ render (pretty Never variable) ++ "'"
115 var = "'" ++ render (pretty Never variable) ++ "'"
116 hint = "Cannot unify rigid type variable " ++ var ++
116 hint = "Cannot unify rigid type variable " ++ var ++
@@ -141,7 +141,7 @@ actuallyUnify span variable1 variable2 = do
141
141
142 (Rigid, _, _, _) -> rigidError variable1
142 (Rigid, _, _, _) -> rigidError variable1
143 (_, Rigid, _, _) -> rigidError variable2
143 (_, Rigid, _, _) -> rigidError variable2
144− _ -> TS.addError span Nothing variable1 variable2
144+ _ -> TS.addError region Nothing variable1 variable2
145
145
146 case (structure desc1, structure desc2) of
146 case (structure desc1, structure desc2) of
147 (Nothing, Nothing) | flex desc1 == Flexible && flex desc1 == Flexible -> merge
147 (Nothing, Nothing) | flex desc1 == Flexible && flex desc1 == Flexible -> merge
@@ -196,5 +196,5 @@ actuallyUnify span variable1 variable2 = do
196 eat (_:xs) (_:ys) = eat xs ys
196 eat (_:xs) (_:ys) = eat xs ys
197 eat xs _ = xs
197 eat xs _ = xs
198
198
199− _ -> TS.addError span Nothing variable1 variable2
199+ _ -> TS.addError region Nothing variable1 variable2
200
200
libraries/Automaton.elm.hiddendeleted−123
@@ -1,123 +0,0 @@
1−module Automaton ( pure, state, hiddenState, run, step
2− , (<<<), (>>>), combine, count, average
3− ) where
4−
5−{-| This library is a way to package up dynamic behavior. It makes it easier to
6−dynamically create dynamic components. See the [original release
7−notes](http://elm-lang.org/blog/announce/0.5.0.elm) on this library to get a feel for how
8−it can be used.
9−
10−# Create
11−@docs pure, state, hiddenState
12−
13−# Evaluate
14−@docs run, step
15−
16−# Combine
17−@docs (>>>), (<<<), combine
18−
19−# Common Automatons
20−@docs count, average
21−-}
22−
23−import open Basics
24−import Signal (lift,foldp,Signal)
25−import open List
26−import Maybe (Just, Nothing)
27−
28−data Automaton a b = Step (a -> (Automaton a b, b))
29−
30−{-| Run an automaton on a given signal. The automaton steps forward whenever the
31−input signal updates.
32−-}
33−run : Automaton a b -> b -> Signal a -> Signal b
34−run auto base inputs =
35− let step a (Step f, _) = f a
36− in lift (\(x,y) -> y) (foldp step (auto,base) inputs)
37−
38−{-| Step an automaton forward once with a given input. -}
39−step : a -> Automaton a b -> (Automaton a b, b)
40−step a (Step f) = f a
41−
42−{-| Compose two automatons, chaining them together. -}
43−(>>>) : Automaton a b -> Automaton b c -> Automaton a c
44−f >>> g =
45− Step (\a -> let (f', b) = step a f
46− (g', c) = step b g
47− in (f' >>> g', c))
48−
49−{-| Compose two automatons, chaining them together. -}
50−(<<<) : Automaton b c -> Automaton a b -> Automaton a c
51−g <<< f = f >>> g
52−
53−{-| Combine a list of automatons into a single automaton that produces a
54−list.
55−-}
56−combine : [Automaton a b] -> Automaton a [b]
57−combine autos =
58− Step (\a -> let (autos', bs) = unzip (map (step a) autos)
59− in (combine autos', bs))
60−
61−{-| Create an automaton with no memory. It just applies the given function to
62−every input.
63−-}
64−pure : (a -> b) -> Automaton a b
65−pure f = Step (\x -> (pure f, f x))
66−
67−
68−{-| Create an automaton with state. Requires an initial state and a step
69−function to step the state forward. For example, an automaton that counted
70−how many steps it has taken would look like this:
71−
72− count = Automaton a Int
73− count = state 0 (\\_ c -> c+1)
74−
75−It is a stateful automaton. The initial state is zero, and the step function
76−increments the state on every step.
77−-}
78−state : b -> (a -> b -> b) -> Automaton a b
79−state s f = Step (\x -> let s' = f x s
80− in (state s' f, s'))
81−
82−{-| Create an automaton with hidden state. Requires an initial state and a
83−step function to step the state forward and produce an output.
84−-}
85−hiddenState : s -> (a -> s -> (s,b)) -> Automaton a b
86−hiddenState s f = Step (\x -> let (s',out) = f x s
87− in (hiddenState s' f, out))
88−
89−{-| Count the number of steps taken. -}
90−count : Automaton a Int
91−count = state 0 (\_ c -> c + 1)
92−
93−type Queue t = ([t],[t])
94−empty = ([],[])
95−enqueue x (en,de) = (x::en, de)
96−dequeue q = case q of
97− ([],[]) -> Nothing
98− (en,[]) -> dequeue ([], reverse en)
99− (en,hd::tl) -> Just (hd, (en,tl))
100−
101−{-| Computes the running average of the last `n` inputs. -}
102−average : Int -> Automaton Float Float
103−average k =
104− let step n (ns,len,sum) =
105− if len == k then stepFull n (ns,len,sum)
106− else ((enqueue n ns, len+1, sum+n), (sum+n) / (toFloat len+1))
107− stepFull n (ns,len,sum) =
108− case dequeue ns of
109− Nothing -> ((ns,len,sum), 0)
110− Just (m,ns') -> let sum' = sum + n - m
111− in ((enqueue n ns', len, sum'), sum' / toFloat len)
112− in hiddenState (empty,0,0) step
113−
114−
115−{-- TODO(evancz): See the following papers for ideas on how to make this
116−library faster and better:
117−
118−- Functional Reactive Programming, Continued
119−- Causal commutative arrows and their optimization
120−
121−Speeding things up is a really low priority. Language features and
122−libraries with nice APIs and are way more important!
123−--}
libraries/AutomatonV2.elm.hiddendeleted−149
@@ -1,149 +0,0 @@
1−module AutomatonV2 where
2−{-| This library is a way to package up dynamic behavior. It makes it easier to
3−dynamically create dynamic components. See the [original release
4−notes](/blog/announce/version-0.5.0.elm) on this library to get a feel for how
5−it can be used.
6−-}
7−
8−import open Basics
9−import Signal (lift,foldp,Signal)
10−import open List
11−import Maybe (Just, Nothing)
12−
13−data Automaton input output = Pure (input -> output)
14− | Stateful state (input -> state -> (output,state))
15−
16−-- The basics
17−
18−-- AFRP name: arr
19−pure: (i -> o) -> Automaton i o
20−pure = Pure
21−
22−-- AFRP name: >>>
23−andThen: Automaton i inter -> Automaton inter o -> Automaton i o
24−andThen first second =
25− case first of
26− Pure f -> case second of -- f is the function from first
27− Pure s -> Pure (s . f) -- s is the function from second
28− Stateful b s -> Stateful b (\i -> s (f i)) -- b is the base state from second
29− Stateful fb f -> case second of -- fb is the base state from first
30− Pure s -> Stateful fb (\i st -> -- sb is the base state from second
31− let (inter, st') = f i st -- i is the input
32− in (s inter, st')) -- st is the input state
33− Stateful sb s -> Stateful (fb, sb) (\i (fst, sst) -> -- inter is the intermediate value
34− let (inter, fst') = f i fst -- st' is the new state
35− (o, sst') = s inter sst -- fst and sst are the state of first and second
36− in (o, (fst', sst'))) -- ect...
37−
38−-- AFRP name: first
39−extendDown: Automaton i o -> Automaton (i,extra) (o,extra)
40−extendDown auto = case auto of
41− Pure fun -> Pure (\(i,extra) -> (fun i, extra))
42− Stateful base fun -> Stateful base (\(i,extra) s -> (fun i s, extra))
43−
44−-- AFRP name: loop
45−loop: s -> Automaton (i,s) (o,s) -> Automaton i o
46−loop base auto = case auto of
47− Pure fun -> Stateful base (curry fun)
48− Stateful base2 fun -> -- fun: (i, s) -> s2 -> ((o, s), s2)
49− let newFun = (\i (s,s2) ->
50− let ((o, s'), s2') = fun (i, s) s2
51− in (o, (s', s2'))) -- newFun: i -> (s, s2) -> (o, (s, s2))
52− in Stateful (base, base2) newFun
53−
54−-- Run an automaton on a given signal
55−run: Automaton i o -> o -> Signal i -> Signal o
56−run auto baseOut input = case auto of
57− Pure fun -> lift fun input
58− Stateful base fun -> lift fst
59− (foldp (\i (o, s) -> fun i s)
60− (baseOut, base) input)
61−
62−
63−-- Other frequently used functions/operators
64−
65−-- Create an automaton with state. Requires an initial state and a step
66−-- function to step the state forward. For example, an automaton that counted
67−-- how many steps it has taken would look like this:
68−--
69−-- count = Automaton a Int
70−-- count = state 0 (\\_ c -> c+1)
71−--
72−-- It is a stateful automaton. The initial state is zero, and the step function
73−-- increments the state on every step.
74−state : s -> (i -> s -> s) -> Automaton i s
75−state base fun = loop base (pure (\(i,s) ->
76− let s' = fun i s
77− in (s',s')))
78−
79−-- Create an automaton with hidden state. Requires an initial state and a
80−-- step function to step the state forward and produce an output.
81−hiddenState : s -> (i -> s -> (s,o)) -> Automaton i o
82−hiddenState base fun = loop base (pure (\(i,s) ->
83− let (o,s') = fun i s
84− in (s',o)))
85−
86−-- AFRP name: second
87−extendUp: Automaton i o -> Automaton (extra,i) (extra,o)
88−extendUp auto =
89− let swap (a, b) = (b, a)
90− in pure swap `andThen` extendDown auto `andThen` pure swap
91−
92−-- (parallel composition)
93−pair: Automaton i1 o1 -> Automaton i2 o2 -> Automaton (i1,i2) (o1,o2)
94−pair f g = extendDown f `andThen` extendUp g
95−
96−branch : Automaton i o1 -> Automaton i o2 -> Automaton i (o1,o2)
97−branch f g =
98− let double = pure (\i -> (i,i))
99− in double `andThen` pair f g
100−
101−combi: Automaton i o -> Automaton i [o] -> Automaton i [o]
102−combi a1 a2 = (a1 `branch` a2) `andThen` pure (uncurry (::))
103−
104−-- Combine a list of automatons into a single automaton that produces a list.
105−combine : [Automaton i o] -> Automaton i [o]
106−combine autos =
107− let l = length autos
108− in if l == 0
109− then pure (\_ -> [])
110− else foldr combi (last autos `andThen` pure (\a -> [a])) (take (l-1) autos)
111−
112−
113−-- Examples of automata
114−
115−-- Count the number of steps taken.
116−count : Automaton a Int
117−count = state 0 (\_ c -> c + 1)
118−
119−type Queue t = ([t],[t])
120−empty = ([],[])
121−enqueue x (en,de) = (x::en, de)
122−dequeue q = case q of
123− ([],[]) -> Nothing
124− (en,[]) -> dequeue ([], reverse en)
125− (en,hd::tl) -> Just (hd, (en,tl))
126−
127−-- Computes the running average of the last `n` inputs.
128−average : Int -> Automaton Float Float
129−average k =
130− let step n (ns,len,sum) =
131− if len == k then stepFull n (ns,len,sum)
132− else ((enqueue n ns, len+1, sum+n), (sum+n) / (toFloat len+1))
133− stepFull n (ns,len,sum) =
134− case dequeue ns of
135− Nothing -> ((ns,len,sum), 0)
136− Just (m,ns') -> let sum' = sum + n - m
137− in ((enqueue n ns', len, sum'), sum' / toFloat len)
138− in hiddenState (empty,0,0) step
139−
140−
141−{-- TODO(evancz): See the following papers for ideas on how to make this
142−library faster and better:
143−
144−- Functional Reactive Programming, Continued -- took some inspirations from this paper (Apanatshka)
145−- Causal commutative arrows and their optimization
146−
147−Speeding things up is a really low priority. Language features and
148−libraries with nice APIs and are way more important!
149−--}
libraries/Basics.elm+27
@@ -39,6 +39,9 @@ which happen to be radians.
39# Polar Coordinates
39# Polar Coordinates
40@docs toPolar, fromPolar
40@docs toPolar, fromPolar
41
41
42+# Floating Point Checks
43+@docs isNaN, isInfinite
44+
42# Tuples
45# Tuples
43@docs fst, snd
46@docs fst, snd
44
47
@@ -271,6 +274,30 @@ ceiling = Native.Basics.ceiling
271toFloat : Int -> Float
274toFloat : Int -> Float
272toFloat = Native.Basics.toFloat
275toFloat = Native.Basics.toFloat
273
276
277+{- | Determines whether a float is an undefined or unrepresentable number.
278+NaN stands for *not a number* and it is [a standardized part of floating point
279+numbers](http://en.wikipedia.org/wiki/NaN).
280+
281+ isNaN (0/0) == True
282+ isNaN (sqrt -1) == True
283+ isNaN (1/0) == False -- infinity is a number
284+ isNaN 1 == False
285+-}
286+isNaN : Float -> Bool
287+isNaN = Native.Basics.isNaN
288+
289+{- | Determines whether a float is positive or negative infinity.
290+
291+ isInfinite (0/0) == False
292+ isInfinite (sqrt -1) == False
293+ isInfinite (1/0) == True
294+ isInfinite 1 == False
295+
296+Notice that NaN is not infinite! For float `n` to be finite implies that
297+`not (isInfinite n || isNaN n)` evaluates to `True`.
298+-}
299+isInfinite : Float -> Bool
300+isInfinite = Native.Basics.isInfinite
274
301
275-- Function Helpers
302-- Function Helpers
276
303
libraries/Date.elm+5−1
@@ -5,7 +5,7 @@ module Date where
5issues with internationalization or locale formatting.
5issues with internationalization or locale formatting.
6
6
7# Conversions
7# Conversions
8−@docs read, toTime
8+@docs read, toTime, fromTime
9
9
10# Extractions
10# Extractions
11@docs year, month, Month, day, dayOfWeek, Day, hour, minute, second
11@docs year, month, Month, day, dayOfWeek, Day, hour, minute, second
@@ -36,6 +36,10 @@ read = Native.Date.read
36toTime : Date -> Time
36toTime : Date -> Time
37toTime = Native.Date.toTime
37toTime = Native.Date.toTime
38
38
39+{-| Take a UNIX time and convert it to a `Date` -}
40+fromTime : Time -> Date
41+fromTime = Native.Date.fromTime
42+
39{-| Extract the year of a given date. Given the date 23 June 1990 at 11:45AM
43{-| Extract the year of a given date. Given the date 23 June 1990 at 11:45AM
40this returns the integer `1990`. -}
44this returns the integer `1990`. -}
41year : Date -> Int
45year : Date -> Int
libraries/Debug.elmnew file+17
@@ -0,0 +1,17 @@
1+module Debug where
2+{-| This library is for investigating bugs or performance problems. It should
3+*not* be used in production code.
4+-}
5+
6+import Native.Debug
7+
8+{-| Log a tagged value on the developer console, and then return the value.
9+
10+ 1 + log "number" 1 -- equals 2, logs "number: 1"
11+ length (log "start" []) -- equals 0, logs "start: []"
12+
13+Notice that `log` is not a pure function! It should *only* be used for
14+investigating bugs or performance problems.
15+-}
16+log : String -> a -> a
17+log = Native.Debug.log
libraries/Dict.elm+3−4
@@ -31,11 +31,10 @@ Insert, remove, and query operations all take *O(log n)* time.
31-}
31-}
32
32
33
33
34−import open Basics
34+import Basics (..)
35−import open Maybe
35+import Maybe (..)
36import Native.Error
36import Native.Error
37import List
37import List
38−import String
39import Native.Utils
38import Native.Utils
40
39
41-- BBlack and NBlack should only be used during the deletion
40-- BBlack and NBlack should only be used during the deletion
@@ -197,7 +196,7 @@ lessBlackTree t = case t of
197
196
198reportRemBug : String -> NColor -> String -> String -> a
197reportRemBug : String -> NColor -> String -> String -> a
199reportRemBug msg c lgot rgot =
198reportRemBug msg c lgot rgot =
200− Native.Error.raise . String.concat <| [
199+ Native.Error.raise <| List.concat [
201 "Internal red-black tree invariant violated, expected ",
200 "Internal red-black tree invariant violated, expected ",
202 msg,
201 msg,
203 "and got",
202 "and got",
libraries/Either.elm+26−4
@@ -26,28 +26,50 @@ data Either a b = Left a | Right b
26
26
27{-| Apply the first function to a `Left` and the second function to a `Right`.
27{-| Apply the first function to a `Left` and the second function to a `Right`.
28This allows the extraction of a value from an `Either`.
28This allows the extraction of a value from an `Either`.
29+
30+ either (\n -> n + 1) sqrt (Left 4) == 5
31+ either (\n -> n + 1) sqrt (Right 4) == 2
32+
33+ map : (a -> b) -> Either err a -> Either err b
34+ map f e = either Left (\x -> Right (f x)) e
29-}
35-}
30either : (a -> c) -> (b -> c) -> Either a b -> c
36either : (a -> c) -> (b -> c) -> Either a b -> c
31either f g e = case e of { Left x -> f x ; Right y -> g y }
37either f g e = case e of { Left x -> f x ; Right y -> g y }
32
38
33−{-| True if the value is a `Left`. -}
39+{-| True if the value is a `Left`.
40+
41+ isLeft (Left "Cat") == True
42+ isLeft (Right 1123) == False
43+-}
34isLeft : Either a b -> Bool
44isLeft : Either a b -> Bool
35isLeft e = case e of { Left _ -> True ; _ -> False }
45isLeft e = case e of { Left _ -> True ; _ -> False }
36
46
37−{-| True if the value is a `Right`. -}
47+{-| True if the value is a `Right`.
48+
49+ isRight (Left "Cat") == False
50+ isRight (Right 1123) == True
51+-}
38isRight : Either a b -> Bool
52isRight : Either a b -> Bool
39isRight e = case e of { Right _ -> True ; _ -> False }
53isRight e = case e of { Right _ -> True ; _ -> False }
40
54
41−{-| Keep only the values held in `Left` values. -}
55+{-| Keep only the values held in `Left` values.
56+
57+ lefts [Left 3, Right 'a', Left 5, Right "eight"] == [3,5]
58+-}
42lefts : [Either a b] -> [a]
59lefts : [Either a b] -> [a]
43lefts es = List.foldr consLeft [] es
60lefts es = List.foldr consLeft [] es
44
61
45−{-| Keep only the values held in `Right` values. -}
62+{-| Keep only the values held in `Right` values.
63+
64+ rights [Left 3, Right 'a', Left 5, Right 'b'] == ['a','b']
65+-}
46rights : [Either a b] -> [b]
66rights : [Either a b] -> [b]
47rights es = List.foldr consRight [] es
67rights es = List.foldr consRight [] es
48
68
49{-| Split into two lists, lefts on the left and rights on the right. So we
69{-| Split into two lists, lefts on the left and rights on the right. So we
50have the equivalence: `(partition es == (lefts es, rights es))`
70have the equivalence: `(partition es == (lefts es, rights es))`
71+
72+ partition [Left 3, Right 'a', Left 5, Right 'b'] == ([3,5],['a','b'])
51-}
73-}
52partition : [Either a b] -> ([a],[b])
74partition : [Either a b] -> ([a],[b])
53partition es = List.foldr consEither ([],[]) es
75partition es = List.foldr consEither ([],[]) es
libraries/Graphics/Collage.elm+1−1
@@ -30,7 +30,7 @@ it as a single unit.
30
30
31-}
31-}
32
32
33−import open Basics
33+import Basics (..)
34import List
34import List
35import Either (Either, Left, Right)
35import Either (Either, Left, Right)
36import Transform2D (Transform2D, identity)
36import Transform2D (Transform2D, identity)
libraries/Graphics/Element.elm+7−4
@@ -37,12 +37,12 @@ If you need more precision, you can create custom positions.
37 midRightAt, topLeftAt, topRightAt, bottomLeftAt, bottomRightAt
37 midRightAt, topLeftAt, topRightAt, bottomLeftAt, bottomRightAt
38-}
38-}
39
39
40−import open Basics
40+import Basics (..)
41import Native.Utils
41import Native.Utils
42import JavaScript as JS
42import JavaScript as JS
43import JavaScript (JSString)
43import JavaScript (JSString)
44import List as List
44import List as List
45−import open Color
45+import Color (..)
46import Maybe (Maybe, Just, Nothing)
46import Maybe (Maybe, Just, Nothing)
47
47
48type Properties = {
48type Properties = {
@@ -53,7 +53,8 @@ type Properties = {
53 color : Maybe Color,
53 color : Maybe Color,
54 href : JSString,
54 href : JSString,
55 tag : JSString,
55 tag : JSString,
56− hover : ()
56+ hover : (),
57+ click : ()
57 }
58 }
58
59
59type Element = { props : Properties, element : ElementPrim }
60type Element = { props : Properties, element : ElementPrim }
@@ -128,7 +129,9 @@ link href e = let p = e.props in
128
129
129emptyStr = JS.fromString ""
130emptyStr = JS.fromString ""
130newElement w h e =
131newElement w h e =
131− { props = Properties (Native.Utils.guid ()) w h 1 Nothing emptyStr emptyStr (), element = e }
132+ { props = Properties (Native.Utils.guid ()) w h 1 Nothing emptyStr emptyStr () ()
133+ , element = e
134+ }
132
135
133data ElementPrim
136data ElementPrim
134 = Image ImageStyle Int Int JSString
137 = Image ImageStyle Int Int JSString
libraries/Graphics/Input.elm+146−167
@@ -1,199 +1,178 @@
1module Graphics.Input where
1module Graphics.Input where
2−
3{-| This module is for creating standard input widgets such as buttons and
2{-| This module is for creating standard input widgets such as buttons and
4−text boxes. In general, functions in this library return a signal representing
3+text fields. All functions in this library follow a general pattern in which
5−events from the user.
4+you create an `Input` that many elements can report to:
5+
6+```haskell
7+clicks : Input ()
8+clicks = input ()
9+
10+clickableYogi : Element
11+clickableYogi = clickable clicks.handle () (image 40 40 "/yogi.jpg")
12+```
6
13
7−The simplest inputs are *one-way inputs*, meaning the user can update
14+Whenever the user clicks on the resulting `clickableYogi` element, it sends an
8−them, but the programmer cannot. If you need to update an input from
15+update to the `clicks` input. You will see this pattern again and again in
9−within the program you want the slightly more complex *two-way inputs*.
16+examples in this library, so just read on to get a better idea of how it works!
10−This document will always show the one-way inputs first, *then* the
11−two-way inputs.
12
17
13−# Buttons
18+# Creating Inputs
14−@docs button, customButton, buttons, customButtons
19+@docs Input, input
15
20
16−# Fields
21+# Basic Input Elements
17−@docs field, password, email, fields, FieldState, emptyFieldState
18
22
19−# Checkboxes
23+To learn about text fields, see the
20−@docs checkbox, checkboxes
24+[`Graphics.Input.Field`](Graphics-Input-Field) library.
21
25
22−# Drop Downs
26+@docs button, customButton, checkbox, dropDown
23−@docs stringDropDown, dropDown
27+
28+# Clicks and Hovers
29+@docs clickable, hoverable
24
30
25−# Mouse Hover
26−@docs hoverable, hoverables
27-}
31-}
28
32
29−import Basics (String)
30−import Signal (Signal,lift,dropRepeats)
33+import Signal (Signal)
31−import Native.Graphics.Input
32−import List
33import Graphics.Element (Element)
34import Graphics.Element (Element)
34−import Maybe (Maybe)
35+import Native.Graphics.Input
35−import JavaScript (JSString)
36
36
37−id x = x
37+{-| This is the key abstraction of this library. An `Input` is a record
38+of two fields:
38
39
39−{-| Create a group of buttons.
40+ 1. `signal` &mdash; all values coming to this input from &ldquo;the world&rdquo;
41+ 2. `handle` &mdash; a way to refer to this particular input and send it values
40
42
41− * The first argument is the default value of the `events` signal.
43+This will make more sense as you see more examples.
42− * The `events` signal represents all of the activity in this group
43− of buttons.
44− * The `button` function creates a button
45− with the given name, like &ldquo;Submit&rdquo; or &ldquo;Cancel&rdquo;.
46− The `a` value is sent to `events` whenever the button is pressed.
47-}
44-}
48−buttons : a -> { events : Signal a,
45+type Input a = { signal : Signal a, handle : Handle a }
49− button : a -> String -> Element }
50−buttons = Native.Graphics.Input.buttons
51
46
52−{-| Create a button with a given label. The result is an `Element` and
47+data Handle a = Handle
53−a signal of units. This signal triggers whenever the button is pressed.
54−-}
55−button : String -> (Element, Signal ())
56−button txt =
57− let pool = buttons ()
58− in (pool.button () txt, pool.events)
59−
60−{-| Create a group of custom buttons.
61−
62− * The first argument is the default value of the `events` signal.
63− * The `events` signal represents all of the activity in this group
64− of custom buttons.
65− * The `customButton` function creates a button with three different visual
66− states, one for up, hovering, and down. The resulting button has dimensions
67− large enough to fit all three possible `Elements`.
68− The `a` value is sent to `events` whenever the button is pressed.
69−-}
70−customButtons : a -> { events : Signal a,
71− customButton : a -> Element -> Element -> Element -> Element }
72−customButtons = Native.Graphics.Input.customButtons
73
48
74−{-| Create a button with custom states for up, hovering, and down
49+{-| This creates a new `Input`. You provide a single argument that will serve
75−(given in that order). The result is an `Element` and a signal of
50+as the initial value of the input&rsquo;s `signal`. For example:
76−units. This signal triggers whenever the button is pressed.
51+
77−-}
52+ numbers : Input Int
78−customButton : Element -> Element -> Element -> (Element, Signal ())
53+ numbers = input 42
79−customButton up hover down =
54+
80− let pool = customButtons ()
55+The initial value of `numbers.signal` is 42, and you will be able
81− in (pool.customButton () up hover down, pool.events)
56+to pipe updates to the input using `numbers.handle`.
82−
57+
83−{-| Create a group of checkboxes.
58+Note: This is an inherently impure function. Specifically, `(input ())` and
84−
59+`(input ())` are actually two different inputs with different signals and handles.
85− * The first argument is the default value of the `events` signal.
86− * The `events` signal represents all of the activity in this group
87− of checkboxes.
88− * The `checkbox` function creates a
89− checkbox with a given state. The `(Bool -> a)` function is used
90− when the checkbox is modified. It takes the new state and turns
91− it into a value that can be sent to `events`. For example, this
92− lets you add an ID to distinguish between checkboxes.
93−-}
94−checkboxes : a -> { events : Signal a,
95− checkbox : (Bool -> a) -> Bool -> Element }
96−checkboxes = Native.Graphics.Input.checkboxes
97−
98−{-| Create a checkbox with a given start state. Unlike `button`, this
99−result is a *signal* of elements. That is because a checkbox has state
100−that updates based on user input. The boolean signal represents the
101−current state of the checkbox.
102−-}
103−checkbox : Bool -> (Signal Element, Signal Bool)
104−checkbox b =
105− let cbs = checkboxes b
106− in (lift (cbs.checkbox id) cbs.events, cbs.events)
107−
108−{-| Detect when the mouse is hovering over some elements. This
109−allows you to create and destroy elements dynamically and still
110−detect hover information.
111-}
60-}
112−hoverables : a -> { events : Signal a,
61+input : a -> Input a
113− hoverable : (Bool -> a) -> Element -> Element }
114−hoverables = Native.Graphics.Input.hoverables
62+input = Native.Graphics.Input.input
115
63
116−{-| Detect when the mouse is hovering over a specific `Element`. -}
64+{-| Create a standard button. The following example begins making a basic
117−hoverable : Element -> (Element, Signal Bool)
65+calculator:
118−hoverable elem =
119− let pool = hoverables False
120− in (pool.hoverable id elem, pool.events)
121
66
122−{-| Represents the current state of a text field. The `string` represents the
67+ data Keys = Number Int | Plus | Minus | Clear
123−characters filling the text field. The `selectionStart` and `selectionEnd`
124−values represent what the user has selected with their mouse or keyboard.
125−For example:
126
68
127− { string="She sells sea shells", selectionStart=3, selectionEnd=0 }
69+ keys : Input Keys
70+ keys = input Clear
128
71
129−This means the user highlighted the substring `"She"` backwards.
72+ calculator : Element
130−-}
73+ calculator =
131−type FieldState = { string:String, selectionStart:Int, selectionEnd:Int }
74+ flow right [ button keys.handle (Number 1) "1"
132−
75+ , button keys.handle (Number 2) "2"
133−{-| Create a group of text input fields.
76+ , button keys.handle Plus "+"
134−
77+ ]
135− * The first argument is the default value of the `events` signal.
78+
136− * The `events` signal represents all of the activity in this group
79+If the user presses the "+" button, `keys.signal` will update to `Plus`. If the
137− of text fields.
80+users presses "2", `keys.signal` will update to `(Number 2)`.
138− * The `field` function creates a
139− field with the given ghost text and initial field state.
140− When the field is modified, the `(FieldState -> a)` function
141− takes the new state and turns
142− it into a value that can be sent to `events`. For example, this
143− lets you add an ID to distinguish between input fields.
144-}
81-}
145−fields : a -> { events : Signal a,
146− field : (FieldState -> a) -> String -> FieldState -> Element }
82+button : Handle a -> a -> String -> Element
147−fields = Native.Graphics.Input.fields
83+button = Native.Graphics.Input.button
148
84
149−{-| The empty field state:
85+{-| Same as `button` but lets you customize buttons to look however you want.
150
86
151− { string="", selectionStart=0, selectionEnd=0 }
87+ click : Input ()
152−-}
88+ click = input ()
153−emptyFieldState : FieldState
154−emptyFieldState = { string="", selectionStart=0, selectionEnd=0 }
155
89
156−{-| Create a field with the given default text. The output is an element
90+ prettyButton : Element
157−that updates to match the user input and a signal of strings representing
91+ prettyButton =
158−the content of the field.
92+ customButton click.handle
93+ (image 100 40 "/button_up.jpg")
94+ (image 100 40 "/button_hover.jpg")
95+ (image 100 40 "/button_down.jpg")
159-}
96-}
160−field : String -> (Signal Element, Signal String)
97+customButton : Handle a -> a -> Element -> Element -> Element -> Element
161−field placeHolder =
162− let tfs = fields emptyFieldState
163− changes = dropRepeats tfs.events
164− in (lift (tfs.field id placeHolder) changes,
165− dropRepeats (lift .string changes))
166−
167−{-| Same as `field` but the UI element blocks out each characters. -}
168−password : String -> (Signal Element, Signal String)
169−password placeHolder =
170− let tfs = Native.Graphics.Input.passwords emptyFieldState
98+customButton = Native.Graphics.Input.customButton
171− changes = dropRepeats tfs.events
99+
172− in (lift (tfs.field id placeHolder) changes,
100+{-| Create a checkbox. The following example creates three synced checkboxes:
173− dropRepeats (lift .string changes))
101+
174−
102+ check : Input Bool
175−{-| Same as `field` but it adds an annotation that this field is for email
103+ check = input False
176−addresses. This is helpful for auto-complete and for mobile users who may
104+
177−get a custom keyboard with an `@` and `.com` button.
105+ boxes : Bool -> Element
106+ boxes checked =
107+ let box = container 40 40 middle (checkbox check.handle id checked)
108+ in flow right [ box, box, box ]
109+
110+ main : Signal Element
111+ main = boxes <~ check.signal
178-}
112-}
179−email : String -> (Signal Element, Signal String)
113+checkbox : Handle a -> (Bool -> a) -> Bool -> Element
180−email placeHolder =
181− let tfs = Native.Graphics.Input.emails emptyFieldState
114+checkbox = Native.Graphics.Input.checkbox
182− changes = dropRepeats tfs.events
115+
183− in (lift (tfs.field id placeHolder) changes,
116+{-| Create a drop-down menu. The following drop-down lets you choose your
184− dropRepeats (lift .string changes))
117+favorite British sport:
185−
118+
186−{-| Create a drop-down menu. When the user selects a string,
119+ data Sport = Football | Cricket | Snooker
187−the current state of the drop-down is set to the associated
120+
188−value. This lets you avoid manually mapping the string onto
121+ sport : Input (Maybe Sport)
189−functions and values.
122+ sport = input Nothing
123+
124+ sportDropDown : Element
125+ sportDropDown =
126+ dropDown sport.handle
127+ [ ("" , Nothing)
128+ , ("Football", Just Football)
129+ , ("Cricket" , Just Cricket)
130+ , ("Snooker" , Just Snooker)
131+ ]
132+
133+If the user selects "Football" from the drop down menue, `sport.signal`
134+will update to `Just Football`.
190-}
135-}
191−dropDown : [(String,a)] -> (Signal Element, Signal a)
136+dropDown : Handle a -> [(String,a)] -> Element
192dropDown = Native.Graphics.Input.dropDown
137dropDown = Native.Graphics.Input.dropDown
193
138
194−{-| Create a drop-down menu for selecting strings. The resulting
139+{-| Detect mouse hovers over a specific `Element`. In the following example,
195−signal of strings represents the string that is currently selected.
140+we will create a hoverable picture called `cat`.
141+
142+ hover : Input Bool
143+ hover = input False
144+
145+ cat : Element
146+ cat = image 30 30 "/cat.jpg"
147+ |> hoverable hover.handle id
148+
149+When the mouse hovers above the `cat` element, `hover.signal` will become
150+`True`. When the mouse leaves it, `hover.signal` will become `False`.
151+-}
152+hoverable : Handle a -> (Bool -> a) -> Element -> Element
153+hoverable = Native.Graphics.Input.hoverable
154+
155+{-| Detect mouse clicks on a specific `Element`. In the following example,
156+we will create a clickable picture called `cat`.
157+
158+ data Picture = Cat | Hat
159+
160+ picture : Input Picture
161+ picture = input Cat
162+
163+ cat : Element
164+ cat = image 30 30 "/cat.jpg"
165+ |> clickable picture.handle Cat
166+
167+ hat : Element
168+ hat = image 30 30 "/hat.jpg"
169+ |> clickable picture.handle Hat
170+
171+When the user clicks on the `cat` element, `picture.signal` receives
172+an update containing the value `Cat`. When the user clicks on the `hat` element,
173+`picture.signal` receives an update containing the value `Hat`. This lets you
174+distinguish which element was clicked. In a more complex example, they could be
175+distinguished with IDs or more complex data structures.
196-}
176-}
197−stringDropDown : [String] -> (Signal Element, Signal String)
177+clickable : Handle a -> a -> Element -> Element
198−stringDropDown strs =
178+clickable = Native.Graphics.Input.clickable
199− dropDown (List.map (\s -> (s,s)) strs)
libraries/Graphics/Input/Field.elmnew file+170
@@ -0,0 +1,170 @@
1+module Graphics.Input.Field where
2+{-| This library provides an API for creating and updating text fields.
3+Text fields use exactly the same approach as [`Graphics.Input`](Graphics-Input)
4+for modelling user input, allowing you to keep track of new events and update
5+text fields programmatically.
6+
7+# Create Fields
8+@docs field, password, email
9+
10+# Field Content
11+@docs Content, Selection, Direction, noContent
12+
13+# Field Style
14+@docs Style, Outline, noOutline, Highlight, noHighlight, Dimensions, uniformly
15+-}
16+
17+import Color (Color)
18+import Color
19+import Graphics.Element (Element)
20+import Graphics.Input (Input, Handle)
21+import Native.Graphics.Input
22+import Text
23+
24+{-| Create uniform dimensions:
25+
26+ uniformly 4 == { left=4, right=4, top=4, bottom=4 }
27+
28+The following example creates an outline where the left, right, top, and bottom
29+edges all have width 1:
30+
31+ Outline grey (uniformly 1) 4
32+-}
33+uniformly : Int -> Dimensions
34+uniformly n = Dimensions n n n n
35+
36+{-| For setting dimensions of a fields padding or border. The left, right, top,
37+and bottom may all have different sizes. The following example creates
38+dimensions such that the left and right are twice as wide as the top and bottom:
39+
40+ myDimensions : Int -> Dimensions
41+ myDimensions n = { left = 2 * n, right = 2 * n, top = n, bottom = n }
42+-}
43+type Dimensions = { left:Int, right:Int, top:Int, bottom:Int }
44+
45+{-| A field can have a outline around it. This lets you set its color, width,
46+and radius. The radius allows you to round the corners of your field. Set the
47+width to zero to make it invisible. Here is an example outline that is grey
48+and thin with slightly rounded corners:
49+
50+ { color = grey, width = uniformly 1, radius = 4 }
51+-}
52+type Outline = { color:Color, width:Dimensions, radius:Int }
53+
54+{-| An outline with zero width, so you cannot see it. -}
55+noOutline : Outline
56+noOutline = Outline Color.grey (uniformly 0) 0
57+
58+{-| When a field has focus, it has a blue highlight around it by default. The
59+`Highlight` lets you set the `color` and `width` of this highlight. Set the
60+`width` to zero to turn the highlight off. Here is an example highlight that
61+is blue and thin:
62+
63+ { color = blue, width = 1 }
64+-}
65+type Highlight = { color:Color, width:Int }
66+
67+{-| An highlight with zero width, so you cannot see it. -}
68+noHighlight : Highlight
69+noHighlight = Highlight Color.blue 0
70+
71+{-| Describe the style of a text box. `style` describes the style of the text
72+itself using [`Text.Style`](/Text#Style). `outline` describes the glowing blue
73+outline that shows up when the field has focus. `outline` describes the line
74+surrounding the text field, and `padding` adds whitespace between the `outline`
75+and the text.
76+
77+The width and height of the text box *includes* the `padding` and `outline`.
78+Say we have a text box that is 40 pixels tall. It has a uniform outline of
79+1 pixel and a uniform padding of 5 pixels. Both of these must be subtracted
80+from the total height to determine how much room there is for text. The
81+`padding` and `outline` appear on the top and bottom, so there will be 28
82+vertical pixels remaining for the text (40 - 1 - 5 - 5 - 1).
83+-}
84+type Style =
85+ { padding : Dimensions
86+ , outline : Outline
87+ , highlight : Highlight
88+ , style : Text.Style
89+ }
90+
91+{-| The default style for a text field. The outline is `Color.grey` with width
92+1 and radius 2. The highlight is `Color.blue` with width 1, and the default
93+text color is black.
94+-}
95+defaultStyle : Style
96+defaultStyle =
97+ { padding = uniformly 4
98+ , outline = Outline Color.grey (uniformly 1) 2
99+ , highlight = Highlight Color.blue 1
100+ , style = Text.defaultStyle
101+ }
102+
103+{-| Represents the current content of a text field. For example:
104+
105+ content = Content "She sells sea shells" (Selection 0 3 Backward)
106+
107+This means the user highlighted the substring `"She"` backwards. The value of
108+`content.string` is `"She sells sea shells"`.
109+-}
110+type Content = { string:String, selection:Selection }
111+
112+{-| The selection within a text field. `start` is never greater than `end`:
113+
114+ Selection 0 0 Forward -- cursor precedes all characters
115+
116+ Selection 5 9 Backward -- highlighting characters starting after
117+ -- the 5th and ending after the 9th
118+-}
119+type Selection = { start:Int, end:Int, direction:Direction }
120+
121+{-| The direction of selection. When the user highlights a selection in a text
122+field, they must do it in a particular direction. This determines which end of
123+the selection moves when they change the selection by pressing Shift-Left or
124+Shift-Right.
125+-}
126+data Direction = Forward | Backward
127+
128+{-| A field with no content:
129+
130+ Content "" (Selection 0 0 Forward)
131+-}
132+noContent : Content
133+noContent = Content "" (Selection 0 0 Forward)
134+
135+{-| Create a text field. The following example creates a time-varying element
136+called `nameField`. As the user types their name, the field will be updated
137+to match what they have entered.
138+
139+ name : Input Content
140+ name = input noContent
141+
142+ nameField : Signal Element
143+ nameField = field defaultStyle name.handle id "Name" <~ name.signal
144+
145+When we use the `field` function, we first give it a visual style. This is
146+the first argument so that it is easier to define your own custom field
147+(`myField = field myStyle`). The next two arguments are a `Handle` and a
148+handler function that processes or augments events before sending them along
149+to the associated `Input`. In the example above we use the `id` function to
150+pass events along unchanged to the `name` `Input`. We then provide the
151+place-holder message to use when no input has been provided yet. Finally,
152+we give the current `Content` of the field. This argument is last because
153+it is most likely to change frequently, making function composition easier.
154+-}
155+field : Style -> Handle a -> (Content -> a) -> String -> Content -> Element
156+field = Native.Graphics.Input.field
157+
158+{-| Same as `field` but the UI element blocks out each characters. -}
159+password : Style -> Handle a -> (Content -> a) -> String -> Content -> Element
160+password = Native.Graphics.Input.password
161+
162+{-| Same as `field` but it adds an annotation that this field is for email
163+addresses. This is helpful for auto-complete and for mobile users who may
164+get a custom keyboard with an `@` and `.com` button.
165+-}
166+email : Style -> Handle a -> (Content -> a) -> String -> Content -> Element
167+email = Native.Graphics.Input.email
168+
169+-- area : Handle a -> (Content -> a) -> Handle b -> ((Int,Int) -> b) -> (Int,Int) -> String -> Content -> Element
170+-- area = Native.Graphics.Input.area
libraries/Http.elm+1−1
@@ -14,7 +14,7 @@ you have very strict latency requirements.
14@docs Response
14@docs Response
15-}
15-}
16
16
17−import open Signal
17+import Signal (..)
18import Native.Http
18import Native.Http
19
19
20{-| The datatype for responses. Success contains only the returned message.
20{-| The datatype for responses. Success contains only the returned message.
libraries/Json.elm+1−1
@@ -17,7 +17,7 @@ module Json where
17
17
18-}
18-}
19
19
20−import open Basics
20+import Basics (..)
21import Dict
21import Dict
22import Maybe (Maybe)
22import Maybe (Maybe)
23import JavaScript as JS
23import JavaScript as JS
libraries/List.elm+1−1
@@ -25,7 +25,7 @@ list must have the same type.
25@docs sort, sortBy, sortWith
25@docs sort, sortBy, sortWith
26-}
26-}
27
27
28−import open Basics
28+import Basics (..)
29import Native.List
29import Native.List
30
30
31{-| Add an element to the front of a list `(1 :: [2,3] == [1,2,3])` -}
31{-| Add an element to the front of a list `(1 :: [2,3] == [1,2,3])` -}
libraries/Maybe.elm+21−3
@@ -21,27 +21,45 @@ numbers).
21-}
21-}
22data Maybe a = Just a | Nothing
22data Maybe a = Just a | Nothing
23
23
24−{-| Apply a function to the contents of a `Maybe`.
24+{-| Provide a default value and a function to extract the contents of a `Maybe`.
25−Return default when given `Nothing`.
25+When given `Nothing` you get the default, when given a `Just` you apply the
26+function to the associated value.
27+
28+ isPositive : Maybe Int -> Bool
29+ isPositive maybeInt = maybe False (\n -> n > 0) maybeInt
30+
31+ map : (a -> b) -> Maybe a -> Maybe b
32+ map f m = maybe Nothing (\x -> Just (f x)) m
26-}
33-}
27maybe : b -> (a -> b) -> Maybe a -> b
34maybe : b -> (a -> b) -> Maybe a -> b
28maybe b f m = case m of
35maybe b f m = case m of
29 Just v -> f v
36 Just v -> f v
30 Nothing -> b
37 Nothing -> b
31
38
32−{-| Check if constructed with `Just`.
39+{-| Check if a maybe happens to be a `Just`.
40+
41+ isJust (Just 42) == True
42+ isJust (Just []) == True
43+ isJust Nothing == False
33-}
44-}
34isJust : Maybe a -> Bool
45isJust : Maybe a -> Bool
35isJust = maybe False (\_ -> True)
46isJust = maybe False (\_ -> True)
36
47
37{-| Check if constructed with `Nothing`.
48{-| Check if constructed with `Nothing`.
49+
50+ isNothing (Just 42) == False
51+ isNothing (Just []) == False
52+ isNothing Nothing == True
38-}
53-}
39isNothing : Maybe a -> Bool
54isNothing : Maybe a -> Bool
40isNothing = not . isJust
55isNothing = not . isJust
41
56
57+cons : Maybe a -> [a] -> [a]
42cons mx xs = maybe xs (\x -> x :: xs) mx
58cons mx xs = maybe xs (\x -> x :: xs) mx
43
59
44{-| Filters out Nothings and extracts the remaining values.
60{-| Filters out Nothings and extracts the remaining values.
61+
62+ justs [Just 0, Nothing, Just 5, Just 7] == [0,5,7]
45-}
63-}
46justs : [Maybe a] -> [a]
64justs : [Maybe a] -> [a]
47justs = foldr cons []
65justs = foldr cons []
libraries/Mouse.elm+1−6
@@ -7,7 +7,7 @@ module Mouse where
7@docs position, x, y
7@docs position, x, y
8
8
9# Button Status
9# Button Status
10−@docs isDown, clicks, isClicked
10+@docs isDown, clicks
11
11
12-}
12-}
13
13
@@ -31,11 +31,6 @@ True when the button is down, and false otherwise. -}
31isDown : Signal Bool
31isDown : Signal Bool
32isDown = Native.Mouse.isDown
32isDown = Native.Mouse.isDown
33
33
34−{-| True immediately after the left mouse-button has been clicked,
35−and false otherwise. -}
36−isClicked : Signal Bool
37−isClicked = Native.Mouse.isClicked
38−
39{-| Always equal to unit. Event triggers on every mouse click. -}
34{-| Always equal to unit. Event triggers on every mouse click. -}
40clicks : Signal ()
35clicks : Signal ()
41clicks = Native.Mouse.clicks
36clicks = Native.Mouse.clicks
libraries/Native/Basics.js+3
@@ -19,6 +19,7 @@ Elm.Native.Basics.make = function(elm) {
19 return Utils.cmp(n,lo) < 0 ? lo : Utils.cmp(n,hi) > 0 ? hi : n; }
19 return Utils.cmp(n,lo) < 0 ? lo : Utils.cmp(n,hi) > 0 ? hi : n; }
20 function xor(a,b) { return a !== b; }
20 function xor(a,b) { return a !== b; }
21 function not(b) { return !b; }
21 function not(b) { return !b; }
22+ function isInfinite(n) { return n === Infinity || n === -Infinity }
22
23
23 function truncate(n) { return n|0; }
24 function truncate(n) { return n|0; }
24
25
@@ -53,6 +54,8 @@ Elm.Native.Basics.make = function(elm) {
53 floor:Math.floor,
54 floor:Math.floor,
54 round:Math.round,
55 round:Math.round,
55 toFloat:function(x) { return x; },
56 toFloat:function(x) { return x; },
57+ isNaN:isNaN,
58+ isInfinite:isInfinite
56 };
59 };
57
60
58 return elm.Native.Basics.values = basics;
61 return elm.Native.Basics.values = basics;
libraries/Native/Bitwise.js+6−6
@@ -13,13 +13,13 @@ Elm.Native.Bitwise.make = function(elm) {
13 function srl(a,offset) { return a >>> offset; }
13 function srl(a,offset) { return a >>> offset; }
14
14
15 return elm.Native.Bitwise.values = {
15 return elm.Native.Bitwise.values = {
16− and: A2(and),
16+ and: F2(and),
17− or : A2(or ),
17+ or : F2(or ),
18− xor: A2(xor),
18+ xor: F2(xor),
19 complement: not,
19 complement: not,
20− shiftLeft : A2(sll),
20+ shiftLeft : F2(sll),
21− shiftRightArithmatic: A2(sra),
21+ shiftRightArithmatic: F2(sra),
22− shiftRightLogical : A2(srl),
22+ shiftRightLogical : F2(srl),
23 };
23 };
24
24
25};
25};
libraries/Native/Color.js+9−2
@@ -6,6 +6,12 @@ Elm.Native.Color.make = function(elm) {
6
6
7 var Utils = Elm.Native.Utils.make(elm);
7 var Utils = Elm.Native.Utils.make(elm);
8
8
9+ function toCss(c) {
10+ return (c._3 === 1)
11+ ? ('rgb(' + c._0 + ', ' + c._1 + ', ' + c._2 + ')')
12+ : ('rgba(' + c._0 + ', ' + c._1 + ', ' + c._2 + ', ' + c._3 + ')');
13+ }
14+
9 function complement(rgb) {
15 function complement(rgb) {
10 var hsv = toHSV(rgb);
16 var hsv = toHSV(rgb);
11 hsv.hue = (hsv.hue + 180) % 360;
17 hsv.hue = (hsv.hue + 180) % 360;
@@ -63,7 +69,8 @@ Elm.Native.Color.make = function(elm) {
63 return elm.Native.Color.values = {
69 return elm.Native.Color.values = {
64 hsva:F4(hsva),
70 hsva:F4(hsva),
65 hsv:F3(hsv),
71 hsv:F3(hsv),
66− complement:complement
72+ complement:complement,
73+ toCss:toCss
67 };
74 };
68
75
69−};
76+};
libraries/Native/Date.js+1
@@ -27,6 +27,7 @@ Elm.Native.Date.make = function(elm) {
27 minute : function(d) { return d.getMinutes(); },
27 minute : function(d) { return d.getMinutes(); },
28 second : function(d) { return d.getSeconds(); },
28 second : function(d) { return d.getSeconds(); },
29 toTime : function(d) { return d.getTime(); },
29 toTime : function(d) { return d.getTime(); },
30+ fromTime: function(t) { return new window.Date(t); },
30 dayOfWeek : function(d) { return { ctor:dayTable[d.getDay()] }; }
31 dayOfWeek : function(d) { return { ctor:dayTable[d.getDay()] }; }
31 };
32 };
32
33
libraries/Native/Debug.jsnew file+24
@@ -0,0 +1,24 @@
1+Elm.Native.Debug = {};
2+Elm.Native.Debug.make = function(elm) {
3+ elm.Native = elm.Native || {};
4+ elm.Native.Debug = elm.Native.Debug || {};
5+ if (elm.Native.Debug.values) return elm.Native.Debug.values;
6+
7+ var show = Elm.Native.Show.make(elm).show;
8+
9+ function log(tag,value) {
10+ var msg = tag + ': ' + show(value);
11+ var process = process || {};
12+ if (process.stdout) {
13+ process.stdout.write(msg);
14+ } else {
15+ console.log(msg);
16+ }
17+ return value;
18+ }
19+
20+ return elm.Native.Debug.values = {
21+ log: F2(log)
22+ };
23+
24+};
libraries/Native/Graphics/Input.js+403−299
@@ -1,303 +1,407 @@
1Elm.Native.Graphics.Input = {};
1Elm.Native.Graphics.Input = {};
2Elm.Native.Graphics.Input.make = function(elm) {
2Elm.Native.Graphics.Input.make = function(elm) {
3−
4− elm.Native = elm.Native || {};
3+ elm.Native = elm.Native || {};
5− elm.Native.Graphics = elm.Native.Graphics || {};
4+ elm.Native.Graphics = elm.Native.Graphics || {};
6− elm.Native.Graphics.Input = elm.Native.Graphics.Input || {};
5+ elm.Native.Graphics.Input = elm.Native.Graphics.Input || {};
7− if (elm.Native.Graphics.Input.values) return elm.Native.Graphics.Input.values;
6+ if (elm.Native.Graphics.Input.values) return elm.Native.Graphics.Input.values;
8−
7+
9− var Render = ElmRuntime.use(ElmRuntime.Render.Element);
8+ var Render = ElmRuntime.use(ElmRuntime.Render.Element);
10− var newNode = ElmRuntime.use(ElmRuntime.Render.Utils).newElement;
9+ var newNode = ElmRuntime.use(ElmRuntime.Render.Utils).newElement;
11−
10+
11+ var toCss = Elm.Native.Color.make(elm).toCss;
12+ var Text = Elm.Native.Text.make(elm);
12− var Signal = Elm.Signal.make(elm);
13+ var Signal = Elm.Signal.make(elm);
13− var newElement = Elm.Graphics.Element.make(elm).newElement;
14+ var newElement = Elm.Graphics.Element.make(elm).newElement;
14− var JS = Elm.Native.JavaScript.make(elm);
15+ var JS = Elm.Native.JavaScript.make(elm);
15− var Utils = Elm.Native.Utils.make(elm);
16+ var Utils = Elm.Native.Utils.make(elm);
16− var Tuple2 = Utils.Tuple2;
17+ var Tuple2 = Utils.Tuple2;
17−
18+
19+ function input(initialValue) {
20+ var signal = Signal.constant(initialValue);
21+ return { _:{}, signal:signal, handle:signal };
22+ }
23+
18− function dropDown(values) {
24+ function renderDropDown(signal, values) {
25+ return function(_) {
19− var entries = JS.fromList(values);
26+ var entries = JS.fromList(values);
20− var events = Signal.constant(entries[0]._1);
27+
21−
22− var drop = newNode('select');
28+ var drop = newNode('select');
23− drop.style.border = '0 solid';
29+ drop.style.border = '0 solid';
30+ drop.style.pointerEvents = 'auto';
24− for (var i = 0; i < entries.length; ++i) {
31+ for (var i = 0; i < entries.length; ++i) {
25− var option = newNode('option');
32+ var option = newNode('option');
26− var name = JS.fromString(entries[i]._0);
33+ var name = JS.fromString(entries[i]._0);
27− option.value = name;
34+ option.value = name;
28− option.innerHTML = name;
35+ option.innerHTML = name;
29− drop.appendChild(option);
36+ drop.appendChild(option);
30− }
37+ }
31− drop.addEventListener('change', function() {
38+ drop.addEventListener('change', function() {
32− elm.notify(events.id, entries[drop.selectedIndex]._1);
39+ elm.notify(signal.id, entries[drop.selectedIndex]._1);
33− });
40+ });
34−
41+
35− var t = drop.cloneNode(true);
42+ var t = drop.cloneNode(true);
36− t.style.visibility = "hidden";
43+ t.style.visibility = "hidden";
37−
44+
38− elm.node.appendChild(t);
45+ elm.node.appendChild(t);
39− var style = window.getComputedStyle(t, null);
46+ var style = window.getComputedStyle(t, null);
40− var w = Math.ceil(style.getPropertyValue("width").slice(0,-2) - 0);
47+ var w = Math.ceil(style.getPropertyValue("width").slice(0,-2) - 0);
41− var h = Math.ceil(style.getPropertyValue("height").slice(0,-2) - 0);
48+ var h = Math.ceil(style.getPropertyValue("height").slice(0,-2) - 0);
42− elm.node.removeChild(t);
49+ elm.node.removeChild(t);
43−
50+ return drop;
51+ };
52+ }
53+
54+ function updateDropDown(node, oldModel, newModel) {
55+ }
56+
57+ function dropDown(signal, values) {
44− var element = A3(newElement, w, h, {
58+ return A3(newElement, 100, 24, {
45− ctor: 'Custom',
59+ ctor: 'Custom',
46− type: 'DropDown',
60+ type: 'DropDown',
47− render: function render(model) { return drop; },
61+ render: renderDropDown(signal,values),
48− update: function update(node, oldModel, newModel) {},
62+ update: updateDropDown,
49− model: {}
63+ model: {}
50− });
64+ });
51−
52− return Tuple2(Signal.constant(element), events);
53− }
65+ }
54−
66+
55− function buttons(defaultValue) {
67+ function renderButton(model) {
56− var events = Signal.constant(defaultValue);
68+ var node = newNode('button');
57−
69+ node.style.display = 'block';
58− function render(model) {
70+ node.style.pointerEvents = 'auto';
59− var b = newNode('button');
71+ node.elm_signal = model.signal;
60− b.style.display = 'block';
72+ node.elm_value = model.value;
61− b.elmEvent = model.event;
62− function click() { elm.notify(events.id, b.elmEvent); }
73+ function click() {
74+ elm.notify(node.elm_signal.id, node.elm_value);
75+ }
63− b.addEventListener('click', click);
76+ node.addEventListener('click', click);
64− b.innerHTML = model.text;
77+ node.innerHTML = model.text;
65− return b;
78+ return node;
66− }
79+ }
67−
80+
68− function update(node, oldModel, newModel) {
81+ function updateButton(node, oldModel, newModel) {
82+ node.elm_signal = newModel.signal;
69− node.elmEvent = newModel.event;
83+ node.elm_value = newModel.value;
70− var txt = newModel.text;
84+ var txt = newModel.text;
71− if (oldModel.text !== txt) node.innerHTML = txt;
85+ if (oldModel.text !== txt) node.innerHTML = txt;
72− }
86+ }
73−
87+
74− function button(evnt, txt) {
88+ function button(signal, value, text) {
75− return A3(newElement, 100, 40, {
89+ return A3(newElement, 100, 40, {
76− ctor: 'Custom',
90+ ctor: 'Custom',
77− type: 'Button',
91+ type: 'Button',
78− render: render,
92+ render: renderButton,
79− update: update,
93+ update: updateButton,
80− model: { event:evnt, text:JS.fromString(txt) }
94+ model: { signal:signal, value:value, text:JS.fromString(text) }
81− });
95+ });
82− }
96+ }
83−
97+
84− return { _:{}, button:F2(button), events:events };
98+ function renderCustomButton(model) {
85− }
99+ var btn = newNode('div');
86−
100+ btn.style.pointerEvents = 'auto';
87− function customButtons(defaultValue) {
101+ btn.elm_signal = model.signal;
88− var events = Signal.constant(defaultValue);
102+ btn.elm_value = model.value;
89−
103+
90− function render(model) {
91− var btn = newNode('div');
92− btn.elmEvent = model.event;
93−
94− btn.elmUp = Render.render(model.up);
104+ btn.elm_up = Render.render(model.up);
95− btn.elmHover = Render.render(model.hover);
105+ btn.elm_hover = Render.render(model.hover);
96− btn.elmDown = Render.render(model.down);
106+ btn.elm_down = Render.render(model.down);
97−
107+
98− function replace(node) {
108+ function replace(node) {
109+ if (node !== btn.firstChild) {
99− if (node !== btn.firstChild) btn.replaceChild(node, btn.firstChild);
110+ btn.replaceChild(node, btn.firstChild);
111+ }
100− }
112+ }
101− var overCount = 0;
113+ var overCount = 0;
102− function over(e) {
114+ function over(e) {
103− if (overCount++ > 0) return;
115+ if (overCount++ > 0) return;
104− replace(btn.elmHover);
116+ replace(btn.elm_hover);
105− }
117+ }
106− function out(e) {
118+ function out(e) {
107− if (btn.contains(e.toElement || e.relatedTarget)) return;
119+ if (btn.contains(e.toElement || e.relatedTarget)) return;
108− overCount = 0;
120+ overCount = 0;
109− replace(btn.elmUp);
121+ replace(btn.elm_up);
110− }
122+ }
111− function up() {
123+ function up() {
112− replace(btn.elmHover);
124+ replace(btn.elm_hover);
113− elm.notify(events.id, btn.elmEvent);
125+ elm.notify(btn.elm_signal.id, btn.elm_value);
114− }
126+ }
115− function down() { replace(btn.elmDown); }
127+ function down() {
128+ replace(btn.elm_down);
129+ }
116− btn.addEventListener('mouseover', over);
130+ btn.addEventListener('mouseover', over);
117− btn.addEventListener('mouseout' , out);
131+ btn.addEventListener('mouseout' , out);
118− btn.addEventListener('mousedown', down);
132+ btn.addEventListener('mousedown', down);
119− btn.addEventListener('mouseup' , up);
133+ btn.addEventListener('mouseup' , up);
120−
134+
121− btn.appendChild(btn.elmUp);
135+ btn.appendChild(btn.elm_up);
122−
136+
123− var clicker = newNode('div');
137+ var clicker = newNode('div');
124− clicker.style.width = btn.elmUp.style.width;
138+ clicker.style.width = btn.elm_up.style.width;
125− clicker.style.height = btn.elmUp.style.height;
139+ clicker.style.height = btn.elm_up.style.height;
126− clicker.style.position = 'absolute';
140+ clicker.style.position = 'absolute';
127− clicker.style.top = 0;
141+ clicker.style.top = 0;
128− btn.appendChild(clicker);
142+ btn.appendChild(clicker);
129−
143+
130− return btn;
144+ return btn;
131− }
145+ }
132−
146+
133− function update(node, oldModel, newModel) {
147+ function updateCustomButton(node, oldModel, newModel) {
134− node.elmEvent = newModel.event;
148+ var signal = newModel.signal;
149+ node.elm_up.elm_signal = signal;
150+ node.elm_hover.elm_signal = signal;
151+ node.elm_down.elm_signal = signal;
152+
153+ var value = newModel.value;
154+ node.elm_up.elm_value = value;
155+ node.elm_hover.elm_value = value;
156+ node.elm_down.elm_value = value;
157+
135− Render.update(node.elmUp, oldModel.up, newModel.up)
158+ Render.update(node.elm_up, oldModel.up, newModel.up)
136− Render.update(node.elmHover, oldModel.hover, newModel.hover)
159+ Render.update(node.elm_hover, oldModel.hover, newModel.hover)
137− Render.update(node.elmDown, oldModel.down, newModel.down)
160+ Render.update(node.elm_down, oldModel.down, newModel.down)
138− }
161+ }
139−
162+
140− function button(evnt, up, hover, down) {
163+ function max3(a,b,c) {
164+ var ab = a > b ? a : b;
165+ return ab > c ? ab : c;
166+ }
167+
168+ function customButton(signal, value, up, hover, down) {
141− return A3(newElement,
169+ return A3(newElement,
142− Math.max(up.props.width, hover.props.width, down.props.width),
170+ max3(up.props.width, hover.props.width, down.props.width),
143− Math.max(up.props.height, hover.props.height, down.props.height),
171+ max3(up.props.height, hover.props.height, down.props.height),
144− { ctor: 'Custom',
172+ { ctor: 'Custom',
145− type: 'CustomButton',
173+ type: 'CustomButton',
146− render: render,
174+ render: renderCustomButton,
147− update: update,
175+ update: updateCustomButton,
148− model: { event:evnt, up:up, hover:hover, down:down }
176+ model: { signal:signal, value:value, up:up, hover:hover, down:down }
149− });
177+ });
150− }
151−
152− return { _:{}, customButton:F4(button), events:events };
153− }
178+ }
154−
179+
155−
180+ function renderCheckbox(model) {
156− function hoverables(defaultValue) {
181+ var node = newNode('input');
157− var events = Signal.constant(defaultValue);
182+ node.type = 'checkbox';
158− function hoverable(handler, elem) {
183+ node.checked = model.checked;
159− function onHover(bool) {
184+ node.style.display = 'block';
160− elm.notify(events.id, handler(bool));
185+ node.style.pointerEvents = 'auto';
161− }
186+ node.elm_signal = model.signal;
162− var props = Utils.replace([['hover',onHover]], elem.props);
163− return { props:props, element:elem.element };
164− }
165− return { _:{}, hoverable:F2(hoverable), events:events };
166− }
167−
168−
169− function checkboxes(defaultValue) {
170− var events = Signal.constant(defaultValue);
171−
172− function render(model) {
173− var b = newNode('input');
174− b.type = 'checkbox';
175− b.checked = model.checked;
176− b.style.display = 'block';
177− b.elmHandler = model.handler;
187+ node.elm_handler = model.handler;
178− function change() { elm.notify(events.id, b.elmHandler(b.checked)); }
188+ function change() {
189+ elm.notify(node.elm_signal.id, node.elm_handler(node.checked));
190+ }
179− b.addEventListener('change', change);
191+ node.addEventListener('change', change);
180− return b;
192+ return node;
181− }
193+ }
182−
194+
183− function update(node, oldModel, newModel) {
195+ function updateCheckbox(node, oldModel, newModel) {
184− node.elmHandler = newModel.handler;
196+ node.elm_signal = newModel.signal;
197+ node.elm_handler = newModel.handler;
185− node.checked = newModel.checked;
198+ node.checked = newModel.checked;
186− return true;
199+ return true;
187− }
200+ }
188−
201+
189− function box(handler, checked) {
202+ function checkbox(signal, handler, checked) {
190− return A3(newElement, 13, 13, {
203+ return A3(newElement, 13, 13, {
191− ctor: 'Custom',
204+ ctor: 'Custom',
192− type: 'CheckBox',
205+ type: 'CheckBox',
193− render: render,
206+ render: renderCheckbox,
194− update: update,
207+ update: updateCheckbox,
195− model: { checked:checked, handler:handler }
208+ model: { signal:signal, handler:handler, checked:checked }
196− });
209+ });
197− }
198−
199− return { _:{}, checkbox:F2(box), events:events };
200− }
210+ }
201−
211+
202− function setRange(node, start, end, dir) {
212+ function setRange(node, start, end, dir) {
203− if (node.parentNode) {
213+ if (node.parentNode) {
204− node.setSelectionRange(start, end, dir);
214+ node.setSelectionRange(start, end, dir);
205− } else {
215+ } else {
206− setTimeout(function(){node.setSelectionRange(start, end, dir);}, 0);
216+ setTimeout(function(){node.setSelectionRange(start, end, dir);}, 0);
207− }
217+ }
208− }
218+ }
209−
219+
210− function mkTextPool(type) { return function fields(defaultValue) {
220+ function updateIfNeeded(css, attribute, latestAttribute) {
211− var events = Signal.constant(defaultValue);
221+ if (css[attribute] !== latestAttribute) {
212−
222+ css[attribute] = latestAttribute;
213− var state = null;
223+ }
214−
224+ }
215− function render(model) {
225+ function cssDimensions(dimensions) {
216− var field = newNode('input');
226+ return dimensions.top + 'px ' +
217− field.elmHandler = model.handler;
227+ dimensions.right + 'px ' +
218−
228+ dimensions.bottom + 'px ' +
219− field.id = 'test';
229+ dimensions.left + 'px';
220− field.type = type;
230+ }
221− field.placeholder = JS.fromString(model.placeHolder);
231+ function updateFieldStyle(css, style) {
222− field.value = JS.fromString(model.state.string);
232+ updateIfNeeded(css, 'padding', cssDimensions(style.padding));
223− setRange(field, model.state.selectionStart, model.state.selectionEnd, 'forward');
233+
224− field.style.border = 'none';
234+ var outline = style.outline;
225− state = model.state;
235+ updateIfNeeded(css, 'border-width', cssDimensions(outline.width));
226−
236+ updateIfNeeded(css, 'border-color', toCss(outline.color));
237+ updateIfNeeded(css, 'border-radius', outline.radius + 'px');
238+
239+ var highlight = style.highlight;
240+ if (highlight.width === 0) {
241+ css.outline = 'none';
242+ } else {
243+ updateIfNeeded(css, 'outline-width', highlight.width + 'px');
244+ updateIfNeeded(css, 'outline-color', toCss(highlight.color));
245+ }
246+
247+ var textStyle = style.style;
248+ updateIfNeeded(css, 'color', toCss(textStyle.color));
249+ if (textStyle.typeface.ctor !== '[]') {
250+ updateIfNeeded(css, 'font-family', Text.toTypefaces(textStyle.typeface));
251+ }
252+ if (textStyle.height.ctor !== "Nothing") {
253+ updateIfNeeded(css, 'font-size', textStyle.height._0 + 'px');
254+ }
255+ updateIfNeeded(css, 'font-weight', textStyle.bold ? 'bold' : 'normal');
256+ updateIfNeeded(css, 'font-style', textStyle.italic ? 'italic' : 'normal');
257+ if (textStyle.line.ctor !== 'Nothing') {
258+ updateIfNeeded(css, 'text-decoration', Text.toLine(textStyle.line._0));
259+ }
260+ }
261+
262+ function renderField(model) {
263+ var field = newNode('input');
264+ updateFieldStyle(field.style, model.style);
265+ field.style.borderStyle = 'solid';
266+ field.style.pointerEvents = 'auto';
267+
268+ field.type = model.type;
269+ field.placeholder = JS.fromString(model.placeHolder);
270+ field.value = JS.fromString(model.content.string);
271+
272+ field.elm_signal = model.signal;
273+ field.elm_handler = model.handler;
274+ field.elm_old_value = field.value;
275+
227− function update() {
276+ function inputUpdate(event) {
228− var start = field.selectionStart,
277+ var curr = field.elm_old_value;
229− end = field.selectionEnd;
278+ var next = field.value;
279+ if (curr === next) {
280+ return;
281+ }
282+
230− if (field.selectionDirection === 'backward') {
283+ var direction = field.selectionDirection === 'forward' ? 'Forward' : 'Backward';
231− start = end;
284+ var start = field.selectionStart;
232− end = field.selectionStart;
285+ var end = field.selectionEnd;
233− }
286+ field.value = field.elm_old_value;
234− state = { _:{},
287+
288+ elm.notify(field.elm_signal.id, field.elm_handler({
289+ _:{},
235− string:JS.toString(field.value),
290+ string: JS.toString(next),
236− selectionStart:start,
291+ selection: {
237− selectionEnd:end };
292+ _:{},
293+ start: start,
294+ end: end,
295+ direction: { ctor: direction }
296+ },
297+ }));
298+ }
299+
300+ function mouseUpdate(event) {
301+ var direction = field.selectionDirection === 'forward' ? 'Forward' : 'Backward';
238− elm.notify(events.id, field.elmHandler(state));
302+ elm.notify(field.elm_signal.id, field.elm_handler({
303+ _:{},
304+ string: field.value,
305+ selection: {
306+ _:{},
307+ start: field.selectionStart,
308+ end: field.selectionEnd,
309+ direction: { ctor: direction }
310+ },
311+ }));
239− }
312+ }
240− function mousedown() {
313+ function mousedown(event) {
241− update();
314+ mouseUpdate(event);
242− elm.node.addEventListener('mouseup', mouseup);
315+ elm.node.addEventListener('mouseup', mouseup);
243− }
316+ }
244− function mouseup() {
317+ function mouseup(event) {
245− update();
318+ mouseUpdate(event);
246− elm.node.removeEventListener('mouseup', mouseup)
319+ elm.node.removeEventListener('mouseup', mouseup)
247− }
320+ }
248− field.addEventListener('keyup', update);
321+ field.addEventListener('input', inputUpdate);
249− field.addEventListener('mousedown', mousedown);
322+ field.addEventListener('mousedown', mousedown);
250−
323+ field.addEventListener('focus', function() {
324+ field.elm_hasFocus = true;
325+ });
326+ field.addEventListener('blur', function() {
327+ field.elm_hasFocus = false;
328+ });
329+
251− return field;
330+ return field;
252− }
331+ }
253−
332+
254− function update(node, oldModel, newModel) {
333+ function updateField(field, oldModel, newModel) {
255− node.elmHandler = newModel.handler;
334+ if (oldModel.style !== newModel.style) {
256− if (state === newModel.state) return;
335+ updateFieldStyle(field.style, newModel.style);
257− var newStr = JS.fromString(newModel.state.string);
336+ }
258− if (node.value !== newStr) node.value = newStr;
337+ field.elm_signal = newModel.signal;
259−
338+ field.elm_handler = newModel.handler;
260− var start = newModel.state.selectionStart;
339+
261− var end = newModel.state.selectionEnd;
340+ field.type = newModel.type;
262− var direction = 'forward';
341+ field.placeholder = JS.fromString(newModel.placeHolder);
263− if (end < start) {
342+ var value = JS.fromString(newModel.content.string);
264− start = end;
343+ field.value = value;
265− end = newModel.state.selectionStart;
344+ field.elm_old_value = value;
266− direction = 'backward';
345+ if (field.elm_hasFocus) {
267− }
346+ var selection = newModel.content.selection;
268−
347+ var direction = selection.direction.ctor === 'Forward' ? 'forward' : 'backward';
269− if (node.selectionStart !== start
270− || node.selectionEnd !== end
271− || node.selectionDirection !== direction) {
272− setRange(node, start, end, direction);
348+ setRange(field, selection.start, selection.end, direction);
273− }
349+ }
274− }
350+ }
275−
351+
352+ function mkField(type) {
276− function field(handler, placeHolder, state) {
353+ function field(style, signal, handler, placeHolder, content) {
354+ var padding = style.padding;
355+ var outline = style.outline.width;
356+ var adjustWidth = padding.left + padding.right + outline.left + outline.right;
357+ var adjustHeight = padding.top + padding.bottom + outline.top + outline.bottom;
277− return A3(newElement, 200, 30,
358+ return A3(newElement, 200, 30, {
278− { ctor: 'Custom',
359+ ctor: 'Custom',
279− type: type + 'Input',
360+ type: type + 'Field',
361+ adjustWidth: adjustWidth,
362+ adjustHeight: adjustHeight,
280− render: render,
363+ render: renderField,
281− update: update,
364+ update: updateField,
365+ model: {
366+ signal:signal,
282− model: { handler:handler,
367+ handler:handler,
283− placeHolder:placeHolder,
368+ placeHolder:placeHolder,
284− state:state }
369+ content:content,
370+ style:style,
371+ type:type
372+ }
285− });
373+ });
286− }
374+ }
287−
375+ return F5(field);
288− return { _:{}, field:F3(field), events:events };
376+ }
377+
378+ function hoverable(signal, handler, elem) {
379+ function onHover(bool) {
380+ elm.notify(signal.id, handler(bool));
381+ }
382+ var props = Utils.replace([['hover',onHover]], elem.props);
383+ return { props:props, element:elem.element };
289− }
384+ }
385+
386+ function clickable(signal, value, elem) {
387+ function onClick(bool) {
388+ elm.notify(signal.id, value);
290− }
389+ }
291−
390+ var props = Utils.replace([['click',onClick]], elem.props);
391+ return { props:props, element:elem.element };
392+ }
393+
292− return elm.Native.Graphics.Input.values = {
394+ return elm.Native.Graphics.Input.values = {
293− buttons:buttons,
395+ input:input,
294− customButtons:customButtons,
396+ button:F3(button),
295− hoverables:hoverables,
397+ customButton:F5(customButton),
296− checkboxes:checkboxes,
398+ checkbox:F3(checkbox),
297− fields:mkTextPool('text'),
399+ dropDown:F2(dropDown),
298− emails:mkTextPool('email'),
400+ field:mkField('text'),
299− passwords:mkTextPool('password'),
401+ email:mkField('email'),
300− dropDown:dropDown
402+ password:mkField('password'),
403+ hoverable:F3(hoverable),
404+ clickable:F3(clickable)
301− };
405+ };
302
406
303};
407};
libraries/Native/Regex.js+11−20
@@ -15,18 +15,16 @@ Elm.Native.Regex.make = function(elm) {
15 function caseInsensitive(re) {
15 function caseInsensitive(re) {
16 return new RegExp(re.source, 'gi');
16 return new RegExp(re.source, 'gi');
17 }
17 }
18− function pattern(raw) {
18+ function regex(raw) {
19 return new RegExp(raw, 'g');
19 return new RegExp(raw, 'g');
20 }
20 }
21
21
22 function contains(re, string) {
22 function contains(re, string) {
23− return re.test(JS.fromString(string));
23+ return JS.fromString(string).match(re) !== null;
24 }
24 }
25
25
26− function findAll(re, string) {
27− return find(Infinity, re, string);
28− }
29 function find(n, re, str) {
26 function find(n, re, str) {
27+ n = n.ctor === "All" ? Infinity : n._0;
30 var out = [];
28 var out = [];
31 var number = 0;
29 var number = 0;
32 var string = JS.fromString(str);
30 var string = JS.fromString(str);
@@ -51,10 +49,8 @@ Elm.Native.Regex.make = function(elm) {
51 return JS.toList(out);
49 return JS.toList(out);
52 }
50 }
53
51
54− function replaceAll(re, replacer, string) {
55− return replace(Infinity, re, replacer, string);
56− }
57 function replace(n, re, replacer, string) {
52 function replace(n, re, replacer, string) {
53+ n = n.ctor === "All" ? Infinity : n._0;
58 var count = 0;
54 var count = 0;
59 function jsReplacer(match) {
55 function jsReplacer(match) {
60 if (count++ > n) return match;
56 if (count++ > n) return match;
@@ -77,10 +73,10 @@ Elm.Native.Regex.make = function(elm) {
77 return string.replace(re, jsReplacer);
73 return string.replace(re, jsReplacer);
78 }
74 }
79
75
80− function split(re, string) {
76+ function split(n, re, str) {
77+ if (n === Infinity) {
81− return JS.toList(JS.fromString(string).split(re));
78+ return JS.toList(JS.fromString(string).split(re));
82− }
79+ }
83− function splitN(n, re, str) {
84 var string = JS.fromString(str);
80 var string = JS.fromString(str);
85 var result;
81 var result;
86 var out = [];
82 var out = [];
@@ -95,18 +91,13 @@ Elm.Native.Regex.make = function(elm) {
95 }
91 }
96
92
97 return Elm.Native.Regex.values = {
93 return Elm.Native.Regex.values = {
98− pattern: pattern,
94+ regex: regex,
99 caseInsensitive: caseInsensitive,
95 caseInsensitive: caseInsensitive,
100 escape: escape,
96 escape: escape,
101
97
102 contains: F2(contains),
98 contains: F2(contains),
103− findAll: F2(findAll),
104 find: F3(find),
99 find: F3(find),
105−
106− replaceAll: F3(replaceAll),
107 replace: F4(replace),
100 replace: F4(replace),
108−
109− split: F2(split),
101+ split: F3(split),
110− splitN: F3(splitN),
111 };
102 };
112−};
103+};
libraries/Native/Show.js−3
@@ -6,10 +6,7 @@ Elm.Native.Show.make = function(elm) {
6
6
7 var NList = Elm.Native.List.make(elm);
7 var NList = Elm.Native.List.make(elm);
8 var List = Elm.List.make(elm);
8 var List = Elm.List.make(elm);
9− var Maybe = Elm.Maybe.make(elm);
10− var JS = Elm.JavaScript.make(elm);
11 var Dict = Elm.Dict.make(elm);
9 var Dict = Elm.Dict.make(elm);
12− var Json = Elm.Json.make(elm);
13 var Tuple2 = Elm.Native.Utils.make(elm).Tuple2;
10 var Tuple2 = Elm.Native.Utils.make(elm).Tuple2;
14
11
15 var toString = function(v) {
12 var toString = function(v) {
libraries/Native/Signal/Http.js+52−49
@@ -1,61 +1,64 @@
1Elm.Native.Http = {};
1Elm.Native.Http = {};
2Elm.Native.Http.make = function(elm) {
2Elm.Native.Http.make = function(elm) {
3
3
4− elm.Native = elm.Native || {};
4+ elm.Native = elm.Native || {};
5− elm.Native.Http = elm.Native.Http || {};
5+ elm.Native.Http = elm.Native.Http || {};
6− if (elm.Native.Http.values) return elm.Native.Http.values;
6+ if (elm.Native.Http.values) return elm.Native.Http.values;
7
7
8+ var JS = Elm.JavaScript.make(elm);
9+ var List = Elm.List.make(elm);
10+ var Signal = Elm.Signal.make(elm);
8
11
9− var JS = Elm.JavaScript.make(elm);
12+ function registerReq(queue,responses) {
10− var List = Elm.List.make(elm);
13+ return function(req) {
11− var Signal = Elm.Signal.make(elm);
14+ if (req.url.length > 0) {
15+ sendReq(queue,responses,req);
16+ }
17+ };
18+ }
12
19
20+ function updateQueue(queue,responses) {
21+ if (queue.length > 0) {
22+ elm.notify(responses.id, queue[0].value);
23+ if (queue[0].value.ctor !== 'Waiting') {
24+ queue.shift();
25+ setTimeout(function() { updateQueue(queue,responses); }, 0);
26+ }
27+ }
28+ }
13
29
14− function registerReq(queue,responses) { return function(req) {
15− if (req.url.ctor !== '[]') { sendReq(queue,responses,req); }
30+ function sendReq(queue,responses,req) {
16− };
31+ var response = { value: { ctor:'Waiting' } };
17− }
32+ queue.push(response);
18
33
19− function updateQueue(queue,responses) {
34+ var request = (window.ActiveXObject
20− if (queue.length > 0) {
21− elm.notify(responses.id, queue[0].value);
22− if (queue[0].value.ctor !== 'Waiting') {
23− queue.shift();
24− setTimeout(function() { updateQueue(queue,responses); }, 0);
25− }
26− }
27− }
28−
29− function sendReq(queue,responses,req) {
30− var response = { value: { ctor:'Waiting' } };
31− queue.push(response);
32−
33− var request = null;
34− if (window.ActiveXObject) { request = new ActiveXObject("Microsoft.XMLHTTP"); }
35+ ? new ActiveXObject("Microsoft.XMLHTTP")
35− if (window.XMLHttpRequest) { request = new XMLHttpRequest(); }
36+ : new XMLHttpRequest());
36− request.onreadystatechange = function(e) {
37− if (request.readyState === 4) {
38− response.value = (request.status >= 200 && request.status < 300 ?
39− { ctor:'Success', _0:JS.toString(request.responseText) } :
40− { ctor:'Failure', _0:request.status, _1:JS.toString(request.statusText) });
41− setTimeout(function() { updateQueue(queue,responses); }, 0);
42− }
43− };
44− request.open(JS.fromString(req.verb), JS.fromString(req.url), true);
45− function setHeader(pair) {
46− request.setRequestHeader( JS.fromString(pair._0), JS.fromString(pair._1) );
47− }
48− List.map(setHeader)(req.headers);
49− request.send(JS.fromString(req.body));
50− }
51
37
52− function send(requests) {
38+ request.onreadystatechange = function(e) {
53− var responses = Signal.constant(elm.Http.values.Waiting);
39+ if (request.readyState === 4) {
54− var sender = A2( Signal.lift, registerReq([],responses), requests );
40+ response.value = (request.status >= 200 && request.status < 300 ?
55− function f(x) { return function(y) { return x; } }
41+ { ctor:'Success', _0:JS.toString(request.responseText) } :
56− return A3( Signal.lift2, f, responses, sender );
42+ { ctor:'Failure', _0:request.status, _1:JS.toString(request.statusText) });
43+ setTimeout(function() { updateQueue(queue,responses); }, 0);
44+ }
45+ };
46+ request.open(JS.fromString(req.verb), JS.fromString(req.url), true);
47+ function setHeader(pair) {
48+ request.setRequestHeader( JS.fromString(pair._0), JS.fromString(pair._1) );
49+ }
50+ List.map(setHeader)(req.headers);
51+ request.send(JS.fromString(req.body));
57− }
52+ }
58
53
59− return elm.Native.Http.values = {send:send};
54+ function send(requests) {
55+ var responses = Signal.constant(elm.Http.values.Waiting);
56+ var sender = A2( Signal.lift, registerReq([],responses), requests );
57+ function f(x) { return function(y) { return x; } }
58+ return A3( Signal.lift2, f, responses, sender );
59+ }
60
60
61+ return elm.Native.Http.values = {
62+ send:send
63+ };
61};
64};
libraries/Native/Signal/Mouse.js+2−6
@@ -20,15 +20,12 @@ Elm.Native.Mouse.make = function(elm) {
20 y.defaultNumberOfKids = 0;
20 y.defaultNumberOfKids = 0;
21
21
22 var isDown = Signal.constant(false);
22 var isDown = Signal.constant(false);
23− var isClicked = Signal.constant(false);
24 var clicks = Signal.constant(Utils.Tuple0);
23 var clicks = Signal.constant(Utils.Tuple0);
25
24
26 var node = elm.display === ElmRuntime.Display.FULLSCREEN ? document : elm.node;
25 var node = elm.display === ElmRuntime.Display.FULLSCREEN ? document : elm.node;
27
26
28− elm.addListener([isClicked.id, clicks.id], node, 'click', function click() {
27+ elm.addListener([clicks.id], node, 'click', function click() {
29− elm.notify(isClicked.id, true);
30 elm.notify(clicks.id, Utils.Tuple0);
28 elm.notify(clicks.id, Utils.Tuple0);
31− elm.notify(isClicked.id, false);
32 });
29 });
33 elm.addListener([isDown.id], node, 'mousedown', function down() {
30 elm.addListener([isDown.id], node, 'mousedown', function down() {
34 elm.notify(isDown.id, true);
31 elm.notify(isDown.id, true);
@@ -44,8 +41,7 @@ Elm.Native.Mouse.make = function(elm) {
44 position: position,
41 position: position,
45 x:x,
42 x:x,
46 y:y,
43 y:y,
47− isClicked: isClicked,
48 isDown: isDown,
44 isDown: isDown,
49 clicks: clicks
45 clicks: clicks
50 };
46 };
51−};
47+};
libraries/Native/Signal/Signal.js−9
@@ -127,12 +127,6 @@ Elm.Native.Signal.make = function(elm) {
127 input.kids.push(this);
127 input.kids.push(this);
128 }
128 }
129
129
130− function dropWhen(s1,b,s2) {
131− var pairs = lift2( F2(function(x,y){return {x:x,y:y};}), s1, s2 );
132− var dropped = new DropIf(function(p){return p.x;},{x:true,y:b},pairs);
133− return lift(function(p){return p.y;}, dropped);
134− }
135−
136 function timestamp(a) {
130 function timestamp(a) {
137 function update() { return Utils.Tuple2(Date.now(), a.value); }
131 function update() { return Utils.Tuple2(Date.now(), a.value); }
138 return new LiftN(update, [a]);
132 return new LiftN(update, [a]);
@@ -225,9 +219,6 @@ Elm.Native.Signal.make = function(elm) {
225 keepIf : F3(function(pred,base,sig) {
219 keepIf : F3(function(pred,base,sig) {
226 return new DropIf(function(x) {return !pred(x);},base,sig); }),
220 return new DropIf(function(x) {return !pred(x);},base,sig); }),
227 dropIf : F3(function(pred,base,sig) { return new DropIf(pred,base,sig); }),
221 dropIf : F3(function(pred,base,sig) { return new DropIf(pred,base,sig); }),
228− keepWhen : F3(function(s1,b,s2) {
229− return dropWhen(lift(function(b){return !b;},s1), b, s2); }),
230− dropWhen : F3(dropWhen),
231 dropRepeats : function(s) { return new DropRepeats(s);},
222 dropRepeats : function(s) { return new DropRepeats(s);},
232 sampleOn : F2(sampleOn),
223 sampleOn : F2(sampleOn),
233 timestamp : timestamp
224 timestamp : timestamp
libraries/Native/String.js+3−2
@@ -144,7 +144,8 @@ Elm.Native.String.make = function(elm) {
144 return str.indexOf(sub) === 0;
144 return str.indexOf(sub) === 0;
145 }
145 }
146 function endsWith(sub, str) {
146 function endsWith(sub, str) {
147+ return str.length >= sub.length &&
147− return str.lastIndexOf(sub) === str.length - sub.length;
148+ str.lastIndexOf(sub) === str.length - sub.length;
148 }
149 }
149 function indexes(sub, str) {
150 function indexes(sub, str) {
150 var subLen = sub.length;
151 var subLen = sub.length;
@@ -248,4 +249,4 @@ Elm.Native.String.make = function(elm) {
248 toList: toList,
249 toList: toList,
249 fromList: fromList,
250 fromList: fromList,
250 };
251 };
251−};
252+};
libraries/Native/Text.js+58−42
@@ -4,11 +4,10 @@ Elm.Native.Text.make = function(elm) {
4 elm.Native.Text = elm.Native.Text || {};
4 elm.Native.Text = elm.Native.Text || {};
5 if (elm.Native.Text.values) return elm.Native.Text.values;
5 if (elm.Native.Text.values) return elm.Native.Text.values;
6
6
7− var JS = Elm.JavaScript.make(elm);
8− var Utils = Elm.Native.Utils.make(elm);
7+ var toCss = Elm.Native.Color.make(elm).toCss;
9− var Color = Elm.Native.Color.make(elm);
10 var Element = Elm.Graphics.Element.make(elm);
8 var Element = Elm.Graphics.Element.make(elm);
11− var show = Elm.Native.Show.make(elm).show;
9+ var List = Elm.Native.List.make(elm);
10+ var Utils = Elm.Native.Utils.make(elm);
12
11
13 function makeSpaces(s) {
12 function makeSpaces(s) {
14 if (s.length == 0) { return s; }
13 if (s.length == 0) { return s; }
@@ -51,13 +50,51 @@ Elm.Native.Text.make = function(elm) {
51 return arr.join('<br/>');
50 return arr.join('<br/>');
52 }
51 }
53
52
54− function toText(str) { return Utils.txt(properEscape(JS.fromString(str))); }
53+ function toText(str) { return Utils.txt(properEscape(str)); }
54+
55+ // conversions from Elm values to CSS
56+ function toTypefaces(list) {
57+ var typefaces = List.toArray(list);
58+ for (var i = typefaces.length; i--; ) {
59+ var typeface = typefaces[i];
60+ if (typeface.indexOf(' ') > -1) {
61+ typefaces[i] = "'" + typeface + "'";
62+ }
63+ }
64+ return typefaces.join(',');
65+ }
66+ function toLine(line) {
67+ var ctor = line.ctor;
68+ return ctor === 'Under' ? 'underline' :
69+ ctor === 'Over' ? 'overline' : 'line-through';
70+ }
55
71
72+ // setting styles of Text
73+ function style(style, text) {
74+ var newText = '<span style="color:' + toCss(style.color) + ';'
75+ if (style.typeface.ctor !== '[]') {
76+ newText += 'font-family:' + toTypefaces(style.typeface) + ';'
77+ }
78+ if (style.height.ctor !== "Nothing") {
79+ newText += 'font-size:' + style.height._0 + 'px;';
80+ }
81+ if (style.bold) {
82+ newText += 'font-weight:bold;';
83+ }
84+ if (style.italic) {
85+ newText += 'font-style:italic;';
86+ }
87+ if (style.line.ctor !== 'Nothing') {
88+ newText += 'text-decoration:' + toLine(style.line._0) + ';';
89+ }
90+ newText += '">' + Utils.makeText(text) + '</span>'
91+ return Utils.txt(newText);
92+ }
56 function height(px, text) {
93 function height(px, text) {
57 return { style: 'font-size:' + px + 'px;', text:text }
94 return { style: 'font-size:' + px + 'px;', text:text }
58 }
95 }
59− function typeface(name, text) {
96+ function typeface(names, text) {
60− return { style: 'font-family:' + name + ';', text:text }
97+ return { style: 'font-family:' + toTypefaces(names) + ';', text:text }
61 }
98 }
62 function monospace(text) {
99 function monospace(text) {
63 return { style: 'font-family:monospace;', text:text }
100 return { style: 'font-family:monospace;', text:text }
@@ -71,25 +108,16 @@ Elm.Native.Text.make = function(elm) {
71 function link(href, text) {
108 function link(href, text) {
72 return { href: toText(href), text:text };
109 return { href: toText(href), text:text };
73 }
110 }
74− function underline(text) {
111+ function line(line, text) {
75− return { line: ' underline', text:text };
112+ return { style: 'text-decoration:' + toLine(line) + ';', text:text };
76− }
77− function overline(text) {
78− return { line: ' overline', text:text };
79− }
80− function strikeThrough(text) {
81− return { line: ' line-through', text:text };
82 }
113 }
83
114
84− function color(c, text) {
115+ function color(color, text) {
85− var color = (c._3 === 1)
86− ? ('rgb(' + c._0 + ', ' + c._1 + ', ' + c._2 + ')')
87− : ('rgba(' + c._0 + ', ' + c._1 + ', ' + c._2 + ', ' + c._3 + ')');
88− return { style: 'color:' + color + ';', text:text };
116+ return { style: 'color:' + toCss(color) + ';', text:text };
89 }
117 }
90
118
91− function position(align) {
119+ function block(align) {
92− function create(text) {
120+ return function(text) {
93 var raw = {
121 var raw = {
94 ctor :'RawHtml',
122 ctor :'RawHtml',
95 html : Utils.makeText(text),
123 html : Utils.makeText(text),
@@ -100,7 +128,6 @@ Elm.Native.Text.make = function(elm) {
100 var pos = A2(Utils.htmlHeight, 0, raw);
128 var pos = A2(Utils.htmlHeight, 0, raw);
101 return A3(Element.newElement, pos._0, pos._1, raw);
129 return A3(Element.newElement, pos._0, pos._1, raw);
102 }
130 }
103− return create;
104 }
131 }
105
132
106 function markdown(text, guid) {
133 function markdown(text, guid) {
@@ -115,36 +142,25 @@ Elm.Native.Text.make = function(elm) {
115 return A3(Element.newElement, pos._0, pos._1, raw);
142 return A3(Element.newElement, pos._0, pos._1, raw);
116 }
143 }
117
144
118− var text = position('left');
119− function asText(v) {
120− return text(monospace(toText(show(v))));
121− }
122−
123− function plainText(v) {
124− return text(toText(v));
125− }
126−
127 return elm.Native.Text.values = {
145 return elm.Native.Text.values = {
128 toText: toText,
146 toText: toText,
129
147
130 height : F2(height),
148 height : F2(height),
131 italic : italic,
149 italic : italic,
132 bold : bold,
150 bold : bold,
133− underline : underline,
151+ line : F2(line),
134− overline : overline,
135− strikeThrough : strikeThrough,
136 monospace : monospace,
152 monospace : monospace,
137 typeface : F2(typeface),
153 typeface : F2(typeface),
138 color : F2(color),
154 color : F2(color),
139 link : F2(link),
155 link : F2(link),
140
156
157+ leftAligned : block('left'),
158+ rightAligned : block('right'),
159+ centered : block('center'),
141− justified : position('justify'),
160+ justified : block('justify'),
142− centered : position('center'),
143− righted : position('right'),
144− text : text,
145− plainText : plainText,
146− markdown : markdown,
161+ markdown : markdown,
147
162
148− asText : asText,
163+ toTypefaces:toTypefaces,
164+ toLine:toLine,
149 };
165 };
150};
166};
libraries/Native/Trampoline.jsnew file+24
@@ -0,0 +1,24 @@
1+Elm.Native.Trampoline = {};
2+Elm.Native.Trampoline.make = function(elm) {
3+ elm.Native = elm.Native || {};
4+ elm.Native.Trampoline = elm.Native.Trampoline || {};
5+ if (elm.Native.Trampoline.values) return elm.Native.Trampoline.values;
6+
7+ // trampoline : Trampoline a -> a
8+ function trampoline(t) {
9+ var tramp = t;
10+ while(true) {
11+ switch(tramp.ctor) {
12+ case "Done":
13+ return tramp._0;
14+ case "Continue":
15+ tramp = tramp._0({ctor: "_Tuple0"});
16+ continue;
17+ }
18+ }
19+ }
20+
21+ return elm.Native.Trampoline.values = {
22+ trampoline:trampoline
23+ };
24+};
libraries/Native/Utils.js+6−8
@@ -9,7 +9,12 @@ Elm.Native.Utils.make = function(elm) {
9 if (x === y) return true;
9 if (x === y) return true;
10 if (typeof x === "object") {
10 if (typeof x === "object") {
11 var c = 0;
11 var c = 0;
12+ for (var i in x) {
13+ ++c;
14+ if (!eq(x[i],y[i])) {
12− for (var i in x) { ++c; if (!eq(x[i],y[i])) return false; }
15+ return false;
16+ }
17+ }
13 return c === Object.keys(y).length;
18 return c === Object.keys(y).length;
14 }
19 }
15 if (typeof x === 'function') {
20 if (typeof x === 'function') {
@@ -76,14 +81,8 @@ Elm.Native.Utils.make = function(elm) {
76
81
77 function makeText(text) {
82 function makeText(text) {
78 var style = '';
83 var style = '';
79− var line = '';
80 var href = '';
84 var href = '';
81 while (true) {
85 while (true) {
82− if (text.line) {
83− line += text.line;
84− text = text.text;
85− continue;
86− }
87 if (text.style) {
86 if (text.style) {
88 style += text.style;
87 style += text.style;
89 text = text.text;
88 text = text.text;
@@ -95,7 +94,6 @@ Elm.Native.Utils.make = function(elm) {
95 continue;
94 continue;
96 }
95 }
97 if (href) text = '<a href="' + href + '">' + text + '</a>';
96 if (href) text = '<a href="' + href + '">' + text + '</a>';
98− if (line) style += 'text-decoration:' + line + ';';
99 if (style) text = '<span style="' + style + '">' + text + '</span>';
97 if (style) text = '<span style="' + style + '">' + text + '</span>';
100 return text;
98 return text;
101 }
99 }
libraries/Prelude.elmdeleted−8
@@ -1,8 +0,0 @@
1−module Prelude where
2−{-| Everything that is automatically imported -}
3−
4−import Native.Show
5−
6−-- Convert almost any value to its string representation.
7−show : a -> String
8−show = Native.Show.show
libraries/Regex.elm+49−56
@@ -3,16 +3,17 @@ module Regex where
3same kind of regular expressions accepted by JavaScript](https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions).
3same kind of regular expressions accepted by JavaScript](https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions).
4
4
5# Create
5# Create
6−@docs pattern, caseInsensitive, escape
6+@docs regex, escape, caseInsensitive
7
7
8−# Match
8+# Helpful Data Structures
9−@docs Match
10
9
11−# Find and Replace
10+These data structures are needed to help define functions like [`find`](#find)
12−@docs contains, find, findAll, replace, replaceAll
11+and [`replace`](#replace).
13
12
14−# Split
13+@docs HowMany, Match
14+
15+# Use
15−@docs split, splitN
16+@docs contains, find, replace, split
16
17
17-}
18-}
18
19
@@ -21,31 +22,35 @@ import Native.Regex
21
22
22data Regex = Regex
23data Regex = Regex
23
24
24−{-| Escape all special characters. So `pattern (escape "$$$")`
25+{-| Escape strings to be regular expressions, making all special characters
25−will match exactly `"$$$"` even though `$` is a special character.
26+safe. So `regex (escape "^a+")` will match exactly `"^a+"` instead of a series
27+of `a`&rsquo;s that start at the beginning of the line.
26-}
28-}
27escape : String -> String
29escape : String -> String
28escape = Native.Regex.escape
30escape = Native.Regex.escape
29
31
30{-| Create a Regex that matches patterns [as specified in JavaScript](https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions#Writing_a_Regular_Expression_Pattern).
32{-| Create a Regex that matches patterns [as specified in JavaScript](https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions#Writing_a_Regular_Expression_Pattern).
33+
31−Be careful to escape backslashes properly!
34+Be careful to escape backslashes properly! For example, `"\w"` is escaping the
35+letter `w` which is probably not what you want. You probably want `"\\w"`
36+instead, which escapes the backslash.
32-}
37-}
33−pattern : String -> Regex
38+regex : String -> Regex
34−pattern = Native.Regex.pattern
39+regex = Native.Regex.regex
35
40
36
41
37−{-| Make a pattern case insensitive -}
42+{-| Make a regex case insensitive -}
38caseInsensitive : Regex -> Regex
43caseInsensitive : Regex -> Regex
39caseInsensitive = Native.Regex.caseInsensitive
44caseInsensitive = Native.Regex.caseInsensitive
40
45
41{-| Check to see if a Regex is contained in a string.
46{-| Check to see if a Regex is contained in a string.
42
47
43```haskell
48```haskell
44− contains (pattern "123") "12345" == True
49+ contains (regex "123") "12345" == True
45− contains (pattern "b+") "aabbcc" == True
50+ contains (regex "b+") "aabbcc" == True
46
51
47− contains (pattern "789") "12345" == False
52+ contains (regex "789") "12345" == False
48− contains (pattern "z+") "aabbcc" == False
53+ contains (regex "z+") "aabbcc" == False
49```
54```
50-}
55-}
51contains : Regex -> String -> Bool
56contains : Regex -> String -> Bool
@@ -55,79 +60,67 @@ contains = Native.Regex.contains
55Here are details on each field:
60Here are details on each field:
56
61
57 * `match` &mdash; the full string of the match.
62 * `match` &mdash; the full string of the match.
58− * `submatches` &mdash; a pattern might have [subpatterns, surrounded by
63+ * `submatches` &mdash; a regex might have [subpatterns, surrounded by
59 parentheses](https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions#Using_Parenthesized_Substring_Matches).
64 parentheses](https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions#Using_Parenthesized_Substring_Matches).
60 If there are N subpatterns, there will be N elements in the `submatches` list.
65 If there are N subpatterns, there will be N elements in the `submatches` list.
61 Each submatch in this list is a `Maybe` because not all subpatterns may trigger.
66 Each submatch in this list is a `Maybe` because not all subpatterns may trigger.
62− For example, `(pattern "(a+)|(b+)")` will either match many `a`&rsquo;s or
67+ For example, `(regex "(a+)|(b+)")` will either match many `a`&rsquo;s or
63 many `b`&rsquo;s, but never both.
68 many `b`&rsquo;s, but never both.
64 * `index` &mdash; the index of the match in the original string.
69 * `index` &mdash; the index of the match in the original string.
65 * `number` &mdash; if you find many matches, you can think of each one
70 * `number` &mdash; if you find many matches, you can think of each one
66 as being labeled with a `number` starting at one. So the first time you
71 as being labeled with a `number` starting at one. So the first time you
67 find a match, that is match `number` one. Second time is match `number` two.
72 find a match, that is match `number` one. Second time is match `number` two.
68− This is useful when paired with `replaceAll` if replacement is dependent on how
73+ This is useful when paired with `replace All` if replacement is dependent on how
69 many times a pattern has appeared before.
74 many times a pattern has appeared before.
70-}
75-}
71type Match = { match : String, submatches : [Maybe String], index : Int, number : Int }
76type Match = { match : String, submatches : [Maybe String], index : Int, number : Int }
72
77
78+{-| `HowMany` is used to specify how many matches you want to make. So
79+`replace All` would replace every match, but `replace (AtMost 2)` would
80+replace at most two matches (i.e. zero, one, two, but never three or more).
81+-}
82+data HowMany = All | AtMost Int
83+
73−{-| Find all of the matches in a string:
84+{-| Find matches in a string:
74
85
75```haskell
86```haskell
76− words = findAll (pattern "\\w+") "hello world"
87+ findTwoCommas = find (AtMost 2) (regex ",")
77
88
78− map .match words == ["hello","world"]
89+ -- map .index (findTwoCommas "a,b,c,d,e") == [1,3]
79− map .index words == [0,6]
90+ -- map .index (findTwoCommas "a b c d e") == []
80
91
81− places = findAll (pattern "[oi]n a (\\w+)") "I am on a boat in a lake."
92+ places = find All (regex "[oi]n a (\\w+)") "I am on a boat in a lake."
82
93
83− map .match places== ["on a boat", "in a lake"]
94+ -- map .match places == ["on a boat", "in a lake"]
84− map .submatches places == [ [Just "boat"], [Just "lake"] ]
95+ -- map .submatches places == [ [Just "boat"], [Just "lake"] ]
85```
96```
86-}
97-}
87−findAll : Regex -> String -> [Match]
88−findAll = Native.Regex.findAll
89−
90−{-| Same as `findAll`, but `find` will quit searching after the *n<sup>th</sup>* match.
91−That means the resulting list has maximum length N, but *it can be shorter*
92−if there are not that many matches in the given string.
93−-}
94−find : Int -> Regex -> String -> [Match]
98+find : HowMany -> Regex -> String -> [Match]
95find = Native.Regex.find
99find = Native.Regex.find
96
100
97−{-| Replace all matches. The function from `Match` to `String` lets
101+{-| Replace matches. The function from `Match` to `String` lets
98you use the details of a specific match when making replacements.
102you use the details of a specific match when making replacements.
99
103
100```haskell
104```haskell
101− devowel = replaceAll (pattern "[aeiou]") (\_ -> "")
105+ devowel = replace All (regex "[aeiou]") (\_ -> "")
102
106
103− devowel "The quick brown fox" == "Th qck brwn fx"
107+ -- devowel "The quick brown fox" == "Th qck brwn fx"
104
108
105− reverseWords = replaceAll (pattern "\\w+") (\{match} -> String.reverse match)
109+ reverseWords = replace All (regex "\\w+") (\{match} -> String.reverse match)
106
110
107− reverseWords "deliver mined parts" == "reviled denim strap"
111+ -- reverseWords "deliver mined parts" == "reviled denim strap"
108```
112```
109-}
113-}
110−replaceAll : Regex -> (Match -> String) -> String -> String
111−replaceAll = Native.Regex.replaceAll
112−
113−{-| Same as `replaceAll`, but `replace` will quit after the *n<sup>th</sup>* match.-}
114−replace : Int -> Regex -> (Match -> String) -> String -> String
114+replace : HowMany -> Regex -> (Match -> String) -> String -> String
115replace = Native.Regex.replace
115replace = Native.Regex.replace
116
116
117{-| Split a string, using the regex as the separator.
117{-| Split a string, using the regex as the separator.
118
118
119```haskell
119```haskell
120− split (pattern " *, *") "a ,b, c,d" == ["a","b","c","d"]
120+ split (AtMost 1) (regex ",") "tom,99,90,85" == ["tom","99,90,85"]
121−```
122−-}
123−split : Regex -> String -> [String]
124−split = Native.Regex.split
125
121
126−{-| Same as `split` but stops after the *n<sup>th</sup>* match.
122+ split All (regex ",") "a,b,c,d" == ["a","b","c","d"]
127−
128−```haskell
129− splitN 1 (pattern ": *") "tom: 99,90,85" == ["tom","99,90,85"]
130```
123```
131-}
124-}
132−splitN : Int -> Regex -> String -> [String]
125+split : HowMany -> Regex -> String -> [String]
133−splitN = Native.Regex.splitN
126+split = Native.Regex.split
libraries/Signal.elm+7−2
@@ -32,6 +32,10 @@ the [`Time`](/docs/Signal/Time.elm) library.
32import Native.Signal
32import Native.Signal
33import List (foldr)
33import List (foldr)
34
34
35+import Basics (fst, snd, not)
36+import Native.Error
37+import Maybe as M
38+
35data Signal a = Signal
39data Signal a = Signal
36
40
37{-| Create a constant signal that never changes. -}
41{-| Create a constant signal that never changes. -}
@@ -122,7 +126,8 @@ Until the first signal becomes false again, all events will be propagated. Elm
122does not allow undefined signals, so a base case must be provided in case the
126does not allow undefined signals, so a base case must be provided in case the
123first signal is not true initially. -}
127first signal is not true initially. -}
124keepWhen : Signal Bool -> a -> Signal a -> Signal a
128keepWhen : Signal Bool -> a -> Signal a -> Signal a
125−keepWhen = Native.Signal.keepWhen
129+keepWhen bs def sig =
130+ snd <~ (keepIf fst (False, def) ((,) <~ (sampleOn sig bs) ~ sig))
126
131
127{-| Drop events when the first signal is true. When the first signal becomes
132{-| Drop events when the first signal is true. When the first signal becomes
128false, the most recent value of the second signal will be propagated. Until the
133false, the most recent value of the second signal will be propagated. Until the
@@ -130,7 +135,7 @@ first signal becomes true again, all events will be propagated. Elm does not
130allow undefined signals, s oa base case must be provided in case the first
135allow undefined signals, s oa base case must be provided in case the first
131signal is true initially. -}
136signal is true initially. -}
132dropWhen : Signal Bool -> a -> Signal a -> Signal a
137dropWhen : Signal Bool -> a -> Signal a -> Signal a
133−dropWhen = Native.Signal.dropWhen
138+dropWhen bs = keepWhen (not <~ bs)
134
139
135{-| Drop updates that repeat the current value of the signal.
140{-| Drop updates that repeat the current value of the signal.
136
141
libraries/String.elm+33−6
@@ -15,7 +15,7 @@ are enclosed in `"double quotes"`. Strings are *not* lists of characters.
15@docs contains, startsWith, endsWith, indexes, indices
15@docs contains, startsWith, endsWith, indexes, indices
16
16
17# Conversions
17# Conversions
18−@docs toInt, toFloat, toList, fromList
18+@docs show, toInt, toFloat, toList, fromList
19
19
20# Formatting
20# Formatting
21Cosmetic operations such as padding with extra characters or trimming whitespace.
21Cosmetic operations such as padding with extra characters or trimming whitespace.
@@ -28,10 +28,15 @@ Cosmetic operations such as padding with extra characters or trimming whitespace
28@docs map, filter, foldl, foldr, any, all
28@docs map, filter, foldl, foldr, any, all
29-}
29-}
30
30
31+import Native.Show
31import Native.String
32import Native.String
32import Maybe (Maybe)
33import Maybe (Maybe)
33
34
34−{-| Check if a string is empty `(isEmpty "" == True)` -}
35+{-| Check if a string is empty.
36+
37+ isEmpty "" == True
38+ isEmpty "the world" == False
39+-}
35isEmpty : String -> Bool
40isEmpty : String -> Bool
36isEmpty = Native.String.isEmpty
41isEmpty = Native.String.isEmpty
37
42
@@ -63,7 +68,11 @@ append = Native.String.append
63concat : [String] -> String
68concat : [String] -> String
64concat = Native.String.concat
69concat = Native.String.concat
65
70
66−{-| Get the length of a string `(length "innumerable" == 11)` -}
71+{-| Get the length of a string.
72+
73+ length "innumerable" == 11
74+
75+-}
67length : String -> Int
76length : String -> Int
68length = Native.String.length
77length = Native.String.length
69
78
@@ -81,7 +90,10 @@ map = Native.String.map
81filter : (Char -> Bool) -> String -> String
90filter : (Char -> Bool) -> String -> String
82filter = Native.String.filter
91filter = Native.String.filter
83
92
93+{-| Reverse a string.
94+
84−{-| Reverse a string. `(reverse "stressed" == "desserts")` -}
95+ reverse "stressed" == "desserts"
96+-}
85reverse : String -> String
97reverse : String -> String
86reverse = Native.String.reverse
98reverse = Native.String.reverse
87
99
@@ -103,6 +115,8 @@ foldr = Native.String.foldr
103
115
104 split "," "cat,dog,cow" == ["cat","dog","cow"]
116 split "," "cat,dog,cow" == ["cat","dog","cow"]
105 split "/" "home/evan/Desktop/" == ["home","evan","Desktop"]
117 split "/" "home/evan/Desktop/" == ["home","evan","Desktop"]
118+
119+Use `Regex.split` if you need something more flexible.
106-}
120-}
107split : String -> String -> [String]
121split : String -> String -> [String]
108split = Native.String.split
122split = Native.String.split
@@ -115,7 +129,10 @@ split = Native.String.split
115join : String -> [String] -> String
129join : String -> [String] -> String
116join = Native.String.join
130join = Native.String.join
117
131
118−{-| Repeat a string N times `(repeat 3 "ha" == "hahaha")` -}
132+{-| Repeat a string N times.
133+
134+ repeat 3 "ha" == "hahaha"
135+-}
119repeat : Int -> String -> String
136repeat : Int -> String -> String
120repeat = Native.String.repeat
137repeat = Native.String.repeat
121
138
@@ -231,7 +248,7 @@ any = Native.String.any
231
248
232 all isDigit "90210" == True
249 all isDigit "90210" == True
233 all isDigit "R2-D2" == False
250 all isDigit "R2-D2" == False
234− any isDigit "heart" == False
251+ all isDigit "heart" == False
235-}
252-}
236all : (Char -> Bool) -> String -> Bool
253all : (Char -> Bool) -> String -> Bool
237all = Native.String.all
254all = Native.String.all
@@ -241,6 +258,8 @@ all = Native.String.all
241 contains "the" "theory" == True
258 contains "the" "theory" == True
242 contains "hat" "theory" == False
259 contains "hat" "theory" == False
243 contains "THE" "theory" == False
260 contains "THE" "theory" == False
261+
262+Use `Regex.contains` if you need something more flexible.
244-}
263-}
245contains : String -> String -> Bool
264contains : String -> String -> Bool
246contains = Native.String.contains
265contains = Native.String.contains
@@ -274,6 +293,14 @@ indexes = Native.String.indexes
274indices : String -> String -> [Int]
293indices : String -> String -> [Int]
275indices = Native.String.indexes
294indices = Native.String.indexes
276
295
296+{-| Turn any kind of value into a string.
297+
298+ show 42 == "42"
299+ show [1,2] == "[1,2]"
300+-}
301+show : a -> String
302+show = Native.Show.show
303+
277{-| Try to convert a string into an int, failing on improperly formatted strings.
304{-| Try to convert a string into an int, failing on improperly formatted strings.
278
305
279 toInt "123" == Just 123
306 toInt "123" == Just 123
libraries/Text.elm+157−45
@@ -1,99 +1,210 @@
1module Text where
1module Text where
2−
3−{-| Functions for displaying text
2+{-| A library for styling and displaying text. Whlie the `String` library
3+focuses on representing and manipulating strings of character strings, the
4+`Text` library focuses on how those strings should look on screen. It lets
5+you make text bold or italic, set the typeface, set the text size, etc.
4
6
5# Creating Text
7# Creating Text
6@docs toText
8@docs toText
7
9
8# Creating Elements
10# Creating Elements
9−@docs plainText, asText, text, centered, justified, righted
10
11
11−# Formatting
12+Each of the following functions places `Text` into a box. The function you use
12−@docs color, typeface, height, link
13+determines the alignment of the text.
14+
15+@docs leftAligned, rightAligned, centered, justified
16+
17+# Links and Style
18+@docs link, Style, style, defaultStyle, Line
19+
20+# Convenience Functions
21+
22+There are two convenience functions for creating an `Element` which can be
23+useful when debugging or prototyping:
13
24
14−# Simple Formatting
25+@docs plainText, asText
26+
27+There are also a bunch of functions to set parts of a `Style` individually:
28+
15−@docs monospace, bold, italic, underline, overline, strikeThrough
29+@docs typeface, monospace, height, color, bold, italic, line
16
30
17-}
31-}
18
32
19−import open Basics
33+import Basics (..)
34+import String
20−import Color (Color)
35+import Color (Color, black)
21import Graphics.Element (Element, Three, Pos, ElementPrim, Properties)
36import Graphics.Element (Element, Three, Pos, ElementPrim, Properties)
22−import Maybe (Maybe)
37+import Maybe (Maybe, Nothing)
23import JavaScript (JSString)
38import JavaScript (JSString)
39+import Native.Show
24import Native.Text
40import Native.Text
25
41
26data Text = Text
42data Text = Text
27
43
44+{-| Styles for lines on text. This allows you to add an underline, an overline,
45+or a strike out text:
46+
47+ line Under (toText "underline")
48+ line Over (toText "overline")
49+ line Through (toText "strike out")
50+-}
51+data Line = Under | Over | Through
52+
53+{-| Representation of all the ways you can style `Text`. If the `typeface` list
54+is empty or the `height` is `Nothing`, the users will fall back on their
55+browser's default settings. The following `Style` is black, 16 pixel tall,
56+underlined, and Times New Roman (assuming that typeface is available on the
57+user's computer):
58+
59+ { typeface = [ "Times New Roman", "serif" ]
60+ , height = Just 16
61+ , color = black
62+ , bold = False
63+ , italic = False
64+ , line = Just Under
65+ }
66+-}
67+type Style =
68+ { typeface : [String]
69+ , height : Maybe Float
70+ , color : Color
71+ , bold : Bool
72+ , italic : Bool
73+ , line : Maybe Line
74+ }
75+
76+{-| Plain black text. It uses the browsers default typeface and text height.
77+No decorations are used:
78+
79+ { typeface = []
80+ , height = Nothing
81+ , color = black
82+ , bold = False
83+ , italic = False
84+ , line = Nothing
85+ }
86+-}
87+defaultStyle : Style
88+defaultStyle =
89+ { typeface = []
90+ , height = Nothing
91+ , color = black
92+ , bold = False
93+ , italic = False
94+ , line = Nothing
95+ }
96+
28−{-| Convert a string into text which can be styled and displayed. -}
97+{-| Convert a string into text which can be styled and displayed. To show the
98+string `"Hello World!"` on screen in italics, you could say:
99+
100+ main = leftAligned (italic (toText "Hello World!"))
101+-}
29toText : String -> Text
102toText : String -> Text
30toText = Native.Text.toText
103toText = Native.Text.toText
31
104
32−{-| Set the typeface of some text. The first argument should be a comma
105+{-| Set the style of some text. For example, if you design a `Style` called
33−separated listing of the desired typefaces:
106+`footerStyle` that is specifically for the bottom of your page, you could apply
107+it to text like this:
108+
109+ style footerStyle (toText "the old prince / 2007")
110+-}
111+style : Style -> Text -> Text
112+style = Native.Text.style
113+
114+{-| Provide a list of prefered typefaces for some text.
34
115
35− "helvetica, arial, sans-serif"
116+ ["helvetica","arial","sans-serif"]
36
117
118+Not every browser has access to the same typefaces, so rendering will use the
119+first typeface in the list that is found on the user's computer. If there are
120+no matches, it will use their default typeface. This works the same as the CSS
37−Works the same as the CSS font-family property.
121+font-family property.
38-}
122-}
39−typeface : String -> Text -> Text
123+typeface : [String] -> Text -> Text
40typeface = Native.Text.typeface
124typeface = Native.Text.typeface
41
125
42−{-| Switch to a monospace typeface. Good for code snippets. -}
126+{-| Switch to a monospace typeface. Good for code snippets.
127+
128+ monospace (toText "foldl (+) 0 [1,2,3]")
129+-}
43monospace : Text -> Text
130monospace : Text -> Text
44monospace = Native.Text.monospace
131monospace = Native.Text.monospace
45
132
46−{-| Create a link. -}
133+{-| Create a link by providing a URL and the text of the link:
134+
135+ link "http://elm-lang.org" (toText "Elm Website")
136+-}
47link : String -> Text -> Text
137link : String -> Text -> Text
48link = Native.Text.link
138link = Native.Text.link
49
139
50−{-| Set the height of text in pixels. -}
140+{-| Set the height of some text:
141+
142+ height 40 (toText "Title")
143+-}
51height : Float -> Text -> Text
144height : Float -> Text -> Text
52height = Native.Text.height
145height = Native.Text.height
53
146
54−{-| Set the color of a string. -}
147+{-| Set the color of some text:
148+
149+ color red (toText "Red")
150+-}
55color : Color -> Text -> Text
151color : Color -> Text -> Text
56color = Native.Text.color
152color = Native.Text.color
57
153
58−{-| Make a string bold. -}
154+{-| Make text bold:
155+
156+ toText "sometimes you want " ++ bold (toText "emphasis")
157+-}
59bold : Text -> Text
158bold : Text -> Text
60bold = Native.Text.bold
159bold = Native.Text.bold
61
160
62−{-| Italicize a string. -}
161+{-| Make text italic:
162+
163+ toText "make it " ++ italic (toText "important")
164+-}
63italic : Text -> Text
165italic : Text -> Text
64italic = Native.Text.italic
166italic = Native.Text.italic
65
167
66−{-| Draw a line above a string. -}
168+{-| Put lines on text:
67−overline : Text -> Text
68−overline = Native.Text.overline
69
169
70−{-| Underline a string. -}
170+ line Under (toText "underlined")
171+ line Over (toText "overlined")
172+ line Through (toText "strike out")
173+-}
71−underline : Text -> Text
174+line : Line -> Text -> Text
72−underline = Native.Text.underline
175+line = Native.Text.line
73
176
74−{-| Draw a line through a string. -}
177+{-| `Text` is aligned along the left side of the text block. This is sometimes
75−strikeThrough : Text -> Text
178+known as *ragged right*.
76−strikeThrough = Native.Text.strikeThrough
179+-}
180+leftAligned : Text -> Element
181+leftAligned = Native.Text.leftAligned
77
182
78−{-| Display justified, styled text. -}
183+{-| `Text` is aligned along the right side of the text block. This is sometimes
184+known as *ragged left*.
185+-}
79−justified : Text -> Element
186+rightAligned : Text -> Element
80−justified = Native.Text.justified
187+rightAligned = Native.Text.rightAligned
81
188
82−{-| Display centered, styled text. -}
189+{-| `Text` is centered in the text block. There is equal spacing on either side
190+of a line of text.
191+-}
83centered : Text -> Element
192centered : Text -> Element
84centered = Native.Text.centered
193centered = Native.Text.centered
85
194
86−{-| Display right justified, styled text. -}
195+{-| `Text` is aligned along the left and right sides of the text block. Word
196+spacing is adjusted to make this possible.
197+-}
87−righted : Text -> Element
198+justified : Text -> Element
88−righted = Native.Text.righted
199+justified = Native.Text.justified
89
200
90−{-| Display styled text. -}
201+{-| Display a string with no styling:
91−text : Text -> Element
92−text = Native.Text.text
93
202
94−{-| Display a plain string. -}
203+ plainText string = leftAligned (toText string)
204+-}
95plainText : String -> Element
205plainText : String -> Element
96−plainText = Native.Text.plainText
206+plainText str =
207+ leftAligned (toText str)
97
208
98{-| for internal use only -}
209{-| for internal use only -}
99markdown : Element
210markdown : Element
@@ -102,9 +213,10 @@ markdown = Native.Text.markdown
102{-| Convert anything to its textual representation and make it displayable in
213{-| Convert anything to its textual representation and make it displayable in
103the browser:
214the browser:
104
215
105− asText == text . monospace . show
216+ asText value = text (monospace (show value))
106
217
107Excellent for debugging.
218Excellent for debugging.
108-}
219-}
109asText : a -> Element
220asText : a -> Element
110−asText = Native.Text.asText
221+asText value =
222+ leftAligned (monospace (toText (Native.Show.show value)))
libraries/Time.elm+1−1
@@ -14,7 +14,7 @@ module Time where
14
14
15-}
15-}
16
16
17−import open Basics
17+import Basics (..)
18import Native.Time
18import Native.Time
19import Signal (Signal)
19import Signal (Signal)
20
20
libraries/Trampoline.elmnew file+49
@@ -0,0 +1,49 @@
1+module Trampoline where
2+{-| A [trampoline](http://en.wikipedia.org/wiki/Tail-recursive_function#Through_trampolining)
3+makes it possible to recursively call a function without growing the stack.
4+
5+Popular JavaScript implementations do not perform any tail-call elimination, so
6+recursive functions can cause a stack overflow if they go to deep. Trampolines
7+permit unbounded recursion despite limitations in JavaScript.
8+
9+This strategy may create many intermediate closures, which is very expensive in
10+JavaScript, so use this library only when it is essential that you recurse deeply.
11+
12+# Trampolines
13+@docs trampoline, Trampoline
14+-}
15+
16+import Native.Trampoline
17+
18+{-| A way to build computations that may be deeply recursive. We will take an
19+example of a tail-recursive function and rewrite it in a way that lets us use
20+a trampoline:
21+
22+ length : [a] -> Int
23+ length list = length' 0 list
24+
25+ length' : Int -> [a] -> Int
26+ length' accum list =
27+ case list of
28+ [] -> accum
29+ hd::tl -> length' (accum+1) tl
30+
31+This finds the length of a list, but if the list is too long, it may cause a
32+stack overflow. We can rewrite it as follows:
33+
34+ length : [a] -> Int
35+ length list = trampoline (length' 0 list)
36+
37+ length' : Int -> [a] -> Trampoline Int
38+ length' accum list =
39+ case list of
40+ [] -> Done accum
41+ hd::tl -> Continue (\() -> length' (accum+1) tl)
42+
43+Now it uses a trampoline and can recurse without growing the stack!
44+-}
45+data Trampoline a = Done a | Continue (() -> Trampoline a)
46+
47+{-| Evaluate a trampolined value in constant space. -}
48+trampoline : Trampoline a -> a
49+trampoline = Native.Trampoline.trampoline
libraries/elm_dependencies.json+6−3
@@ -1,9 +1,9 @@
1−{ "version": "0.11"
1+{ "version": "0.12"
2, "summary": "Elm's standard libraries"
2, "summary": "Elm's standard libraries"
3−, "description": "The full set of standard libraries for Elm. This library is pegged to the version number of the compiler, so if you are using Elm 0.11, you should be using version 0.11 of the standard libraries."
3+, "description": "The full set of standard libraries for Elm. This library is pegged to the version number of the compiler, so if you are using Elm 0.12, you should be using version 0.12 of the standard libraries."
4, "license": "BSD3"
4, "license": "BSD3"
5, "repository": "http://github.com/evancz/Elm.git"
5, "repository": "http://github.com/evancz/Elm.git"
6−, "elm-version": "0.11"
6+, "elm-version": "0.12"
7, "dependencies": {}
7, "dependencies": {}
8, "exposed-modules":
8, "exposed-modules":
9 [ "Basics"
9 [ "Basics"
@@ -11,11 +11,13 @@
11 , "Char"
11 , "Char"
12 , "Color"
12 , "Color"
13 , "Date"
13 , "Date"
14+ , "Debug"
14 , "Dict"
15 , "Dict"
15 , "Either"
16 , "Either"
16 , "Graphics.Element"
17 , "Graphics.Element"
17 , "Graphics.Collage"
18 , "Graphics.Collage"
18 , "Graphics.Input"
19 , "Graphics.Input"
20+ , "Graphics.Input.Field"
19 , "Http"
21 , "Http"
20 , "JavaScript"
22 , "JavaScript"
21 , "JavaScript.Experimental"
23 , "JavaScript.Experimental"
@@ -32,6 +34,7 @@
32 , "Text"
34 , "Text"
33 , "Time"
35 , "Time"
34 , "Touch"
36 , "Touch"
37+ , "Trampoline"
35 , "Transform2D"
38 , "Transform2D"
36 , "WebSocket"
39 , "WebSocket"
37 , "Window"
40 , "Window"
runtime/HotSwap.js+2−2
@@ -5,8 +5,8 @@
5// structure.
5// structure.
6ElmRuntime.swap = function(from, to) {
6ElmRuntime.swap = function(from, to) {
7 function similar(nodeOld,nodeNew) {
7 function similar(nodeOld,nodeNew) {
8− idOkay = nodeOld.id === nodeNew.id;
8+ var idOkay = nodeOld.id === nodeNew.id;
9− lengthOkay = nodeOld.kids.length === nodeNew.kids.length;
9+ var lengthOkay = nodeOld.kids.length === nodeNew.kids.length;
10 return idOkay && lengthOkay;
10 return idOkay && lengthOkay;
11 }
11 }
12 function swap(nodeOld,nodeNew) {
12 function swap(nodeOld,nodeNew) {
runtime/Init.js+1−1
@@ -91,7 +91,7 @@ function init(display, container, module, ports, moduleToReplace) {
91 checkPorts(elm);
91 checkPorts(elm);
92 } catch(e) {
92 } catch(e) {
93 var directions = "<br/>&nbsp; &nbsp; Open the developer console for more details."
93 var directions = "<br/>&nbsp; &nbsp; Open the developer console for more details."
94− Module.main = Elm.Text.make(elm).text('<code>' + e.message + directions + '</code>');
94+ Module.main = Elm.Text.make(elm).leftAligned('<code>' + e.message + directions + '</code>');
95 reportAnyErrors = function() { throw e; }
95 reportAnyErrors = function() { throw e; }
96 }
96 }
97 inputs = ElmRuntime.filterDeadInputs(inputs);
97 inputs = ElmRuntime.filterDeadInputs(inputs);
runtime/Render/Collage.js+1
@@ -254,6 +254,7 @@ function makeCanvas(w,h) {
254function render(model) {
254function render(model) {
255 var div = newElement('div');
255 var div = newElement('div');
256 div.style.overflow = 'hidden';
256 div.style.overflow = 'hidden';
257+ div.style.position = 'relative';
257 update(div, model, model);
258 update(div, model, model);
258 return div;
259 return div;
259}
260}
runtime/Render/Element.js+71−18
@@ -7,10 +7,16 @@ var newElement = Utils.newElement, extract = Utils.extract,
7 addTransform = Utils.addTransform, removeTransform = Utils.removeTransform,
7 addTransform = Utils.addTransform, removeTransform = Utils.removeTransform,
8 fromList = Utils.fromList, eq = Utils.eq;
8 fromList = Utils.fromList, eq = Utils.eq;
9
9
10−function setProps(props, e) {
10+function setProps(elem, e) {
11+ var props = elem.props;
12+ var element = elem.element;
13+ var width = props.width - (element.adjustWidth || 0);
14+ var height = props.height - (element.adjustHeight || 0);
11− e.style.width = (props.width |0) + 'px';
15+ e.style.width = (width |0) + 'px';
12− e.style.height = (props.height|0) + 'px';
16+ e.style.height = (height|0) + 'px';
17+ if (props.opacity !== 1) {
13− if (props.opacity !== 1) { e.style.opacity = props.opacity; }
18+ e.style.opacity = props.opacity;
19+ }
14 if (props.color.ctor === 'Just') {
20 if (props.color.ctor === 'Just') {
15 e.style.backgroundColor = extract(props.color._0);
21 e.style.backgroundColor = extract(props.color._0);
16 }
22 }
@@ -28,15 +34,30 @@ function setProps(props, e) {
28 e.appendChild(a);
34 e.appendChild(a);
29 }
35 }
30 if (props.hover.ctor !== '_Tuple0') {
36 if (props.hover.ctor !== '_Tuple0') {
31− var overCount = 0;
37+ e.style.pointerEvents = 'auto';
38+ e.elm_hover_handler = props.hover;
39+ e.elm_hover_count = 0;
32 e.addEventListener('mouseover', function() {
40 e.addEventListener('mouseover', function() {
33− if (overCount++ > 0) return;
41+ if (e.elm_hover_count++ > 0) return;
34− props.hover(true);
42+ var handler = e.elm_hover_handler;
43+ if (handler !== null) {
44+ handler(true);
45+ }
35 });
46 });
36 e.addEventListener('mouseout', function(evt) {
47 e.addEventListener('mouseout', function(evt) {
37 if (e.contains(evt.toElement || evt.relatedTarget)) return;
48 if (e.contains(evt.toElement || evt.relatedTarget)) return;
38− overCount = 0;
49+ e.elm_hover_count = 0;
39− props.hover(false);
50+ var handler = e.elm_hover_handler;
51+ if (handler !== null) {
52+ handler(false);
53+ }
54+ });
55+ }
56+ if (props.click.ctor !== '_Tuple0') {
57+ e.style.pointerEvents = 'auto';
58+ e.elm_click_handler = props.click;
59+ e.addEventListener('click', function() {
60+ e.elm_click_handler(Tuple0);
40 });
61 });
41 }
62 }
42 return e;
63 return e;
@@ -99,6 +120,8 @@ function goDown(e) { return e }
99function goRight(e) { e.style.styleFloat = e.style.cssFloat = "left"; return e; }
120function goRight(e) { e.style.styleFloat = e.style.cssFloat = "left"; return e; }
100function flowWith(f, array) {
121function flowWith(f, array) {
101 var container = newElement('div');
122 var container = newElement('div');
123+ if (f == goIn) container.style.pointerEvents = 'none';
124+
102 for (var i = array.length; i--; ) {
125 for (var i = array.length; i--; ) {
103 container.appendChild(f(render(array[i])));
126 container.appendChild(f(render(array[i])));
104 }
127 }
@@ -126,7 +149,12 @@ function toPos(pos) {
126
149
127// must clear right, left, top, bottom, and transform
150// must clear right, left, top, bottom, and transform
128// before calling this function
151// before calling this function
129−function setPos(pos,w,h,e) {
152+function setPos(pos,elem,e) {
153+ var element = elem.element;
154+ var props = elem.props;
155+ var w = props.width + (element.adjustWidth ? element.adjustWidth : 0);
156+ var h = props.height + (element.adjustHeight ? element.adjustHeight : 0);
157+
130 e.style.position = 'absolute';
158 e.style.position = 'absolute';
131 e.style.margin = 'auto';
159 e.style.margin = 'auto';
132 var transform = '';
160 var transform = '';
@@ -146,7 +174,7 @@ function setPos(pos,w,h,e) {
146
174
147function container(pos,elem) {
175function container(pos,elem) {
148 var e = render(elem);
176 var e = render(elem);
149− setPos(pos, elem.props.width, elem.props.height, e);
177+ setPos(pos, elem, e);
150 var div = newElement('div');
178 var div = newElement('div');
151 div.style.position = 'relative';
179 div.style.position = 'relative';
152 div.style.overflow = 'hidden';
180 div.style.overflow = 'hidden';
@@ -183,7 +211,7 @@ function rawHtml(elem) {
183 return div;
211 return div;
184}
212}
185
213
186−function render(elem) { return setProps(elem.props, makeElement(elem)); }
214+function render(elem) { return setProps(elem, makeElement(elem)); }
187function makeElement(e) {
215function makeElement(e) {
188 var elem = e.element;
216 var elem = e.element;
189 switch(elem.ctor) {
217 switch(elem.ctor) {
@@ -209,7 +237,9 @@ function update(node, curr, next) {
209 case "RawHtml":
237 case "RawHtml":
210 // only markdown blocks have guids, so this must be a text block
238 // only markdown blocks have guids, so this must be a text block
211 if (nextE.guid === null) {
239 if (nextE.guid === null) {
240+ if(currE.html.valueOf() !== nextE.html.valueOf()) {
212− node.innerHTML = nextE.html;
241+ node.innerHTML = nextE.html;
242+ }
213 break;
243 break;
214 }
244 }
215 if (nextE.guid !== currE.guid) {
245 if (nextE.guid !== currE.guid) {
@@ -275,7 +305,7 @@ function update(node, curr, next) {
275 break;
305 break;
276 case "Container":
306 case "Container":
277 update(node.firstChild, currE._1, nextE._1);
307 update(node.firstChild, currE._1, nextE._1);
278− setPos(nextE._0, nextE._1.props.width, nextE._1.props.height, node.firstChild);
308+ setPos(nextE._0, nextE._1, node.firstChild);
279 break;
309 break;
280 case "Custom":
310 case "Custom":
281 if (currE.type === nextE.type) {
311 if (currE.type === nextE.type) {
@@ -289,10 +319,19 @@ function update(node, curr, next) {
289}
319}
290
320
291function updateProps(node, curr, next) {
321function updateProps(node, curr, next) {
292− var props = next.props, currP = curr.props, e = node;
322+ var props = next.props;
323+ var currP = curr.props;
324+ var e = node;
325+ var element = next.element;
326+ var width = props.width - (element.adjustWidth || 0);
327+ var height = props.height - (element.adjustHeight || 0);
328+ if (width !== currP.width) {
293− if (props.width !== currP.width) e.style.width = (props.width |0) + 'px';
329+ e.style.width = (width|0) + 'px';
330+ }
331+ if (height !== currP.height) {
294− if (props.height !== currP.height) e.style.height = (props.height|0) + 'px';
332+ e.style.height = (height|0) + 'px';
333+ }
295− if (props.opacity !== 1 && props.opacity !== currP.opacity) {
334+ if (props.opacity !== currP.opacity) {
296 e.style.opacity = props.opacity;
335 e.style.opacity = props.opacity;
297 }
336 }
298 var nextColor = (props.color.ctor === 'Just' ?
337 var nextColor = (props.color.ctor === 'Just' ?
@@ -317,6 +356,20 @@ function updateProps(node, curr, next) {
317 node.lastNode.href = props.href;
356 node.lastNode.href = props.href;
318 }
357 }
319 }
358 }
359+
360+ // update hover handlers
361+ if (props.hover.ctor !== '_Tuple0') {
362+ e.elm_hover_handler = props.hover;
363+ } else if (e.elm_hover_handler) {
364+ e.elm_hover_handler = null;
365+ }
366+
367+ // update click handlers
368+ if (props.click.ctor !== '_Tuple0') {
369+ e.elm_click_handler = props.click;
370+ } else if (e.elm_click_handler) {
371+ e.elm_click_handler = null;
372+ }
320}
373}
321
374
322return { render:render, update:update };
375return { render:render, update:update };
server/elm-server.cabal+1−1
@@ -10,7 +10,7 @@ License-file: LICENSE
10
10
11Author: Evan Czaplicki
11Author: Evan Czaplicki
12Maintainer: info@elm-lang.org
12Maintainer: info@elm-lang.org
13−Copyright: Copyright: (c) 2011-2013 Evan Czaplicki
13+Copyright: Copyright: (c) 2011-2014 Evan Czaplicki
14
14
15Category: Compiler, Language
15Category: Compiler, Language
16
16
tests/Tests/Property.hs+17−16
@@ -10,7 +10,7 @@ import Text.Parsec.Combinator (eof)
10import Text.PrettyPrint as P
10import Text.PrettyPrint as P
11
11
12import SourceSyntax.Literal as Lit
12import SourceSyntax.Literal as Lit
13−import SourceSyntax.Pattern as Pat
13+import qualified SourceSyntax.Pattern as P
14import SourceSyntax.PrettyPrint (Pretty, pretty)
14import SourceSyntax.PrettyPrint (Pretty, pretty)
15import Parse.Helpers (IParser, iParse)
15import Parse.Helpers (IParser, iParse)
16import Parse.Literal (literal)
16import Parse.Literal (literal)
@@ -31,24 +31,25 @@ propertyTests =
31 where
31 where
32 -- This test was autogenerated from the Pattern test and should be
32 -- This test was autogenerated from the Pattern test and should be
33 -- left in all its ugly glory.
33 -- left in all its ugly glory.
34− longPat = Pat.PData "I" [ Pat.PLiteral (Lit.Chr '+')
34+ longPat = P.Data "I" [ P.Literal (Lit.Chr '+')
35− , Pat.PRecord [
35+ , P.Record
36− "q7yclkcm7k_ikstrczv_"
36+ [ "q7yclkcm7k_ikstrczv_"
37− , "wQRv6gKsvvkjw4b5F"
37+ , "wQRv6gKsvvkjw4b5F"
38− ,"c9'eFfhk9FTvsMnwF_D"
38+ ,"c9'eFfhk9FTvsMnwF_D"
39− ,"yqxhEkHvRFwZ"
39+ ,"yqxhEkHvRFwZ"
40− ,"o"
40+ ,"o"
41− ,"nbUlCn3y3NnkVoxhW"
41+ ,"nbUlCn3y3NnkVoxhW"
42− ,"iJ0MNy3KZ_lrs"
42+ ,"iJ0MNy3KZ_lrs"
43− ,"ug"
43+ ,"ug"
44− ,"sHHsX"
44+ ,"sHHsX"
45− ,"mRKs9d"
45+ ,"mRKs9d"
46− ,"o2KiCX5'ZRzHJfRi8" ]
46+ ,"o2KiCX5'ZRzHJfRi8" ]
47− , Pat.PVar "su'BrrbPUK6I33Eq" ]
47+ , P.Var "su'BrrbPUK6I33Eq"
48+ ]
48
49
49prop_parse_print :: (Pretty a, Arbitrary a, Eq a) => IParser a -> a -> Bool
50prop_parse_print :: (Pretty a, Arbitrary a, Eq a) => IParser a -> a -> Bool
50prop_parse_print p x =
51prop_parse_print p x =
51 either (const False) (== x) . parse_print p $ x
52 either (const False) (== x) . parse_print p $ x
52
53
53parse_print :: (Pretty a) => IParser a -> a -> Either String a
54parse_print :: (Pretty a) => IParser a -> a -> Either String a
54−parse_print p = either (Left . show) (Right) . iParse (p <* eof) . P.renderStyle P.style {mode=P.LeftMode} . pretty
55+parse_print p = either (Left . show) Right . iParse (p <* eof) . P.renderStyle P.style {mode=P.LeftMode} . pretty
tests/Tests/Property/Arbitrary.hs+91−76
@@ -8,98 +8,112 @@ import Test.QuickCheck.Gen
8import qualified Data.Set as Set
8import qualified Data.Set as Set
9import qualified Parse.Helpers (reserveds)
9import qualified Parse.Helpers (reserveds)
10
10
11−import SourceSyntax.Literal
11+import qualified SourceSyntax.Literal as L
12−import SourceSyntax.Pattern
12+import qualified SourceSyntax.Pattern as P
13−import SourceSyntax.Type hiding (listOf)
13+import qualified SourceSyntax.Type as T
14−
14+
15−instance Arbitrary Literal where
15+instance Arbitrary L.Literal where
16+ arbitrary =
17+ oneof
16− arbitrary = oneof [ IntNum <$> arbitrary
18+ [ L.IntNum <$> arbitrary
17− , FloatNum <$> (arbitrary `suchThat` noE)
19+ , L.FloatNum <$> (arbitrary `suchThat` noE)
18− , Chr <$> arbitrary
20+ , L.Chr <$> arbitrary
19− -- This is too permissive
21+ -- This is too permissive
20− , Str <$> arbitrary
22+ , L.Str <$> arbitrary
21− -- Booleans aren't actually source syntax
23+ -- Booleans aren't actually source syntax
22− -- , Boolean <$> arbitrary
24+ -- , Boolean <$> arbitrary
23− ]
25+ ]
26+
24− shrink l = case l of
27+ shrink lit =
28+ case lit of
25− IntNum n -> IntNum <$> shrink n
29+ L.IntNum n -> L.IntNum <$> shrink n
26− FloatNum f -> FloatNum <$> (filter noE . shrink $ f)
30+ L.FloatNum f -> L.FloatNum <$> (filter noE . shrink $ f)
27− Chr c -> Chr <$> shrink c
31+ L.Chr c -> L.Chr <$> shrink c
28− Str s -> Str <$> shrink s
32+ L.Str s -> L.Str <$> shrink s
29− Boolean b -> Boolean <$> shrink b
33+ L.Boolean b -> L.Boolean <$> shrink b
30
34
31noE :: Double -> Bool
35noE :: Double -> Bool
32noE = notElem 'e' . show
36noE = notElem 'e' . show
33
37
38+genVector :: Int -> (Int -> Gen a) -> Gen [a]
39+genVector n generator = do
40+ len <- choose (0,n)
41+ let m = n `div` (len + 1)
42+ vectorOf len $ generator m
34
43
35−instance Arbitrary Pattern where
44+instance Arbitrary P.Pattern where
36 arbitrary = sized pat
45 arbitrary = sized pat
46+ where
37− where pat :: Int -> Gen Pattern
47+ pat :: Int -> Gen P.Pattern
38− pat n = oneof [ pure PAnything
48+ pat n =
49+ oneof
50+ [ pure P.Anything
39− , PVar <$> lowVar
51+ , P.Var <$> lowVar
40− , PRecord <$> (listOf1 lowVar)
52+ , P.Record <$> (listOf1 lowVar)
41− , PLiteral <$> arbitrary
53+ , P.Literal <$> arbitrary
42− , PAlias <$> lowVar <*> pat (n-1)
54+ , P.Alias <$> lowVar <*> pat (n-1)
43− , PData <$> capVar <*> sizedPats
55+ , P.Data <$> capVar <*> genVector n pat
44− ]
56+ ]
45− where sizedPats = do
57+
46− len <- choose (0,n)
47− let m = n `div` (len + 1)
48− vectorOf len $ pat m
49−
50− shrink pat = case pat of
58+ shrink pat =
51− PAnything -> []
59+ case pat of
60+ P.Anything -> []
52− PVar v -> PVar <$> shrinkWHead v
61+ P.Var v -> P.Var <$> shrinkWHead v
53− PRecord fs -> PRecord <$> (filter (all $ not . null) . filter (not . null) $ shrink fs)
62+ P.Literal l -> P.Literal <$> shrink l
54− PLiteral l -> PLiteral <$> shrink l
55− PAlias s p -> p : (PAlias <$> shrinkWHead s <*> shrink p)
63+ P.Alias s p -> p : (P.Alias <$> shrinkWHead s <*> shrink p)
56− PData s ps -> ps ++ (PData <$> shrinkWHead s <*> shrink ps)
64+ P.Data s ps -> ps ++ (P.Data <$> shrinkWHead s <*> shrink ps)
65+ P.Record fs ->
66+ P.Record <$> filter (all notNull) (filter notNull (shrink fs))
67+ where
68+ notNull = not . null
57
69
58shrinkWHead :: Arbitrary a => [a] -> [[a]]
70shrinkWHead :: Arbitrary a => [a] -> [[a]]
59shrinkWHead [] = error "Should be nonempty"
71shrinkWHead [] = error "Should be nonempty"
60shrinkWHead (x:xs) = (x:) <$> shrink xs
72shrinkWHead (x:xs) = (x:) <$> shrink xs
61
73
62−instance Arbitrary Type where
74+instance Arbitrary T.Type where
63 arbitrary = sized tipe
75 arbitrary = sized tipe
76+ where
64− where tipe :: Int -> Gen Type
77+ tipe :: Int -> Gen T.Type
78+ tipe n =
79+ let depthTipe = tipe =<< choose (0,n)
80+ field = (,) <$> lowVar <*> depthTipe
81+ fields = genVector n (\m -> (,) <$> lowVar <*> tipe m)
82+ fields1 = (:) <$> field <*> fields
83+ in
84+ oneof
65− tipe n = oneof [ Lambda <$> depthTipe <*> depthTipe
85+ [ T.Lambda <$> depthTipe <*> depthTipe
66− , Var <$> lowVar
86+ , T.Var <$> lowVar
67− , Data <$> capVar <*> depthTipes
87+ , T.Data <$> capVar <*> genVector n tipe
68− , Record <$> fields <*> pure Nothing
88+ , T.Record <$> fields <*> pure Nothing
69− , Record <$> fields1 <*> (Just <$> lowVar)
89+ , T.Record <$> fields1 <*> (Just <$> lowVar)
70− ]
90+ ]
71− where depthTipe = choose (0,n) >>= tipe
91+
72− depthTipes = do
73− len <- choose (0,n)
74− let m = n `div` (len + 1)
75− vectorOf len $ tipe m
76−
77− field = (,) <$> lowVar <*> depthTipe
78− fields = do
79− len <- choose (0,n)
80− let m = n `div` (len + 1)
81− vectorOf len $ (,) <$> lowVar <*> tipe m
82− fields1 = (:) <$> field <*> fields
83−
84− shrink tipe = case tipe of
92+ shrink tipe =
93+ case tipe of
85− Lambda s t -> s : t : (Lambda <$> shrink s <*> shrink t)
94+ T.Lambda s t -> s : t : (T.Lambda <$> shrink s <*> shrink t)
86− Var _ -> []
95+ T.Var _ -> []
87− Data n ts -> ts ++ (Data <$> shrinkWHead n <*> shrink ts)
96+ T.Data n ts -> ts ++ (T.Data <$> shrinkWHead n <*> shrink ts)
88− Record fs t -> map snd fs ++ case t of
97+ T.Record fs t -> map snd fs ++ record
98+ where
99+ record =
100+ case t of
89− Nothing -> Record <$> shrinkList shrinkField fs <*> pure Nothing
101+ Nothing -> T.Record <$> shrinkList shrinkField fs <*> pure Nothing
90− Just _ ->
102+ Just _ ->
91− do
92− fields <- filter (not . null) $ shrinkList shrinkField fs
103+ do fields <- filter (not . null) $ shrinkList shrinkField fs
93− return $ Record fields t
104+ return $ T.Record fields t
105+
94− where shrinkField (n,t) = (,) <$> shrinkWHead n <*> shrink t
106+ shrinkField (n,t) = (,) <$> shrinkWHead n <*> shrink t
95
107
96lowVar :: Gen String
108lowVar :: Gen String
97lowVar = notReserved $ (:) <$> lower <*> listOf varLetter
109lowVar = notReserved $ (:) <$> lower <*> listOf varLetter
110+ where
98− where lower = elements ['a'..'z']
111+ lower = elements ['a'..'z']
99
112
100capVar :: Gen String
113capVar :: Gen String
101capVar = notReserved $ (:) <$> upper <*> listOf varLetter
114capVar = notReserved $ (:) <$> upper <*> listOf varLetter
115+ where
102− where upper = elements ['A'..'Z']
116+ upper = elements ['A'..'Z']
103
117
104varLetter :: Gen Char
118varLetter :: Gen Char
105varLetter = elements $ ['a'..'z'] ++ ['A'..'Z'] ++ ['0'..'9'] ++ ['\'', '_']
119varLetter = elements $ ['a'..'z'] ++ ['A'..'Z'] ++ ['0'..'9'] ++ ['\'', '_']
@@ -109,5 +123,6 @@ notReserved = flip exceptFor Parse.Helpers.reserveds
109
123
110exceptFor :: (Ord a) => Gen a -> [a] -> Gen a
124exceptFor :: (Ord a) => Gen a -> [a] -> Gen a
111exceptFor g xs = g `suchThat` notAnX
125exceptFor g xs = g `suchThat` notAnX
126+ where
112− where notAnX = flip Set.notMember xset
127+ notAnX = flip Set.notMember xset
113− xset = Set.fromList xs
128+ xset = Set.fromList xs