on master help sign in
Merge branch 'master' into webgl
b080f8dEvan Czaplicki
.gitignore+4
@@ -13,3 +13,7 @@ data
13build
13build
14cache
14cache
15*~
15*~
16+tests/elm/build/
17+tests/elm/cache/
18+tests/elm/exe.js
19+node_modules/
.gitmodulesnew file+9
@@ -0,0 +1,9 @@
1+[submodule "IO"]
2+ path = IO
3+ url = https://github.com/maxsnew/IO.git
4+[submodule "automaton"]
5+ path = automaton
6+ url = https://github.com/evancz/automaton.git
7+[submodule "Elm-Test"]
8+ path = Elm-Test
9+ url = https://github.com/deadfoxygrandpa/Elm-Test.git
CONTRIBUTING.md+20−19
@@ -5,31 +5,32 @@ describes the basic standards for opening pull requests:
5
5
6## Branches
6## Branches
7
7
8− * The master branch of Elm is for tagging previous releases
8+ * [The master branch](https://github.com/elm-lang/Elm/tree/master) is the
9− and non-breaking changes, like bug fixes. This branch is
9+ home of the next release of the compiler so new features and improvements
10− handy for folks who want to build the most recent public
10+ get merged there. Most pull requests should target this branch!
11− release from source.
12
11
13− * The dev branch is where the most active development occurs.
12+ * [The stable branch](https://github.com/elm-lang/Elm/tree/stable) is for
14− It is the home of the next release of the compiler so new
13+ tagging previous releases and critical bug fixes. This branch is handy for
15− features and improvements get merged there.
14+ folks who want to build the most recent public release from source.
15+
16+If you are working on a fairly large feature, we will probably want to merge it
17+in as its own branch and do some testing before bringing it into the master
18+branch. This way we can keep releases of the master branch independent of new
19+features.
16
20
17## Opening a pull request
21## Opening a pull request
18
22
19−**Please open PRs against the [dev branch of
23+**Please open PRs against the [master branch of
20−Elm](http://github.com/evancz/elm/tree/dev) whenever possible.** Changes that
24+Elm](http://github.com/elm-lang/elm/tree/master) whenever possible.**
21−are compatible with the API of master will be merged to master as soon as
22−possible. Changes that affect Elm's API will be merged to master with a future
23−release of the compiler.
24
25
25−Note that changes in the master branch of [Elm](https://github.com/evancz/Elm/)
26+Note that changes in the master branch of [Elm](https://github.com/elm-lang/Elm/)
26are able to be compiled against the master branch of the [elm-lang.org
27are able to be compiled against the master branch of the [elm-lang.org
27−repo](https://github.com/evancz/elm-lang.org), and the dev branch of
28+repo](https://github.com/elm-lang/elm-lang.org), and the stable branch of
28−[Elm](https://github.com/evancz/Elm/) is able to be built with the dev branch of
29+[Elm](https://github.com/elm-lang/Elm/) is able to be built with the stable
29−the [elm-lang.org repo](https://github.com/evancz/elm-lang.org). Please make
30+branch of the [elm-lang.org repo](https://github.com/elm-lang/elm-lang.org).
30−sure that your changes maintain this compatibility.
31+Please make sure that your changes maintain this compatibility.
31
32
32## Licensing
33## Licensing
33
34
34−You should sign the [contributor agreement](ContributorAgreement.pdf)
35+You need to sign the [contributor agreement](ContributorAgreement.pdf)
35−and send it to <info@elm-lang.org> before opening your pull request.
36+and send it to <info@elm-lang.org> before opening your pull request.
Elm-Testnew file+1

Submodule changed.

Elm.cabal+27−17
@@ -1,5 +1,5 @@
1Name: Elm
1Name: Elm
2−Version: 0.12
2+Version: 0.12.1
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
@@ -27,7 +27,7 @@ Cabal-version: >=1.9
27
27
28source-repository head
28source-repository head
29 type: git
29 type: git
30− location: git://github.com/evancz/Elm.git
30+ location: git://github.com/elm-lang/Elm.git
31
31
32Library
32Library
33 exposed-modules: Elm.Internal.Dependencies,
33 exposed-modules: Elm.Internal.Dependencies,
@@ -95,8 +95,9 @@ Library
95 Paths_Elm
95 Paths_Elm
96
96
97 Build-depends: aeson,
97 Build-depends: aeson,
98+ aeson-pretty,
98 base >=4.2 && <5,
99 base >=4.2 && <5,
99− binary >= 0.6.4.0,
100+ binary >= 0.7.0.0,
100 blaze-html >= 0.5 && < 0.8,
101 blaze-html >= 0.5 && < 0.8,
101 blaze-markup,
102 blaze-markup,
102 bytestring,
103 bytestring,
@@ -178,8 +179,9 @@ Executable elm
178 Paths_Elm
179 Paths_Elm
179
180
180 Build-depends: aeson,
181 Build-depends: aeson,
182+ aeson-pretty,
181 base >=4.2 && <5,
183 base >=4.2 && <5,
182− binary >= 0.6.4.0,
184+ binary >= 0.7.0.0,
183 blaze-html >= 0.5 && < 0.8,
185 blaze-html >= 0.5 && < 0.8,
184 blaze-markup,
186 blaze-markup,
185 bytestring,
187 bytestring,
@@ -224,7 +226,7 @@ Executable elm-doc
224 Build-depends: aeson,
226 Build-depends: aeson,
225 aeson-pretty,
227 aeson-pretty,
226 base >=4.2 && <5,
228 base >=4.2 && <5,
227− binary >= 0.6.4.0,
229+ binary >= 0.7.0.0,
228 bytestring,
230 bytestring,
229 cmdargs,
231 cmdargs,
230 containers >= 0.3,
232 containers >= 0.3,
@@ -239,35 +241,33 @@ Executable elm-doc
239 text,
241 text,
240 union-find
242 union-find
241
243
242−Test-Suite test-elm
244+Test-Suite compiler-tests
243 Type: exitcode-stdio-1.0
245 Type: exitcode-stdio-1.0
244− Hs-Source-Dirs: tests, compiler
246+ Hs-Source-Dirs: tests/hs, compiler
245− Main-is: Main.hs
247+ Main-is: CompilerTest.hs
246 other-modules: Tests.Compiler
248 other-modules: Tests.Compiler
247 Tests.Property
249 Tests.Property
248 Tests.Property.Arbitrary
250 Tests.Property.Arbitrary
249 SourceSyntax.Helpers
251 SourceSyntax.Helpers
250 SourceSyntax.Literal
252 SourceSyntax.Literal
251 SourceSyntax.PrettyPrint
253 SourceSyntax.PrettyPrint
252− build-depends: base,
253− directory,
254− Elm,
255− test-framework,
254+ build-depends: test-framework,
256 test-framework-hunit,
255 test-framework-hunit,
257 test-framework-quickcheck2 >= 0.3,
256 test-framework-quickcheck2 >= 0.3,
258 HUnit,
257 HUnit,
259− pretty,
260 QuickCheck >= 2 && < 3,
258 QuickCheck >= 2 && < 3,
261− filemanip,
262 aeson,
259 aeson,
260+ aeson-pretty,
263 base >=4.2 && <5,
261 base >=4.2 && <5,
264− binary >= 0.6.4.0,
262+ binary >= 0.7.0.0,
265− blaze-html == 0.5.* || == 0.6.*,
263+ blaze-html,
266− blaze-markup == 0.5.1.*,
264+ blaze-markup,
267 bytestring,
265 bytestring,
268 cmdargs,
266 cmdargs,
269 containers >= 0.3,
267 containers >= 0.3,
270 directory,
268 directory,
269+ Elm,
270+ filemanip,
271 filepath,
271 filepath,
272 indents,
272 indents,
273 language-ecmascript >=0.15 && < 1.0,
273 language-ecmascript >=0.15 && < 1.0,
@@ -280,3 +280,13 @@ Test-Suite test-elm
280 transformers >= 0.2,
280 transformers >= 0.2,
281 union-find,
281 union-find,
282 unordered-containers
282 unordered-containers
283+
284+Test-Suite lib-tests
285+ Type: exitcode-stdio-1.0
286+ Hs-Source-Dirs: tests/hs
287+ Main-is: LibTest.hs
288+ build-depends: base,
289+ directory,
290+ Elm,
291+ filepath,
292+ process
IOnew file+1

Submodule changed.

README.md+11−46
@@ -4,55 +4,20 @@ Learn about the Elm programming language at [elm-lang.org](http://elm-lang.org/)
4
4
5## Install
5## Install
6
6
7−**Arch Linux** &mdash; follow [these directions](https://github.com/elm-lang/Elm/wiki/Installing-Elm#arch-linux) and then
7+Follow [these instructions][installer] if you just want to use Elm. To build
8−jump to the [My First Project](#my-first-project) section.
8+the compiler from source, run the following commands:
9−<br/>
10−**OS X 10.9 or XCode 5** &mdash; follow
11−[these directions](http://justtesting.org/post/64947952690/the-glasgow-haskell-compiler-ghc-on-os-x-10-9)
12−before continuing with the platform agnostic directions below.
13
9
14−**Platform Agnostic** &mdash;
10+ [installer]: https://github.com/elm-lang/elm-platform/blob/master/README.md#elm-platform
15−download the [Haskell Platform 2012.2.0.0 or later](http://hackage.haskell.org/platform/).
16−Once the Haskell Platform is installed:
17
11
18− cabal update
12+```bash
19− cabal install elm
13+git clone https://github.com/elm-lang/Elm.git
20− cabal install elm-server
14+cd Elm
15+cabal configure
16+cabal build
17+```
21
18
22−## Use
19+This will build the compiler in `/dist/build/elm/elm` but it will not be on
23−
20+your PATH.
24−To use `elm` and `elm-server` you may need to add a new directory to your PATH.
25−
26−Cabal should tell you where your executables are located upon
27−successful installation. It'll be something like `/home/evan/.cabal/bin`
28−which you should append to your PATH variable.
29−See this tutorial if you are new to changing your PATH in
30−[Unix/Linux](http://www.cyberciti.biz/faq/unix-linux-adding-path/).
31−
32−## My First Project
33−
34−Now we will create a simple Elm project.
35−The following commands will set-up a very basic project and start the Elm server.
36−
37− mkdir helloElm
38− cd helloElm
39− printf "import Mouse\n\nmain = lift asText Mouse.position" > Main.elm
40− elm-server
41−
42−The first two commands create a new directory and navigate into it. The `printf`
43−commands place a simple program into `Main.elm`. Do this manually if you do not
44−have `printf`. The final command starts the Elm server at [localhost:8000](http://localhost:8000/),
45−allowing you to navigate to `Main.elm` and see your first program in action.
46−
47−#### Final Notes
48−
49−The `elm` package provides
50−[some utility functions](http://hackage.haskell.org/package/Elm) for
51−working with Elm in Haskell. This can be useful for creating tooling
52−for Elm, and has been useful for projects like
53−[the website](http://elm-lang.org/) and
54−[`elm-get`](https://github.com/elm-lang/elm-get). Email the list if you
55−want to rely on these functions!
56
21
57If you are stuck, email
22If you are stuck, email
58[the list](https://groups.google.com/forum/?fromgroups#!forum/elm-discuss)
23[the list](https://groups.google.com/forum/?fromgroups#!forum/elm-discuss)
automatonnew file+1

Submodule changed.

changelog.md+8−6
@@ -1,5 +1,12 @@
1
1
2−## 0.13
2+## 0.12.1
3+
4+## Improvements:
5+
6+ * New Array library (thanks entirely to @Xashili)
7+ * Json.Value can flow through ports
8+ * Improve speed and stack usage in List library (thanks to @maxsnew)
9+ * Add Dict.filter and Dict.partition (thanks to @hdgarrood)
3
10
4#### Breaking Changes:
11#### Breaking Changes:
5
12
@@ -7,11 +14,6 @@
7 * Revamp JavaScript.Experimental library to have slightly better names
14 * Revamp JavaScript.Experimental library to have slightly better names
8 * Remove JavaScript library which was made redundant by ports
15 * Remove JavaScript library which was made redundant by ports
9
16
10−## Improvements:
11−
12− * Json.Value can flow through ports, so you can bring in values even
13− if they don't conform to a consistent type.
14−
15## 0.12
17## 0.12
16
18
17#### Breaking Changes:
19#### Breaking Changes:
compiler/Elm/Internal/Dependencies.hs+41−4
@@ -5,9 +5,12 @@ import Control.Applicative
5import Control.Monad.Error
5import Control.Monad.Error
6import qualified Control.Exception as E
6import qualified Control.Exception as E
7import Data.Aeson
7import Data.Aeson
8+import Data.Aeson.Encode.Pretty
8import qualified Data.List as List
9import qualified Data.List as List
9import qualified Data.ByteString.Lazy as BS
10import qualified Data.ByteString.Lazy as BS
10import qualified Data.HashMap.Strict as Map
11import qualified Data.HashMap.Strict as Map
12+import qualified Data.Text as T
13+
11import qualified Elm.Internal.Name as N
14import qualified Elm.Internal.Name as N
12import qualified Elm.Internal.Version as V
15import qualified Elm.Internal.Version as V
13import qualified Elm.Internal.Paths as Path
16import qualified Elm.Internal.Paths as Path
@@ -22,14 +25,32 @@ data Deps = Deps
22 , exposed :: [String]
25 , exposed :: [String]
23 , elmVersion :: V.Version
26 , elmVersion :: V.Version
24 , dependencies :: [(N.Name,V.Version)]
27 , dependencies :: [(N.Name,V.Version)]
25− } deriving Show
28+ } deriving (Show, Eq, Ord)
26
29
27data MiniDeps = Mini [(N.Name,V.Version)]
30data MiniDeps = Mini [(N.Name,V.Version)]
31+ deriving (Show, Eq, Ord)
32+
33+instance ToJSON MiniDeps where
34+ toJSON (Mini m) = toJSON m
28
35
29instance FromJSON MiniDeps where
36instance FromJSON MiniDeps where
30 parseJSON (Object obj) = Mini <$> getDependencies obj
37 parseJSON (Object obj) = Mini <$> getDependencies obj
31 parseJSON _ = mzero
38 parseJSON _ = mzero
32
39
40+instance ToJSON Deps where
41+ toJSON d = object [
42+ "version" .= version d,
43+ "summary" .= summary d,
44+ "description" .= description d,
45+ "license" .= license d,
46+ "repository" .= repo d,
47+ "exposed-modules" .= exposed d,
48+ "elm-version" .= elmVersion d,
49+ "dependencies" .= (jsonDeps . dependencies $ d)
50+ ]
51+ where jsonDeps = Map.fromList . map (mapFst (T.pack . show))
52+ mapFst f (a,b) = (f a, b)
53+
33instance FromJSON Deps where
54instance FromJSON Deps where
34 parseJSON (Object obj) =
55 parseJSON (Object obj) =
35 do version <- get obj "version" "your projects version number"
56 do version <- get obj "version" "your projects version number"
@@ -110,8 +131,24 @@ withDeps handle path =
110 case result of
131 case result of
111 Right bytes -> return bytes
132 Right bytes -> return bytes
112 Left _ -> throwError $
133 Left _ -> throwError $
113− "could not find file " ++ path ++
134+ "could not find " ++ path ++ " file. You may need to create one.\n" ++
114− "\n You may need to create a dependency file for your project."
135+ " For an example of how to fill in the dependencies file, check out\n" ++
136+ " <https://github.com/evancz/automaton/blob/master/elm_dependencies.json>"
115
137
116depsAt :: FilePath -> ErrorT String IO Deps
138depsAt :: FilePath -> ErrorT String IO Deps
117−depsAt = withDeps id
139+depsAt = withDeps id
140+
141+-- | Encode dependencies in a canonical JSON format
142+prettyJSON :: Deps -> BS.ByteString
143+prettyJSON = encodePretty' config
144+ where config = defConfig { confCompare = order }
145+ order = keyOrder [ "name",
146+ "version",
147+ "summary",
148+ "description",
149+ "license",
150+ "repo",
151+ "exposed-modules",
152+ "elm-version",
153+ "dependencies"
154+ ]
compiler/Elm/Internal/Name.hs+2−2
@@ -10,7 +10,7 @@ import qualified Data.Maybe as Maybe
10import Data.Typeable
10import Data.Typeable
11
11
12data Name = Name { user :: String, project :: String }
12data Name = Name { user :: String, project :: String }
13− deriving (Typeable,Eq)
13+ deriving (Typeable,Eq, Ord)
14
14
15instance Binary Name where
15instance Binary Name where
16 get = Name <$> get <*> get
16 get = Name <$> get <*> get
@@ -48,4 +48,4 @@ errorMsg string =
48 unlines
48 unlines
49 [ "Dependency file has an invalid name: " ++ string
49 [ "Dependency file has an invalid name: " ++ string
50 , "Must have format user/project and match a public github project."
50 , "Must have format user/project and match a public github project."
51− ]
51+ ]
compiler/Generate/JavaScript.hs+2−1
@@ -34,10 +34,11 @@ include alias moduleName =
34
34
35internalImports :: String -> Statement ()
35internalImports :: String -> Statement ()
36internalImports name =
36internalImports name =
37− VarDeclStmt ()
37+ VarDeclStmt ()
38 [ varDecl "_N" (obj "Elm.Native")
38 [ varDecl "_N" (obj "Elm.Native")
39 , include "_U" "_N.Utils"
39 , include "_U" "_N.Utils"
40 , include "_L" "_N.List"
40 , include "_L" "_N.List"
41+ , include "_A" "_N.Array"
41 , include "_E" "_N.Error"
42 , include "_E" "_N.Error"
42 , varDecl "$moduleName" (string name)
43 , varDecl "$moduleName" (string name)
43 ]
44 ]
compiler/Generate/JavaScript/Ports.hs+16−9
@@ -20,7 +20,7 @@ check x jsType continue =
20 JSNumber -> [typeof "number"]
20 JSNumber -> [typeof "number"]
21 JSBoolean -> [typeof "boolean"]
21 JSBoolean -> [typeof "boolean"]
22 JSString -> [typeof "string", instanceof "String"]
22 JSString -> [typeof "string", instanceof "String"]
23− JSArray -> [instanceof "Array"]
23+ JSArray -> [(obj "_U.isJSArray" <|)]
24 JSObject fields -> [jsFold OpLAnd (typeof "object" : map member fields)]
24 JSObject fields -> [jsFold OpLAnd (typeof "object" : map member fields)]
25
25
26incoming :: Type -> Expression ()
26incoming :: Type -> Expression ()
@@ -38,7 +38,7 @@ inc tipe x =
38
38
39 Data "Json.Value" [] ->
39 Data "Json.Value" [] ->
40 obj "Native.Json.fromJS" <| x
40 obj "Native.Json.fromJS" <| x
41−
41+
42 Data ctor []
42 Data ctor []
43 | ctor == "Int" -> from JSNumber
43 | ctor == "Int" -> from JSNumber
44 | ctor == "Float" -> from JSNumber
44 | ctor == "Float" -> from JSNumber
@@ -55,8 +55,12 @@ inc tipe x =
55
55
56 | ctor == "_List" ->
56 | ctor == "_List" ->
57 check x JSArray (obj "_L.fromArray" <| array)
57 check x JSArray (obj "_L.fromArray" <| array)
58+
59+ | ctor == "Array.Array" ->
60+ check x JSArray (obj "_A.fromJSArray" <| array)
61+
58− where
62+ where
59− array = DotRef () x (var "map") <| incoming t
63+ array = DotRef () x (var "map") <| incoming t
60
64
61 Data ctor ts
65 Data ctor ts
62 | Help.isTuple ctor -> check x JSArray tuple
66 | Help.isTuple ctor -> check x JSArray tuple
@@ -67,10 +71,10 @@ inc tipe x =
67 , inc t (BracketRef () x (IntLit () n)))
71 , inc t (BracketRef () x (IntLit () n)))
68
72
69 Data _ _ ->
73 Data _ _ ->
70− error "bad ADT got to port generation code"
74+ error "bad ADT got to incoming port generation code"
71
75
72 Record _ (Just _) ->
76 Record _ (Just _) ->
73− error "bad record got to port generation code"
77+ error "bad record got to incoming port generation code"
74
78
75 Record fields Nothing ->
79 Record fields Nothing ->
76 check x (JSObject (map fst fields)) object
80 check x (JSObject (map fst fields)) object
@@ -117,16 +121,19 @@ out tipe x =
117 | ctor == "_List" ->
121 | ctor == "_List" ->
118 DotRef () (obj "_L.toArray" <| x) (var "map") <| outgoing t
122 DotRef () (obj "_L.toArray" <| x) (var "map") <| outgoing t
119
123
124+ | ctor == "Array.Array" ->
125+ DotRef () (obj "_A.toJSArray" <| x) (var "map") <| outgoing t
126+
120 Data ctor ts
127 Data ctor ts
121 | Help.isTuple ctor ->
128 | Help.isTuple ctor ->
122 let convert n t = out t $ DotRef () x $ var ('_':show n)
129 let convert n t = out t $ DotRef () x $ var ('_':show n)
123 in ArrayLit () $ zipWith convert [0..] ts
130 in ArrayLit () $ zipWith convert [0..] ts
124−
131+
125 Data _ _ ->
132 Data _ _ ->
126− error "bad ADT got to port generation code"
133+ error "bad ADT got to outgoing port generation code"
127
134
128 Record _ (Just _) ->
135 Record _ (Just _) ->
129− error "bad record got to port generation code"
136+ error "bad record got to outgoing port generation code"
130
137
131 Record fields Nothing ->
138 Record fields Nothing ->
132 ObjectLit () keys
139 ObjectLit () keys
compiler/Type/ExtraChecks.hs+2−3
@@ -60,8 +60,7 @@ portTypes rules expr =
60 | otherwise -> err' True "an unsupported type"
60 | otherwise -> err' True "an unsupported type"
61 where
61 where
62 primitives =
62 primitives =
63− ["Int","Float","String","Bool","Maybe.Maybe","_List","Json.Value"]
63+ ["Int","Float","String","Bool","Maybe.Maybe","_List","Array.Array","Json.Value"]
64−
65 validConstructor =
64 validConstructor =
66 ctor `elem` primitives || Help.isTuple ctor
65 ctor `elem` primitives || Help.isTuple ctor
67
66
@@ -102,7 +101,7 @@ portTypes rules expr =
102 , txt [ "It contains ", kind, ":\n" ]
101 , txt [ "It contains ", kind, ":\n" ]
103 , (P.nest 4 . SPP.pretty $ Alias.realias rules tipe) <> P.text "\n"
102 , (P.nest 4 . SPP.pretty $ Alias.realias rules tipe) <> P.text "\n"
104 , txt [ "Acceptable values for ", dir "incoming" "outgoing", " ports include:" ]
103 , txt [ "Acceptable values for ", dir "incoming" "outgoing", " ports include:" ]
105− , txt [ " Ints, Floats, Bools, Strings, Maybes, Lists, Tuples," ]
104+ , txt [ " Ints, Floats, Bools, Strings, Maybes, Lists, Arrays, Tuples," ]
106 , txt [ " Json.Values, ", dir "" "first-order functions, ", "and concrete records." ]
105 , txt [ " Json.Values, ", dir "" "first-order functions, ", "and concrete records." ]
107 ] ++ if couldBeAlias then aliasWarning else []
106 ] ++ if couldBeAlias then aliasWarning else []
108
107
compiler/Type/Unify.hs+5−1
@@ -86,6 +86,10 @@ actuallyUnify region variable1 variable2 = do
86 TS.addError region (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+ appendableError maybe =
90+ TS.addError region (Just $ Maybe.fromMaybe msg maybe) variable1 variable2
91+ where msg = "An appendable must be of type String, List, or Text."
92+
89 unifyComparable var name
93 unifyComparable var name
90 | name `elem` ["Int","Float","Char","String","comparable"] = flexAndUnify var
94 | name `elem` ["Int","Float","Char","String","comparable"] = flexAndUnify var
91 | otherwise = comparableError Nothing
95 | otherwise = comparableError Nothing
@@ -108,7 +112,7 @@ actuallyUnify region variable1 variable2 = do
108 do struct <- liftIO $ collectApps varFlex
112 do struct <- liftIO $ collectApps varFlex
109 case struct of
113 case struct of
110 List _ -> flexAndUnify varSuper
114 List _ -> flexAndUnify varSuper
111− _ -> comparableError Nothing
115+ _ -> appendableError Nothing
112
116
113 rigidError variable = TS.addError region (Just hint) variable1 variable2
117 rigidError variable = TS.addError region (Just hint) variable1 variable2
114 where
118 where
libraries/Array.elm+90−82
@@ -1,23 +1,23 @@
1module Array where
1module Array where
2
2
3−{-| A library for immutable arrays. The elements in an array must have the same
3+{-| A library for fast immutable arrays. The elements in an array must have the
4−type. The arrays are implemented in Relaxed Radix Balanced-Trees for fast
4+same type. The arrays are implemented in Relaxed Radix Balanced-Trees for fast
5−reads, updates, and concatenation.
5+reads, updates, and appends.
6
6
7−If you use more then one map or zip function on an array, consider turning it
7+# Creating Arrays
8−into a list before operating on it, and then turning it back into an array.
8+@docs empty, repeat, initialize, fromList
9
9
10# Basics
10# Basics
11−@docs empty, length, get, getMaybe, getSafe
11+@docs length, push, append
12
12
13−# Putting Arrays Together
13+# Get and Set
14−@docs fill, fromList, concat, set, updates, push
14+@docs get, getOrElse, getOrFail, set
15
15
16# Taking Arrays Apart
16# Taking Arrays Apart
17−@docs toList, toIndexedList, indices, slice
17+@docs slice, toList, toIndexedList
18
18
19−# Mapping, folding, zipping
19+# Mapping and Folding
20−@docs map, indexedMap, foldl, foldr, zip, zipWith
20+@docs map, indexedMap, foldl, foldr
21-}
21-}
22
22
23import Native.Array
23import Native.Array
@@ -27,17 +27,29 @@ import List
27
27
28data Array a = Array
28data Array a = Array
29
29
30−{-| Fills an array with a given length and a default element.
30+{-| Initialize an array. `initialize n f` creates an array of length `n` with
31+the element at index `i` initialized to the result of `(f i)`.
31
32
32− fill 3 5 == fromList [5,5,5]
33+ initialize 4 id == fromList [0,1,2,3]
34+ initialize 4 (\n -> n*n) == fromList [0,1,4,9]
35+ initialize 4 (always 0) == fromList [0,0,0,0]
33-}
36-}
34−fill : Int -> a -> Array a
37+initialize : Int -> (Int -> a) -> Array a
35−fill len e = fromList <| List.map (always e) [1..len]
38+initialize = Native.Array.initialize
39+
40+{-| Creates an array with a given length, filled with a default element.
41+
42+ repeat 5 0 == fromList [0,0,0,0,0]
43+ repeat 3 "cat" == fromList ["cat","cat","cat"]
44+
45+Notice that `repeat 3 x` is the same as `initialize 3 (always x)`.
46+-}
47+repeat : Int -> a -> Array a
48+repeat n e = initialize n (always e)
36
49
37−-- TODO: make this a native function.
38{-| Create an array from a list. -}
50{-| Create an array from a list. -}
39fromList : [a] -> Array a
51fromList : [a] -> Array a
40−fromList = List.foldl (Native.Array.push) Native.Array.empty
52+fromList = Native.Array.fromList
41
53
42{-| Create a list of elements from an array.
54{-| Create a list of elements from an array.
43
55
@@ -46,24 +58,19 @@ fromList = List.foldl (Native.Array.push) Native.Array.empty
46toList : Array a -> [a]
58toList : Array a -> [a]
47toList = Native.Array.toList
59toList = Native.Array.toList
48
60
49−{-| Create a list of the possible indices of an array.
50−
51− indices (fromList [3,5,8] == [0,1,2])
52−-}
53−indices : Array a -> [Int]
54−indices a = [0..Native.Array.length a - 1]
55−
56-- TODO: make this a native function.
61-- TODO: make this a native function.
57−{-| Create a list of tuples (Index, Element) from an array.
62+{-| Create an indexed list from an array. Each element of the array will be
63+paired with its index.
58
64
59− toIndexedList (fromList [3,5,8]) == [(0,3), (1,5), (2,8)]
65+ toIndexedList (fromList ["cat","dog"]) == [(0,"cat"), (1,"dog")]
60-}
66-}
61toIndexedList : Array a -> [(Int, a)]
67toIndexedList : Array a -> [(Int, a)]
68+toIndexedList array =
62−toIndexedList a = List.zip (indices a) (Native.Array.toList a)
69+ List.zip [ 0 .. Native.Array.length array - 1 ] (Native.Array.toList array)
63
70
64{-| Apply a function on every element in an array.
71{-| Apply a function on every element in an array.
65
72
66− map (\x -> x*x) (fromList [1,2,3]) == fromList [1,4,9]
73+ map sqrt (fromList [1,4,9]) == fromList [1,2,3]
67-}
74-}
68map : (a -> b) -> Array a -> Array b
75map : (a -> b) -> Array a -> Array b
69map = Native.Array.map
76map = Native.Array.map
@@ -75,36 +82,29 @@ map = Native.Array.map
75indexedMap : (Int -> a -> b) -> Array a -> Array b
82indexedMap : (Int -> a -> b) -> Array a -> Array b
76indexedMap = Native.Array.indexedMap
83indexedMap = Native.Array.indexedMap
77
84
78−{-| Reduce an array from the left.
85+{-| Reduce an array from the left. Read `foldl` as &ldquo;fold from the left&rdquo;.
79
86
80− foldl (+) 0 (fill 3 5) == 15
87+ foldl (::) [] (fromList [1,2,3]) == [3,2,1]
81-}
88-}
82foldl : (a -> b -> b) -> b -> Array a -> b
89foldl : (a -> b -> b) -> b -> Array a -> b
83foldl = Native.Array.foldl
90foldl = Native.Array.foldl
84
91
85−{-| Reduce an array from the right.
92+{-| Reduce an array from the right. Read `foldr` as &ldquo;fold from the right&rdquo;.
86
93
87− foldr (::) [] (fromList [1,2,3]) == [3,2,1]
94+ foldr (+) 0 (repeat 3 5) == 15
88-}
95-}
89foldr : (a -> b -> b) -> b -> Array a -> b
96foldr : (a -> b -> b) -> b -> Array a -> b
90foldr = Native.Array.foldr
97foldr = Native.Array.foldr
91
98
92−{-| Zip the elements of two arrays via a tuple into a new array. If one array is
99+{-| Keep only elements that satisfy the predicate:
93−longer, the extra elements are dropped.
94−
95− zip (fromList [1,2,3,4]) (fromList [0,0,0]) = fromList [(1,0), (2,0), (3,0)]
96−-}
97−zip : Array a -> Array b -> Array (a,b)
98−zip = zipWith (,)
99−
100−{-| Zips the elements of two arrays via a function into a new array. If one array
101−is longer, the extra elements are dropped.
102
100
103− zipWith (+) (fill 3 5) (fill 5 8) == fill 3 13
101+ filter isEven (fromList [1..6]) == (fromList [2,4,6])
104-}
102-}
105−zipWith : (a -> b -> c) -> Array a -> Array b -> Array c
103+filter : (a -> Bool) -> Array a -> Array a
106−zipWith f a b =
104+filter isOkay arr =
105+ let update x xs = if isOkay x then Native.Array.push x xs else xs
106+ in
107− fromList <| List.zipWith f (Native.Array.toList a) (Native.Array.toList b)
107+ Native.Array.foldl update Native.Array.empty arr
108
108
109{-| Return an empty array.
109{-| Return an empty array.
110
110
@@ -120,57 +120,65 @@ empty = Native.Array.empty
120push : a -> Array a -> Array a
120push : a -> Array a -> Array a
121push = Native.Array.push
121push = Native.Array.push
122
122
123−{-| Return the element at the index. Breaks, if index is out of range. If the
123+{-| Get the element at a particular index.
124−array length is unkown, use safeGet oder getWithDefault.
125
124
126− get 2 (A.fromList [3,2,1]) == 1
125+ getOrFail 0 (A.fromList [0,1,2]) == 0
126+
127+Warning: this function will result in a runtime error if the index is not found,
128+so it is best to use `get` or `getOrElse` unless you are sure the index will be
129+found.
127-}
130-}
128−get : Int -> Array a -> a
131+getOrFail : Int -> Array a -> a
129−get = Native.Array.get
132+getOrFail = Native.Array.get
130
133
131{-| Return Just the element at the index or Nothing if the index is out of range.
134{-| Return Just the element at the index or Nothing if the index is out of range.
132
135
133− getMaybe 2 (A.fromList [3,2,1]) == Just 2
136+ get 0 (fromList [0,1,2]) == Just 0
137+ get 2 (fromList [0,1,2]) == Just 2
134− getMaybe 5 (A.fromList [3,2,1]) == Nothing
138+ get 5 (fromList [0,1,2]) == Nothing
139+ get -1 (fromList [0,1,2]) == Nothing
135-}
140-}
136−getMaybe : Int -> Array a -> Maybe a
141+get : Int -> Array a -> Maybe a
142+get i array =
137−getMaybe i array = if Native.Array.length array > i
143+ if 0 <= i && i < Native.Array.length array
138− then Just (Native.Array.get i array)
144+ then Just (Native.Array.get i array)
139− else Nothing
145+ else Nothing
140
146
141−{-| Get the element at the index. If the index is out of range, the given default
147+{-| Get the element at the index. Or if the index is out of range, a default
142−element is returned.
148+value is returned.
143
149
144− getSafe 0 2 (A.fromList [3,2,1]) == 1
150+ getOrElse 0 2 (fromList [0,1,2]) == 2
145− getSafe 0 5 (A.fromList [3,2,1]) == 0
151+ getOrElse 0 5 (fromList [0,1,2]) == 0
146-}
152-}
147−getSafe : a -> Int -> Array a -> a
153+getOrElse : a -> Int -> Array a -> a
154+getOrElse default i array =
148−getSafe default i array = if Native.Array.length array > i
155+ if 0 <= i && i < Native.Array.length array
149− then Native.Array.get i array else default
156+ then Native.Array.get i array
157+ else default
150
158
151−{-| Set the element at the index. Returns the updated array, or if the index is
159+{-| Set the element at a particular index. Returns an updated array.
152−out of range, the unaltered array.
160+If the index is out of range, the array is unaltered.
153
161
154 set 1 7 (fromList [1,2,3]) == fromList [1,7,3]
162 set 1 7 (fromList [1,2,3]) == fromList [1,7,3]
155-}
163-}
156set : Int -> a -> Array a -> Array a
164set : Int -> a -> Array a -> Array a
157set = Native.Array.set
165set = Native.Array.set
158
166
159−{-| Update an array with a a list tuples, wherein the first Int is the index.
167+{-| Get a sub-section of an array: `(slice start end array)`. The `start` is a
168+zero-based index where we will start our slice. The `end` is a zero-based index
169+that indicates the end of the slice. The slice extracts up to but not including
170+`end`.
160
171
161− updates [(1,7),(2,8)] (fill 3 1) == fromList [1,7,8]
172+ slice 0 3 (fromList [0,1,2,3,4]) == fromList [0,1,2]
162−-}
173+ slice 1 4 (fromList [0,1,2,3,4]) == fromList [1,2,3]
163−updates : [(Int, a)] -> Array a -> Array a
174+
164−updates us array = List.foldl (uncurry Native.Array.set) array us
175+Both the `start` and `end` indexes can be negative, indicating an offset from
176+the end of the array.
165
177
166−{-| Slice an array given a range. The selection is inclusive, so the last
178+ slice 1 -1 (fromList [0,1,2,3,4]) == fromList [1,2,3]
167−element in the selection will also be in the new array. This may change in the
179+ slice -2 5 (fromList [0,1,2,3,4]) == fromList [3,4]
168−future.
169−You can select from the end by giving a negative Int.
170
180
171− slice 1 2 (fromList [0,1,2,3,4]) == fromList [1,2]
181+This makes it pretty easy to `pop` the last element off of an array: `slice 0 -1 array`
172− slice 1 -2 (fromList [0,1,2,3,4]) == fromList [1,2,3]
173− slice -3 -2 (fromList [0,1,2,3,4]) == fromList [2,3]
174-}
182-}
175slice : Int -> Int -> Array a -> Array a
183slice : Int -> Int -> Array a -> Array a
176slice = Native.Array.slice
184slice = Native.Array.slice
@@ -182,9 +190,9 @@ slice = Native.Array.slice
182length : Array a -> Int
190length : Array a -> Int
183length = Native.Array.length
191length = Native.Array.length
184
192
185−{-| Concat two arrays to a new one.
193+{-| Append two arrays to a new one.
186
194
187− concat (fill 3 1) (fill 4 2) == fromList [1,1,1,2,2,2,2]
195+ append (array 2 42) (array 3 81) == fromList [42,42,81,81,81]
188-}
196-}
189−concat : Array a -> Array a -> Array a
197+append : Array a -> Array a -> Array a
190−concat = Native.Array.concat
198+append = Native.Array.append
libraries/Dict.elm+76−18
@@ -1,6 +1,8 @@
1module Dict (empty,singleton,insert,update
1module Dict (empty,singleton,insert,update
2− ,lookup,findWithDefault
2+ ,get,getOrElse,getOrFail
3 ,remove,member
3 ,remove,member
4+ ,filter
5+ ,partition
4 ,foldl,foldr,map
6 ,foldl,foldr,map
5 ,union,intersect,diff
7 ,union,intersect,diff
6 ,keys,values
8 ,keys,values
@@ -17,7 +19,7 @@ Insert, remove, and query operations all take *O(log n)* time.
17@docs empty, singleton, insert, update, remove
19@docs empty, singleton, insert, update, remove
18
20
19# Query
21# Query
20−@docs member, lookup, findWithDefault
22+@docs member, get, getOrElse, getOrFail
21
23
22# Combine
24# Combine
23@docs union, intersect, diff
25@docs union, intersect, diff
@@ -26,7 +28,7 @@ Insert, remove, and query operations all take *O(log n)* time.
26@docs keys, values, toList, fromList
28@docs keys, values, toList, fromList
27
29
28# Transform
30# Transform
29−@docs map, foldl, foldr
31+@docs map, foldl, foldr, filter, partition
30
32
31-}
33-}
32
34
@@ -84,33 +86,74 @@ max t =
84 RBNode _ _ _ _ r -> max r
86 RBNode _ _ _ _ r -> max r
85 RBEmpty _ -> Native.Error.raise "(max Empty) is not defined"
87 RBEmpty _ -> Native.Error.raise "(max Empty) is not defined"
86
88
87−{-| Lookup the value associated with a key. -}
89+{-| Get the value associated with a key. If the key is not found, return
90+`Nothing`. This is useful when you are not sure if a key will be in the
91+dictionary.
92+
93+ animals = fromList [ ("Tom", Cat), ("Jerry", Mouse) ]
94+
95+ get "Tom" animals == Just Cat
96+ get "Mouse" animals == Just Mouse
97+ get "Spike" animals == Nothing
98+
99+The `getOrElse` and `getOrFail` are built-in ways to handle common ways of
100+using the resulting `Maybe`.
101+-}
88−lookup : comparable -> Dict comparable v -> Maybe v
102+get : comparable -> Dict comparable v -> Maybe v
89−lookup k t =
103+get k t =
90 case t of
104 case t of
91 RBEmpty LBlack -> Nothing
105 RBEmpty LBlack -> Nothing
92 RBNode _ k' v l r ->
106 RBNode _ k' v l r ->
93 case Native.Utils.compare k k' of
107 case Native.Utils.compare k k' of
94− LT -> lookup k l
108+ LT -> get k l
95 EQ -> Just v
109 EQ -> Just v
96− GT -> lookup k r
110+ GT -> get k r
111+
112+{-| Get the value associated with a key. If the key is not found,
113+return a default value.
97
114
98−{-| Find the value associated with a key. If the key is not found,
115+ animals = fromList [ ("Tom", Cat), ("Jerry", Mouse) ]
99−return the default value. -}
116+
117+ getOrElse Dog "Tom" animals == Cat
118+ getOrElse Dog "Mouse" animals == Mouse
119+ getOrElse Dog "Spike" animals == Dog
120+-}
100−findWithDefault : v -> comparable -> Dict comparable v -> v
121+getOrElse : v -> comparable -> Dict comparable v -> v
101−findWithDefault base k t =
122+getOrElse base k t =
102 case t of
123 case t of
103 RBEmpty LBlack -> base
124 RBEmpty LBlack -> base
104 RBNode _ k' v l r ->
125 RBNode _ k' v l r ->
105 case Native.Utils.compare k k' of
126 case Native.Utils.compare k k' of
106− LT -> findWithDefault base k l
127+ LT -> getOrElse base k l
107 EQ -> v
128 EQ -> v
108− GT -> findWithDefault base k r
129+ GT -> getOrElse base k r
130+
131+{-| Get the value associated with a key.
132+
133+ animals = fromList [ ("Tom", Cat), ("Jerry", Mouse) ]
134+
135+ getOrFail "Tom" animals == Cat
136+ getOrFail "Mouse" animals == Mouse
137+ getOrFail "Spike" animals == -- Runtime Error!
138+
139+Warning: this function will result in a runtime error if the key is not found,
140+so it is best to use `get` or `getOrElse` unless you are sure the key will be
141+found.
142+-}
143+getOrFail : comparable -> Dict comparable v -> v
144+getOrFail k t =
145+ case t of
146+ RBEmpty LBlack -> Native.Error.raise "key not found when using 'getOrFail'"
147+ RBNode _ k' v l r ->
148+ case Native.Utils.compare k k' of
149+ LT -> getOrFail k l
150+ EQ -> v
151+ GT -> getOrFail k r
109
152
110{-| Determine if a key is in a dictionary. -}
153{-| Determine if a key is in a dictionary. -}
111member : comparable -> Dict comparable v -> Bool
154member : comparable -> Dict comparable v -> Bool
112-- Does t contain k?
155-- Does t contain k?
113−member k t = isJust <| lookup k t
156+member k t = isJust <| get k t
114
157
115ensureBlackRoot : Dict k v -> Dict k v
158ensureBlackRoot : Dict k v -> Dict k v
116ensureBlackRoot t =
159ensureBlackRoot t =
@@ -327,9 +370,7 @@ union t1 t2 = foldl insert t2 t1
327{-| Keep a key-value pair when its key appears in the second dictionary.
370{-| Keep a key-value pair when its key appears in the second dictionary.
328Preference is given to values in the first dictionary. -}
371Preference is given to values in the first dictionary. -}
329intersect : Dict comparable v -> Dict comparable v -> Dict comparable v
372intersect : Dict comparable v -> Dict comparable v -> Dict comparable v
330−intersect t1 t2 =
373+intersect t1 t2 = filter (\k _ -> k `member` t2) t1
331− let combine k v t = if k `member` t2 then insert k v t else t
332− in foldl combine empty t1
333
374
334{-| Keep a key-value pair when its key does not appear in the second dictionary.
375{-| Keep a key-value pair when its key does not appear in the second dictionary.
335Preference is given to the first dictionary. -}
376Preference is given to the first dictionary. -}
@@ -351,3 +392,20 @@ toList t = foldr (\k v acc -> (k,v) :: acc) [] t
351{-| Convert an association list into a dictionary. -}
392{-| Convert an association list into a dictionary. -}
352fromList : [(comparable,v)] -> Dict comparable v
393fromList : [(comparable,v)] -> Dict comparable v
353fromList assocs = List.foldl (\(k,v) d -> insert k v d) empty assocs
394fromList assocs = List.foldl (\(k,v) d -> insert k v d) empty assocs
395+
396+{-| Keep a key-value pair when it satisfies a predicate. -}
397+filter : (comparable -> v -> Bool) -> Dict comparable v -> Dict comparable v
398+filter p dict =
399+ let add k v t = if p k v then insert k v t else t
400+ in foldl add empty dict
401+
402+{-| Partition a dictionary according to a predicate. The first dictionary
403+contains all key-value pairs which satisfy the predicate, and the second
404+contains the rest.
405+-}
406+partition : (comparable -> v -> Bool) -> Dict comparable v -> (Dict comparable v, Dict comparable v)
407+partition p dict =
408+ let add k v (t1, t2) = if p k v
409+ then (insert k v t1, t2)
410+ else (t1, insert k v t2)
411+ in foldl add (empty, empty) dict
libraries/Graphics/Input.elm+1−1
@@ -89,7 +89,7 @@ button = Native.Graphics.Input.button
89
89
90 prettyButton : Element
90 prettyButton : Element
91 prettyButton =
91 prettyButton =
92− customButton click.handle
92+ customButton click.handle ()
93 (image 100 40 "/button_up.jpg")
93 (image 100 40 "/button_up.jpg")
94 (image 100 40 "/button_hover.jpg")
94 (image 100 40 "/button_hover.jpg")
95 (image 100 40 "/button_down.jpg")
95 (image 100 40 "/button_down.jpg")
libraries/List.elm+25−15
@@ -163,13 +163,19 @@ maximum = foldl1 max
163minimum : [comparable] -> comparable
163minimum : [comparable] -> comparable
164minimum = foldl1 min
164minimum = foldl1 min
165
165
166−{-| Split a list based on the predicate. -}
166+{-| Partition a list based on a predicate. The first list contains all values
167+that satisfy the predicate, and the second list contains all the value that do
168+not.
169+
170+ partition (\x -> x < 3) [0..5] == ([0,1,2], [3,4,5])
171+ partition isEven [0..5] == ([0,2,4], [1,3,5])
172+-}
167partition : (a -> Bool) -> [a] -> ([a],[a])
173partition : (a -> Bool) -> [a] -> ([a],[a])
168−partition pred lst =
174+partition pred =
169− case lst of
175+ let step x (ts, fs) = if pred x
170− [] -> ([],[])
176+ then (x::ts, fs)
171− x::xs -> let (bs,cs) = partition pred xs in
177+ else (ts, x::fs)
172− if pred x then (x::bs,cs) else (bs,x::cs)
178+ in foldr step ([],[])
173
179
174{-| Combine two lists, combining them into tuples pairwise.
180{-| Combine two lists, combining them into tuples pairwise.
175If one list is longer, the extra elements are dropped.
181If one list is longer, the extra elements are dropped.
@@ -188,12 +194,14 @@ If one list is longer, the extra elements are dropped.
188zipWith : (a -> b -> c) -> [a] -> [b] -> [c]
194zipWith : (a -> b -> c) -> [a] -> [b] -> [c]
189zipWith = Native.List.zipWith
195zipWith = Native.List.zipWith
190
196
191−{-| Decompose a list of tuples. -}
197+{-| Decompose a list of tuples.
198+
199+ unzip [(0, True), (17, False), (1337, True)] == ([0,17,1337], [True,False,True])
200+-}
192unzip : [(a,b)] -> ([a],[b])
201unzip : [(a,b)] -> ([a],[b])
193−unzip pairs =
202+unzip =
194− case pairs of
203+ let step (x,y) (xs, ys) = (x::xs, y::ys)
195− [] -> ([],[])
204+ in foldr step ([], [])
196− (x,y)::ps -> let (xs,ys) = (unzip ps) in (x::xs,y::ys)
197
205
198{-| Places the given value between all of the lists in the second
206{-| Places the given value between all of the lists in the second
199argument and concatenates the result.
207argument and concatenates the result.
@@ -209,10 +217,12 @@ join = Native.List.join
209-}
217-}
210intersperse : a -> [a] -> [a]
218intersperse : a -> [a] -> [a]
211intersperse sep xs =
219intersperse sep xs =
212− case xs of
220+ case xs of
213− a::b::cs -> a :: sep :: intersperse sep (b::cs)
221+ [] -> []
214− [a] -> [a]
222+ hd::tl ->
215− [] -> []
223+ let step x rest = sep :: x :: rest
224+ spersed = foldr step [] tl
225+ in hd :: spersed
216
226
217{-| Take the first n members of a list: `(take 2 [1,2,3,4] == [1,2])` -}
227{-| Take the first n members of a list: `(take 2 [1,2,3,4] == [1,2])` -}
218take : Int -> [a] -> [a]
228take : Int -> [a] -> [a]
libraries/Native/Array.js+202−56
@@ -1,4 +1,4 @@
1−Elm.Native.Array = {};
1+Elm.Native.Array = {};
2Elm.Native.Array.make = function(elm) {
2Elm.Native.Array.make = function(elm) {
3 elm.Native = elm.Native || {};
3 elm.Native = elm.Native || {};
4 elm.Native.Array = elm.Native.Array || {};
4 elm.Native.Array = elm.Native.Array || {};
@@ -24,38 +24,144 @@ Elm.Native.Array.make = function(elm) {
24 // An empty array.
24 // An empty array.
25 var empty = { ctor:"_Array", height:0, table:new Array() };
25 var empty = { ctor:"_Array", height:0, table:new Array() };
26
26
27− // Gets the value at index i recursively.
28− function get(i, a) {
27+ function get(i, array) {
29− if (a.height == 0) {
30− if (i < a.table.length) {
28+ if (i < 0 || i >= length(array)) {
31− return a.table[i];
32− } else {
33− throw new Error("Index "+ i +" is out of range. Check the length of your array first or use getSafe or getMaybe.");
29+ throw new Error("Index " + i + " is out of range. Check the length of " +
30+ "your array first or use getMaybe or getWithDefault.");
34 }
31 }
32+ return unsafeGet(i, array);
35− }
33+ }
36
34
37− var slot = getSlot(i, a);
35+ function unsafeGet(i, array) {
36+ for (var x = array.height; x > 0; x--) {
37+ var slot = i >> (x * 5);
38+ if (slot > 0) {
38− var sub = slot > 0 ? a.lengths[slot-1] : 0;
39+ while (array.lengths[slot - 1] > i) { slot--; }
40+ i -= array.lengths[slot - 1];
41+ }
42+ array = array.table[slot];
43+ }
39− return get(i - sub, a.table[slot]);
44+ return array.table[i];
40 }
45 }
41
46
42 // Sets the value at the index i. Only the nodes leading to i will get
47 // Sets the value at the index i. Only the nodes leading to i will get
43 // copied and updated.
48 // copied and updated.
44− function set(i, item, a) {
49+ function set(i, item, array) {
45− if (length(a) <= i) {
50+ if (i < 0 || length(array) <= i) {
46− return a;
51+ return array;
47 }
52 }
48− var newA = nodeCopy(a);
53+ return unsafeSet(i, item, array);
49− newA.table = a.table.slice();
54+ }
50
55
56+ function unsafeSet(i, item, array) {
57+ array = nodeCopy(array);
58+
51− if (a.height == 0) {
59+ if (array.height == 0) {
52− newA.table[i] = item;
60+ array.table[i] = item;
53 } else {
61 } else {
54− var slot = getSlot(i, a);
62+ var slot = getSlot(i, array);
55− var sub = slot > 0 ? a.lengths[slot-1] : 0;
63+ if (slot > 0) {
56− newA.table[slot] = set(i - sub, item, a.table[slot]);
64+ i -= array.lengths[slot - 1];
65+ }
66+ array.table[slot] = unsafeSet(i, item, array.table[slot]);
67+ }
68+ return array;
69+ }
70+
71+ function initialize(len, f) {
72+ if (len == 0) { return empty; }
73+ var h = Math.floor(Math.log(len)/Math.log(M));
74+ return initialize_(f, h, 0, len);
75+ }
76+
77+ function initialize_(f, h, from, to) {
78+ if (h == 0) {
79+ var table = new Array((to - from) % (M + 1));
80+ for (var i = 0; i < table.length; i++) {
81+ table[i] = f(from + i);
82+ }
83+ return { ctor:"_Array", height:0, table:table };
84+ }
85+
86+ var step = Math.pow(M, h);
87+ var table = new Array(Math.ceil((to - from) / step));
88+ var lengths = new Array(table.length);
89+ for (var i = 0; i < table.length; i++) {
90+ table[i] = initialize_( f, h - 1, from + (i * step)
91+ , Math.min(from + ((i + 1) * step), to));
92+ lengths[i] = length(table[i]) + (i > 0 ? lengths[i-1] : 0);
93+ }
94+ return { ctor:"_Array", height:h, table:table, lengths:lengths };
95+ }
96+
97+ function fromList(list) {
98+ if (list == List.Nil) { return empty; }
99+
100+ // Allocate M sized blocks (table) and write list elements to it.
101+ var table = new Array(M);
102+ var nodes = new Array();
103+ var i = 0;
104+
105+ while (list.ctor !== '[]') {
106+ table[i] = list._0;
107+ list = list._1;
108+ i++;
109+
110+ // table is full, so we can push a leaf containing it into the
111+ // next node.
112+ if (i == M) {
113+ fromListPush({ ctor:"_Array", height:0, table:table }
114+ , nodes);
115+ table = new Array(M);
116+ i = 0;
117+ }
118+ }
119+
120+ // Maybe there is something left on the table.
121+ if (i > 0) {
122+ fromListPush({ ctor:"_Array", height:0, table:table.splice(0,i) }
123+ , nodes);
124+ }
125+
126+ // Go through all of the nodes and eventually push them into higher nodes.
127+ for (var h = 0; h < nodes.length - 1; h++) {
128+ if (nodes[h].table.length > 0) {
129+ fromListPush(nodes[h], nodes);
130+ }
131+ }
132+
133+ var head = nodes[nodes.length - 1];
134+ if (head.height > 0 && head.table.length == 1) {
135+ return head.table[0];
136+ } else {
137+ return head;
138+ }
139+ }
140+
141+ // Push a node into a higher node as a child.
142+ function fromListPush(toPush, nodes) {
143+ var h = toPush.height;
144+
145+ // Maybe the node on this height does not exist.
146+ if (nodes.length == h) {
147+ nodes.push({ ctor:"_Array", height:h + 1
148+ , table:new Array()
149+ , lengths:new Array() });
150+ }
151+
152+ nodes[h].table.push(toPush);
153+ var len = length(toPush);
154+ if (nodes[h].lengths.length > 0) {
155+ len += nodes[h].lengths[nodes[h].lengths.length - 1];
156+ }
157+ nodes[h].lengths.push(len);
158+
159+ if (nodes[h].table.length == M) {
160+ fromListPush(nodes[h], nodes);
161+ nodes[h] = { ctor:"_Array", height:h + 1
162+ , table:new Array()
163+ , lengths:new Array() };
57 }
164 }
58− return newA;
59 }
165 }
60
166
61 // Pushes an item via push_ to the bottom right of a tree.
167 // Pushes an item via push_ to the bottom right of a tree.
@@ -65,7 +171,7 @@ Elm.Native.Array.make = function(elm) {
65 return pushed;
171 return pushed;
66 }
172 }
67
173
68− newTree = create(item, a.height);
174+ var newTree = create(item, a.height);
69 return siblise(a, newTree);
175 return siblise(a, newTree);
70 }
176 }
71
177
@@ -143,22 +249,19 @@ Elm.Native.Array.make = function(elm) {
143 }
249 }
144
250
145 function foldl(f, b, a) {
251 function foldl(f, b, a) {
146− for (var i = a.table.length - 1; i >= 0; i--) {
252+ for (var i = 0; i < a.table.length; i++) {
147 b = A2(f, a.height == 0 ? a.table[i] : foldl(f, b, a.table[i]), b);
253 b = A2(f, a.height == 0 ? a.table[i] : foldl(f, b, a.table[i]), b);
148 }
254 }
149 return b;
255 return b;
150 }
256 }
151
257
152 function foldr(f, b, a) {
258 function foldr(f, b, a) {
153− for (var i = 0; i < a.table.length; i++) {
259+ for (var i = a.table.length; i--; ) {
154 b = A2(f, a.height == 0 ? a.table[i] : foldr(f, b, a.table[i]), b);
260 b = A2(f, a.height == 0 ? a.table[i] : foldr(f, b, a.table[i]), b);
155 }
261 }
156 return b;
262 return b;
157 }
263 }
158
264
159− // Returns a sliced tree. "to" is inclusive, but this may change,
160− // when I understand, why e.g. JS does not handle it this way. :-)
161− // If "from" or "to" is negative, they will select from the end on.
162 // TODO: currently, it slices the right, then the left. This can be
265 // TODO: currently, it slices the right, then the left. This can be
163 // optimized.
266 // optimized.
164 function slice(from, to, a) {
267 function slice(from, to, a) {
@@ -175,7 +278,7 @@ Elm.Native.Array.make = function(elm) {
175 // Handle leaf level.
278 // Handle leaf level.
176 if (a.height == 0) {
279 if (a.height == 0) {
177 var newA = { ctor:"_Array", height:0 };
280 var newA = { ctor:"_Array", height:0 };
178− newA.table = a.table.slice(0, to + 1);
281+ newA.table = a.table.slice(0, to);
179 return newA;
282 return newA;
180 }
283 }
181
284
@@ -232,15 +335,15 @@ Elm.Native.Array.make = function(elm) {
232 return newA;
335 return newA;
233 }
336 }
234
337
235− // Concats two trees.
338+ // Appends two trees.
236− // TODO: Add support for concatting trees of different sizes. Current
339+ // TODO: Add support for appending trees of different sizes. Current
237− // behavior will just rise the lower tree and then concat them.
340+ // behavior will just rise the lower tree and then append them.
238− function concat(a, b) {
341+ function append(a,b) {
239− if (b.height > a.height) { return concat(parentise(a, b.height), b); }
342+ if (b.height > a.height) { return append(parentise(a, b.height), b); }
240− if (a.height > b.height) { return concat(a, parentise(b, a.height)); }
343+ if (a.height > b.height) { return append(a, parentise(b, a.height)); }
241− if (a.height == 0) { return concat(parentise(a, 1), parentise(b, 1)); }
344+ if (a.height == 0) { return append(parentise(a, 1), parentise(b, 1)); }
242
345
243− var c = concat_(a, b);
346+ var c = append_(a, b);
244 if (c[1].table.length > 0) {
347 if (c[1].table.length > 0) {
245 return siblise(c[0], c[1]);
348 return siblise(c[0], c[1]);
246 } else {
349 } else {
@@ -249,9 +352,9 @@ Elm.Native.Array.make = function(elm) {
249 }
352 }
250
353
251 // Returns an array of two nodes. The second node _may_ be empty. This case
354 // Returns an array of two nodes. The second node _may_ be empty. This case
252− // needs to be handled by the function, that called concat_. May be only
355+ // needs to be handled by the function, that called append_. May be only
253 // called for trees with an minimal height of 1.
356 // called for trees with an minimal height of 1.
254− function concat_(a, b) {
357+ function append_(a, b) {
255 if (a.height == 1) {
358 if (a.height == 1) {
256 // Check if balancing is needed and return based on that.
359 // Check if balancing is needed and return based on that.
257 var toRemove = calcToRemove(a, b);
360 var toRemove = calcToRemove(a, b);
@@ -262,18 +365,18 @@ Elm.Native.Array.make = function(elm) {
262 return shuffle(a, b, toRemove);
365 return shuffle(a, b, toRemove);
263 }
366 }
264
367
265− var concated = concat_(botRight(a), botLeft(b));
368+ var appended = append_(botRight(a), botLeft(b));
266 a = nodeCopy(a), b = nodeCopy(b);
369 a = nodeCopy(a), b = nodeCopy(b);
267
370
268 // Adjust the bottom right side of the new tree.
371 // Adjust the bottom right side of the new tree.
269− a.table[a.table.length - 1] = concated[0];
372+ a.table[a.table.length - 1] = appended[0];
270− a.lengths[a.lengths.length - 1] = length(concated[0])
373+ a.lengths[a.lengths.length - 1] = length(appended[0])
271 a.lengths[a.lengths.length - 1] += a.lengths.length > 1 ? a.lengths[a.lengths.length - 2] : 0;
374 a.lengths[a.lengths.length - 1] += a.lengths.length > 1 ? a.lengths[a.lengths.length - 2] : 0;
272
375
273 // Adjust the bottom left side of the new tree.
376 // Adjust the bottom left side of the new tree.
274− if (concated[1].table.length > 0) {
377+ if (appended[1].table.length > 0) {
275− b.table[0] = concated[1];
378+ b.table[0] = appended[1];
276− b.lengths[0] = length(concated[1]);
379+ b.lengths[0] = length(appended[1]);
277 for (var i = 1, len = length(b.table[0]); i < b.lengths.length; i++) {
380 for (var i = 1, len = length(b.table[0]); i < b.lengths.length; i++) {
278 len += length(b.table[i]);
381 len += length(b.table[i]);
279 b.lengths[i] = len;
382 b.lengths[i] = len;
@@ -423,21 +526,19 @@ Elm.Native.Array.make = function(elm) {
423 }
526 }
424
527
425 // Returns how many items are in the tree.
528 // Returns how many items are in the tree.
426− function length(a) {
529+ function length(array) {
427− if (a.height == 0) {
530+ if (array.height == 0) {
428− return a.table.length;
531+ return array.table.length;
429 } else {
532 } else {
430− return a.lengths[a.lengths.length - 1];
533+ return array.lengths[array.lengths.length - 1];
431 }
534 }
432 }
535 }
433
536
434 // Calculates in which slot of "table" the item probably is, then
537 // Calculates in which slot of "table" the item probably is, then
435 // find the exact slot via forward searching in "lengths". Returns the index.
538 // find the exact slot via forward searching in "lengths". Returns the index.
436 function getSlot(i, a) {
539 function getSlot(i, a) {
437− var slot = Math.floor(i / (Math.pow(M, a.height)));
540+ var slot = i >> (5 * a.height);
438− while (a.lengths[slot] <= i) {
541+ while (a.lengths[slot - 1] > i) { slot--; }
439− slot++
440− }
441 return slot;
542 return slot;
442 }
543 }
443
544
@@ -472,10 +573,52 @@ Elm.Native.Array.make = function(elm) {
472 , lengths:[length(a), length(a) + length(b)] };
573 , lengths:[length(a), length(a) + length(b)] };
473 }
574 }
474
575
576+ function toJSArray(a) {
577+ var jsArray = new Array(length(a));
578+ toJSArray_(jsArray, 0, a);
579+ return jsArray;
580+ }
581+
582+ function toJSArray_(jsArray, i, a) {
583+ for (var t = 0; t < a.table.length; t++) {
584+ if (a.height == 0) {
585+ jsArray[i + t] = a.table[t];
586+ } else {
587+ var inc = t == 0 ? 0 : a.lengths[t - 1];
588+ toJSArray_(jsArray, i + inc, a.table[t]);
589+ }
590+ }
591+ }
592+
593+ function fromJSArray(jsArray) {
594+ if (jsArray.length == 0) { return empty; }
595+ var h = Math.floor(Math.log(jsArray.length) / Math.log(M));
596+ return fromJSArray_(jsArray, h, 0, jsArray.length);
597+ }
598+
599+ function fromJSArray_(jsArray, h, from, to) {
600+ if (h == 0) {
601+ return { ctor:"_Array", height:0
602+ , table:jsArray.slice(from, to) };
603+ }
604+
605+ var step = Math.pow(M, h);
606+ var table = new Array(Math.ceil((to - from) / step));
607+ var lengths = new Array(table.length);
608+ for (var i = 0; i < table.length; i++) {
609+ table[i] = fromJSArray_( jsArray, h - 1, from + (i * step)
610+ , Math.min(from + ((i + 1) * step), to));
611+ lengths[i] = length(table[i]) + (i > 0 ? lengths[i-1] : 0);
612+ }
613+ return { ctor:"_Array", height:h, table:table, lengths:lengths };
614+ }
615+
475 Elm.Native.Array.values = {
616 Elm.Native.Array.values = {
476 empty:empty,
617 empty:empty,
618+ fromList:fromList,
477 toList:toList,
619 toList:toList,
478− concat:F2(concat),
620+ initialize:F2(initialize),
621+ append:F2(append),
479 push:F2(push),
622 push:F2(push),
480 slice:F3(slice),
623 slice:F3(slice),
481 get:F2(get),
624 get:F2(get),
@@ -484,7 +627,10 @@ Elm.Native.Array.make = function(elm) {
484 indexedMap:F2(indexedMap),
627 indexedMap:F2(indexedMap),
485 foldl:F3(foldl),
628 foldl:F3(foldl),
486 foldr:F3(foldr),
629 foldr:F3(foldr),
487− length:length
630+ length:length,
631+
632+ toJSArray:toJSArray,
633+ fromJSArray:fromJSArray
488 };
634 };
489
635
490 return elm.Native.Array.values = Elm.Native.Array.values;
636 return elm.Native.Array.values = Elm.Native.Array.values;
libraries/Native/Error.js+2−4
@@ -4,8 +4,6 @@ Elm.Native.Error.make = function(elm) {
4 elm.Native.Error = elm.Native.Error || {};
4 elm.Native.Error = elm.Native.Error || {};
5 if (elm.Native.Error.values) return elm.Native.Error.values;
5 if (elm.Native.Error.values) return elm.Native.Error.values;
6
6
7− var fromString = Elm.Native.JavaScript.make(elm).fromString;
8−
9 function indent(lines) {
7 function indent(lines) {
10 var msg = '';
8 var msg = '';
11 for (var i = 0; i < lines.length; ++i) {
9 for (var i = 0; i < lines.length; ++i) {
@@ -26,7 +24,7 @@ Elm.Native.Error.make = function(elm) {
26 throw new Error('Runtime error in module ' + moduleName + ' (' + span + '):' + msg);
24 throw new Error('Runtime error in module ' + moduleName + ' (' + span + '):' + msg);
27 }
25 }
28
26
29− function raise(str) { throw new Error(fromString(str)); }
27+ function raise(str) { throw new Error(str); }
30
28
31 return elm.Native.Error.values = { Case: Case, If: If, raise: raise };
29 return elm.Native.Error.values = { Case: Case, If: If, raise: raise };
32−};
30+};
libraries/Native/Graphics/Input.js−29
@@ -134,13 +134,6 @@ Elm.Native.Graphics.Input.make = function(elm) {
134
134
135 btn.appendChild(btn.elm_up);
135 btn.appendChild(btn.elm_up);
136
136
137− var clicker = newNode('div');
138− clicker.style.width = btn.elm_up.style.width;
139− clicker.style.height = btn.elm_up.style.height;
140− clicker.style.position = 'absolute';
141− clicker.style.top = 0;
142− btn.appendChild(clicker);
143−
144 return btn;
137 return btn;
145 }
138 }
146
139
@@ -297,29 +290,7 @@ Elm.Native.Graphics.Input.make = function(elm) {
297 }));
290 }));
298 }
291 }
299
292
300− function mouseUpdate(event) {
301− var direction = field.selectionDirection === 'forward' ? 'Forward' : 'Backward';
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− }));
312− }
313− function mousedown(event) {
314− mouseUpdate(event);
315− elm.node.addEventListener('mouseup', mouseup);
316− }
317− function mouseup(event) {
318− mouseUpdate(event);
319− elm.node.removeEventListener('mouseup', mouseup)
320− }
321 field.addEventListener('input', inputUpdate);
293 field.addEventListener('input', inputUpdate);
322− field.addEventListener('mousedown', mousedown);
323 field.addEventListener('focus', function() {
294 field.addEventListener('focus', function() {
324 field.elm_hasFocus = true;
295 field.elm_hasFocus = true;
325 });
296 });
libraries/Native/String.js+2−2
@@ -73,7 +73,7 @@ Elm.Native.String.make = function(elm) {
73 return result;
73 return result;
74 }
74 }
75
75
76− function sub(start, end, str) {
76+ function slice(start, end, str) {
77 return str.slice(start,end);
77 return str.slice(start,end);
78 }
78 }
79 function left(n, str) {
79 function left(n, str) {
@@ -216,7 +216,7 @@ Elm.Native.String.make = function(elm) {
216 join: F2(join),
216 join: F2(join),
217 repeat: F2(repeat),
217 repeat: F2(repeat),
218
218
219− sub: F3(sub),
219+ slice: F3(slice),
220 left: F2(left),
220 left: F2(left),
221 right: F2(right),
221 right: F2(right),
222 dropLeft: F2(dropLeft),
222 dropLeft: F2(dropLeft),
libraries/Native/Text.js+1
@@ -153,6 +153,7 @@ Elm.Native.Text.make = function(elm) {
153 typeface : F2(typeface),
153 typeface : F2(typeface),
154 color : F2(color),
154 color : F2(color),
155 link : F2(link),
155 link : F2(link),
156+ style : F2(style),
156
157
157 leftAligned : block('left'),
158 leftAligned : block('left'),
158 rightAligned : block('right'),
159 rightAligned : block('right'),
libraries/Native/Utils.js+39−22
@@ -5,23 +5,30 @@ Elm.Native.Utils.make = function(elm) {
5 elm.Native.Utils = elm.Native.Utils || {};
5 elm.Native.Utils = elm.Native.Utils || {};
6 if (elm.Native.Utils.values) return elm.Native.Utils.values;
6 if (elm.Native.Utils.values) return elm.Native.Utils.values;
7
7
8− function eq(x,y) {
8+ function eq(l,r) {
9− if (x === y) return true;
9+ var stack = [{'x': l, 'y': r}]
10+ while (stack.length > 0) {
11+ var front = stack.pop();
12+ var x = front.x;
13+ var y = front.y;
14+ if (x === y) continue;
10− if (typeof x === "object") {
15+ if (typeof x === "object") {
11− var c = 0;
16+ var c = 0;
12− for (var i in x) {
17+ for (var i in x) {
13− ++c;
18+ ++c;
14− if (!eq(x[i],y[i])) {
19+ stack.push({ 'x': x[i], 'y': y[i] });
15− return false;
16 }
20 }
21+ if (c !== Object.keys(y).length) {
22+ return false;
23+ };
24+ } else if (typeof x === 'function') {
25+ throw new Error('Equality error: general function equality is ' +
26+ 'undecidable, and therefore, unsupported');
27+ } else {
28+ return false;
17 }
29 }
18− return c === Object.keys(y).length;
19 }
30 }
20− if (typeof x === 'function') {
21− throw new Error('Equality error: general function equality is ' +
22− 'undecidable, and therefore, unsupported');
23− }
24− return x === y;
31+ return true;
25 }
32 }
26
33
27 // code in Generate/JavaScript.hs depends on the particular
34 // code in Generate/JavaScript.hs depends on the particular
@@ -30,11 +37,15 @@ Elm.Native.Utils.make = function(elm) {
30 function compare(x,y) { return { ctor: ord[cmp(x,y)+1] } }
37 function compare(x,y) { return { ctor: ord[cmp(x,y)+1] } }
31 function cmp(x,y) {
38 function cmp(x,y) {
32 var ord;
39 var ord;
33− if (typeof x !== 'object' || x instanceof String){
40+ if (typeof x !== 'object'){
34 return x === y ? EQ : x < y ? LT : GT;
41 return x === y ? EQ : x < y ? LT : GT;
35 }
42 }
36−
43+ else if (x.isChar){
44+ var a = x.toString();
45+ var b = y.toString();
46+ return a === b ? EQ : a < b ? LT : GT;
47+ }
37− if (x.ctor === "::" || x.ctor === "[]") {
48+ else if (x.ctor === "::" || x.ctor === "[]") {
38 while (true) {
49 while (true) {
39 if (x.ctor === "[]" && y.ctor === "[]") return EQ;
50 if (x.ctor === "[]" && y.ctor === "[]") return EQ;
40 if (x.ctor !== y.ctor) return x.ctor === '[]' ? LT : GT;
51 if (x.ctor !== y.ctor) return x.ctor === '[]' ? LT : GT;
@@ -44,8 +55,7 @@ Elm.Native.Utils.make = function(elm) {
44 y = y._1;
55 y = y._1;
45 }
56 }
46 }
57 }
47−
48− if (x.ctor.slice(0,6) === '_Tuple') {
58+ else if (x.ctor.slice(0,6) === '_Tuple') {
49 var n = x.ctor.slice(6) - 0;
59 var n = x.ctor.slice(6) - 0;
50 var err = 'cannot compare tuples with more than 6 elements.';
60 var err = 'cannot compare tuples with more than 6 elements.';
51 if (n === 0) return EQ;
61 if (n === 0) return EQ;
@@ -58,9 +68,11 @@ Elm.Native.Utils.make = function(elm) {
58 if (n >= 7) throw new Error('Comparison error: ' + err); } } } } } }
68 if (n >= 7) throw new Error('Comparison error: ' + err); } } } } } }
59 return EQ;
69 return EQ;
60 }
70 }
71+ else {
61− throw new Error('Comparison error: comparison is only defined on ints, ' +
72+ throw new Error('Comparison error: comparison is only defined on ints, ' +
62− 'floats, times, chars, strings, lists of comparable values, ' +
73+ 'floats, times, chars, strings, lists of comparable values, ' +
63− 'and tuples of comparable values.')
74+ 'and tuples of comparable values.');
75+ }
64 }
76 }
65
77
66
78
@@ -205,6 +217,10 @@ Elm.Native.Utils.make = function(elm) {
205 return Tuple2(posx, posy);
217 return Tuple2(posx, posy);
206 }
218 }
207
219
220+ function isJSArray(a) {
221+ return a instanceof Array;
222+ }
223+
208 return elm.Native.Utils.values = {
224 return elm.Native.Utils.values = {
209 eq:eq,
225 eq:eq,
210 cmp:cmp,
226 cmp:cmp,
@@ -224,6 +240,7 @@ Elm.Native.Utils.make = function(elm) {
224 mod : F2(mod),
240 mod : F2(mod),
225 htmlHeight: F2(htmlHeight),
241 htmlHeight: F2(htmlHeight),
226 getXY: getXY,
242 getXY: getXY,
243+ isJSArray: isJSArray,
227 toFloat: function(x) { return +x; }
244 toFloat: function(x) { return +x; }
228 };
245 };
229};
246};
libraries/Set.elm+11−1
@@ -2,6 +2,7 @@
2module Set (empty,singleton,insert,remove
2module Set (empty,singleton,insert,remove
3 ,member
3 ,member
4 ,foldl,foldr,map
4 ,foldl,foldr,map
5+ ,filter,partition
5 ,union,intersect,diff
6 ,union,intersect,diff
6 ,toList,fromList
7 ,toList,fromList
7 ) where
8 ) where
@@ -25,7 +26,7 @@ Insert, remove, and query operations all take *O(log n)* time.
25@docs toList, fromList
26@docs toList, fromList
26
27
27# Transform
28# Transform
28−@docs map, foldl, foldr
29+@docs map, foldl, foldr, filter, partition
29
30
30-}
31-}
31
32
@@ -88,3 +89,12 @@ foldr f b s = Dict.foldr (\k _ b -> f k b) b s
88{-| Map a function onto a set, creating a new set with no duplicates. -}
89{-| Map a function onto a set, creating a new set with no duplicates. -}
89map : (comparable -> comparable') -> Set comparable -> Set comparable'
90map : (comparable -> comparable') -> Set comparable -> Set comparable'
90map f s = fromList (List.map f (toList s))
91map f s = fromList (List.map f (toList s))
92+
93+{-| Create a new set consisting only of elements which satisfy a predicate. -}
94+filter : (comparable -> Bool) -> Set comparable -> Set comparable
95+filter p set = Dict.filter (\k _ -> p k) set
96+
97+{-| Create two new sets; the first consisting of elements which satisfy a
98+predicate, the second consisting of elements which do not. -}
99+partition : (comparable -> Bool) -> Set comparable -> (Set comparable, Set comparable)
100+partition p set = Dict.partition (\k _ -> p k) set
libraries/Signal.elm+8−13
@@ -31,10 +31,7 @@ the `Time` library.
31
31
32import Native.Signal
32import Native.Signal
33import List (foldr)
33import List (foldr)
34−
35import Basics (fst, snd, not)
34import Basics (fst, snd, not)
36−import Native.Error
37−import Maybe as M
38
35
39data Signal a = Signal
36data Signal a = Signal
40
37
@@ -120,20 +117,18 @@ initially. -}
120dropIf : (a -> Bool) -> a -> Signal a -> Signal a
117dropIf : (a -> Bool) -> a -> Signal a -> Signal a
121dropIf = Native.Signal.dropIf
118dropIf = Native.Signal.dropIf
122
119
123−{-| Keep events only when the first signal is true. When the first signal
120+{-| Keep events only when the first signal is true. Elm does not allow undefined
124−becomes true, the most recent value of the second signal will be propagated.
125−Until the first signal becomes false again, all events will be propagated. Elm
126−does not allow undefined signals, so a base case must be provided in case the
121+signals, so a base case must be provided in case the first signal is not true
127−first signal is not true initially. -}
122+initially.
123+-}
128keepWhen : Signal Bool -> a -> Signal a -> Signal a
124keepWhen : Signal Bool -> a -> Signal a -> Signal a
129keepWhen bs def sig =
125keepWhen bs def sig =
130 snd <~ (keepIf fst (False, def) ((,) <~ (sampleOn sig bs) ~ sig))
126 snd <~ (keepIf fst (False, def) ((,) <~ (sampleOn sig bs) ~ sig))
131
127
132−{-| Drop events when the first signal is true. When the first signal becomes
128+{-| Drop events when the first signal is true. Elm does not allow undefined
133−false, the most recent value of the second signal will be propagated. Until the
134−first signal becomes true again, all events will be propagated. Elm does not
135−allow undefined signals, s oa base case must be provided in case the first
129+signals, so a base case must be provided in case the first signal is true
136−signal is true initially. -}
130+initially.
131+-}
137dropWhen : Signal Bool -> a -> Signal a -> Signal a
132dropWhen : Signal Bool -> a -> Signal a -> Signal a
138dropWhen bs = keepWhen (not <~ bs)
133dropWhen bs = keepWhen (not <~ bs)
139
134
libraries/String.elm+9−9
@@ -6,10 +6,10 @@ are enclosed in `"double quotes"`. Strings are *not* lists of characters.
6@docs isEmpty, length, reverse, repeat
6@docs isEmpty, length, reverse, repeat
7
7
8# Building and Splitting
8# Building and Splitting
9−@docs cons, uncons, append, concat, split, join, words, lines
9+@docs cons, uncons, append, concat, split, join, words, lines
10
10
11# Get Substrings
11# Get Substrings
12−@docs sub, left, right, dropLeft, dropRight
12+@docs slice, left, right, dropLeft, dropRight
13
13
14# Check for Substrings
14# Check for Substrings
15@docs contains, startsWith, endsWith, indexes, indices
15@docs contains, startsWith, endsWith, indexes, indices
@@ -114,7 +114,7 @@ foldr = Native.String.foldr
114{-| Split a string using a given separator.
114{-| Split a string using a given separator.
115
115
116 split "," "cat,dog,cow" == ["cat","dog","cow"]
116 split "," "cat,dog,cow" == ["cat","dog","cow"]
117− split "/" "home/evan/Desktop/" == ["home","evan","Desktop"]
117+ split "/" "home/evan/Desktop/" == ["home","evan","Desktop", ""]
118
118
119Use `Regex.split` if you need something more flexible.
119Use `Regex.split` if you need something more flexible.
120-}
120-}
@@ -139,13 +139,13 @@ repeat = Native.String.repeat
139{-| Take a substring given a start and end index. Negative indexes
139{-| Take a substring given a start and end index. Negative indexes
140are taken starting from the *end* of the list.
140are taken starting from the *end* of the list.
141
141
142− sub 7 9 "snakes on a plane!" == "on"
142+ slice 7 9 "snakes on a plane!" == "on"
143− sub 0 6 "snakes on a plane!" == "snakes"
143+ slice 0 6 "snakes on a plane!" == "snakes"
144− sub 0 -7 "snakes on a plane!" == "snakes on a"
144+ slice 0 -7 "snakes on a plane!" == "snakes on a"
145− sub -6 -1 "snakes on a plane!" == "plane"
145+ slice -6 -1 "snakes on a plane!" == "plane"
146-}
146-}
147−sub : Int -> Int -> String -> String
147+slice : Int -> Int -> String -> String
148−sub = Native.String.sub
148+slice = Native.String.slice
149
149
150{-| Take N characters from the left side of a string. -}
150{-| Take N characters from the left side of a string. -}
151left : Int -> String -> String
151left : Int -> String -> String
libraries/elm_dependencies.json+6−5
@@ -1,12 +1,13 @@
1−{ "version": "0.12"
1+{ "version": "0.12.1"
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.12, you should be using version 0.12 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.1, you should be using version 0.12.1 of the standard libraries."
4, "license": "BSD3"
4, "license": "BSD3"
5−, "repository": "http://github.com/evancz/Elm.git"
5+, "repository": "http://github.com/elm-lang/Elm.git"
6−, "elm-version": "0.12"
6+, "elm-version": "0.12.1"
7, "dependencies": {}
7, "dependencies": {}
8, "exposed-modules":
8, "exposed-modules":
9+ [ "Array"
9− [ "Basics"
10+ , "Basics"
10 , "Bitwise"
11 , "Bitwise"
11 , "Char"
12 , "Char"
12 , "Color"
13 , "Color"
runtime/Render/Element.js+8−2
@@ -31,6 +31,7 @@ function setProps(elem, e) {
31 a.style.display = 'block';
31 a.style.display = 'block';
32 a.style.position = 'absolute';
32 a.style.position = 'absolute';
33 e.style.position = 'relative';
33 e.style.position = 'relative';
34+ a.style.pointerEvents = 'auto';
34 e.appendChild(a);
35 e.appendChild(a);
35 }
36 }
36 if (props.hover.ctor !== '_Tuple0') {
37 if (props.hover.ctor !== '_Tuple0') {
@@ -45,8 +46,9 @@ function setProps(elem, e) {
45function addClick(e, handler) {
46function addClick(e, handler) {
46 e.style.pointerEvents = 'auto';
47 e.style.pointerEvents = 'auto';
47 e.elm_click_handler = handler;
48 e.elm_click_handler = handler;
48− function trigger() {
49+ function trigger(ev) {
49 e.elm_click_handler(Utils.Tuple0);
50 e.elm_click_handler(Utils.Tuple0);
51+ ev.stopPropagation();
50 }
52 }
51 e.elm_click_trigger = trigger;
53 e.elm_click_trigger = trigger;
52 e.addEventListener('click', trigger);
54 e.addEventListener('click', trigger);
@@ -63,14 +65,16 @@ function addHover(e, handler) {
63 e.elm_hover_handler = handler;
65 e.elm_hover_handler = handler;
64 e.elm_hover_count = 0;
66 e.elm_hover_count = 0;
65
67
66− function over() {
68+ function over(evt) {
67 if (e.elm_hover_count++ > 0) return;
69 if (e.elm_hover_count++ > 0) return;
68 e.elm_hover_handler(true);
70 e.elm_hover_handler(true);
71+ evt.stopPropagation();
69 }
72 }
70 function out(evt) {
73 function out(evt) {
71 if (e.contains(evt.toElement || evt.relatedTarget)) return;
74 if (e.contains(evt.toElement || evt.relatedTarget)) return;
72 e.elm_hover_count = 0;
75 e.elm_hover_count = 0;
73 e.elm_hover_handler(false);
76 e.elm_hover_handler(false);
77+ evt.stopPropagation();
74 }
78 }
75 e.elm_hover_over = over;
79 e.elm_hover_over = over;
76 e.elm_hover_out = out;
80 e.elm_hover_out = out;
@@ -232,6 +236,7 @@ function rawHtml(elem) {
232 }
236 }
233 document.body.removeChild(div);
237 document.body.removeChild(div);
234 div.style.visibility = 'visible';
238 div.style.visibility = 'visible';
239+ div.style.pointerEvents = 'auto';
235 return div;
240 return div;
236}
241}
237
242
@@ -375,6 +380,7 @@ function updateProps(node, curr, next) {
375 a.style.display = 'block';
380 a.style.display = 'block';
376 a.style.position = 'absolute';
381 a.style.position = 'absolute';
377 e.style.position = 'relative';
382 e.style.position = 'relative';
383+ a.style.pointerEvents = 'auto';
378 e.appendChild(a);
384 e.appendChild(a);
379 } else {
385 } else {
380 node.lastNode.href = props.href;
386 node.lastNode.href = props.href;
server/LICENSEdeleted−30
@@ -1,30 +0,0 @@
1−Copyright (c)2012-2014, Evan Czaplicki
2−
3−All rights reserved.
4−
5−Redistribution and use in source and binary forms, with or without
6−modification, are permitted provided that the following conditions are met:
7−
8− * Redistributions of source code must retain the above copyright
9− notice, this list of conditions and the following disclaimer.
10−
11− * Redistributions in binary form must reproduce the above
12− copyright notice, this list of conditions and the following
13− disclaimer in the documentation and/or other materials provided
14− with the distribution.
15−
16− * Neither the name of Evan Czaplicki nor the names of other
17− contributors may be used to endorse or promote products derived
18− from this software without specific prior written permission.
19−
20−THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21−"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22−LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23−A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24−OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25−SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26−LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27−DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28−THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29−(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30−OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
server/Server.hsdeleted−127
@@ -1,127 +0,0 @@
1−{-# OPTIONS_GHC -Wall #-}
2−{-# LANGUAGE OverloadedStrings, DeriveDataTypeable #-}
3−module Main where
4−
5−import Control.Applicative ((<$>),(<|>))
6−import Control.Monad (guard)
7−import Control.Monad.Trans (MonadIO(liftIO))
8−import qualified Data.ByteString as BS
9−import qualified Data.ByteString.Char8 as BSC
10−import qualified Data.HashMap.Strict as Map
11−import qualified Data.Version as Version
12−import System.Console.CmdArgs
13−import System.Directory
14−import System.Exit
15−import System.FilePath
16−import System.Process
17−import System.IO (hGetContents, Handle)
18−
19−import Paths_elm_server (version)
20−import qualified Elm.Internal.Paths as Elm
21−import Snap.Core
22−import Snap.Http.Server
23−import Snap.Util.FileServe
24−
25−data Flags = Flags
26− { port :: Int
27− , runtime :: Maybe FilePath
28− } deriving (Data,Typeable,Show,Eq)
29−
30−flags :: Flags
31−flags = Flags
32− { port = 8000 &= help "set the port of the server"
33− , runtime = Nothing &= typFile
34− &= help "Specify a custom location for Elm's runtime system."
35− } &= help "Quickly reload Elm projects in your browser. Just refresh to recompile.\n\
36− \It serves static files and freshly recompiled Elm files."
37− &= helpArg [explicit, name "help", name "h"]
38− &= versionArg [ explicit, name "version", name "v"
39− , summary (Version.showVersion version)
40− ]
41− &= summary ("Elm Server " ++ Version.showVersion version ++
42− ", (c) Evan Czaplicki 2011-2014")
43−
44−
45−config :: Config Snap a
46−config = setAccessLog ConfigNoLog (setErrorLog ConfigNoLog defaultConfig)
47−
48−-- | Set up the server.
49−main :: IO ()
50−main = do
51− cargs <- cmdArgs flags
52− putStrLn $ "Elm Server " ++ Version.showVersion version ++
53− ": Just refresh a page to recompile it!"
54− httpServe (setPort (port cargs) config) $
55− serveRuntime (maybe Elm.runtime id (runtime cargs))
56− <|> serveElm
57− <|> serveDirectoryWith directoryConfig "."
58−
59−directoryConfig :: MonadSnap m => DirectoryConfig m
60−directoryConfig =
61− fancyDirectoryConfig
62− { indexGenerator = defaultIndexGenerator defaultMimeTypes indexStyle
63− , mimeTypes = Map.insert ".elm" "text/html" defaultMimeTypes
64− }
65−
66−indexStyle :: BS.ByteString
67−indexStyle =
68− "body { margin:0; font-family:sans-serif; background:rgb(245,245,245);\
69− \ font-family: calibri, verdana, helvetica, arial; }\
70− \div.header { padding: 40px 50px; font-size: 24px; }\
71− \div.content { padding: 0 40px }\
72− \div.footer { display:none; }\
73− \table { width:100%; border-collapse:collapse; }\
74− \td { padding: 6px 10px; }\
75− \tr:nth-child(odd) { background:rgb(216,221,225); }\
76− \td { font-family:monospace }\
77− \th { background:rgb(90,99,120); color:white; text-align:left;\
78− \ padding:10px; font-weight:normal; }"
79−
80−runtimeName :: String
81−runtimeName = "elm-runtime.js"
82−
83−serveRuntime :: FilePath -> Snap ()
84−serveRuntime runtimePath =
85− do file <- BSC.unpack . rqPathInfo <$> getRequest
86− guard (file == runtimeName)
87− serveFileAs "application/javascript" runtimePath
88−
89−serveElm :: Snap ()
90−serveElm =
91− do file <- BSC.unpack . rqPathInfo <$> getRequest
92− exists <- liftIO $ doesFileExist file
93− guard (exists && takeExtension file == ".elm")
94− onSuccess (compile file) (serve file)
95− where
96− compile file =
97− let elmArgs = [ "--make", "--runtime=" ++ runtimeName, file ]
98− in createProcess $ (proc "elm" elmArgs) { std_out = CreatePipe }
99−
100− serve file =
101− serveFileAs "text/html; charset=UTF-8" ("build" </> replaceExtension file "html")
102−
103−failure :: String -> Snap ()
104−failure msg =
105− do modifyResponse $ setResponseStatus 404 "Not found"
106− writeBS $ BSC.pack msg
107−
108−onSuccess :: IO (t, Maybe Handle, t1, ProcessHandle) -> Snap () -> Snap ()
109−onSuccess action success =
110− do (_, stdout, _, handle) <- liftIO action
111− exitCode <- liftIO $ waitForProcess handle
112− case (exitCode, stdout) of
113− (ExitFailure 127, _) ->
114− failure "Error: elm compiler not found in your path."
115−
116− (ExitFailure _, Just out) ->
117− failure =<< liftIO (hGetContents out)
118−
119− (ExitFailure _, Nothing) ->
120− failure "See command line for error message."
121−
122− (ExitSuccess, _) -> success
123−
124−{--
125−pageTitle :: String -> String
126−pageTitle = dropExtension . takeBaseName
127−--}
server/Setup.hsdeleted−2
@@ -1,2 +0,0 @@
1−import Distribution.Simple
2−main = defaultMain
server/elm-server.cabaldeleted−41
@@ -1,41 +0,0 @@
1−Name: elm-server
2−Version: 0.12
3−Synopsis: Server for developing Elm projects
4−Description: Provides a standalone Snap server that serves static files.
5− For Elm files, it recompiles them and serves them as HTML,
6− so you can just refresh to see the new version.
7−
8−Homepage: http://elm-lang.org
9−
10−License: BSD3
11−License-file: LICENSE
12−
13−Author: Evan Czaplicki
14−Maintainer: info@elm-lang.org
15−Copyright: Copyright: (c) 2011-2014 Evan Czaplicki
16−
17−Category: Compiler, Language
18−
19−Build-type: Simple
20−
21−--Extra-source-files: README.md
22−Cabal-version: >=1.8
23−
24−source-repository head
25− type: git
26− location: git://github.com/evancz/Elm.git
27−
28−Executable elm-server
29− Main-is: Server.hs
30− Build-depends: base >=4.2 && <5,
31− bytestring,
32− cmdargs,
33− containers >= 0.3,
34− directory,
35− filepath,
36− Elm >= 0.12,
37− snap-core,
38− snap-server,
39− mtl,
40− process,
41− unordered-containers
tests/elm/Test.elmnew file+37
@@ -0,0 +1,37 @@
1+module Main where
2+
3+import ElmTest.Assertion as A
4+import ElmTest.Run as R
5+import ElmTest.Runner.Console (runDisplay)
6+import ElmTest.Test (..)
7+
8+import IO.IO (..)
9+import IO.Runner (Request, Response)
10+import IO.Runner as Run
11+
12+import Test.Array as Array
13+import Test.Dict as Dict
14+import Test.List as List
15+import Test.Set as Set
16+import Test.String as String
17+import Test.Trampoline as Trampoline
18+
19+tests : Test
20+tests = suite "Elm Standard Library Tests" [ List.tests,
21+ String.tests,
22+ Trampoline.tests,
23+ Array.tests,
24+ Dict.tests,
25+ Set.tests
26+ ]
27+
28+console : IO ()
29+console = runDisplay tests
30+
31+port requests : Signal [{ mPut : Maybe String
32+ , mExit : Maybe Int
33+ , mGet : Bool
34+ }]
35+port requests = Run.run responses console
36+
37+port responses : Signal (Maybe String)
tests/elm/Test/Array.elmnew file+62
@@ -0,0 +1,62 @@
1+module Test.Array (tests) where
2+
3+import List
4+import Array
5+import Native.Array
6+
7+import ElmTest.Assertion (..)
8+import ElmTest.Test (..)
9+
10+tests : Test
11+tests =
12+ let creationTests = suite "Creation"
13+ [ test "empty" <| assertEqual Array.empty (Array.fromList [])
14+ , test "initialize" <| assertEqual (Array.initialize 4 id) (Array.fromList [0,1,2,3])
15+ , test "initialize 2" <| assertEqual (Array.initialize 4 (\n -> n*n)) (Array.fromList [0,1,4,9])
16+ , test "initialize 3" <| assertEqual (Array.initialize 4 (always 0)) (Array.fromList [0,0,0,0])
17+ , test "initialize Empty" <| assertEqual (Array.initialize 0 id) Array.empty
18+ , test "initialize 4" <| assertEqual (Array.initialize 2 (always 0)) (Array.fromList [0,0])
19+ , test "repeat" <| assertEqual (Array.repeat 5 40) (Array.fromList [40,40,40,40,40])
20+ , test "repeat 2" <| assertEqual (Array.repeat 5 0) (Array.fromList [0,0,0,0,0])
21+ , test "repeat 3" <| assertEqual (Array.repeat 3 "cat") (Array.fromList ["cat","cat","cat"])
22+ , test "fromList" <| assertEqual (Array.fromList []) Array.empty
23+ ]
24+ basicsTests = suite "Basics"
25+ [ test "length" <| assertEqual 3 (Array.length (Array.fromList [1,2,3]))
26+ , test "length - Long" <| assertEqual 10000 (Array.length (Array.repeat 10000 0))
27+ , test "push" <| assertEqual (Array.fromList [1,2,3]) (Array.push 3 (Array.fromList [1,2]))
28+ , test "append" <| assertEqual [42,42,81,81,81] (Array.toList (Array.append (Array.repeat 2 42) (Array.repeat 3 81)))
29+ ]
30+ getAndSetTests = suite "Get and Set"
31+ [ test "get" <| assertEqual (Just 2) (Array.get 1 (Array.fromList [3,2,1]))
32+ , test "get 2" <| assertEqual Nothing (Array.get 5 (Array.fromList [3,2,1]))
33+ , test "get 3" <| assertEqual Nothing (Array.get -1 (Array.fromList [3,2,1]))
34+ , test "getOrElse 1" <| assertEqual 1 (Array.getOrElse 0 2 (Array.fromList [3,2,1]))
35+ , test "getOrElse 2" <| assertEqual 0 (Array.getOrElse 0 5 (Array.fromList [3,2,1]))
36+ , test "getOrFail" <| assertEqual 1 (Array.getOrFail 2 (Array.fromList [3,2,1]))
37+ , test "set" <| assertEqual (Array.fromList [1,7,3]) (Array.set 1 7 (Array.fromList [1,2,3]))
38+ ]
39+ takingArraysApartTests = suite "Taking Arrays Apart"
40+ [ test "toList" <| assertEqual [3,5,8] (Array.toList (Array.fromList [3,5,8]))
41+ , test "toIndexedList" <| assertEqual [(0,"cat"), (1,"dog")] (Array.toIndexedList (Array.fromList ["cat","dog"]))
42+ , test "slice 1" <| assertEqual (Array.fromList [0,1,2]) (Array.slice 0 3 (Array.fromList [0,1,2,3,4]))
43+ , test "slice 2" <| assertEqual (Array.fromList [1,2,3]) (Array.slice 1 4 (Array.fromList [0,1,2,3,4]))
44+ , test "slice 3" <| assertEqual (Array.fromList [1,2,3]) (Array.slice 1 -1 (Array.fromList [0,1,2,3,4]))
45+ , test "slice 4" <| assertEqual (Array.fromList [2]) (Array.slice -3 -2 (Array.fromList [0,1,2,3,4]))
46+ ]
47+ mappingAndFoldingTests = suite "Mapping and Folding"
48+ [ test "map" <| assertEqual (Array.fromList [1,2,3]) (Array.map sqrt (Array.fromList [1,4,9]))
49+ , test "indexedMap" <| assertEqual (Array.fromList [0,5,10]) (Array.indexedMap (*) (Array.fromList [5,5,5]))
50+ , test "foldl" <| assertEqual [3,2,1] (Array.foldl (::) [] (Array.fromList [1,2,3]))
51+ , test "foldr 1" <| assertEqual 15 (Array.foldr (+) 0 (Array.repeat 3 5))
52+ , test "foldr 2" <| assertEqual [1,2,3] (Array.foldr (::) [] (Array.fromList [1,2,3]))
53+ , test "filter" <| assertEqual (Array.fromList [2,4,6]) (Array.filter (\x -> x `mod` 2 == 0) (Array.fromList [1..6]))
54+ ]
55+ nativeTests = suite "Conversion to JS Arrays"
56+ [ test "jsArrays" <| assertEqual (Array.fromList [1..1100]) (Native.Array.fromJSArray (Native.Array.toJSArray (Array.fromList [1..1100])))
57+ ]
58+ in
59+ suite "Array"
60+ [ creationTests, basicsTests, getAndSetTests
61+ , takingArraysApartTests, mappingAndFoldingTests, nativeTests
62+ ]
tests/elm/Test/Dict.elmnew file+26
@@ -0,0 +1,26 @@
1+module Test.Dict (tests) where
2+
3+import Dict
4+import List
5+
6+import ElmTest.Assertion (..)
7+import ElmTest.Test (..)
8+
9+animals : Dict.Dict String String
10+animals = Dict.fromList [ ("Tom", "cat"), ("Jerry", "mouse") ]
11+
12+tests : Test
13+tests =
14+ let getTests =
15+ [ test "get 1" <| assertEqual (Just "cat") (Dict.get "Tom" animals)
16+ , test "get 2" <| assertEqual Nothing (Dict.get "Spike" animals)
17+ , test "getOrElse 1" <| assertEqual "mouse" (Dict.getOrElse "dog" "Jerry" animals)
18+ , test "getOrElse 2" <| assertEqual "dog" (Dict.getOrElse "dog" "Spike" animals)
19+ , test "getOrFail" <| assertEqual "cat" (Dict.getOrFail "Tom" animals)
20+ ]
21+ filterTests =
22+ [ test "filter" <| assertEqual (Dict.singleton "Tom" "cat") (Dict.filter (\k v -> k == "Tom") animals)
23+ , test "partition" <| assertEqual (Dict.singleton "Tom" "cat", Dict.singleton "Jerry" "mouse") (Dict.partition (\k v -> k == "Tom") animals)
24+ ]
25+ in
26+ suite "Dict Tests" <| List.concat [ getTests, filterTests ]
tests/elm/Test/List.elmnew file+38
@@ -0,0 +1,38 @@
1+module Test.List (tests) where
2+
3+import List
4+
5+import ElmTest.Assertion (..)
6+import ElmTest.Test (..)
7+
8+tests : Test
9+tests =
10+ let partitionTests =
11+ let p1 = id
12+ p2 x = x < 3
13+ isEven n = n `mod` 2 == 0
14+ in suite "partition Tests" [ test "simple partition" <| assertEqual ([True],[False]) (List.partition p1 [False, True]),
15+ test "order check" <| assertEqual ([2,1], [5,6]) (List.partition p2 [2,5,6,1]),
16+ test "partition doc check 1" <| assertEqual ([0,1,2], [3,4,5]) (partition p2 [0..5]),
17+ test "partition doc check 2" <| assertEqual ([0,2,4], [1,3,5]) (partition isEven [0..5]),
18+ let n = 100000
19+ ts = repeat n True
20+ fs = repeat n False
21+ in test "partition stress test" <| assertEqual (ts, fs) (partition p1 (fs++ts))
22+ ]
23+ unzipTests = suite "unzip Tests" [
24+ test "unzip doc check" <| assertEqual ([0,17,1337],[True,False,True]) (unzip [(0, True), (17, False), (1337, True)]),
25+ let n = 100000
26+ ts = repeat n True
27+ fs = repeat n False
28+ in test "unzip stress test" <| assertEqual (ts, fs) (unzip (zip ts fs))
29+ ]
30+ intersperseTests = suite "intersperse Tests" [
31+ test "intersperse doc check" <| assertEqual ["turtles","on","turtles","on","turtles"] (intersperse "on" ["turtles","turtles","turtles"]),
32+ let n = 100000
33+ ts = repeat n True
34+ fs = repeat n False
35+ in test "intersperse stress test" <| assertEqual (tail . List.concat <| zipWith (\x y -> [x,y]) fs ts)
36+ (intersperse False ts)
37+ ]
38+ in suite "List Tests" [partitionTests, unzipTests, intersperseTests]
tests/elm/Test/Set.elmnew file+27
@@ -0,0 +1,27 @@
1+module Test.Set (tests) where
2+
3+import Set
4+import Set (Set)
5+import List
6+
7+import ElmTest.Assertion (..)
8+import ElmTest.Test (..)
9+
10+set : Set Int
11+set = Set.fromList [1..100]
12+
13+setPart1 : Set Int
14+setPart1 = Set.fromList [1..50]
15+
16+setPart2 : Set Int
17+setPart2 = Set.fromList [51..100]
18+
19+pred : Int -> Bool
20+pred x = x <= 50
21+
22+tests : Test
23+tests =
24+ let
25+ filterTests = suite "filter Tests" [test "Simple filter" <| assertEqual setPart1 <| Set.filter pred set]
26+ partitionTests = suite "partition Tests" [test "Simple partition" <| assertEqual (setPart1, setPart2) <| Set.partition pred set]
27+ in suite "Set Tests" [partitionTests, filterTests]
tests/elm/Test/String.elmnew file+37
@@ -0,0 +1,37 @@
1+module Test.String (tests) where
2+
3+import List
4+import String (..)
5+
6+import ElmTest.Assertion (..)
7+import ElmTest.Test (..)
8+
9+tests : Test
10+tests =
11+ let simpleTests = suite "Simple Stuff"
12+ [ test "is empty" <| assert (isEmpty "")
13+ , test "is not empty" <| assert (not (isEmpty ("the world")))
14+ , test "length" <| assertEqual 11 (length "innumerable")
15+ , test "endsWith" (assert <| endsWith "ship" "spaceship")
16+ , test "reverse" <| assertEqual "desserts" (reverse "stressed")
17+ , test "repeat" <| assertEqual "hahaha" (repeat 3 "ha")
18+ ]
19+
20+ combiningTests = suite "Combining Strings"
21+ [ test "uncons non-empty" <| assertEqual (Just ('a',"bc")) (uncons "abc")
22+ , test "uncons empty" <| assertEqual Nothing (uncons "")
23+ , test "append 1" <| assertEqual "butterfly" (append "butter" "fly")
24+ , test "append 2" <| assertEqual "butter" (append "butter" "")
25+ , test "append 3" <| assertEqual "butter" (append "" "butter")
26+ , test "concat" <| assertEqual "nevertheless" (concat ["never","the","less"])
27+ , test "split commas" <| assertEqual ["cat","dog","cow"] (split "," "cat,dog,cow")
28+ , test "split slashes"<| assertEqual ["home","steve","Desktop", ""] (split "/" "home/steve/Desktop/")
29+ , test "join spaces" <| assertEqual "cat dog cow" (join " " ["cat","dog","cow"])
30+ , test "join slashes" <| assertEqual "home/steve/Desktop" (join "/" ["home","steve","Desktop"])
31+ , test "slice 1" <| assertEqual "c" (slice 2 3 "abcd")
32+ , test "slice 2" <| assertEqual "abc" (slice 0 3 "abcd")
33+ , test "slice 3" <| assertEqual "abc" (slice 0 -1 "abcd")
34+ , test "slice 4" <| assertEqual "cd" (slice -2 4 "abcd")
35+ ]
36+ in
37+ suite "String" [ simpleTests, combiningTests ]
tests/elm/Test/Trampoline.elmnew file+29
@@ -0,0 +1,29 @@
1+module Test.Trampoline (tests) where
2+
3+import Trampoline (..)
4+
5+import ElmTest.Assertion (..)
6+import ElmTest.Test (..)
7+
8+badSum : Int -> Int
9+badSum n =
10+ let loop x acc =
11+ case x of
12+ 0 -> acc
13+ _ -> loop (x-1) (acc+x)
14+ in loop n 0
15+
16+goodSum : Int -> Int
17+goodSum n =
18+ let sumT x acc =
19+ case x of
20+ 0 -> Done acc
21+ _ -> Continue (\_ -> sumT (x-1) (acc+x))
22+ in trampoline <| sumT n 0
23+
24+tests : Test
25+tests =
26+ let mkLoopCheck n = test ("Equivalent Loop Check #"++ show n) (assertEqual (badSum n) (goodSum n))
27+ loopChecks = suite "Equivalent to untrampolined Tests" <| map mkLoopCheck [0..25]
28+ noStackOverflow = test "Trampoline Deep Recursion Test" (assertEqual 500000500000 (goodSum 1000000))
29+ in suite "Trampoline Tests" [noStackOverflow, loopChecks]
tests/Main.hs → tests/hs/CompilerTest.hsrenamed

The content is the same.

tests/hs/LibTest.hsnew file+30
@@ -0,0 +1,30 @@
1+module Main where
2+
3+import Control.Monad (unless)
4+import Data.List (isInfixOf)
5+import System.Directory
6+import System.Exit
7+import System.FilePath
8+import System.Process
9+
10+import Elm.Internal.Paths as Elm
11+
12+main :: IO ()
13+main = do
14+ top <- getCurrentDirectory
15+ let ioScript s = top</>"IO"</>s
16+ runCmd "git submodule update --init"
17+ out <- readProcess "npm" ["ls", "--parseable"] ""
18+ unless ("jsdom" `isInfixOf` out) $ runCmd "npm install jsdom"
19+ setCurrentDirectory $ top</>"tests"</>"elm"
20+ runCmd $ concat [top</>"dist"</>"build"</>"elm"</>"elm --make --only-js --src-dir=" , top</>"automaton", " --src-dir=", top</>"IO", " --src-dir=", top</>"Elm-Test", " Test.elm"]
21+ runCmd $ unwords ["cat ", ioScript "prescript.js", Elm.runtime, "build"</>"Test.js", ioScript "handler.js", "> exe.js"]
22+ exitWith =<< waitForProcess =<< (runCommand "node exe.js")
23+ where runCmd cmd = do
24+ putStrLn cmd
25+ exitCode <- waitForProcess =<< runCommand cmd
26+ case exitCode of
27+ ExitSuccess -> return ()
28+ ExitFailure _ -> error "something went wrong"
29+
30+
tests/Tests/Compiler.hs → tests/hs/Tests/Compiler.hsrenamed

The content is the same.

tests/Tests/Property.hs → tests/hs/Tests/Property.hsrenamed

The content is the same.

tests/Tests/Property/Arbitrary.hs → tests/hs/Tests/Property/Arbitrary.hsrenamed

The content is the same.

tests/test-files/bad/BBTArgs → tests/hs/test-files/bad/BBTArgsrenamed

The content is the same.

tests/test-files/bad/InfiniteType.elm → tests/hs/test-files/bad/InfiniteType.elmrenamed

The content is the same.

tests/test-files/bad/NonElementMain.elm → tests/hs/test-files/bad/NonElementMain.elmrenamed

The content is the same.

tests/test-files/bad/Strings/ExtraClose.elm → tests/hs/test-files/bad/Strings/ExtraClose.elmrenamed

The content is the same.

tests/test-files/good/AliasSubstitution.elm → tests/hs/test-files/good/AliasSubstitution.elmrenamed

The content is the same.

tests/test-files/good/NoExpressions.elm → tests/hs/test-files/good/NoExpressions.elmrenamed

The content is the same.

tests/test-files/good/Otherwise.elm → tests/hs/test-files/good/Otherwise.elmrenamed

The content is the same.

tests/test-files/good/Ports.elm → tests/hs/test-files/good/Ports.elmrenamed

The content is the same.

tests/test-files/good/QuotesAndComments.elm → tests/hs/test-files/good/QuotesAndComments.elmrenamed

The content is the same.

tests/test-files/good/Soundness/Apply.elm → tests/hs/test-files/good/Soundness/Apply.elmrenamed

The content is the same.

tests/test-files/good/Soundness/ApplyAnnotated.elm → tests/hs/test-files/good/Soundness/ApplyAnnotated.elmrenamed

The content is the same.

tests/test-files/good/Soundness/Id.elm → tests/hs/test-files/good/Soundness/Id.elmrenamed

The content is the same.

tests/test-files/good/Soundness/IdAnnotated.elm → tests/hs/test-files/good/Soundness/IdAnnotated.elmrenamed

The content is the same.

tests/test-files/good/Soundness/TrickyId.elm → tests/hs/test-files/good/Soundness/TrickyId.elmrenamed

The content is the same.

tests/test-files/good/Soundness/TrickyIdAnnotated.elm → tests/hs/test-files/good/Soundness/TrickyIdAnnotated.elmrenamed

The content is the same.

tests/test-files/good/Strings/Multiline.elm → tests/hs/test-files/good/Strings/Multiline.elmrenamed

The content is the same.

tests/test-files/good/Strings/MultilineNormal.elm → tests/hs/test-files/good/Strings/MultilineNormal.elmrenamed

The content is the same.

tests/test-files/good/Unify/LockedVars.elm → tests/hs/test-files/good/Unify/LockedVars.elmrenamed

The content is the same.

tests/test-files/good/Unify/NonHomogeneousRecords.elm → tests/hs/test-files/good/Unify/NonHomogeneousRecords.elmrenamed

The content is the same.