on master help sign in
Merge branch 'master' into stable
8060970Evan Czaplicki
.gitignore+4
@@ -11,3 +11,7 @@ data
11*/ElmFiles/*
11*/ElmFiles/*
12.DS_Store
12.DS_Store
13*~
13*~
14+tests/elm/build/
15+tests/elm/cache/
16+tests/elm/exe.js
17+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+26−16
@@ -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
@@ -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,
@@ -177,8 +178,9 @@ Executable elm
177 Paths_Elm
178 Paths_Elm
178
179
179 Build-depends: aeson,
180 Build-depends: aeson,
181+ aeson-pretty,
180 base >=4.2 && <5,
182 base >=4.2 && <5,
181− binary >= 0.6.4.0,
183+ binary >= 0.7.0.0,
182 blaze-html >= 0.5 && < 0.8,
184 blaze-html >= 0.5 && < 0.8,
183 blaze-markup,
185 blaze-markup,
184 bytestring,
186 bytestring,
@@ -222,7 +224,7 @@ Executable elm-doc
222 Build-depends: aeson,
224 Build-depends: aeson,
223 aeson-pretty,
225 aeson-pretty,
224 base >=4.2 && <5,
226 base >=4.2 && <5,
225− binary >= 0.6.4.0,
227+ binary >= 0.7.0.0,
226 bytestring,
228 bytestring,
227 cmdargs,
229 cmdargs,
228 containers >= 0.3,
230 containers >= 0.3,
@@ -236,35 +238,33 @@ Executable elm-doc
236 text,
238 text,
237 union-find
239 union-find
238
240
239−Test-Suite test-elm
241+Test-Suite compiler-tests
240 Type: exitcode-stdio-1.0
242 Type: exitcode-stdio-1.0
241− Hs-Source-Dirs: tests, compiler
243+ Hs-Source-Dirs: tests/hs, compiler
242− Main-is: Main.hs
244+ Main-is: CompilerTest.hs
243 other-modules: Tests.Compiler
245 other-modules: Tests.Compiler
244 Tests.Property
246 Tests.Property
245 Tests.Property.Arbitrary
247 Tests.Property.Arbitrary
246 SourceSyntax.Helpers
248 SourceSyntax.Helpers
247 SourceSyntax.Literal
249 SourceSyntax.Literal
248 SourceSyntax.PrettyPrint
250 SourceSyntax.PrettyPrint
249− build-depends: base,
250− directory,
251− Elm,
252− test-framework,
251+ build-depends: test-framework,
253 test-framework-hunit,
252 test-framework-hunit,
254 test-framework-quickcheck2 >= 0.3,
253 test-framework-quickcheck2 >= 0.3,
255 HUnit,
254 HUnit,
256− pretty,
257 QuickCheck >= 2 && < 3,
255 QuickCheck >= 2 && < 3,
258− filemanip,
259 aeson,
256 aeson,
257+ aeson-pretty,
260 base >=4.2 && <5,
258 base >=4.2 && <5,
261− binary >= 0.6.4.0,
259+ binary >= 0.7.0.0,
262− blaze-html == 0.5.* || == 0.6.*,
260+ blaze-html,
263− blaze-markup == 0.5.1.*,
261+ blaze-markup,
264 bytestring,
262 bytestring,
265 cmdargs,
263 cmdargs,
266 containers >= 0.3,
264 containers >= 0.3,
267 directory,
265 directory,
266+ Elm,
267+ filemanip,
268 filepath,
268 filepath,
269 indents,
269 indents,
270 language-ecmascript >=0.15 && < 1.0,
270 language-ecmascript >=0.15 && < 1.0,
@@ -276,3 +276,13 @@ Test-Suite test-elm
276 transformers >= 0.2,
276 transformers >= 0.2,
277 union-find,
277 union-find,
278 unordered-containers
278 unordered-containers
279+
280+Test-Suite lib-tests
281+ Type: exitcode-stdio-1.0
282+ Hs-Source-Dirs: tests/hs
283+ Main-is: LibTest.hs
284+ build-depends: base,
285+ directory,
286+ Elm,
287+ filepath,
288+ process
IOnew file+1

Submodule changed.

README.md+12−47
@@ -1,58 +1,23 @@
1Learn about the Elm programming language at [elm-lang.org](http://elm-lang.org/).
1Learn about the Elm programming language at [elm-lang.org](http://elm-lang.org/).
2
2
3−[![Build Status](https://travis-ci.org/evancz/Elm.png)](https://travis-ci.org/evancz/Elm)
3+[![Build Status](https://travis-ci.org/elm-lang/Elm.png)](https://travis-ci.org/elm-lang/Elm)
4
4
5## Install
5## Install
6
6
7−**Arch Linux** &mdash; follow [these directions](https://github.com/evancz/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/evancz/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+15
@@ -1,4 +1,19 @@
1
1
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)
10+
11+#### Breaking Changes:
12+
13+ * Revamp Json library, simpler with better names
14+ * Revamp JavaScript.Experimental library to have slightly better names
15+ * Remove JavaScript library which was made redundant by ports
16+
2## 0.12
17## 0.12
3
18
4#### 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+1−2
@@ -39,7 +39,6 @@ internalImports name =
39 , include "_U" "_N.Utils"
39 , include "_U" "_N.Utils"
40 , include "_L" "_N.List"
40 , include "_L" "_N.List"
41 , include "_E" "_N.Error"
41 , include "_E" "_N.Error"
42− , include "_J" "_N.JavaScript"
43 , varDecl "$moduleName" (string name)
42 , varDecl "$moduleName" (string name)
44 ]
43 ]
45
44
@@ -164,7 +163,7 @@ expression (A region expr) =
164
163
165 ExplicitList es ->
164 ExplicitList es ->
166 do es' <- mapM expression es
165 do es' <- mapM expression es
167− return $ obj "_J.toList" <| ArrayLit () es'
166+ return $ obj "_L.fromArray" <| ArrayLit () es'
168
167
169 Data name es ->
168 Data name es ->
170 do es' <- mapM expression es
169 do es' <- mapM expression es
compiler/Generate/JavaScript/Ports.hs+15−16
@@ -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 ()
@@ -35,17 +35,17 @@ inc tipe x =
35 case tipe of
35 case tipe of
36 Lambda _ _ -> error "functions should not be allowed through input ports"
36 Lambda _ _ -> error "functions should not be allowed through input ports"
37 Var _ -> error "type variables should not be allowed through input ports"
37 Var _ -> error "type variables should not be allowed through input ports"
38+
39+ Data "Json.Value" [] ->
40+ obj "Native.Json.fromJS" <| x
41+
38 Data ctor []
42 Data ctor []
39− | ctor == "Int" -> elm JSNumber
43+ | ctor == "Int" -> from JSNumber
40− | ctor == "Float" -> elm JSNumber
44+ | ctor == "Float" -> from JSNumber
41− | ctor == "Bool" -> elm JSBoolean
45+ | ctor == "Bool" -> from JSBoolean
42− | ctor == "String" -> elm JSString
46+ | ctor == "String" -> from JSString
43− | ctor == "JavaScript.JSNumber" -> js JSNumber
44− | ctor == "JavaScript.JSBool" -> js JSBoolean
45− | ctor == "JavaScript.JSString" -> js JSString
46 where
47 where
47− elm checks = check x checks (obj ("_J.to" ++ ctor) <| x)
48− js checks = check x checks x
48+ from checks = check x checks x
49
49
50 Data ctor [t]
50 Data ctor [t]
51 | ctor == "Maybe.Maybe" ->
51 | ctor == "Maybe.Maybe" ->
@@ -54,7 +54,7 @@ inc tipe x =
54 (obj "Maybe.Just" <| inc t x)
54 (obj "Maybe.Just" <| inc t x)
55
55
56 | ctor == "_List" ->
56 | ctor == "_List" ->
57− check x JSArray (obj "_J.toList" <| array)
57+ check x JSArray (obj "_L.fromArray" <| array)
58 where
58 where
59 array = DotRef () x (var "map") <| incoming t
59 array = DotRef () x (var "map") <| incoming t
60
60
@@ -104,10 +104,9 @@ out tipe x =
104
104
105 Var _ -> error "type variables should not be allowed through input ports"
105 Var _ -> error "type variables should not be allowed through input ports"
106 Data ctor []
106 Data ctor []
107− | ctor `elem` ["Int","Float","Bool","String"] -> obj ("_J.from" ++ ctor) <| x
107+ | ctor `elem` ["Int","Float","Bool","String"] -> x
108− | ctor `elem` jsPrims -> x
108+ | ctor == "Json.Value" ->
109− where
109+ obj "Native.Json.toJS" <| x
110− jsPrims = map ("JavaScript.JS"++) ["Number","Bool","String"]
111
110
112 Data ctor [t]
111 Data ctor [t]
113 | ctor == "Maybe.Maybe" ->
112 | ctor == "Maybe.Maybe" ->
@@ -116,7 +115,7 @@ out tipe x =
116 (out t (DotRef () x (var "_0")))
115 (out t (DotRef () x (var "_0")))
117
116
118 | ctor == "_List" ->
117 | ctor == "_List" ->
119− DotRef () (obj "_J.fromList" <| x) (var "map") <| outgoing t
118+ DotRef () (obj "_L.toArray" <| x) (var "map") <| outgoing t
120
119
121 Data ctor ts
120 Data ctor ts
122 | Help.isTuple ctor ->
121 | Help.isTuple ctor ->
compiler/Metadata/Prelude.hs+3−1
@@ -25,7 +25,9 @@ prelude = string ++ text ++ map (\n -> (n, Hiding [])) modules
25 text = map ((,) "Text") [ As "Text", Hiding ["link", "color", "height"] ]
25 text = map ((,) "Text") [ As "Text", Hiding ["link", "color", "height"] ]
26 string = map ((,) "String") [ As "String", Importing ["show"] ]
26 string = map ((,) "String") [ As "String", Importing ["show"] ]
27 modules = [ "Basics", "Signal", "List", "Maybe", "Time", "Color"
27 modules = [ "Basics", "Signal", "List", "Maybe", "Time", "Color"
28− , "Graphics.Element", "Graphics.Collage", "Native.Ports" ]
28+ , "Graphics.Element", "Graphics.Collage"
29+ , "Native.Ports", "Native.Json"
30+ ]
29
31
30interfaces :: Bool -> IO Interfaces
32interfaces :: Bool -> IO Interfaces
31interfaces noPrelude =
33interfaces noPrelude =
compiler/Parse/Helpers.hs+5−3
@@ -79,9 +79,11 @@ innerVarChar :: IParser Char
79innerVarChar = alphaNum <|> char '_' <|> char '\'' <?> ""
79innerVarChar = alphaNum <|> char '_' <|> char '\'' <?> ""
80
80
81makeVar :: IParser Char -> IParser String
81makeVar :: IParser Char -> IParser String
82+makeVar p = do
82−makeVar p = do v <- (:) <$> p <*> many innerVarChar
83+ v <- (:) <$> p <*> many innerVarChar
83− guard (v `notElem` reserveds)
84+ if v `elem` reserveds
85+ then fail $ "unexpected keyword '" ++ v ++ "', variables cannot be keywords"
84− return v
86+ else return v
85
87
86reserved :: String -> IParser String
88reserved :: String -> IParser String
87reserved word =
89reserved word =
compiler/Type/ExtraChecks.hs+10−14
@@ -8,7 +8,6 @@ module Type.ExtraChecks (mainType, occurs, portTypes) where
8
8
9import Control.Applicative ((<$>),(<*>))
9import Control.Applicative ((<$>),(<*>))
10import Control.Monad.State
10import Control.Monad.State
11−import qualified Data.List as List
12import qualified Data.Map as Map
11import qualified Data.Map as Map
13import qualified Data.Traversable as Traverse
12import qualified Data.Traversable as Traverse
14import qualified Data.UnionFind.IO as UF
13import qualified Data.UnionFind.IO as UF
@@ -56,9 +55,15 @@ portTypes rules expr =
56 isValid isTopLevel seenFunc seenSignal direction name tipe =
55 isValid isTopLevel seenFunc seenSignal direction name tipe =
57 case tipe of
56 case tipe of
58 ST.Data ctor ts
57 ST.Data ctor ts
59− | isJs ctor || isElm ctor -> mapM_ valid ts
58+ | validConstructor -> mapM_ valid ts
60 | ctor == "Signal.Signal" -> handleSignal ts
59 | ctor == "Signal.Signal" -> handleSignal ts
61 | otherwise -> err' True "an unsupported type"
60 | otherwise -> err' True "an unsupported type"
61+ where
62+ primitives =
63+ ["Int","Float","String","Bool","Maybe.Maybe","_List","Json.Value"]
64+
65+ validConstructor =
66+ ctor `elem` primitives || Help.isTuple ctor
62
67
63 ST.Var _ -> err "free type variables"
68 ST.Var _ -> err "free type variables"
64
69
@@ -80,14 +85,6 @@ portTypes rules expr =
80 isValid' = isValid False
85 isValid' = isValid False
81 valid = isValid' seenFunc seenSignal direction name
86 valid = isValid' seenFunc seenSignal direction name
82
87
83− isJs ctor =
84− List.isPrefixOf "JavaScript." ctor
85− && length (filter (=='.') ctor) == 1
86−
87− isElm ctor =
88− ctor `elem` ["Int","Float","String","Bool","Maybe.Maybe","_List"]
89− || Help.isTuple ctor
90−
91 handleSignal ts
88 handleSignal ts
92 | seenFunc = err "functions that involve signals"
89 | seenFunc = err "functions that involve signals"
93 | seenSignal = err "signals-of-signals"
90 | seenSignal = err "signals-of-signals"
@@ -104,10 +101,9 @@ portTypes rules expr =
104 , " through port '", name, "' is invalid." ]
101 , " through port '", name, "' is invalid." ]
105 , txt [ "It contains ", kind, ":\n" ]
102 , txt [ "It contains ", kind, ":\n" ]
106 , (P.nest 4 . SPP.pretty $ Alias.realias rules tipe) <> P.text "\n"
103 , (P.nest 4 . SPP.pretty $ Alias.realias rules tipe) <> P.text "\n"
107− , txt [ "Acceptable values for ", dir "incoming" "outgoing"
104+ , txt [ "Acceptable values for ", dir "incoming" "outgoing", " ports include:" ]
108− , " ports include JavaScript values and" ]
109− , txt [ "the following Elm values: Ints, Floats, Bools, Strings, Maybes," ]
105+ , txt [ " Ints, Floats, Bools, Strings, Maybes, Lists, Tuples," ]
110− , txt [ "Lists, Tuples, ", dir "" "first-order functions, ", "and concrete records." ]
106+ , txt [ " Json.Values, ", dir "" "first-order functions, ", "and concrete records." ]
111 ] ++ if couldBeAlias then aliasWarning else []
107 ] ++ if couldBeAlias then aliasWarning else []
112
108
113 aliasWarning =
109 aliasWarning =
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.elmnew file+189
@@ -0,0 +1,189 @@
1+module Array where
2+
3+{-| A library for fast immutable arrays. The elements in an array must have the
4+same type. The arrays are implemented in Relaxed Radix Balanced-Trees for fast
5+reads, updates, and appends.
6+
7+# Creating Arrays
8+@docs empty, repeat, initialize, fromList
9+
10+# Basics
11+@docs length, push, append
12+
13+# Get and Set
14+@docs get, getOrElse, getOrFail, set
15+
16+# Taking Arrays Apart
17+@docs toList, toIndexedList, slice
18+
19+# Mapping and Folding
20+@docs map, indexedMap, foldl, foldr
21+-}
22+
23+import Native.Array
24+import Basics (..)
25+import Maybe (..)
26+import List
27+
28+data Array a = Array
29+
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)`.
32+
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]
36+-}
37+initialize : Int -> (Int -> a) -> Array a
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)
49+
50+{-| Create an array from a list. -}
51+fromList : [a] -> Array a
52+fromList = Native.Array.fromList
53+
54+{-| Create a list of elements from an array.
55+
56+ toList (fromList [3,5,8]) == [3,5,8]
57+-}
58+toList : Array a -> [a]
59+toList = Native.Array.toList
60+
61+-- TODO: make this a native function.
62+{-| Create an indexed list from an array. Each element of the array will be
63+paired with its index.
64+
65+ toIndexedList (fromList ["cat","dog"]) == [(0,"cat"), (1,"dog")]
66+-}
67+toIndexedList : Array a -> [(Int, a)]
68+toIndexedList array =
69+ List.zip [ 0 .. Native.Array.length array - 1 ] (Native.Array.toList array)
70+
71+{-| Apply a function on every element in an array.
72+
73+ map sqrt (fromList [1,4,9]) == fromList [1,2,3]
74+-}
75+map : (a -> b) -> Array a -> Array b
76+map = Native.Array.map
77+
78+{-| Apply a function on every element with its index as first argument.
79+
80+ indexedMap (*) (fromList [5,5,5]) == fromList [0,5,10]
81+-}
82+indexedMap : (Int -> a -> b) -> Array a -> Array b
83+indexedMap = Native.Array.indexedMap
84+
85+{-| Reduce an array from the left. Read `foldl` as &ldquo;fold from the left&rdquo;.
86+
87+ foldl (::) [] (fromList [1,2,3]) == [3,2,1]
88+-}
89+foldl : (a -> b -> b) -> b -> Array a -> b
90+foldl = Native.Array.foldl
91+
92+{-| Reduce an array from the right. Read `foldr` as &ldquo;fold from the right&rdquo;.
93+
94+ foldr (+) 0 (repeat 3 5) == 15
95+-}
96+foldr : (a -> b -> b) -> b -> Array a -> b
97+foldr = Native.Array.foldr
98+
99+{-| Keep only elements that satisfy the predicate:
100+
101+ filter isEven (fromList [1..6]) == (fromList [2,4,6])
102+-}
103+filter : (a -> Bool) -> Array a -> Array a
104+filter isOkay arr =
105+ let update x xs = if isOkay x then Native.Array.push x xs else xs
106+ in
107+ Native.Array.foldl update Native.Array.empty arr
108+
109+{-| Return an empty array.
110+
111+ length empty == 0
112+-}
113+empty : Array a
114+empty = Native.Array.empty
115+
116+{-| Push an element to the end of an array.
117+
118+ push 3 (fromList [1,2]) == fromList [1,2,3]
119+-}
120+push : a -> Array a -> Array a
121+push = Native.Array.push
122+
123+{-| Get the element at a particular index.
124+
125+ getOrFail 2 (A.fromList [3,2,1]) == 1
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.
130+-}
131+getOrFail : Int -> Array a -> a
132+getOrFail = Native.Array.get
133+
134+{-| Return Just the element at the index or Nothing if the index is out of range.
135+
136+ get 2 (fromList [3,2,1]) == Just 2
137+ get 5 (fromList [3,2,1]) == Nothing
138+ get -1 (fromList [3,2,1]) == Nothing
139+-}
140+get : Int -> Array a -> Maybe a
141+get i array =
142+ if 0 <= i && i < Native.Array.length array
143+ then Just (Native.Array.get i array)
144+ else Nothing
145+
146+{-| Get the element at the index. Or if the index is out of range, a default
147+value is returned.
148+
149+ getOrElse 0 2 (fromList [3,2,1]) == 1
150+ getOrElse 0 5 (fromList [3,2,1]) == 0
151+-}
152+getOrElse : a -> Int -> Array a -> a
153+getOrElse default i array =
154+ if 0 <= i && i < Native.Array.length array
155+ then Native.Array.get i array
156+ else default
157+
158+{-| Set the element at a particular index. Returns an updated array.
159+If the index is out of range, the array is unaltered.
160+
161+ set 1 7 (fromList [1,2,3]) == fromList [1,7,3]
162+-}
163+set : Int -> a -> Array a -> Array a
164+set = Native.Array.set
165+
166+{-| Slice an array given a range. The selection is inclusive, so the last
167+element in the selection will also be in the new array. This may change in the
168+future. You can select from the end by giving a negative Int.
169+
170+ slice 1 2 (fromList [0,1,2,3,4]) == fromList [1,2]
171+ slice 1 -2 (fromList [0,1,2,3,4]) == fromList [1,2,3]
172+ slice -3 -2 (fromList [0,1,2,3,4]) == fromList [2,3]
173+-}
174+slice : Int -> Int -> Array a -> Array a
175+slice = Native.Array.slice
176+
177+{-| Return the length of an array.
178+
179+ length (fromList [1,2,3]) == 3
180+-}
181+length : Array a -> Int
182+length = Native.Array.length
183+
184+{-| Append two arrays to a new one.
185+
186+ append (array 2 42) (array 3 81) == fromList [42,42,81,81,81]
187+-}
188+append : Array a -> Array a -> Array a
189+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/Collage.elm−1
@@ -38,7 +38,6 @@ import Native.Graphics.Collage
38import Graphics.Element (Element)
38import Graphics.Element (Element)
39import Color (Color, black, Gradient)
39import Color (Color, black, Gradient)
40import Maybe (Maybe)
40import Maybe (Maybe)
41−import JavaScript (JSString)
42
41
43type Form = {
42type Form = {
44 theta : Float,
43 theta : Float,
libraries/Graphics/Element.elm+10−13
@@ -39,8 +39,6 @@ If you need more precision, you can create custom positions.
39
39
40import Basics (..)
40import Basics (..)
41import Native.Utils
41import Native.Utils
42−import JavaScript as JS
43−import JavaScript (JSString)
44import List as List
42import List as List
45import Color (..)
43import Color (..)
46import Maybe (Maybe, Just, Nothing)
44import Maybe (Maybe, Just, Nothing)
@@ -51,8 +49,8 @@ type Properties = {
51 height : Int,
49 height : Int,
52 opacity : Float,
50 opacity : Float,
53 color : Maybe Color,
51 color : Maybe Color,
54− href : JSString,
52+ href : String,
55− tag : JSString,
53+ tag : String,
56 hover : (),
54 hover : (),
57 click : ()
55 click : ()
58 }
56 }
@@ -120,21 +118,20 @@ with a link like this: `/facts-about-animals.elm#all-about-badgers`
120-}
118-}
121tag : String -> Element -> Element
119tag : String -> Element -> Element
122tag name e = let p = e.props in
120tag name e = let p = e.props in
123− { element=e.element, props={p | tag <- JS.fromString name} }
121+ { element=e.element, props={p | tag <- name} }
124
122
125{-| Create an `Element` that is a hyper-link. -}
123{-| Create an `Element` that is a hyper-link. -}
126link : String -> Element -> Element
124link : String -> Element -> Element
127link href e = let p = e.props in
125link href e = let p = e.props in
128− { element=e.element, props={p | href <- JS.fromString href} }
126+ { element=e.element, props={p | href <- href} }
129
127
130−emptyStr = JS.fromString ""
131newElement w h e =
128newElement w h e =
132− { props = Properties (Native.Utils.guid ()) w h 1 Nothing emptyStr emptyStr () ()
129+ { props = Properties (Native.Utils.guid ()) w h 1 Nothing "" "" () ()
133 , element = e
130 , element = e
134 }
131 }
135
132
136data ElementPrim
133data ElementPrim
137− = Image ImageStyle Int Int JSString
134+ = Image ImageStyle Int Int String
138 | Container Position Element
135 | Container Position Element
139 | Flow Direction [Element]
136 | Flow Direction [Element]
140 | Spacer
137 | Spacer
@@ -145,13 +142,13 @@ data ImageStyle = Plain | Fitted | Cropped (Int,Int) | Tiled
145
142
146{-| Create an image given a width, height, and image source. -}
143{-| Create an image given a width, height, and image source. -}
147image : Int -> Int -> String -> Element
144image : Int -> Int -> String -> Element
148−image w h src = newElement w h (Image Plain w h (JS.fromString src))
145+image w h src = newElement w h (Image Plain w h src)
149
146
150{-| Create a fitted image given a width, height, and image source.
147{-| Create a fitted image given a width, height, and image source.
151This will crop the picture to best fill the given dimensions.
148This will crop the picture to best fill the given dimensions.
152-}
149-}
153fittedImage : Int -> Int -> String -> Element
150fittedImage : Int -> Int -> String -> Element
154−fittedImage w h src = newElement w h (Image Fitted w h (JS.fromString src))
151+fittedImage w h src = newElement w h (Image Fitted w h src)
155
152
156{-| Create a cropped image. Take a rectangle out of the picture starting
153{-| Create a cropped image. Take a rectangle out of the picture starting
157at the given top left coordinate. If you have a 140-by-140 image,
154at the given top left coordinate. If you have a 140-by-140 image,
@@ -161,11 +158,11 @@ the following will cut a 100-by-100 square out of the middle of it.
161-}
158-}
162croppedImage : (Int,Int) -> Int -> Int -> String -> Element
159croppedImage : (Int,Int) -> Int -> Int -> String -> Element
163croppedImage pos w h src =
160croppedImage pos w h src =
164− newElement w h (Image (Cropped pos) w h (JS.fromString src))
161+ newElement w h (Image (Cropped pos) w h src)
165
162
166tiledImage : Int -> Int -> String -> Element
163tiledImage : Int -> Int -> String -> Element
167tiledImage w h src =
164tiledImage w h src =
168− newElement w h (Image Tiled w h (JS.fromString src))
165+ newElement w h (Image Tiled w h src)
169
166
170data Three = P | Z | N
167data Three = P | Z | N
171data Pos = Absolute Int | Relative Float
168data Pos = Absolute Int | Relative Float
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/JavaScript.elmdeleted−74
@@ -1,74 +0,0 @@
1−
2−module JavaScript where
3−
4−{-|This library does basic conversions between Elm and JS values. This allows
5−the internal data structures of Elm to change and improve with no impact on JS
6−integration.
7−
8−It is intended to be imported as `import JavaScript as JS`. That way functions
9−like `JS.toInt` convert JavaScript *to* Elm integers and functions like
10−`JS.fromString` gets JavaScript *from* Elm strings.
11−
12−# Javascript to Elm
13−@docs toString, toInt, toFloat, toBool, toList
14−
15−# JavaScript from Elm
16−@docs fromString, fromInt, fromFloat, fromBool, fromList
17−-}
18−{-
19−# DOM Nodes and Elements
20−@docs toElement, fromElement
21−-}
22−
23−import Native.JavaScript
24−
25−data JSNumber = JSNumber
26−data JSBool = JSBool
27−data JSString = JSString
28−data JSArray a = JSArray a
29−data JSDomNode = JSDomNode
30−data JSObject = JSObject
31−
32−{-| Requires that the input array be uniform (all members have the same type) -}
33−toList : JSArray a -> [a]
34−toList = Native.JavaScript.toList
35−
36−toInt : JSNumber -> Int
37−toInt = Native.JavaScript.toInt
38−
39−toFloat : JSNumber -> Float
40−toFloat = Native.JavaScript.toFloat
41−
42−toBool : JSBool -> Bool
43−toBool = Native.JavaScript.toBool
44−
45−toString : JSString -> String
46−toString = Native.JavaScript.toString
47−
48−
49−{-| Produces a uniform JavaScript array with all members of the same type. -}
50−fromList : [a] -> JSArray a
51−fromList = Native.JavaScript.fromList
52−
53−fromInt : Int -> JSNumber
54−fromInt = Native.JavaScript.fromInt
55−
56−fromFloat : Float -> JSNumber
57−fromFloat = Native.JavaScript.fromFloat
58−
59−fromBool : Bool -> JSBool
60−fromBool = Native.JavaScript.fromBool
61−
62−fromString : String -> JSString
63−fromString = Native.JavaScript.fromString
64−
65−{-
66−{-| Turn an `Element` into a DOM node. -}
67−fromElement : Element -> JSDomNode
68−fromElement = Native.JavaScript.fromElement
69−
70−{-| Turn a DOM node into an `Element`. You can resize the node
71−using the normal `width` and `height` functions. -}
72−toElement : Int -> Int -> JSDomNode -> Element
73−toElement = Native.JavaScript.toElement
74−-}
libraries/JavaScript/Experimental.elm+31−16
@@ -8,34 +8,49 @@ improve as we find its key failings.
8@docs toRecord, fromRecord
8@docs toRecord, fromRecord
9-}
9-}
10
10
11−import JavaScript (JSObject)
12import Native.JavaScript
11import Native.JavaScript
12+import Native.Json
13+import Json
14+
15+data RawObject = RawObject
13
16
14{-| Turn arbitrary JavaScript objects into Elm records.
17{-| Turn arbitrary JavaScript objects into Elm records.
15Arrays are converted into lists, nested objects are allowed.
18Arrays are converted into lists, nested objects are allowed.
16No `null` values or non-homogeneous arrays.
19No `null` values or non-homogeneous arrays.
17
20
18− -- OK objects
21+ -- OK objects
19− { student:"Steve", scores:[83,94,99,72] }
22+ { student:"Steve", scores:[83,94,99,72] }
20− { errorLevel:10, critical:true }
23+ { errorLevel:10, critical:true }
21
24
22− -- BAD objects
25+ -- BAD objects
23− { answer:null }
26+ { answer:null }
24− { info:[true,42,'what'] }
27+ { info:[true,42,'what'] }
25-}
28-}
26−toRecord : JSObject -> a
29+toRecord : RawObject -> a
27toRecord = Native.JavaScript.toRecord
30toRecord = Native.JavaScript.toRecord
28
31
29{-| Turn arbitrary Elm records into JavaScript objects.
32{-| Turn arbitrary Elm records into JavaScript objects.
30Lists become arrays, nested records are allowed. No ADTs.
33Lists become arrays, nested records are allowed. No ADTs.
31
34
32− -- OK records
35+ -- OK records
33− { student="Steve", scores=[83,94,99,72] }
36+ { student="Steve", scores=[83,94,99,72] }
34− { errorLevel=10, critical=True }
37+ { errorLevel=10, critical=True }
38+
39+ -- BAD records
40+ { answer = Nothing }
41+ { result = Left "An error occurred" }
42+-}
43+fromRecord : a -> RawObject
44+fromRecord = Native.JavaScript.fromRecord
45+
46+{-| Turn a raw JavaScript object into a `Json.Value` as described in the
47+`Json` library.
48+-}
49+toJson : RawObject -> Json.Value
50+toJson = Native.Json.fromJS
35
51
36− -- BAD records
52+{-| Turn a `Json.Value` (as described in the `Json` library) into a raw
37− { answer = Nothing }
53+JavaScript object.
38− { result = Left "An error occurred" }
39-}
54-}
40−fromRecord : a -> JSObject
55+fromJson : Json.Value -> RawObject
41−fromRecord = Native.JavaScript.fromRecord
56+fromJson = Native.Json.toJS
libraries/Json.elm+25−110
@@ -3,132 +3,47 @@ module Json where
3
3
4{-| Library for working with [JSON](https://en.wikipedia.org/wiki/JSON) values.
4{-| Library for working with [JSON](https://en.wikipedia.org/wiki/JSON) values.
5
5
6−# Json Values
7−@docs JsonValue
8−
9−# Strings
10−@docs fromString, toString
6+@docs Value, fromString, toString
11−
12−# JS Strings
13−@docs fromJSString, toJSString
14−
15−# JS Objects
16−@docs fromJSObject, toJSObject
17
7
18-}
8-}
19
9
20−import Basics (..)
21import Dict
10import Dict
22import Maybe (Maybe)
11import Maybe (Maybe)
23−import JavaScript as JS
24import Native.Json
12import Native.Json
25−import JavaScript (JSObject, JSString)
26
13
27−{-| This datatype can represent all valid values that can be held in a JSON
14+{-| This datatype can represent all valid JSON values. A `Value` can be sent
28−object. In Elm, a proper JSON object is represented as a (Dict String JsonValue)
15+through ports, and the runtime will do a conversion like this:
29−which is a mapping from strings to Json Values. -}
16+
30−data JsonValue
17+ [2,'abc',null] == Array [Number 2, String "abc", Null]
18+
19+JSON is an intentional subset of JavaScript values which excludes functions.
20+This ensures that impure functions cannot sneak into Elm through ports.
21+-}
22+data Value
31 = String String
23 = String String
32 | Number Float
24 | Number Float
33 | Boolean Bool
25 | Boolean Bool
34 | Null
26 | Null
35− | Array [JsonValue]
27+ | Array [Value]
36− | Object (Dict.Dict String JsonValue)
28+ | Object (Dict.Dict String Value)
37−
38
29
39−-- String Converters
40
30
41−{-| Convert a `JsonValue` into a prettified string.
31+{-| Convert a `Value` into a prettified string.
42The first argument is a separator token (e.g. \" \", \"\\n\", etc.) that will
32The first argument is a separator token (e.g. \" \", \"\\n\", etc.) that will
43−be used for indentation in the prettified string version of the JSON. -}
33+be used for indentation in the prettified string version of the JSON.
44−toString : String -> JsonValue -> String
45−toString sep v = JS.toString (Native.Json.toJSString sep v)
46
34
47−{-| Convert a proper JSON object into a JavaScript string.
35+ toString "" Null == "null"
48−Note that the type JSString seen here is not the same as the type constructor
36+ toString "" (Number 4.0) == "4.0"
49−JsonString used elsewhere in this module. -}
37+-}
50−toJSString : String -> JsonValue -> JSString
38+toString : String -> Value -> String
51−toJSString = Native.Json.toJSString
39+toString sep value = Native.Json.toString sep value
52
40
53{-| Parse a string representation of a proper JSON object into
41{-| Parse a string representation of a proper JSON object into
54−its Elm representation. -}
42+its Elm representation.
55−fromString : String -> Maybe JsonValue
56−fromString s = Native.Json.fromJSString (JS.fromString s)
57−
58−{-| Parse a JavaScript string representation of a proper JSON object into
59−its Elm representation. -}
60−fromJSString : JSString -> Maybe JsonValue
61−fromJSString = Native.Json.fromJSString
62−
63−{-| Convert a JS object into a `JsonValue`. -}
64−fromJSObject : JSObject -> JsonValue
65−fromJSObject = Native.Json.fromJSObject
66
43
67−{-| Convert a `JsonValue` into a `JSObject`. Paired with the
44+ fromString "null" == Just Null
68−[`JavaScript.Experimental` library](/docs/JavaScript/Experimental.elm),
45+ fromString "[true,3]" == Just (Array [Boolean True, Number 3])
69−This lets you convert strings into Elm records:
46+ fromString "{'abc':4}" == Just (Object (Dict.fromList [("abc", Number 4)]))
70−
71− import JavaScript.Experimental as JS
72−
73− stringToRecord str =
74− case fromString str of
75− Just jsonValue -> Just (JS.toRecord (toJSObject jsonValue))
76− Nothing -> Nothing
77-}
47-}
78−toJSObject : JsonValue -> JSObject
48+fromString : String -> Maybe Value
79−toJSObject = Native.Json.toJSObject
49+fromString str = Native.Json.fromString str
80−
81− {-- Extract Elm values from Json values
82−
83− string : JsonValue -> String
84− string v = case v of { String s -> s ; _ -> "" }
85−
86− number : JsonValue -> Float
87− number v = case v of { Number n -> n ; _ -> 0 }
88−
89− boolean : JsonValue -> Bool
90− boolean v = case v of { Boolean b -> b ; _ -> False }
91−
92− array : JsonValue -> [JsonValue]
93− array v = case v of { Array a -> a ; _ -> [] }
94−
95− object : JsonValue -> Dict String JsonValue
96− object v = case v of { Object o -> o ; _ -> Dict.empty }
97−
98−
99− -- Extract Elm values from dictionaries of Json values
100−
101− {-| Find a value in a Json Object using the passed get function. If the key is
102− not found, this returns the given default/base value. -}
103− find get base =
104− let f key dict =
105− case Dict.lookup key dict of
106− Nothing -> base
107− Just v -> get v
108− in f
109−
110− {-| Find a string value in an Elm Json object. If the key is not found or the
111− value found is not a string, this returns the empty string. -}
112− findString : String -> Object -> String
113− findString = find string ""
114−
115− {-| Find a number value in an Elm Json object. If the key is not found or the
116− value found is not a number, this returns 0 -}
117− findNumber : String -> Object -> Float
118− findNumber = find number 0
119−
120− {-| Find a boolean value in an Elm Json object. If the key is not found or the
121− value found is not a boolean, this returns the False. -}
122− findBoolean : String -> Object -> Bool
123− findBoolean = find boolean False
124−
125− {-| Find an array value in an Elm Json object. If the key is not found or the
126− value found is not an array, this returns an empty list. -}
127− findArray : String -> Object -> [JsonValue]
128− findArray = find array []
129−
130− {-| Find an object value in an Elm Json object. If the key is not found or the
131− value found is not an object, this returns an empty object. -}
132− findObject : String -> Object -> Object
133− findObject = find object Dict.empty
134− --}
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.jsnew file+597
@@ -0,0 +1,597 @@
1+Elm.Native.Array = {};
2+Elm.Native.Array.make = function(elm) {
3+ elm.Native = elm.Native || {};
4+ elm.Native.Array = elm.Native.Array || {};
5+ if (elm.Native.Array.values) return elm.Native.Array.values;
6+ if ('values' in Elm.Native.Array)
7+ return elm.Native.Array.values = Elm.Native.Array.values;
8+
9+ var List = Elm.Native.List.make(elm);
10+
11+ // A RRB-Tree has two distinct data types.
12+ // Leaf -> "height" is always 0
13+ // "table" is an array of elements
14+ // Node -> "height" is always greater than 0
15+ // "table" is an array of child nodes
16+ // "lengths" is an array of accumulated lengths of the child nodes
17+
18+ // M is the maximal table size. 32 seems fast. E is the allowed increase
19+ // of search steps when concatting to find an index. Lower values will
20+ // decrease balancing, but will increase search steps.
21+ var M = 32;
22+ var E = 2;
23+
24+ // An empty array.
25+ var empty = { ctor:"_Array", height:0, table:new Array() };
26+
27+ function get(i, array) {
28+ if (i < 0 || i >= length(array)) {
29+ throw new Error("Index " + i + " is out of range. Check the length of " +
30+ "your array first or use getMaybe or getWithDefault.");
31+ }
32+ return unsafeGet(i, array);
33+ }
34+
35+ function unsafeGet(i, array) {
36+ for (var x = array.height; x > 0; x--) {
37+ var slot = i >> (x * 5);
38+ if (slot > 0) {
39+ while (array.lengths[slot - 1] > i) { slot--; }
40+ i -= array.lengths[slot - 1];
41+ }
42+ array = array.table[slot];
43+ }
44+ return array.table[i];
45+ }
46+
47+ // Sets the value at the index i. Only the nodes leading to i will get
48+ // copied and updated.
49+ function set(i, item, array) {
50+ if (i < 0 || length(array) <= i) {
51+ return array;
52+ }
53+ return unsafeSet(i, item, array);
54+ }
55+
56+ function unsafeSet(i, item, array) {
57+ array = nodeCopy(array);
58+
59+ if (array.height == 0) {
60+ array.table[i] = item;
61+ } else {
62+ var slot = getSlot(i, array);
63+ if (slot > 0) {
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() };
164+ }
165+ }
166+
167+ // Pushes an item via push_ to the bottom right of a tree.
168+ function push(item, a) {
169+ var pushed = push_(item, a);
170+ if (pushed !== null) {
171+ return pushed;
172+ }
173+
174+ var newTree = create(item, a.height);
175+ return siblise(a, newTree);
176+ }
177+
178+ // Recursively tries to push an item to the bottom-right most
179+ // tree possible. If there is no space left for the item,
180+ // null will be returned.
181+ function push_(item, a) {
182+ // Handle resursion stop at leaf level.
183+ if (a.height == 0) {
184+ if (a.table.length < M) {
185+ var newA = { ctor:"_Array", height:0, table:a.table.slice() };
186+ newA.table.push(item);
187+ return newA;
188+ } else {
189+ return null;
190+ }
191+ }
192+
193+ // Recursively push
194+ var pushed = push_(item, botRight(a));
195+
196+ // There was space in the bottom right tree, so the slot will
197+ // be updated.
198+ if (pushed != null) {
199+ var newA = nodeCopy(a);
200+ newA.table[newA.table.length - 1] = pushed;
201+ newA.lengths[newA.lengths.length - 1]++;
202+ return newA
203+ }
204+
205+ // When there was no space left, check if there is space left
206+ // for a new slot with a tree which contains only the item
207+ // at the bottom.
208+ if (a.table.length < M) {
209+ var newSlot = create(item, a.height - 1);
210+ var newA = nodeCopy(a);
211+ newA.table.push(newSlot);
212+ newA.lengths.push(newA.lengths[newA.lengths.length - 1] + length(newSlot));
213+ return newA
214+ } else {
215+ return null;
216+ }
217+ }
218+
219+ // Converts an array into a list of elements.
220+ function toList(a) {
221+ return toList_(List.Nil, a);
222+ }
223+
224+ function toList_(list, a) {
225+ for (var i = a.table.length - 1; i >= 0; i--) {
226+ list = a.height == 0 ? List.Cons(a.table[i], list) : toList_(list, a.table[i]);
227+ }
228+ return list;
229+ }
230+
231+ // Maps a function over the elements of an array.
232+ function map(f, a) {
233+ var newA = { ctor:"_Array", height:a.height, table:new Array(a.table) };
234+ if (a.height > 0) { newA.lengths = a.lengths; }
235+ for (var i = 0; i < a.table.length; i++) {
236+ newA.table[i] = a.height == 0 ? f(a.table[i]) : map(f, a.table[i]);
237+ }
238+ return newA;
239+ }
240+
241+ // Maps a function over the elements with their index as first argument.
242+ function indexedMap(f, a) {
243+ var newA = { ctor:"_Array", height:a.height, table:new Array(a.table) };
244+ if (a.height > 0) { newA.lengths = a.lengths; }
245+ for (var i = 0; i < a.table.length; i++) {
246+ newA.table[i] = a.height == 0 ? A2(f, i, a.table[i]) : indexedMap(f, a.table[i]);
247+ }
248+ return newA;
249+ }
250+
251+ function foldl(f, b, a) {
252+ for (var i = 0; i < a.table.length; i++) {
253+ b = A2(f, a.height == 0 ? a.table[i] : foldl(f, b, a.table[i]), b);
254+ }
255+ return b;
256+ }
257+
258+ function foldr(f, b, a) {
259+ for (var i = a.table.length; i--; ) {
260+ b = A2(f, a.height == 0 ? a.table[i] : foldr(f, b, a.table[i]), b);
261+ }
262+ return b;
263+ }
264+
265+ // Returns a sliced tree. "to" is inclusive, but this may change,
266+ // when I understand, why e.g. JS does not handle it this way. :-)
267+ // If "from" or "to" is negative, they will select from the end on.
268+ // TODO: currently, it slices the right, then the left. This can be
269+ // optimized.
270+ function slice(from, to, a) {
271+ if (from < 0) { from += length(a); }
272+ if (to < 0) { to += length(a); }
273+ return sliceLeft(from, sliceRight(to, a));
274+ }
275+
276+ function sliceRight(to, a) {
277+ if (to == length(a)) {
278+ return a;
279+ }
280+
281+ // Handle leaf level.
282+ if (a.height == 0) {
283+ var newA = { ctor:"_Array", height:0 };
284+ newA.table = a.table.slice(0, to + 1);
285+ return newA;
286+ }
287+
288+ // Slice the right recursively.
289+ var right = getSlot(to, a);
290+ var sliced = sliceRight(to - (right > 0 ? a.lengths[right - 1] : 0), a.table[right]);
291+
292+ // Maybe the a node is not even needed, as sliced contains the whole slice.
293+ if (right == 0) {
294+ return sliced;
295+ }
296+
297+ // Create new node.
298+ var newA = { ctor:"_Array", height:a.height
299+ , table:a.table.slice(0, right + 1)
300+ , lengths:a.lengths.slice(0, right + 1) };
301+ newA.table[right] = sliced;
302+ newA.lengths[right] = length(sliced) + (right > 0 ? newA.lengths[right - 1] : 0);
303+ return newA;
304+ }
305+
306+ function sliceLeft(from, a) {
307+ if (from == 0) {
308+ return a;
309+ }
310+
311+ // Handle leaf level.
312+ if (a.height == 0) {
313+ var newA = { ctor:"_Array", height:0 };
314+ newA.table = a.table.slice(from, a.table.length + 1);
315+ return newA;
316+ }
317+
318+ // Slice the left recursively.
319+ var left = getSlot(from, a);
320+ var sliced = sliceLeft(from - (left > 0 ? a.lengths[left - 1] : 0), a.table[left]);
321+
322+ // Maybe the a node is not even needed, as sliced contains the whole slice.
323+ if (left == a.table.length - 1) {
324+ return sliced;
325+ }
326+
327+ // Create new node.
328+ var newA = { ctor:"_Array", height:a.height
329+ , table:a.table.slice(left, a.table.length + 1)
330+ , lengths:new Array(a.table.length - left) };
331+ newA.table[left] = sliced;
332+ var len = 0;
333+ for (var i = 0; i < newA.table.length; i++) {
334+ len += length(newA.table[i]);
335+ newA.lengths[i] = len;
336+ }
337+
338+ return newA;
339+ }
340+
341+ // Appends two trees.
342+ // TODO: Add support for appending trees of different sizes. Current
343+ // behavior will just rise the lower tree and then append them.
344+ function append(a,b) {
345+ if (b.height > a.height) { return append(parentise(a, b.height), b); }
346+ if (a.height > b.height) { return append(a, parentise(b, a.height)); }
347+ if (a.height == 0) { return append(parentise(a, 1), parentise(b, 1)); }
348+
349+ var c = append_(a, b);
350+ if (c[1].table.length > 0) {
351+ return siblise(c[0], c[1]);
352+ } else {
353+ return c[0];
354+ }
355+ }
356+
357+ // Returns an array of two nodes. The second node _may_ be empty. This case
358+ // needs to be handled by the function, that called append_. May be only
359+ // called for trees with an minimal height of 1.
360+ function append_(a, b) {
361+ if (a.height == 1) {
362+ // Check if balancing is needed and return based on that.
363+ var toRemove = calcToRemove(a, b);
364+ if (toRemove <= E) {
365+ return [a,b];
366+ }
367+
368+ return shuffle(a, b, toRemove);
369+ }
370+
371+ var appended = append_(botRight(a), botLeft(b));
372+ a = nodeCopy(a), b = nodeCopy(b);
373+
374+ // Adjust the bottom right side of the new tree.
375+ a.table[a.table.length - 1] = appended[0];
376+ a.lengths[a.lengths.length - 1] = length(appended[0])
377+ a.lengths[a.lengths.length - 1] += a.lengths.length > 1 ? a.lengths[a.lengths.length - 2] : 0;
378+
379+ // Adjust the bottom left side of the new tree.
380+ if (appended[1].table.length > 0) {
381+ b.table[0] = appended[1];
382+ b.lengths[0] = length(appended[1]);
383+ for (var i = 1, len = length(b.table[0]); i < b.lengths.length; i++) {
384+ len += length(b.table[i]);
385+ b.lengths[i] = len;
386+ }
387+ } else {
388+ b.table.shift();
389+ for (var i = 1; i < b.lengths.length; i++) {
390+ b.lengths[i] = b.lengths[i] - b.lengths[0];
391+ }
392+ b.lengths.shift();
393+ }
394+
395+ // Check if balancing is needed and return based on that.
396+ var toRemove = calcToRemove(a, b);
397+ if (toRemove <= E || b.table.length == 0) {
398+ return [a,b];
399+ }
400+
401+ return shuffle(a, b, toRemove);
402+ }
403+
404+ // Returns the extra search steps for E. Refer to the paper.
405+ function calcToRemove(a, b) {
406+ var subLengths = 0;
407+ for (var i = 0; i < a.table.length; i++) {
408+ subLengths += a.table[i].table.length;
409+ }
410+ for (var i = 0; i < b.table.length; i++) {
411+ subLengths += b.table[i].table.length;
412+ }
413+
414+ var toRemove = a.table.length + b.table.length
415+ return toRemove - (Math.floor((subLengths - 1) / M) + 1);
416+ }
417+
418+ // get2, set2 and saveSlot are helpers for accessing elements over two arrays.
419+ function get2(a, b, index) {
420+ return index < a.length ? a[index] : b[index - a.length];
421+ }
422+
423+ function set2(a, b, index, value) {
424+ if (index < a.length) {
425+ a[index] = value;
426+ } else {
427+ b[index - a.length] = value;
428+ }
429+ }
430+
431+ function saveSlot(a, b, index, slot) {
432+ set2(a.table, b.table, index, slot);
433+
434+ var l = (index == 0 || index == a.lengths.length) ?
435+ 0 : get2(a.lengths, a.lengths, index - 1);
436+ set2(a.lengths, b.lengths, index, l + length(slot));
437+ }
438+
439+ // Creates a node or leaf with a given length at their arrays for perfomance.
440+ // Is only used by shuffle.
441+ function createNode(h, length) {
442+ if (length < 0) { length = 0; }
443+ var a = { ctor:"_Array", height:h, table:new Array(length) };
444+ if (h > 0) {
445+ a.lengths = new Array(length);
446+ }
447+ return a;
448+ }
449+
450+ // Returns an array of two balanced nodes.
451+ function shuffle(a, b, toRemove) {
452+ var newA = createNode(a.height, Math.min(M, a.table.length + b.table.length - toRemove));
453+ var newB = createNode(a.height, newA.table.length - (a.table.length + b.table.length - toRemove));
454+
455+ // Skip the slots with size M. More precise: copy the slot references
456+ // to the new node
457+ var read = 0;
458+ while (get2(a.table, b.table, read).table.length % M == 0) {
459+ set2(newA.table, newB.table, read, get2(a.table, b.table, read));
460+ set2(newA.lengths, newB.lengths, read, get2(a.lengths, b.lengths, read));
461+ read++;
462+ }
463+
464+ // Pulling items from left to right, caching in a slot before writing
465+ // it into the new nodes.
466+ var write = read;
467+ var slot = new createNode(a.height - 1, 0);
468+ var from = 0;
469+
470+ // If the current slot is still containing data, then there will be at
471+ // least one more write, so we do not break this loop yet.
472+ while (read - write - (slot.table.length > 0 ? 1 : 0) < toRemove) {
473+ // Find out the max possible items for copying.
474+ var source = get2(a.table, b.table, read);
475+ var to = Math.min(M - slot.table.length, source.table.length)
476+
477+ // Copy and adjust size table.
478+ slot.table = slot.table.concat(source.table.slice(from, to));
479+ if (slot.height > 0) {
480+ var len = slot.lengths.length;
481+ for (var i = len; i < len + to - from; i++) {
482+ slot.lengths[i] = length(slot.table[i]);
483+ slot.lengths[i] += (i > 0 ? slot.lengths[i - 1] : 0);
484+ }
485+ }
486+
487+ from += to;
488+
489+ // Only proceed to next slots[i] if the current one was
490+ // fully copied.
491+ if (source.table.length <= to) {
492+ read++; from = 0;
493+ }
494+
495+ // Only create a new slot if the current one is filled up.
496+ if (slot.table.length == M) {
497+ saveSlot(newA, newB, write, slot);
498+ slot = createNode(a.height - 1,0);
499+ write++;
500+ }
501+ }
502+
503+ // Cleanup after the loop. Copy the last slot into the new nodes.
504+ if (slot.table.length > 0) {
505+ saveSlot(newA, newB, write, slot);
506+ write++;
507+ }
508+
509+ // Shift the untouched slots to the left
510+ while (read < a.table.length + b.table.length ) {
511+ saveSlot(newA, newB, write, get2(a.table, b.table, read));
512+ read++; write++;
513+ }
514+
515+ return [newA, newB];
516+ }
517+
518+ // Navigation functions
519+ function botRight(a) { return a.table[a.table.length - 1]; }
520+ function botLeft(a) { return a.table[0]; }
521+
522+ // Copies a node for updating. Note that you should not use this if
523+ // only updating only one of "table" or "lengths" for performance reasons.
524+ function nodeCopy(a) {
525+ var newA = { ctor:"_Array", height:a.height
526+ , table:a.table.slice() };
527+ if (a.height > 0) { newA.lengths = a.lengths.slice(); }
528+ return newA;
529+ }
530+
531+ // Returns how many items are in the tree.
532+ function length(array) {
533+ if (array.height == 0) {
534+ return array.table.length;
535+ } else {
536+ return array.lengths[array.lengths.length - 1];
537+ }
538+ }
539+
540+ // Calculates in which slot of "table" the item probably is, then
541+ // find the exact slot via forward searching in "lengths". Returns the index.
542+ function getSlot(i, a) {
543+ var slot = i >> (5 * a.height);
544+ while (a.lengths[slot - 1] > i) { slot--; }
545+ return slot;
546+ }
547+
548+ // Recursively creates a tree with a given height containing
549+ // only the given item.
550+ function create(item, h) {
551+ if (h == 0) {
552+ return { ctor:"_Array", height:0
553+ , table:[item] };
554+ } else {
555+ return { ctor:"_Array", height:h
556+ , table:[create(item, h - 1)]
557+ , lengths:[1] };
558+ }
559+ }
560+
561+ // Recursively creates a tree that contains the given tree.
562+ function parentise(tree, h) {
563+ if (h == tree.height) {
564+ return tree;
565+ } else {
566+ return { ctor:"_Array", height:h
567+ , table:[parentise(tree, h - 1)]
568+ , lengths:[length(tree)] };
569+ }
570+ }
571+
572+ // Emphasizes blood brotherhood beneath two trees.
573+ function siblise(a, b) {
574+ return { ctor:"_Array", height:a.height + 1
575+ , table:[a, b]
576+ , lengths:[length(a), length(a) + length(b)] };
577+ }
578+
579+ Elm.Native.Array.values = {
580+ empty:empty,
581+ fromList:fromList,
582+ toList:toList,
583+ initialize:F2(initialize),
584+ append:F2(append),
585+ push:F2(push),
586+ slice:F3(slice),
587+ get:F2(get),
588+ set:F3(set),
589+ map:F2(map),
590+ indexedMap:F2(indexedMap),
591+ foldl:F3(foldl),
592+ foldr:F3(foldr),
593+ length:length
594+ };
595+
596+ return elm.Native.Array.values = Elm.Native.Array.values;
597+}
libraries/Native/Date.js+1−2
@@ -4,12 +4,11 @@ Elm.Native.Date.make = function(elm) {
4 elm.Native.Date = elm.Native.Date || {};
4 elm.Native.Date = elm.Native.Date || {};
5 if (elm.Native.Date.values) return elm.Native.Date.values;
5 if (elm.Native.Date.values) return elm.Native.Date.values;
6
6
7− var JS = Elm.JavaScript.make(elm);
8 var Maybe = Elm.Maybe.make(elm);
7 var Maybe = Elm.Maybe.make(elm);
9
8
10 function dateNow() { return new window.Date; }
9 function dateNow() { return new window.Date; }
11 function readDate(str) {
10 function readDate(str) {
12− var d = new window.Date(JS.fromString(str));
11+ var d = new window.Date(str);
13 if (isNaN(d.getTime())) return Maybe.Nothing;
12 if (isNaN(d.getTime())) return Maybe.Nothing;
14 return Maybe.Just(d);
13 return Maybe.Just(d);
15 }
14 }
libraries/Native/Graphics/Input.js+9−38
@@ -12,7 +12,7 @@ Elm.Native.Graphics.Input.make = function(elm) {
12 var Text = Elm.Native.Text.make(elm);
12 var Text = Elm.Native.Text.make(elm);
13 var Signal = Elm.Signal.make(elm);
13 var Signal = Elm.Signal.make(elm);
14 var newElement = Elm.Graphics.Element.make(elm).newElement;
14 var newElement = Elm.Graphics.Element.make(elm).newElement;
15− var JS = Elm.Native.JavaScript.make(elm);
15+ var List = Elm.Native.List.make(elm);
16 var Utils = Elm.Native.Utils.make(elm);
16 var Utils = Elm.Native.Utils.make(elm);
17 var Tuple2 = Utils.Tuple2;
17 var Tuple2 = Utils.Tuple2;
18
18
@@ -23,14 +23,14 @@ Elm.Native.Graphics.Input.make = function(elm) {
23
23
24 function renderDropDown(signal, values) {
24 function renderDropDown(signal, values) {
25 return function(_) {
25 return function(_) {
26− var entries = JS.fromList(values);
26+ var entries = List.toArray(values);
27
27
28 var drop = newNode('select');
28 var drop = newNode('select');
29 drop.style.border = '0 solid';
29 drop.style.border = '0 solid';
30 drop.style.pointerEvents = 'auto';
30 drop.style.pointerEvents = 'auto';
31 for (var i = 0; i < entries.length; ++i) {
31 for (var i = 0; i < entries.length; ++i) {
32 var option = newNode('option');
32 var option = newNode('option');
33− var name = JS.fromString(entries[i]._0);
33+ var name = entries[i]._0;
34 option.value = name;
34 option.value = name;
35 option.innerHTML = name;
35 option.innerHTML = name;
36 drop.appendChild(option);
36 drop.appendChild(option);
@@ -91,7 +91,7 @@ Elm.Native.Graphics.Input.make = function(elm) {
91 type: 'Button',
91 type: 'Button',
92 render: renderButton,
92 render: renderButton,
93 update: updateButton,
93 update: updateButton,
94− model: { signal:signal, value:value, text:JS.fromString(text) }
94+ model: { signal:signal, value:value, text:text }
95 });
95 });
96 }
96 }
97
97
@@ -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
@@ -266,8 +259,8 @@ Elm.Native.Graphics.Input.make = function(elm) {
266 field.style.pointerEvents = 'auto';
259 field.style.pointerEvents = 'auto';
267
260
268 field.type = model.type;
261 field.type = model.type;
269− field.placeholder = JS.fromString(model.placeHolder);
262+ field.placeholder = model.placeHolder;
270− field.value = JS.fromString(model.content.string);
263+ field.value = model.content.string;
271
264
272 field.elm_signal = model.signal;
265 field.elm_signal = model.signal;
273 field.elm_handler = model.handler;
266 field.elm_handler = model.handler;
@@ -287,7 +280,7 @@ Elm.Native.Graphics.Input.make = function(elm) {
287
280
288 elm.notify(field.elm_signal.id, field.elm_handler({
281 elm.notify(field.elm_signal.id, field.elm_handler({
289 _:{},
282 _:{},
290− string: JS.toString(next),
283+ string: next,
291 selection: {
284 selection: {
292 _:{},
285 _:{},
293 start: start,
286 start: start,
@@ -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 });
@@ -338,8 +309,8 @@ Elm.Native.Graphics.Input.make = function(elm) {
338 field.elm_handler = newModel.handler;
309 field.elm_handler = newModel.handler;
339
310
340 field.type = newModel.type;
311 field.type = newModel.type;
341− field.placeholder = JS.fromString(newModel.placeHolder);
312+ field.placeholder = newModel.placeHolder;
342− var value = JS.fromString(newModel.content.string);
313+ var value = newModel.content.string;
343 field.value = value;
314 field.value = value;
344 field.elm_old_value = value;
315 field.elm_old_value = value;
345 if (field.elm_hasFocus) {
316 if (field.elm_hasFocus) {
libraries/Native/JavaScript.js+59−91
@@ -1,100 +1,68 @@
1Elm.Native.JavaScript = {};
1Elm.Native.JavaScript = {};
2Elm.Native.JavaScript.make = function(elm) {
2Elm.Native.JavaScript.make = function(elm) {
3− elm.Native = elm.Native || {};
3+ elm.Native = elm.Native || {};
4− elm.Native.JavaScript = elm.Native.JavaScript || {};
4+ elm.Native.JavaScript = elm.Native.JavaScript || {};
5− if (elm.Native.JavaScript.values) return elm.Native.JavaScript.values;
5+ if (elm.Native.JavaScript.values) return elm.Native.JavaScript.values;
6
6
7− var List = Elm.Native.List.make(elm);
7+ var List = Elm.Native.List.make(elm);
8− var Render = ElmRuntime.use(ElmRuntime.Render.Element);
8+ var Render = ElmRuntime.use(ElmRuntime.Render.Element);
9
9
10− function fromJS(v) {
10+ function fromJS(v) {
11− var type = typeof v;
11+ var type = typeof v;
12− if (type === 'number' ) return v;
12+ if (type === 'number' ) return v;
13− if (type === 'boolean') return v;
13+ if (type === 'boolean') return v;
14− if (type === 'string' ) return v;
14+ if (type === 'string' ) return v;
15− if (v instanceof Array) {
15+ if (v instanceof Array) {
16− var arr = [];
16+ var arr = [];
17− var len = v.length;
17+ var len = v.length;
18− for (var i = 0; i < len; ++i) {
18+ for (var i = 0; i < len; ++i) {
19− var x = fromJS(v[i]);
19+ var x = fromJS(v[i]);
20− if (x !== null) arr.push(x);
20+ if (x !== null) arr.push(x);
21− }
21+ }
22− return List.fromArray(arr);
22+ return List.fromArray(arr);
23− }
23+ }
24− if (type === 'object') {
24+ if (type === 'object') {
25− var rec = { _:{} };
25+ var rec = { _:{} };
26− for (var f in v) {
26+ for (var f in v) {
27− var x = fromJS(v[f]);
27+ var x = fromJS(v[f]);
28− if (x !== null) rec[f] = x;
28+ if (x !== null) rec[f] = x;
29− }
29+ }
30− return rec;
30+ return rec;
31− }
31+ }
32− return null;
32+ return null;
33− }
33+ }
34
34
35− function toJS(v) {
35+ function toJS(v) {
36− var type = typeof v;
36+ var type = typeof v;
37− if (type === 'number' || type === 'boolean' || type === 'string') return v;
37+ if (type === 'number' || type === 'boolean' || type === 'string') return v;
38− if (type === 'object' && '_' in v) {
38+ if (type === 'object' && '_' in v) {
39− var obj = {};
39+ var obj = {};
40− for (var k in v) {
40+ for (var k in v) {
41− var x = toJS(v[k]);
41+ var x = toJS(v[k]);
42− if (x !== null) obj[k] = x;
42+ if (x !== null) obj[k] = x;
43− }
43+ }
44− return obj;
44+ return obj;
45− }
45+ }
46− if (type === 'object' && (v.ctor === '::' || v.ctor === '[]')) {
46+ if (type === 'object' && (v.ctor === '::' || v.ctor === '[]')) {
47− var array = List.toArray(v);
47+ var array = List.toArray(v);
48− for (var i = array.length; i--; ) {
48+ for (var i = array.length; i--; ) {
49− array[i] = toJS(array[i]);
49+ array[i] = toJS(array[i]);
50− }
50+ }
51− return array;
51+ return array;
52− }
52+ }
53− return null;
53+ return null;
54− }
54+ }
55
55
56− function fromRecord(r) {
56+ function fromRecord(r) {
57− if (typeof r === 'object' && '_' in r) {
57+ if (typeof r === 'object' && '_' in r) {
58− return toJS(r);
58+ return toJS(r);
59− }
59+ }
60− throw new Error("'fromRecord' must be called on a record.");
60+ throw new Error("'fromRecord' must be called on a record.");
61− }
61+ }
62
62
63− function id(n) { return n; }
64−
65− function toElement(w,h,domNode) {
66− return A3( newElement, w, h, {
67− ctor: 'Custom',
68− type: 'DomNode',
69− render: function(node) { return node; },
70− update: function(node,oldNode,newNode) {
71− if (node === newNode) return;
72− node.parentNode.replaceChild(newNode, node);
73− },
74− model: domNode
75− });
76− }
77−
78− function fromElement(element) {
79− return Render.render(element);
80− }
81−
82− return elm.Native.JavaScript.values = {
63+ return elm.Native.JavaScript.values = {
83− toInt : function(n) { return n|0; },
84− toFloat : function(n) { return +n; },
85− toBool : id,
86− toString : id,
87− toList : List.fromArray,
88− fromString : id,
89− fromList : List.toArray,
90− fromInt : id,
91− fromFloat : id,
92− fromBool : id,
93−
94− toElement : toElement,
95− fromElement : fromElement,
96− toRecord : fromJS,
64+ toRecord : fromJS,
97− fromRecord : fromRecord
65+ fromRecord : fromRecord
98− };
66+ };
99
67
100};
68};
libraries/Native/Json.js+71−58
@@ -1,72 +1,85 @@
1Elm.Native.Json = {};
1Elm.Native.Json = {};
2Elm.Native.Json.make = function(elm) {
2Elm.Native.Json.make = function(elm) {
3
3
4− elm.Native = elm.Native || {};
4+ elm.Native = elm.Native || {};
5− elm.Native.Json = elm.Native.Json || {};
5+ elm.Native.Json = elm.Native.Json || {};
6− if (elm.Native.Json.values) return elm.Native.Json.values;
6+ if (elm.Native.Json.values) return elm.Native.Json.values;
7
7
8− var Maybe = Elm.Maybe.make(elm);
8+ var Maybe = Elm.Maybe.make(elm);
9− var Dict = Elm.Dict.make(elm);
9+ var Dict = Elm.Dict.make(elm);
10− var List = Elm.List.make(elm);
10+ var List = Elm.Native.List.make(elm);
11− var JS = Elm.JavaScript.make(elm);
12− var Utils = Elm.Native.Utils.make(elm);
11+ var Utils = Elm.Native.Utils.make(elm);
13
12
14− function fromValue(v) {
13+ function toJS(v) {
15− switch (v.ctor) {
14+ switch (v.ctor) {
16− case 'Null' : return null;
15+ case 'Null' : return null;
17− case 'String' : return JS.fromString(v._0);
16+ case 'String' : return v._0;
17+ case 'Number' : return v._0;
18+ case 'Boolean': return v._0;
18− case 'Object' :
19+ case 'Object' :
19− var obj = {};
20+ var obj = {};
20− var array = JS.fromList(Dict.toList(v._0));
21+ var array = List.toArray(Dict.toList(v._0));
21− for (var i = array.length; i--; ) {
22+ for (var i = array.length; i--; ) {
22− obj[JS.fromString(array[i]._0)] = fromValue(array[i]._1);
23+ var entry = array[i];
24+ obj[entry._0] = toJS(entry._1);
23− }
25+ }
24− return obj;
26+ return obj;
25− case 'Array' :
27+ case 'Array' :
26− var array = JS.fromList(v._0);
28+ var array = List.toArray(v._0);
27− for (var i = array.length; i--; ) {
29+ for (var i = array.length; i--; ) {
28− array[i] = fromValue(array[i]);
30+ array[i] = toJS(array[i]);
29− }
31+ }
30− return array;
32+ return array;
31− default :
33+ }
32− return v._0;
33 }
34 }
34− }
35
35
36− function toPrettyJSString(sep, obj) {
36+ function toString(sep, value) {
37− return JSON.stringify(fromValue(obj), null, JS.fromString(sep));
37+ return JSON.stringify(toJS(value), null, sep);
38− }
38+ }
39
39
40− function toValue(v) {
40+ function fromJS(v) {
41− switch (typeof v) {
41+ switch (typeof v) {
42− case 'string' : return { ctor:"String", _0: JS.toString(v) };
42+ case 'string' : return { ctor:"String" , _0: v };
43− case 'number' : return { ctor:"Number", _0: JS.toFloat(v) };
43+ case 'number' : return { ctor:"Number" , _0: v };
44− case 'boolean': return { ctor:"Boolean" , _0: JS.toBool(v) };
44+ case 'boolean': return { ctor:"Boolean", _0: v };
45− case 'object' :
45+ case 'object' :
46− if (v === null) return { ctor:"Null" };
46+ if (v === null) return { ctor:"Null" };
47− if (v instanceof Array) {
47+ if (v instanceof Array) {
48+ var array = new Array(v.length);
48− for (var i = v.length; i--; ) { v[i] = toValue(v[i]); }
49+ for (var i = v.length; i--; ) {
50+ array[i] = fromJS(v[i]);
51+ }
52+ return {
49− return { ctor:"Array", _0: JS.toList(v) };
53+ ctor:"Array",
54+ _0: List.fromArray(array)
55+ };
50− }
56+ }
51− var array = [];
57+ var array = [];
58+ for (var key in v) {
59+ var value = fromJS(v[key]);
52− for (var k in v) array.push(Utils.Tuple2(JS.toString(k), toValue(v[k])));
60+ array.push(Utils.Tuple2(key, value));
61+ }
62+ var list = List.fromArray(array);
63+ return {
64+ ctor:"Object",
53− return { ctor:"Object", _0: Dict.fromList(JS.toList(array)) };
65+ _0: Dict.fromList(list)
66+ };
67+ }
54 }
68 }
55− }
56
69
57− function fromJSString(str) {
70+ function fromString(str) {
58− try {
71+ try {
59− return Maybe.Just(toValue(JSON.parse(str)));
72+ return Maybe.Just(fromJS(JSON.parse(str)));
60− } catch (e) {
73+ } catch (e) {
61− return Maybe.Nothing;
74+ return Maybe.Nothing;
75+ }
62 }
76 }
63− }
64
77
65− return elm.Native.Json.values = {
78+ return elm.Native.Json.values = {
66− toJSString : F2(toPrettyJSString),
79+ toString : F2(toString),
67− fromJSString : fromJSString,
80+ fromString : fromString,
68− toJSObject : fromValue,
81+ fromJS : fromJS,
69− fromJSObject : toValue
82+ toJS : toJS,
70− };
83+ };
71
84
72};
85};
libraries/Native/Regex.js+14−14
@@ -6,8 +6,8 @@ Elm.Native.Regex.make = function(elm) {
6 if ('values' in Elm.Native.Regex)
6 if ('values' in Elm.Native.Regex)
7 return elm.Native.Regex.values = Elm.Native.Regex.values;
7 return elm.Native.Regex.values = Elm.Native.Regex.values;
8
8
9+ var List = Elm.Native.List.make(elm);
9 var Maybe = Elm.Maybe.make(elm);
10 var Maybe = Elm.Maybe.make(elm);
10− var JS = Elm.JavaScript.make(elm);
11
11
12 function escape(str) {
12 function escape(str) {
13 return str.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
13 return str.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
@@ -20,14 +20,14 @@ Elm.Native.Regex.make = function(elm) {
20 }
20 }
21
21
22 function contains(re, string) {
22 function contains(re, string) {
23− return JS.fromString(string).match(re) !== null;
23+ return string.match(re) !== null;
24 }
24 }
25
25
26 function find(n, re, str) {
26 function find(n, re, str) {
27 n = n.ctor === "All" ? Infinity : n._0;
27 n = n.ctor === "All" ? Infinity : n._0;
28 var out = [];
28 var out = [];
29 var number = 0;
29 var number = 0;
30− var string = JS.fromString(str);
30+ var string = str;
31 var result;
31 var result;
32 while (number++ < n && (result = re.exec(string))) {
32 while (number++ < n && (result = re.exec(string))) {
33 var i = result.length - 1;
33 var i = result.length - 1;
@@ -36,17 +36,17 @@ Elm.Native.Regex.make = function(elm) {
36 var submatch = result[i];
36 var submatch = result[i];
37 subs[--i] = submatch === undefined
37 subs[--i] = submatch === undefined
38 ? Maybe.Nothing
38 ? Maybe.Nothing
39− : Maybe.Just(JS.toString(submatch));
39+ : Maybe.Just(submatch);
40 }
40 }
41 out.push({
41 out.push({
42 _:{},
42 _:{},
43− match: JS.toString(result[0]),
43+ match: result[0],
44− submatches: JS.toList(subs),
44+ submatches: List.fromArray(subs),
45 index: result.index,
45 index: result.index,
46 number: number,
46 number: number,
47 });
47 });
48 }
48 }
49− return JS.toList(out);
49+ return List.fromArray(out);
50 }
50 }
51
51
52 function replace(n, re, replacer, string) {
52 function replace(n, re, replacer, string) {
@@ -60,24 +60,24 @@ Elm.Native.Regex.make = function(elm) {
60 var submatch = arguments[i];
60 var submatch = arguments[i];
61 submatches[--i] = submatch === undefined
61 submatches[--i] = submatch === undefined
62 ? Maybe.Nothing
62 ? Maybe.Nothing
63− : Maybe.Just(JS.toString(submatch));
63+ : Maybe.Just(submatch);
64 }
64 }
65− return JS.fromString(replacer({
65+ return replacer({
66 _:{},
66 _:{},
67 match:match,
67 match:match,
68− submatches:JS.toList(submatches),
68+ submatches:List.fromArray(submatches),
69 index:arguments[i-1],
69 index:arguments[i-1],
70 number:count
70 number:count
71− }));
71+ });
72 }
72 }
73 return string.replace(re, jsReplacer);
73 return string.replace(re, jsReplacer);
74 }
74 }
75
75
76 function split(n, re, str) {
76 function split(n, re, str) {
77 if (n === Infinity) {
77 if (n === Infinity) {
78− return JS.toList(JS.fromString(string).split(re));
78+ return List.fromArray(string.split(re));
79 }
79 }
80− var string = JS.fromString(str);
80+ var string = str;
81 var result;
81 var result;
82 var out = [];
82 var out = [];
83 var start = re.lastIndex;
83 var start = re.lastIndex;
@@ -87,7 +87,7 @@ Elm.Native.Regex.make = function(elm) {
87 start = re.lastIndex;
87 start = re.lastIndex;
88 }
88 }
89 out.push(string.slice(start));
89 out.push(string.slice(start));
90− return JS.toList(out);
90+ return List.fromArray(out);
91 }
91 }
92
92
93 return Elm.Native.Regex.values = {
93 return Elm.Native.Regex.values = {
libraries/Native/Show.js+4
@@ -5,6 +5,7 @@ Elm.Native.Show.make = function(elm) {
5 if (elm.Native.Show.values) return elm.Native.Show.values;
5 if (elm.Native.Show.values) return elm.Native.Show.values;
6
6
7 var NList = Elm.Native.List.make(elm);
7 var NList = Elm.Native.List.make(elm);
8+ var Array = Elm.Array.make(elm);
8 var List = Elm.List.make(elm);
9 var List = Elm.List.make(elm);
9 var Dict = Elm.Dict.make(elm);
10 var Dict = Elm.Dict.make(elm);
10 var Tuple2 = Elm.Native.Utils.make(elm).Tuple2;
11 var Tuple2 = Elm.Native.Utils.make(elm).Tuple2;
@@ -43,6 +44,9 @@ Elm.Native.Show.make = function(elm) {
43 output.push(toString(v[k]));
44 output.push(toString(v[k]));
44 }
45 }
45 return "(" + output.join(",") + ")";
46 return "(" + output.join(",") + ")";
47+ } else if (v.ctor === "_Array") {
48+ var list = Array.toList(v);
49+ return "Array.fromList " + toString(list);
46 } else if (v.ctor === "::") {
50 } else if (v.ctor === "::") {
47 var output = '[' + toString(v._0);
51 var output = '[' + toString(v._0);
48 v = v._1;
52 v = v._1;
libraries/Native/Signal/Http.js+6−7
@@ -5,7 +5,6 @@ Elm.Native.Http.make = function(elm) {
5 elm.Native.Http = elm.Native.Http || {};
5 elm.Native.Http = elm.Native.Http || {};
6 if (elm.Native.Http.values) return elm.Native.Http.values;
6 if (elm.Native.Http.values) return elm.Native.Http.values;
7
7
8− var JS = Elm.JavaScript.make(elm);
9 var List = Elm.List.make(elm);
8 var List = Elm.List.make(elm);
10 var Signal = Elm.Signal.make(elm);
9 var Signal = Elm.Signal.make(elm);
11
10
@@ -38,17 +37,17 @@ Elm.Native.Http.make = function(elm) {
38 request.onreadystatechange = function(e) {
37 request.onreadystatechange = function(e) {
39 if (request.readyState === 4) {
38 if (request.readyState === 4) {
40 response.value = (request.status >= 200 && request.status < 300 ?
39 response.value = (request.status >= 200 && request.status < 300 ?
41− { ctor:'Success', _0:JS.toString(request.responseText) } :
40+ { ctor:'Success', _0:request.responseText } :
42− { ctor:'Failure', _0:request.status, _1:JS.toString(request.statusText) });
41+ { ctor:'Failure', _0:request.status, _1:request.statusText });
43 setTimeout(function() { updateQueue(queue,responses); }, 0);
42 setTimeout(function() { updateQueue(queue,responses); }, 0);
44 }
43 }
45 };
44 };
46− request.open(JS.fromString(req.verb), JS.fromString(req.url), true);
45+ request.open(req.verb, req.url, true);
47 function setHeader(pair) {
46 function setHeader(pair) {
48− request.setRequestHeader( JS.fromString(pair._0), JS.fromString(pair._1) );
47+ request.setRequestHeader( pair._0, pair._1 );
49 }
48 }
50− List.map(setHeader)(req.headers);
49+ A2( List.map, setHeader, req.headers );
51− request.send(JS.fromString(req.body));
50+ request.send(req.body);
52 }
51 }
53
52
54 function send(requests) {
53 function send(requests) {
libraries/Native/Signal/Touch.js+3−3
@@ -6,7 +6,7 @@ Elm.Native.Touch.make = function(elm) {
6 if (elm.Native.Touch.values) return elm.Native.Touch.values;
6 if (elm.Native.Touch.values) return elm.Native.Touch.values;
7
7
8 var Signal = Elm.Signal.make(elm);
8 var Signal = Elm.Signal.make(elm);
9− var JS = Elm.JavaScript.make(elm);
9+ var List = Elm.Native.List.make(elm);
10 var Utils = Elm.Native.Utils.make(elm);
10 var Utils = Elm.Native.Utils.make(elm);
11
11
12 function Dict() {
12 function Dict() {
@@ -136,7 +136,7 @@ Elm.Native.Touch.make = function(elm) {
136 return sig;
136 return sig;
137 }
137 }
138
138
139− var touches = dependency(JS.toList);
139+ var touches = dependency(List.fromArray);
140
140
141 var taps = function() {
141 var taps = function() {
142 var sig = dependency(function(_) { return tap; });
142 var sig = dependency(function(_) { return tap; });
@@ -149,4 +149,4 @@ Elm.Native.Touch.make = function(elm) {
149
149
150 return elm.Native.Touch.values = { touches: touches, taps: taps };
150 return elm.Native.Touch.values = { touches: touches, taps: taps };
151
151
152−};
152+};
libraries/Native/Signal/WebSocket.js+3−5
@@ -6,12 +6,11 @@ Elm.Native.WebSocket.make = function(elm) {
6 if (elm.Native.WebSocket.values) return elm.Native.WebSocket.values;
6 if (elm.Native.WebSocket.values) return elm.Native.WebSocket.values;
7
7
8 var Signal = Elm.Signal.make(elm);
8 var Signal = Elm.Signal.make(elm);
9− var JS = Elm.JavaScript.make(elm);
10 var List = Elm.Native.List.make(elm);
9 var List = Elm.Native.List.make(elm);
11
10
12 function open(url, outgoing) {
11 function open(url, outgoing) {
13 var incoming = Signal.constant(List.Nil);
12 var incoming = Signal.constant(List.Nil);
14− var ws = new WebSocket(JS.fromString(url));
13+ var ws = new WebSocket(url);
15
14
16 var pending = [];
15 var pending = [];
17 var ready = false;
16 var ready = false;
@@ -22,12 +21,11 @@ Elm.Native.WebSocket.make = function(elm) {
22 ready = true;
21 ready = true;
23 };
22 };
24 ws.onmessage = function(event) {
23 ws.onmessage = function(event) {
25− elm.notify(incoming.id, JS.toString(event.data));
24+ elm.notify(incoming.id, event.data);
26 };
25 };
27
26
28 function send(msg) {
27 function send(msg) {
29− var s = JS.fromString(msg);
30− ready ? ws.send(s) : pending.push(s);
28+ ready ? ws.send(msg) : pending.push(msg);
31 }
29 }
32
30
33 function take1(x,y) { return x }
31 function take1(x,y) { return x }
libraries/Native/String.js+9−9
@@ -8,7 +8,7 @@ Elm.Native.String.make = function(elm) {
8
8
9 var Char = Elm.Char.make(elm);
9 var Char = Elm.Char.make(elm);
10 var Maybe = Elm.Maybe.make(elm);
10 var Maybe = Elm.Maybe.make(elm);
11− var JS = Elm.JavaScript.make(elm);
11+ var List = Elm.Native.List.make(elm);
12 var Utils = Elm.Native.Utils.make(elm);
12 var Utils = Elm.Native.Utils.make(elm);
13
13
14 function isEmpty(str) {
14 function isEmpty(str) {
@@ -26,7 +26,7 @@ Elm.Native.String.make = function(elm) {
26 return a + b;
26 return a + b;
27 }
27 }
28 function concat(strs) {
28 function concat(strs) {
29− return JS.fromList(strs).join('');
29+ return List.toArray(strs).join('');
30 }
30 }
31 function length(str) {
31 function length(str) {
32 return str.length;
32 return str.length;
@@ -59,10 +59,10 @@ Elm.Native.String.make = function(elm) {
59 }
59 }
60
60
61 function split(sep, str) {
61 function split(sep, str) {
62− return JS.toList(str.split(sep));
62+ return List.fromArray(str.split(sep));
63 }
63 }
64 function join(sep, strs) {
64 function join(sep, strs) {
65− return JS.fromList(strs).join(sep);
65+ return List.toArray(strs).join(sep);
66 }
66 }
67 function repeat(n, str) {
67 function repeat(n, str) {
68 var result = '';
68 var result = '';
@@ -111,10 +111,10 @@ Elm.Native.String.make = function(elm) {
111 }
111 }
112
112
113 function words(str) {
113 function words(str) {
114− return JS.toList(str.split(/\s+/g));
114+ return List.fromArray(str.split(/\s+/g));
115 }
115 }
116 function lines(str) {
116 function lines(str) {
117− return JS.toList(str.split(/\r\n|\r|\n/g));
117+ return List.fromArray(str.split(/\r\n|\r|\n/g));
118 }
118 }
119
119
120 function toUpper(str) {
120 function toUpper(str) {
@@ -155,7 +155,7 @@ Elm.Native.String.make = function(elm) {
155 is.push(i);
155 is.push(i);
156 i = i + subLen;
156 i = i + subLen;
157 }
157 }
158− return JS.toList(is);
158+ return List.fromArray(is);
159 }
159 }
160
160
161 function toInt(s) {
161 function toInt(s) {
@@ -193,10 +193,10 @@ Elm.Native.String.make = function(elm) {
193 }
193 }
194
194
195 function toList(str) {
195 function toList(str) {
196− return JS.toList(str.split('').map(Utils.chr));
196+ return List.fromArray(str.split('').map(Utils.chr));
197 }
197 }
198 function fromList(chars) {
198 function fromList(chars) {
199− return JS.fromList(chars).join('');
199+ return List.toArray(chars).join('');
200 }
200 }
201
201
202 return Elm.Native.String.values = {
202 return Elm.Native.String.values = {
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+1−1
@@ -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-}
libraries/Text.elm−1
@@ -35,7 +35,6 @@ import String
35import Color (Color, black)
35import Color (Color, black)
36import Graphics.Element (Element, Three, Pos, ElementPrim, Properties)
36import Graphics.Element (Element, Three, Pos, ElementPrim, Properties)
37import Maybe (Maybe, Nothing)
37import Maybe (Maybe, Nothing)
38−import JavaScript (JSString)
39import Native.Show
38import Native.Show
40import Native.Text
39import Native.Text
41
40
libraries/elm_dependencies.json+6−6
@@ -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"
@@ -19,7 +20,6 @@
19 , "Graphics.Input"
20 , "Graphics.Input"
20 , "Graphics.Input.Field"
21 , "Graphics.Input.Field"
21 , "Http"
22 , "Http"
22− , "JavaScript"
23 , "JavaScript.Experimental"
23 , "JavaScript.Experimental"
24 , "Json"
24 , "Json"
25 , "Keyboard"
25 , "Keyboard"
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.11
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.11,
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+54
@@ -0,0 +1,54 @@
1+module Test.Array (tests) where
2+
3+import List
4+import Array
5+
6+import ElmTest.Assertion (..)
7+import ElmTest.Test (..)
8+
9+tests : Test
10+tests =
11+ let creationTests = suite "Creation"
12+ [ test "empty" <| assertEqual Array.empty (Array.fromList [])
13+ , test "initialize" <| assertEqual (Array.initialize 4 id) (Array.fromList [0,1,2,3])
14+ , test "initialize 2" <| assertEqual (Array.initialize 4 (\n -> n*n)) (Array.fromList [0,1,4,9])
15+ , test "initialize 3" <| assertEqual (Array.initialize 4 (always 0)) (Array.fromList [0,0,0,0])
16+ , test "initialize Empty" <| assertEqual (Array.initialize 0 id) Array.empty
17+ , test "initialize 4" <| assertEqual (Array.initialize 2 (always 0)) (Array.fromList [0,0])
18+ , test "repeat" <| assertEqual (Array.repeat 5 40) (Array.fromList [40,40,40,40,40])
19+ , test "repeat 2" <| assertEqual (Array.repeat 5 0) (Array.fromList [0,0,0,0,0])
20+ , test "repeat 3" <| assertEqual (Array.repeat 3 "cat") (Array.fromList ["cat","cat","cat"])
21+ , test "fromList" <| assertEqual (Array.fromList []) Array.empty
22+ ]
23+ basicsTests = suite "Basics"
24+ [ test "length" <| assertEqual (Array.length (Array.fromList [1,2,3])) 3
25+ , test "length - Long" <| assertEqual (Array.length (Array.repeat 10000 0)) 10000
26+ , test "push" <| assertEqual (Array.push 3 (Array.fromList [1,2])) (Array.fromList [1,2,3])
27+ , test "append" <| assertEqual (Array.toList <| Array.append (Array.repeat 2 42) (Array.repeat 3 81)) ([42,42,81,81,81])
28+ ]
29+ getAndSetTests = suite "Get and Set"
30+ [ test "get" <| assertEqual (Array.get 1 (Array.fromList [3,2,1])) (Just 2)
31+ , test "get 2" <| assertEqual (Array.get 5 (Array.fromList [3,2,1])) Nothing
32+ , test "get 3" <| assertEqual (Array.get -1 (Array.fromList [3,2,1])) Nothing
33+ , test "getOrElse 1" <| assertEqual (Array.getOrElse 0 2 (Array.fromList [3,2,1])) 1
34+ , test "getOrElse 2" <| assertEqual (Array.getOrElse 0 5 (Array.fromList [3,2,1])) 0
35+ , test "getOrFail" <| assertEqual (Array.getOrFail 2 (Array.fromList [3,2,1])) 1
36+ , test "set" <| assertEqual (Array.set 1 7 (Array.fromList [1,2,3])) (Array.fromList [1,7,3])
37+ ]
38+ takingArraysApartTests = suite "Taking Arrays Apart"
39+ [ test "toList" <| assertEqual (Array.toList (Array.fromList [3,5,8])) [3,5,8]
40+ , test "toIndexedList" <| assertEqual (Array.toIndexedList (Array.fromList ["cat","dog"])) [(0,"cat"), (1,"dog")]
41+ , test "slice" <| assertEqual (Array.slice 1 2 (Array.fromList [0,1,2,3,4])) (Array.fromList [1,2])
42+ , test "slice 2" <| assertEqual (Array.slice 1 -2 (Array.fromList [0,1,2,3,4])) (Array.fromList [1,2,3])
43+ , test "slice 3" <| assertEqual (Array.slice -3 -2 (Array.fromList [0,1,2,3,4])) (Array.fromList [2,3])
44+ ]
45+ mappingAndFoldingTests = suite "Mapping and Folding"
46+ [ test "map" <| assertEqual (Array.map sqrt (Array.fromList [1,4,9])) (Array.fromList [1,2,3])
47+ , test "indexedMap" <| assertEqual (Array.indexedMap (*) (Array.fromList [5,5,5])) (Array.fromList [0,5,10])
48+ , test "foldl" <| assertEqual (Array.foldl (::) [] (Array.fromList [1,2,3])) [3,2,1]
49+ , test "foldr" <| assertEqual (Array.foldr (+) 0 (Array.repeat 3 5)) 15
50+ , test "foldr 2" <| assertEqual (Array.foldr (::) [] (Array.fromList [1,2,3])) [1,2,3]
51+ , test "filter" <| assertEqual (Array.filter (\x -> x `mod` 2 == 0) (Array.fromList [1..6])) (Array.fromList [2,4,6])
52+ ]
53+ in
54+ suite "Array Tests" [creationTests, basicsTests, getAndSetTests, takingArraysApartTests, mappingAndFoldingTests]
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+34
@@ -0,0 +1,34 @@
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 isEmptyTests = suite "isEmpty Tests" [
12+ test "empty is empty" <| assert <| isEmpty "",
13+ test "not empty" <| assert <| not . isEmpty <| "the world"
14+ ]
15+ lengthTest = test "length of innumerable" <| assertEqual 11 (length "innumerable")
16+ reverseTest = test "reverse test" <| assertEqual "desserts" (reverse "stressed")
17+ repeatTest = test "repeat test" <| assertEqual "hahaha" (repeat 3 "ha")
18+ unconsTests = suite "uncons Tests" [
19+ test "nonempty uncons" <| assertEqual (Just ('a',"bc")) (uncons "abc"),
20+ test "empty uncons" <| assertEqual Nothing (uncons "")
21+ ]
22+ appendTest = test "append test" <| assertEqual "butterfly" (append "butter" "fly")
23+ concatTest = test "concat test" <| assertEqual "nevertheless" (concat ["never","the","less"])
24+ splitTests = suite "split Tests" [
25+ test "split commas" <| assertEqual ["cat","dog","cow"] (split "," "cat,dog,cow"),
26+ test "split slashes"<| assertEqual ["home","evan","Desktop", ""] (split "/" "home/evan/Desktop/")
27+ ]
28+ joinTests = suite "join Tests" [
29+ test "join spaces" <| assertEqual "cat dog cow" (join " " ["cat","dog","cow"]),
30+ test "join slashes" <| assertEqual "home/evan/Desktop" (join "/" ["home","evan","Desktop"])
31+ ]
32+
33+ endsWithTest = test "endsWith Check" (assert <| endsWith "h" "th")
34+ in suite "String Tests" [isEmptyTests, lengthTest, reverseTest, repeatTest, unconsTests, appendTest, concatTest, splitTests, joinTests, endsWithTest]
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.