on master help sign in
Merge remote-tracking branch 'elm-lang/webgl' into webgl
99c1139John P Mayer Jr
Elm-Test+1−1

Submodule changed.

Elm.cabal+8−5
@@ -1,5 +1,5 @@
1Name: Elm
1Name: Elm
2−Version: 0.12
2+Version: 0.12.1
3Synopsis: The Elm language module.
3Synopsis: The Elm language module.
4Description: Elm aims to make client-side web-development more pleasant.
4Description: Elm aims to make client-side web-development more pleasant.
5 It is a statically/strongly typed, functional reactive
5 It is a statically/strongly typed, functional reactive
@@ -27,7 +27,7 @@ Cabal-version: >=1.9
27
27
28source-repository head
28source-repository head
29 type: git
29 type: git
30− location: git://github.com/evancz/Elm.git
30+ location: git://github.com/elm-lang/Elm.git
31
31
32Library
32Library
33 exposed-modules: Elm.Internal.Dependencies,
33 exposed-modules: Elm.Internal.Dependencies,
@@ -95,6 +95,7 @@ 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.7.0.0,
100 binary >= 0.7.0.0,
100 blaze-html >= 0.5 && < 0.8,
101 blaze-html >= 0.5 && < 0.8,
@@ -178,6 +179,7 @@ Executable elm
178 Paths_Elm
179 Paths_Elm
179
180
180 Build-depends: aeson,
181 Build-depends: aeson,
182+ aeson-pretty,
181 base >=4.2 && <5,
183 base >=4.2 && <5,
182 binary >= 0.7.0.0,
184 binary >= 0.7.0.0,
183 blaze-html >= 0.5 && < 0.8,
185 blaze-html >= 0.5 && < 0.8,
@@ -255,10 +257,11 @@ Test-Suite compiler-tests
255 HUnit,
257 HUnit,
256 QuickCheck >= 2 && < 3,
258 QuickCheck >= 2 && < 3,
257 aeson,
259 aeson,
260+ aeson-pretty,
258 base >=4.2 && <5,
261 base >=4.2 && <5,
259 binary >= 0.7.0.0,
262 binary >= 0.7.0.0,
260− blaze-html == 0.5.* || == 0.6.*,
263+ blaze-html,
261− blaze-markup == 0.5.1.*,
264+ blaze-markup,
262 bytestring,
265 bytestring,
263 cmdargs,
266 cmdargs,
264 containers >= 0.3,
267 containers >= 0.3,
@@ -286,4 +289,4 @@ Test-Suite lib-tests
286 directory,
289 directory,
287 Elm,
290 Elm,
288 filepath,
291 filepath,
289− process >= 1.2
292+ process
automaton+1−1

Submodule changed.

changelog.md+8−6
@@ -1,5 +1,12 @@
1
1
2−## 0.13
2+## 0.12.1
3+
4+## Improvements:
5+
6+ * New Array library (thanks entirely to @Xashili)
7+ * Json.Value can flow through ports
8+ * Improve speed and stack usage in List library (thanks to @maxsnew)
9+ * Add Dict.filter and Dict.partition (thanks to @hdgarrood)
3
10
4#### Breaking Changes:
11#### Breaking Changes:
5
12
@@ -7,11 +14,6 @@
7 * Revamp JavaScript.Experimental library to have slightly better names
14 * Revamp JavaScript.Experimental library to have slightly better names
8 * Remove JavaScript library which was made redundant by ports
15 * Remove JavaScript library which was made redundant by ports
9
16
10−## Improvements:
11−
12− * Json.Value can flow through ports, so you can bring in values even
13− if they don't conform to a consistent type.
14−
15## 0.12
17## 0.12
16
18
17#### Breaking Changes:
19#### Breaking Changes:
compiler/Elm/Internal/Dependencies.hs+41−4
@@ -5,9 +5,12 @@ import Control.Applicative
5import Control.Monad.Error
5import Control.Monad.Error
6import qualified Control.Exception as E
6import qualified Control.Exception as E
7import Data.Aeson
7import Data.Aeson
8+import Data.Aeson.Encode.Pretty
8import qualified Data.List as List
9import qualified Data.List as List
9import qualified Data.ByteString.Lazy as BS
10import qualified Data.ByteString.Lazy as BS
10import qualified Data.HashMap.Strict as Map
11import qualified Data.HashMap.Strict as Map
12+import qualified Data.Text as T
13+
11import qualified Elm.Internal.Name as N
14import qualified Elm.Internal.Name as N
12import qualified Elm.Internal.Version as V
15import qualified Elm.Internal.Version as V
13import qualified Elm.Internal.Paths as Path
16import qualified Elm.Internal.Paths as Path
@@ -22,14 +25,32 @@ data Deps = Deps
22 , exposed :: [String]
25 , exposed :: [String]
23 , elmVersion :: V.Version
26 , elmVersion :: V.Version
24 , dependencies :: [(N.Name,V.Version)]
27 , dependencies :: [(N.Name,V.Version)]
25− } deriving Show
28+ } deriving (Show, Eq, Ord)
26
29
27data MiniDeps = Mini [(N.Name,V.Version)]
30data MiniDeps = Mini [(N.Name,V.Version)]
31+ deriving (Show, Eq, Ord)
32+
33+instance ToJSON MiniDeps where
34+ toJSON (Mini m) = toJSON m
28
35
29instance FromJSON MiniDeps where
36instance FromJSON MiniDeps where
30 parseJSON (Object obj) = Mini <$> getDependencies obj
37 parseJSON (Object obj) = Mini <$> getDependencies obj
31 parseJSON _ = mzero
38 parseJSON _ = mzero
32
39
40+instance ToJSON Deps where
41+ toJSON d = object [
42+ "version" .= version d,
43+ "summary" .= summary d,
44+ "description" .= description d,
45+ "license" .= license d,
46+ "repository" .= repo d,
47+ "exposed-modules" .= exposed d,
48+ "elm-version" .= elmVersion d,
49+ "dependencies" .= (jsonDeps . dependencies $ d)
50+ ]
51+ where jsonDeps = Map.fromList . map (mapFst (T.pack . show))
52+ mapFst f (a,b) = (f a, b)
53+
33instance FromJSON Deps where
54instance FromJSON Deps where
34 parseJSON (Object obj) =
55 parseJSON (Object obj) =
35 do version <- get obj "version" "your projects version number"
56 do version <- get obj "version" "your projects version number"
@@ -110,8 +131,24 @@ withDeps handle path =
110 case result of
131 case result of
111 Right bytes -> return bytes
132 Right bytes -> return bytes
112 Left _ -> throwError $
133 Left _ -> throwError $
113− "could not find file " ++ path ++
134+ "could not find " ++ path ++ " file. You may need to create one.\n" ++
114− "\n You may need to create a dependency file for your project."
135+ " For an example of how to fill in the dependencies file, check out\n" ++
136+ " <https://github.com/evancz/automaton/blob/master/elm_dependencies.json>"
115
137
116depsAt :: FilePath -> ErrorT String IO Deps
138depsAt :: FilePath -> ErrorT String IO Deps
117−depsAt = withDeps id
139+depsAt = withDeps id
140+
141+-- | Encode dependencies in a canonical JSON format
142+prettyJSON :: Deps -> BS.ByteString
143+prettyJSON = encodePretty' config
144+ where config = defConfig { confCompare = order }
145+ order = keyOrder [ "name",
146+ "version",
147+ "summary",
148+ "description",
149+ "license",
150+ "repo",
151+ "exposed-modules",
152+ "elm-version",
153+ "dependencies"
154+ ]
compiler/Elm/Internal/Name.hs+2−2
@@ -10,7 +10,7 @@ import qualified Data.Maybe as Maybe
10import Data.Typeable
10import Data.Typeable
11
11
12data Name = Name { user :: String, project :: String }
12data Name = Name { user :: String, project :: String }
13− deriving (Typeable,Eq)
13+ deriving (Typeable,Eq, Ord)
14
14
15instance Binary Name where
15instance Binary Name where
16 get = Name <$> get <*> get
16 get = Name <$> get <*> get
@@ -48,4 +48,4 @@ errorMsg string =
48 unlines
48 unlines
49 [ "Dependency file has an invalid name: " ++ string
49 [ "Dependency file has an invalid name: " ++ string
50 , "Must have format user/project and match a public github project."
50 , "Must have format user/project and match a public github project."
51− ]
51+ ]
compiler/Generate/JavaScript.hs+2−1
@@ -34,10 +34,11 @@ include alias moduleName =
34
34
35internalImports :: String -> Statement ()
35internalImports :: String -> Statement ()
36internalImports name =
36internalImports name =
37− VarDeclStmt ()
37+ VarDeclStmt ()
38 [ varDecl "_N" (obj "Elm.Native")
38 [ varDecl "_N" (obj "Elm.Native")
39 , include "_U" "_N.Utils"
39 , include "_U" "_N.Utils"
40 , include "_L" "_N.List"
40 , include "_L" "_N.List"
41+ , include "_A" "_N.Array"
41 , include "_E" "_N.Error"
42 , include "_E" "_N.Error"
42 , varDecl "$moduleName" (string name)
43 , varDecl "$moduleName" (string name)
43 ]
44 ]
compiler/Generate/JavaScript/Ports.hs+15−8
@@ -38,7 +38,7 @@ inc tipe x =
38
38
39 Data "Json.Value" [] ->
39 Data "Json.Value" [] ->
40 obj "Native.Json.fromJS" <| x
40 obj "Native.Json.fromJS" <| x
41−
41+
42 Data ctor []
42 Data ctor []
43 | ctor == "Int" -> from JSNumber
43 | ctor == "Int" -> from JSNumber
44 | ctor == "Float" -> from JSNumber
44 | ctor == "Float" -> from JSNumber
@@ -55,8 +55,12 @@ inc tipe x =
55
55
56 | ctor == "_List" ->
56 | ctor == "_List" ->
57 check x JSArray (obj "_L.fromArray" <| array)
57 check x JSArray (obj "_L.fromArray" <| array)
58+
59+ | ctor == "Array.Array" ->
60+ check x JSArray (obj "_A.fromJSArray" <| array)
61+
58− where
62+ where
59− array = DotRef () x (var "map") <| incoming t
63+ array = DotRef () x (var "map") <| incoming t
60
64
61 Data ctor ts
65 Data ctor ts
62 | Help.isTuple ctor -> check x JSArray tuple
66 | Help.isTuple ctor -> check x JSArray tuple
@@ -67,10 +71,10 @@ inc tipe x =
67 , inc t (BracketRef () x (IntLit () n)))
71 , inc t (BracketRef () x (IntLit () n)))
68
72
69 Data _ _ ->
73 Data _ _ ->
70− error "bad ADT got to port generation code"
74+ error "bad ADT got to incoming port generation code"
71
75
72 Record _ (Just _) ->
76 Record _ (Just _) ->
73− error "bad record got to port generation code"
77+ error "bad record got to incoming port generation code"
74
78
75 Record fields Nothing ->
79 Record fields Nothing ->
76 check x (JSObject (map fst fields)) object
80 check x (JSObject (map fst fields)) object
@@ -117,16 +121,19 @@ out tipe x =
117 | ctor == "_List" ->
121 | ctor == "_List" ->
118 DotRef () (obj "_L.toArray" <| x) (var "map") <| outgoing t
122 DotRef () (obj "_L.toArray" <| x) (var "map") <| outgoing t
119
123
124+ | ctor == "Array.Array" ->
125+ DotRef () (obj "_A.toJSArray" <| x) (var "map") <| outgoing t
126+
120 Data ctor ts
127 Data ctor ts
121 | Help.isTuple ctor ->
128 | Help.isTuple ctor ->
122 let convert n t = out t $ DotRef () x $ var ('_':show n)
129 let convert n t = out t $ DotRef () x $ var ('_':show n)
123 in ArrayLit () $ zipWith convert [0..] ts
130 in ArrayLit () $ zipWith convert [0..] ts
124−
131+
125 Data _ _ ->
132 Data _ _ ->
126− error "bad ADT got to port generation code"
133+ error "bad ADT got to outgoing port generation code"
127
134
128 Record _ (Just _) ->
135 Record _ (Just _) ->
129− error "bad record got to port generation code"
136+ error "bad record got to outgoing port generation code"
130
137
131 Record fields Nothing ->
138 Record fields Nothing ->
132 ObjectLit () keys
139 ObjectLit () keys
compiler/Type/ExtraChecks.hs+2−3
@@ -60,8 +60,7 @@ portTypes rules expr =
60 | otherwise -> err' True "an unsupported type"
60 | otherwise -> err' True "an unsupported type"
61 where
61 where
62 primitives =
62 primitives =
63− ["Int","Float","String","Bool","Maybe.Maybe","_List","Json.Value"]
63+ ["Int","Float","String","Bool","Maybe.Maybe","_List","Array.Array","Json.Value"]
64−
65 validConstructor =
64 validConstructor =
66 ctor `elem` primitives || Help.isTuple ctor
65 ctor `elem` primitives || Help.isTuple ctor
67
66
@@ -102,7 +101,7 @@ portTypes rules expr =
102 , txt [ "It contains ", kind, ":\n" ]
101 , txt [ "It contains ", kind, ":\n" ]
103 , (P.nest 4 . SPP.pretty $ Alias.realias rules tipe) <> P.text "\n"
102 , (P.nest 4 . SPP.pretty $ Alias.realias rules tipe) <> P.text "\n"
104 , txt [ "Acceptable values for ", dir "incoming" "outgoing", " ports include:" ]
103 , txt [ "Acceptable values for ", dir "incoming" "outgoing", " ports include:" ]
105− , txt [ " Ints, Floats, Bools, Strings, Maybes, Lists, Tuples," ]
104+ , txt [ " Ints, Floats, Bools, Strings, Maybes, Lists, Arrays, Tuples," ]
106 , txt [ " Json.Values, ", dir "" "first-order functions, ", "and concrete records." ]
105 , txt [ " Json.Values, ", dir "" "first-order functions, ", "and concrete records." ]
107 ] ++ if couldBeAlias then aliasWarning else []
106 ] ++ if couldBeAlias then aliasWarning else []
108
107
compiler/Type/Unify.hs+5−1
@@ -86,6 +86,10 @@ actuallyUnify region variable1 variable2 = do
86 TS.addError region (Just $ Maybe.fromMaybe msg maybe) variable1 variable2
86 TS.addError region (Just $ Maybe.fromMaybe msg maybe) variable1 variable2
87 where msg = "A comparable must be an Int, Float, Char, String, list, or tuple."
87 where msg = "A comparable must be an Int, Float, Char, String, list, or tuple."
88
88
89+ appendableError maybe =
90+ TS.addError region (Just $ Maybe.fromMaybe msg maybe) variable1 variable2
91+ where msg = "An appendable must be of type String, List, or Text."
92+
89 unifyComparable var name
93 unifyComparable var name
90 | name `elem` ["Int","Float","Char","String","comparable"] = flexAndUnify var
94 | name `elem` ["Int","Float","Char","String","comparable"] = flexAndUnify var
91 | otherwise = comparableError Nothing
95 | otherwise = comparableError Nothing
@@ -108,7 +112,7 @@ actuallyUnify region variable1 variable2 = do
108 do struct <- liftIO $ collectApps varFlex
112 do struct <- liftIO $ collectApps varFlex
109 case struct of
113 case struct of
110 List _ -> flexAndUnify varSuper
114 List _ -> flexAndUnify varSuper
111− _ -> comparableError Nothing
115+ _ -> appendableError Nothing
112
116
113 rigidError variable = TS.addError region (Just hint) variable1 variable2
117 rigidError variable = TS.addError region (Just hint) variable1 variable2
114 where
118 where
libraries/Array.elm+31−22
@@ -11,10 +11,10 @@ reads, updates, and appends.
11@docs length, push, append
11@docs length, push, append
12
12
13# Get and Set
13# Get and Set
14−@docs get, getSafe, getUnsafe, set
14+@docs get, getOrElse, getOrFail, set
15
15
16# Taking Arrays Apart
16# Taking Arrays Apart
17−@docs toList, toIndexedList, slice
17+@docs slice, toList, toIndexedList
18
18
19# Mapping and Folding
19# Mapping and Folding
20@docs map, indexedMap, foldl, foldr
20@docs map, indexedMap, foldl, foldr
@@ -122,20 +122,21 @@ push = Native.Array.push
122
122
123{-| Get the element at a particular index.
123{-| Get the element at a particular index.
124
124
125− getUnsafe 2 (A.fromList [3,2,1]) == 1
125+ getOrFail 0 (A.fromList [0,1,2]) == 0
126
126
127Warning: this function will result in a runtime error if the index is not found,
127Warning: this function will result in a runtime error if the index is not found,
128−so it is best to use `get` or `getSafe` unless you are very confident the index
128+so it is best to use `get` or `getOrElse` unless you are sure the index will be
129−will be found.
129+found.
130-}
130-}
131−getUnsafe : Int -> Array a -> a
131+getOrFail : Int -> Array a -> a
132−getUnsafe = Native.Array.get
132+getOrFail = Native.Array.get
133
133
134{-| Return Just the element at the index or Nothing if the index is out of range.
134{-| Return Just the element at the index or Nothing if the index is out of range.
135
135
136− get 2 (fromList [3,2,1]) == Just 2
136+ get 0 (fromList [0,1,2]) == Just 0
137+ get 2 (fromList [0,1,2]) == Just 2
137− get 5 (fromList [3,2,1]) == Nothing
138+ get 5 (fromList [0,1,2]) == Nothing
138− get -1 (fromList [3,2,1]) == Nothing
139+ get -1 (fromList [0,1,2]) == Nothing
139-}
140-}
140get : Int -> Array a -> Maybe a
141get : Int -> Array a -> Maybe a
141get i array =
142get i array =
@@ -143,14 +144,14 @@ get i array =
143 then Just (Native.Array.get i array)
144 then Just (Native.Array.get i array)
144 else Nothing
145 else Nothing
145
146
146−{-| Get the element at the index. If the index is out of range, the given default
147+{-| Get the element at the index. Or if the index is out of range, a default
147−element is returned.
148+value is returned.
148
149
149− getSafe 0 2 (fromList [3,2,1]) == 1
150+ getOrElse 0 2 (fromList [0,1,2]) == 2
150− getSafe 0 5 (fromList [3,2,1]) == 0
151+ getOrElse 0 5 (fromList [0,1,2]) == 0
151-}
152-}
152−getSafe : a -> Int -> Array a -> a
153+getOrElse : a -> Int -> Array a -> a
153−getSafe default i array =
154+getOrElse default i array =
154 if 0 <= i && i < Native.Array.length array
155 if 0 <= i && i < Native.Array.length array
155 then Native.Array.get i array
156 then Native.Array.get i array
156 else default
157 else default
@@ -163,13 +164,21 @@ If the index is out of range, the array is unaltered.
163set : Int -> a -> Array a -> Array a
164set : Int -> a -> Array a -> Array a
164set = Native.Array.set
165set = Native.Array.set
165
166
166−{-| Slice an array given a range. The selection is inclusive, so the last
167+{-| Get a sub-section of an array: `(slice start end array)`. The `start` is a
167−element in the selection will also be in the new array. This may change in the
168+zero-based index where we will start our slice. The `end` is a zero-based index
168−future. You can select from the end by giving a negative Int.
169+that indicates the end of the slice. The slice extracts up to but not including
170+`end`.
169
171
170− slice 1 2 (fromList [0,1,2,3,4]) == fromList [1,2]
172+ slice 0 3 (fromList [0,1,2,3,4]) == fromList [0,1,2]
171− slice 1 -2 (fromList [0,1,2,3,4]) == fromList [1,2,3]
173+ slice 1 4 (fromList [0,1,2,3,4]) == fromList [1,2,3]
174+
175+Both the `start` and `end` indexes can be negative, indicating an offset from
176+the end of the array.
177+
178+ slice 1 -1 (fromList [0,1,2,3,4]) == fromList [1,2,3]
172− slice -3 -2 (fromList [0,1,2,3,4]) == fromList [2,3]
179+ slice -2 5 (fromList [0,1,2,3,4]) == fromList [3,4]
180+
181+This makes it pretty easy to `pop` the last element off of an array: `slice 0 -1 array`
173-}
182-}
174slice : Int -> Int -> Array a -> Array a
183slice : Int -> Int -> Array a -> Array a
175slice = Native.Array.slice
184slice = Native.Array.slice
libraries/Dict.elm+20−20
@@ -1,5 +1,5 @@
1module Dict (empty,singleton,insert,update
1module Dict (empty,singleton,insert,update
2− ,get,getSafe,getUnsafe
2+ ,get,getOrElse,getOrFail
3 ,remove,member
3 ,remove,member
4 ,filter
4 ,filter
5 ,partition
5 ,partition
@@ -19,7 +19,7 @@ Insert, remove, and query operations all take *O(log n)* time.
19@docs empty, singleton, insert, update, remove
19@docs empty, singleton, insert, update, remove
20
20
21# Query
21# Query
22−@docs member, get, getMaybe, getWithDefault
22+@docs member, get, getOrElse, getOrFail
23
23
24# Combine
24# Combine
25@docs union, intersect, diff
25@docs union, intersect, diff
@@ -96,7 +96,7 @@ dictionary.
96 get "Mouse" animals == Just Mouse
96 get "Mouse" animals == Just Mouse
97 get "Spike" animals == Nothing
97 get "Spike" animals == Nothing
98
98
99−The `getSafe` and `getUnsafe` are built-in ways to handle common ways of
99+The `getOrElse` and `getOrFail` are built-in ways to handle common ways of
100using the resulting `Maybe`.
100using the resulting `Maybe`.
101-}
101-}
102get : comparable -> Dict comparable v -> Maybe v
102get : comparable -> Dict comparable v -> Maybe v
@@ -114,41 +114,41 @@ return a default value.
114
114
115 animals = fromList [ ("Tom", Cat), ("Jerry", Mouse) ]
115 animals = fromList [ ("Tom", Cat), ("Jerry", Mouse) ]
116
116
117− getSafe Dog "Tom" animals == Cat
117+ getOrElse Dog "Tom" animals == Cat
118− getSafe Dog "Mouse" animals == Mouse
118+ getOrElse Dog "Mouse" animals == Mouse
119− getSafe Dog "Spike" animals == Dog
119+ getOrElse Dog "Spike" animals == Dog
120-}
120-}
121−getSafe : v -> comparable -> Dict comparable v -> v
121+getOrElse : v -> comparable -> Dict comparable v -> v
122−getSafe base k t =
122+getOrElse base k t =
123 case t of
123 case t of
124 RBEmpty LBlack -> base
124 RBEmpty LBlack -> base
125 RBNode _ k' v l r ->
125 RBNode _ k' v l r ->
126 case Native.Utils.compare k k' of
126 case Native.Utils.compare k k' of
127− LT -> getSafe base k l
127+ LT -> getOrElse base k l
128 EQ -> v
128 EQ -> v
129− GT -> getSafe base k r
129+ GT -> getOrElse base k r
130
130
131{-| Get the value associated with a key.
131{-| Get the value associated with a key.
132
132
133 animals = fromList [ ("Tom", Cat), ("Jerry", Mouse) ]
133 animals = fromList [ ("Tom", Cat), ("Jerry", Mouse) ]
134
134
135− get "Tom" animals == Cat
135+ getOrFail "Tom" animals == Cat
136− get "Mouse" animals == Mouse
136+ getOrFail "Mouse" animals == Mouse
137− get "Spike" animals == -- Runtime Error!
137+ getOrFail "Spike" animals == -- Runtime Error!
138
138
139Warning: this function will result in a runtime error if the key is not found,
139Warning: this function will result in a runtime error if the key is not found,
140−so it is best to use `get` or `getSafe` unless you are very confident the key
140+so it is best to use `get` or `getOrElse` unless you are sure the key will be
141−will be found.
141+found.
142-}
142-}
143−getUnsafe : comparable -> Dict comparable v -> v
143+getOrFail : comparable -> Dict comparable v -> v
144−getUnsafe k t =
144+getOrFail k t =
145 case t of
145 case t of
146− RBEmpty LBlack -> Native.Error.raise "key not found when using 'getUnsafe'"
146+ RBEmpty LBlack -> Native.Error.raise "key not found when using 'getOrFail'"
147 RBNode _ k' v l r ->
147 RBNode _ k' v l r ->
148 case Native.Utils.compare k k' of
148 case Native.Utils.compare k k' of
149− LT -> getUnsafe k l
149+ LT -> getOrFail k l
150 EQ -> v
150 EQ -> v
151− GT -> getUnsafe k r
151+ GT -> getOrFail k r
152
152
153{-| Determine if a key is in a dictionary. -}
153{-| Determine if a key is in a dictionary. -}
154member : comparable -> Dict comparable v -> Bool
154member : comparable -> Dict comparable v -> Bool
libraries/List.elm+18−14
@@ -171,11 +171,11 @@ not.
171 partition isEven [0..5] == ([0,2,4], [1,3,5])
171 partition isEven [0..5] == ([0,2,4], [1,3,5])
172-}
172-}
173partition : (a -> Bool) -> [a] -> ([a],[a])
173partition : (a -> Bool) -> [a] -> ([a],[a])
174−partition pred lst =
174+partition pred =
175− case lst of
175+ let step x (ts, fs) = if pred x
176− [] -> ([],[])
176+ then (x::ts, fs)
177− x::xs -> let (bs,cs) = partition pred xs in
177+ else (ts, x::fs)
178− if pred x then (x::bs,cs) else (bs,x::cs)
178+ in foldr step ([],[])
179
179
180{-| Combine two lists, combining them into tuples pairwise.
180{-| Combine two lists, combining them into tuples pairwise.
181If one list is longer, the extra elements are dropped.
181If one list is longer, the extra elements are dropped.
@@ -194,12 +194,14 @@ If one list is longer, the extra elements are dropped.
194zipWith : (a -> b -> c) -> [a] -> [b] -> [c]
194zipWith : (a -> b -> c) -> [a] -> [b] -> [c]
195zipWith = Native.List.zipWith
195zipWith = Native.List.zipWith
196
196
197−{-| 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+-}
198unzip : [(a,b)] -> ([a],[b])
201unzip : [(a,b)] -> ([a],[b])
199−unzip pairs =
202+unzip =
200− case pairs of
203+ let step (x,y) (xs, ys) = (x::xs, y::ys)
201− [] -> ([],[])
204+ in foldr step ([], [])
202− (x,y)::ps -> let (xs,ys) = (unzip ps) in (x::xs,y::ys)
203
205
204{-| 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
205argument and concatenates the result.
207argument and concatenates the result.
@@ -215,10 +217,12 @@ join = Native.List.join
215-}
217-}
216intersperse : a -> [a] -> [a]
218intersperse : a -> [a] -> [a]
217intersperse sep xs =
219intersperse sep xs =
218− case xs of
220+ case xs of
219− a::b::cs -> a :: sep :: intersperse sep (b::cs)
221+ [] -> []
220− [a] -> [a]
222+ hd::tl ->
221− [] -> []
223+ let step x rest = sep :: x :: rest
224+ spersed = foldr step [] tl
225+ in hd :: spersed
222
226
223{-| 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])` -}
224take : Int -> [a] -> [a]
228take : Int -> [a] -> [a]
libraries/Native/Array.js+72−27
@@ -1,4 +1,4 @@
1−Elm.Native.Array = {};
1+Elm.Native.Array = {};
2Elm.Native.Array.make = function(elm) {
2Elm.Native.Array.make = function(elm) {
3 elm.Native = elm.Native || {};
3 elm.Native = elm.Native || {};
4 elm.Native.Array = elm.Native.Array || {};
4 elm.Native.Array = elm.Native.Array || {};
@@ -24,7 +24,6 @@ Elm.Native.Array.make = function(elm) {
24 // An empty array.
24 // An empty array.
25 var empty = { ctor:"_Array", height:0, table:new Array() };
25 var empty = { ctor:"_Array", height:0, table:new Array() };
26
26
27− // Gets the value at index i recursively.
28 function get(i, array) {
27 function get(i, array) {
29 if (i < 0 || i >= length(array)) {
28 if (i < 0 || i >= length(array)) {
30 throw new Error("Index " + i + " is out of range. Check the length of " +
29 throw new Error("Index " + i + " is out of range. Check the length of " +
@@ -34,31 +33,39 @@ Elm.Native.Array.make = function(elm) {
34 }
33 }
35
34
36 function unsafeGet(i, array) {
35 function unsafeGet(i, array) {
37− if (array.height == 0) {
36+ for (var x = array.height; x > 0; x--) {
38− return array.table[i];
37+ var slot = i >> (x * 5);
38+ if (slot > 0) {
39+ while (array.lengths[slot - 1] > i) { slot--; }
40+ i -= array.lengths[slot - 1];
39 }
41 }
40− var slot = getSlot(i, array);
42+ array = array.table[slot];
41− var offset = slot > 0 ? array.lengths[slot-1] : 0;
43+ }
42− return unsafeGet(i - offset, array.table[slot]);
44+ return array.table[i];
43 }
45 }
44
46
45 // Sets the value at the index i. Only the nodes leading to i will get
47 // Sets the value at the index i. Only the nodes leading to i will get
46 // copied and updated.
48 // copied and updated.
47− function set(i, item, a) {
49+ function set(i, item, array) {
48− if (length(a) <= i) {
50+ if (i < 0 || length(array) <= i) {
49− return a;
51+ return array;
50 }
52 }
51− var newA = nodeCopy(a);
53+ return unsafeSet(i, item, array);
52− newA.table = a.table.slice();
54+ }
53
55
56+ function unsafeSet(i, item, array) {
57+ array = nodeCopy(array);
58+
54− if (a.height == 0) {
59+ if (array.height == 0) {
55− newA.table[i] = item;
60+ array.table[i] = item;
56 } else {
61 } else {
57− var slot = getSlot(i, a);
62+ var slot = getSlot(i, array);
63+ if (slot > 0) {
58− var sub = slot > 0 ? a.lengths[slot-1] : 0;
64+ i -= array.lengths[slot - 1];
65+ }
59− newA.table[slot] = set(i - sub, item, a.table[slot]);
66+ array.table[slot] = unsafeSet(i, item, array.table[slot]);
60 }
67 }
61− return newA;
68+ return array;
62 }
69 }
63
70
64 function initialize(len, f) {
71 function initialize(len, f) {
@@ -255,9 +262,6 @@ Elm.Native.Array.make = function(elm) {
255 return b;
262 return b;
256 }
263 }
257
264
258− // Returns a sliced tree. "to" is inclusive, but this may change,
259− // when I understand, why e.g. JS does not handle it this way. :-)
260− // If "from" or "to" is negative, they will select from the end on.
261 // TODO: currently, it slices the right, then the left. This can be
265 // TODO: currently, it slices the right, then the left. This can be
262 // optimized.
266 // optimized.
263 function slice(from, to, a) {
267 function slice(from, to, a) {
@@ -274,7 +278,7 @@ Elm.Native.Array.make = function(elm) {
274 // Handle leaf level.
278 // Handle leaf level.
275 if (a.height == 0) {
279 if (a.height == 0) {
276 var newA = { ctor:"_Array", height:0 };
280 var newA = { ctor:"_Array", height:0 };
277− newA.table = a.table.slice(0, to + 1);
281+ newA.table = a.table.slice(0, to);
278 return newA;
282 return newA;
279 }
283 }
280
284
@@ -533,10 +537,8 @@ Elm.Native.Array.make = function(elm) {
533 // Calculates in which slot of "table" the item probably is, then
537 // Calculates in which slot of "table" the item probably is, then
534 // find the exact slot via forward searching in "lengths". Returns the index.
538 // find the exact slot via forward searching in "lengths". Returns the index.
535 function getSlot(i, a) {
539 function getSlot(i, a) {
536− var slot = Math.floor(i / (Math.pow(M, a.height)));
540+ var slot = i >> (5 * a.height);
537− while (a.lengths[slot] <= i) {
541+ while (a.lengths[slot - 1] > i) { slot--; }
538− slot++
539− }
540 return slot;
542 return slot;
541 }
543 }
542
544
@@ -571,6 +573,46 @@ Elm.Native.Array.make = function(elm) {
571 , lengths:[length(a), length(a) + length(b)] };
573 , lengths:[length(a), length(a) + length(b)] };
572 }
574 }
573
575
576+ function toJSArray(a) {
577+ var jsArray = new Array(length(a));
578+ toJSArray_(jsArray, 0, a);
579+ return jsArray;
580+ }
581+
582+ function toJSArray_(jsArray, i, a) {
583+ for (var t = 0; t < a.table.length; t++) {
584+ if (a.height == 0) {
585+ jsArray[i + t] = a.table[t];
586+ } else {
587+ var inc = t == 0 ? 0 : a.lengths[t - 1];
588+ toJSArray_(jsArray, i + inc, a.table[t]);
589+ }
590+ }
591+ }
592+
593+ function fromJSArray(jsArray) {
594+ if (jsArray.length == 0) { return empty; }
595+ var h = Math.floor(Math.log(jsArray.length) / Math.log(M));
596+ return fromJSArray_(jsArray, h, 0, jsArray.length);
597+ }
598+
599+ function fromJSArray_(jsArray, h, from, to) {
600+ if (h == 0) {
601+ return { ctor:"_Array", height:0
602+ , table:jsArray.slice(from, to) };
603+ }
604+
605+ var step = Math.pow(M, h);
606+ var table = new Array(Math.ceil((to - from) / step));
607+ var lengths = new Array(table.length);
608+ for (var i = 0; i < table.length; i++) {
609+ table[i] = fromJSArray_( jsArray, h - 1, from + (i * step)
610+ , Math.min(from + ((i + 1) * step), to));
611+ lengths[i] = length(table[i]) + (i > 0 ? lengths[i-1] : 0);
612+ }
613+ return { ctor:"_Array", height:h, table:table, lengths:lengths };
614+ }
615+
574 Elm.Native.Array.values = {
616 Elm.Native.Array.values = {
575 empty:empty,
617 empty:empty,
576 fromList:fromList,
618 fromList:fromList,
@@ -585,7 +627,10 @@ Elm.Native.Array.make = function(elm) {
585 indexedMap:F2(indexedMap),
627 indexedMap:F2(indexedMap),
586 foldl:F3(foldl),
628 foldl:F3(foldl),
587 foldr:F3(foldr),
629 foldr:F3(foldr),
588− length:length
630+ length:length,
631+
632+ toJSArray:toJSArray,
633+ fromJSArray:fromJSArray
589 };
634 };
590
635
591 return elm.Native.Array.values = Elm.Native.Array.values;
636 return elm.Native.Array.values = Elm.Native.Array.values;
libraries/Native/Error.js+2−4
@@ -4,8 +4,6 @@ Elm.Native.Error.make = function(elm) {
4 elm.Native.Error = elm.Native.Error || {};
4 elm.Native.Error = elm.Native.Error || {};
5 if (elm.Native.Error.values) return elm.Native.Error.values;
5 if (elm.Native.Error.values) return elm.Native.Error.values;
6
6
7− var fromString = Elm.Native.JavaScript.make(elm).fromString;
8−
9 function indent(lines) {
7 function indent(lines) {
10 var msg = '';
8 var msg = '';
11 for (var i = 0; i < lines.length; ++i) {
9 for (var i = 0; i < lines.length; ++i) {
@@ -26,7 +24,7 @@ Elm.Native.Error.make = function(elm) {
26 throw new Error('Runtime error in module ' + moduleName + ' (' + span + '):' + msg);
24 throw new Error('Runtime error in module ' + moduleName + ' (' + span + '):' + msg);
27 }
25 }
28
26
29− function raise(str) { throw new Error(fromString(str)); }
27+ function raise(str) { throw new Error(str); }
30
28
31 return elm.Native.Error.values = { Case: Case, If: If, raise: raise };
29 return elm.Native.Error.values = { Case: Case, If: If, raise: raise };
32−};
30+};
libraries/Native/String.js+2−2
@@ -73,7 +73,7 @@ Elm.Native.String.make = function(elm) {
73 return result;
73 return result;
74 }
74 }
75
75
76− function sub(start, end, str) {
76+ function slice(start, end, str) {
77 return str.slice(start,end);
77 return str.slice(start,end);
78 }
78 }
79 function left(n, str) {
79 function left(n, str) {
@@ -216,7 +216,7 @@ Elm.Native.String.make = function(elm) {
216 join: F2(join),
216 join: F2(join),
217 repeat: F2(repeat),
217 repeat: F2(repeat),
218
218
219− sub: F3(sub),
219+ slice: F3(slice),
220 left: F2(left),
220 left: F2(left),
221 right: F2(right),
221 right: F2(right),
222 dropLeft: F2(dropLeft),
222 dropLeft: F2(dropLeft),
libraries/Native/Utils.js+21−14
@@ -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− }
20− if (typeof x === 'function') {
21− throw new Error('Equality error: general function equality is ' +
22− 'undecidable, and therefore, unsupported');
23 }
30 }
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
libraries/String.elm+8−8
@@ -6,10 +6,10 @@ are enclosed in `"double quotes"`. Strings are *not* lists of characters.
6@docs isEmpty, length, reverse, repeat
6@docs isEmpty, length, reverse, repeat
7
7
8# Building and Splitting
8# Building and Splitting
9−@docs cons, uncons, append, concat, split, join, words, lines
9+@docs cons, uncons, append, concat, split, join, words, lines
10
10
11# Get Substrings
11# Get Substrings
12−@docs sub, left, right, dropLeft, dropRight
12+@docs slice, left, right, dropLeft, dropRight
13
13
14# Check for Substrings
14# Check for Substrings
15@docs contains, startsWith, endsWith, indexes, indices
15@docs contains, startsWith, endsWith, indexes, indices
@@ -139,13 +139,13 @@ repeat = Native.String.repeat
139{-| Take a substring given a start and end index. Negative indexes
139{-| Take a substring given a start and end index. Negative indexes
140are taken starting from the *end* of the list.
140are taken starting from the *end* of the list.
141
141
142− sub 7 9 "snakes on a plane!" == "on"
142+ slice 7 9 "snakes on a plane!" == "on"
143− sub 0 6 "snakes on a plane!" == "snakes"
143+ slice 0 6 "snakes on a plane!" == "snakes"
144− sub 0 -7 "snakes on a plane!" == "snakes on a"
144+ slice 0 -7 "snakes on a plane!" == "snakes on a"
145− sub -6 -1 "snakes on a plane!" == "plane"
145+ slice -6 -1 "snakes on a plane!" == "plane"
146-}
146-}
147−sub : Int -> Int -> String -> String
147+slice : Int -> Int -> String -> String
148−sub = Native.String.sub
148+slice = Native.String.slice
149
149
150{-| Take N characters from the left side of a string. -}
150{-| Take N characters from the left side of a string. -}
151left : Int -> String -> String
151left : Int -> String -> String
libraries/elm_dependencies.json+6−5
@@ -1,12 +1,13 @@
1−{ "version": "0.12"
1+{ "version": "0.12.1"
2, "summary": "Elm's standard libraries"
2, "summary": "Elm's standard libraries"
3−, "description": "The full set of standard libraries for Elm. This library is pegged to the version number of the compiler, so if you are using Elm 0.12, you should be using version 0.12 of the standard libraries."
3+, "description": "The full set of standard libraries for Elm. This library is pegged to the version number of the compiler, so if you are using Elm 0.12.1, you should be using version 0.12.1 of the standard libraries."
4, "license": "BSD3"
4, "license": "BSD3"
5−, "repository": "http://github.com/evancz/Elm.git"
5+, "repository": "http://github.com/elm-lang/Elm.git"
6−, "elm-version": "0.12"
6+, "elm-version": "0.12.1"
7, "dependencies": {}
7, "dependencies": {}
8, "exposed-modules":
8, "exposed-modules":
9+ [ "Array"
9− [ "Basics"
10+ , "Basics"
10 , "Bitwise"
11 , "Bitwise"
11 , "Char"
12 , "Char"
12 , "Color"
13 , "Color"
tests/elm/Test.elm+13−5
@@ -9,13 +9,21 @@ import IO.IO (..)
9import IO.Runner (Request, Response)
9import IO.Runner (Request, Response)
10import IO.Runner as Run
10import IO.Runner as Run
11
11
12−import Test.String as String
13−import Test.Trampoline as Trampoline
14import Test.Array as Array
12import Test.Array as Array
15import Test.Dict as Dict
13import Test.Dict as Dict
16−
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+
17−tests : [Test]
19+tests : Test
20+tests = suite "Elm Standard Library Tests" [ List.tests,
21+ String.tests,
18−tests = String.tests ++ Trampoline.tests ++ Array.tests ++ Dict.tests
22+ Trampoline.tests,
23+ Array.tests,
24+ Dict.tests,
25+ Set.tests
26+ ]
19
27
20console : IO ()
28console : IO ()
21console = runDisplay tests
29console = runDisplay tests
tests/elm/Test/Array.elm+37−29
@@ -2,13 +2,14 @@ module Test.Array (tests) where
2
2
3import List
3import List
4import Array
4import Array
5+import Native.Array
5
6
6import ElmTest.Assertion (..)
7import ElmTest.Assertion (..)
7import ElmTest.Test (..)
8import ElmTest.Test (..)
8
9
9−tests : [Test]
10+tests : Test
10tests =
11tests =
11− let creationTests =
12+ let creationTests = suite "Creation"
12 [ test "empty" <| assertEqual Array.empty (Array.fromList [])
13 [ test "empty" <| assertEqual Array.empty (Array.fromList [])
13 , test "initialize" <| assertEqual (Array.initialize 4 id) (Array.fromList [0,1,2,3])
14 , 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 2" <| assertEqual (Array.initialize 4 (\n -> n*n)) (Array.fromList [0,1,4,9])
@@ -20,35 +21,42 @@ tests =
20 , test "repeat 3" <| assertEqual (Array.repeat 3 "cat") (Array.fromList ["cat","cat","cat"])
21 , test "repeat 3" <| assertEqual (Array.repeat 3 "cat") (Array.fromList ["cat","cat","cat"])
21 , test "fromList" <| assertEqual (Array.fromList []) Array.empty
22 , test "fromList" <| assertEqual (Array.fromList []) Array.empty
22 ]
23 ]
23− basicsTests =
24+ basicsTests = suite "Basics"
24− [ test "length" <| assertEqual (Array.length (Array.fromList [1,2,3])) 3
25+ [ test "length" <| assertEqual 3 (Array.length (Array.fromList [1,2,3]))
25− , test "length - Long" <| assertEqual (Array.length (Array.repeat 10000 0)) 10000
26+ , test "length - Long" <| assertEqual 10000 (Array.length (Array.repeat 10000 0))
26− , test "push" <| assertEqual (Array.push 3 (Array.fromList [1,2])) (Array.fromList [1,2,3])
27+ , test "push" <| assertEqual (Array.fromList [1,2,3]) (Array.push 3 (Array.fromList [1,2]))
27− , test "append" <| assertEqual (Array.toList <| Array.append (Array.repeat 2 42) (Array.repeat 3 81)) ([42,42,81,81,81])
28+ , test "append" <| assertEqual [42,42,81,81,81] (Array.toList (Array.append (Array.repeat 2 42) (Array.repeat 3 81)))
28 ]
29 ]
29− getAndSetTests =
30+ getAndSetTests = suite "Get and Set"
30− [ test "get" <| assertEqual (Array.get 1 (Array.fromList [3,2,1])) (Just 2)
31+ [ test "get" <| assertEqual (Just 2) (Array.get 1 (Array.fromList [3,2,1]))
31− , test "get 2" <| assertEqual (Array.get 5 (Array.fromList [3,2,1])) Nothing
32+ , test "get 2" <| assertEqual Nothing (Array.get 5 (Array.fromList [3,2,1]))
32− , test "get 3" <| assertEqual (Array.get -1 (Array.fromList [3,2,1])) Nothing
33+ , test "get 3" <| assertEqual Nothing (Array.get -1 (Array.fromList [3,2,1]))
33− , test "getSafe 1" <| assertEqual (Array.getSafe 0 2 (Array.fromList [3,2,1])) 1
34+ , test "getOrElse 1" <| assertEqual 1 (Array.getOrElse 0 2 (Array.fromList [3,2,1]))
34− , test "getSafe 2" <| assertEqual (Array.getSafe 0 5 (Array.fromList [3,2,1])) 0
35+ , test "getOrElse 2" <| assertEqual 0 (Array.getOrElse 0 5 (Array.fromList [3,2,1]))
35− , test "getUnsafe" <| assertEqual (Array.getUnsafe 2 (Array.fromList [3,2,1])) 1
36+ , test "getOrFail" <| assertEqual 1 (Array.getOrFail 2 (Array.fromList [3,2,1]))
36− , test "set" <| assertEqual (Array.set 1 7 (Array.fromList [1,2,3])) (Array.fromList [1,7,3])
37+ , test "set" <| assertEqual (Array.fromList [1,7,3]) (Array.set 1 7 (Array.fromList [1,2,3]))
37 ]
38 ]
38− takingArraysApartTests =
39+ takingArraysApartTests = suite "Taking Arrays Apart"
39− [ test "toList" <| assertEqual (Array.toList (Array.fromList [3,5,8])) [3,5,8]
40+ [ test "toList" <| assertEqual [3,5,8] (Array.toList (Array.fromList [3,5,8]))
40− , test "toIndexedList" <| assertEqual (Array.toIndexedList (Array.fromList ["cat","dog"])) [(0,"cat"), (1,"dog")]
41+ , test "toIndexedList" <| assertEqual [(0,"cat"), (1,"dog")] (Array.toIndexedList (Array.fromList ["cat","dog"]))
41− , test "slice" <| assertEqual (Array.slice 1 2 (Array.fromList [0,1,2,3,4])) (Array.fromList [1,2])
42+ , test "slice 1" <| assertEqual (Array.fromList [0,1,2]) (Array.slice 0 3 (Array.fromList [0,1,2,3,4]))
42− , test "slice 2" <| assertEqual (Array.slice 1 -2 (Array.fromList [0,1,2,3,4])) (Array.fromList [1,2,3])
43+ , test "slice 2" <| assertEqual (Array.fromList [1,2,3]) (Array.slice 1 4 (Array.fromList [0,1,2,3,4]))
44+ , test "slice 3" <| assertEqual (Array.fromList [1,2,3]) (Array.slice 1 -1 (Array.fromList [0,1,2,3,4]))
43− , test "slice 3" <| assertEqual (Array.slice -3 -2 (Array.fromList [0,1,2,3,4])) (Array.fromList [2,3])
45+ , test "slice 4" <| assertEqual (Array.fromList [2]) (Array.slice -3 -2 (Array.fromList [0,1,2,3,4]))
44 ]
46 ]
45− mappingAndFoldingTests =
47+ mappingAndFoldingTests = suite "Mapping and Folding"
46− [ test "map" <| assertEqual (Array.map sqrt (Array.fromList [1,4,9])) (Array.fromList [1,2,3])
48+ [ test "map" <| assertEqual (Array.fromList [1,2,3]) (Array.map sqrt (Array.fromList [1,4,9]))
47− , test "indexedMap" <| assertEqual (Array.indexedMap (*) (Array.fromList [5,5,5])) (Array.fromList [0,5,10])
49+ , test "indexedMap" <| assertEqual (Array.fromList [0,5,10]) (Array.indexedMap (*) (Array.fromList [5,5,5]))
48− , test "foldl" <| assertEqual (Array.foldl (::) [] (Array.fromList [1,2,3])) [3,2,1]
50+ , test "foldl" <| assertEqual [3,2,1] (Array.foldl (::) [] (Array.fromList [1,2,3]))
49− , test "foldr" <| assertEqual (Array.foldr (+) 0 (Array.repeat 3 5)) 15
51+ , test "foldr 1" <| assertEqual 15 (Array.foldr (+) 0 (Array.repeat 3 5))
50− , test "foldr 2" <| assertEqual (Array.foldr (::) [] (Array.fromList [1,2,3])) [1,2,3]
52+ , test "foldr 2" <| assertEqual [1,2,3] (Array.foldr (::) [] (Array.fromList [1,2,3]))
51− , test "filter" <| assertEqual (Array.filter (\x -> x `mod` 2 == 0) (Array.fromList [1..6])) (Array.fromList [2,4,6])
53+ , test "filter" <| assertEqual (Array.fromList [2,4,6]) (Array.filter (\x -> x `mod` 2 == 0) (Array.fromList [1..6]))
54+ ]
55+ nativeTests = suite "Conversion to JS Arrays"
56+ [ test "jsArrays" <| assertEqual (Array.fromList [1..1100]) (Native.Array.fromJSArray (Native.Array.toJSArray (Array.fromList [1..1100])))
52 ]
57 ]
53 in
58 in
59+ suite "Array"
60+ [ creationTests, basicsTests, getAndSetTests
54− List.concat [creationTests, basicsTests, getAndSetTests, takingArraysApartTests, mappingAndFoldingTests]
61+ , takingArraysApartTests, mappingAndFoldingTests, nativeTests
62+ ]
tests/elm/Test/Dict.elm+5−5
@@ -9,18 +9,18 @@ import ElmTest.Test (..)
9animals : Dict.Dict String String
9animals : Dict.Dict String String
10animals = Dict.fromList [ ("Tom", "cat"), ("Jerry", "mouse") ]
10animals = Dict.fromList [ ("Tom", "cat"), ("Jerry", "mouse") ]
11
11
12−tests : [Test]
12+tests : Test
13tests =
13tests =
14 let getTests =
14 let getTests =
15 [ test "get 1" <| assertEqual (Just "cat") (Dict.get "Tom" animals)
15 [ test "get 1" <| assertEqual (Just "cat") (Dict.get "Tom" animals)
16 , test "get 2" <| assertEqual Nothing (Dict.get "Spike" animals)
16 , test "get 2" <| assertEqual Nothing (Dict.get "Spike" animals)
17− , test "getSafe 1" <| assertEqual "mouse" (Dict.getSafe "dog" "Jerry" animals)
17+ , test "getOrElse 1" <| assertEqual "mouse" (Dict.getOrElse "dog" "Jerry" animals)
18− , test "getSafe 2" <| assertEqual "dog" (Dict.getSafe "dog" "Spike" animals)
18+ , test "getOrElse 2" <| assertEqual "dog" (Dict.getOrElse "dog" "Spike" animals)
19− , test "getUnsafe" <| assertEqual "cat" (Dict.getUnsafe "Tom" animals)
19+ , test "getOrFail" <| assertEqual "cat" (Dict.getOrFail "Tom" animals)
20 ]
20 ]
21 filterTests =
21 filterTests =
22 [ test "filter" <| assertEqual (Dict.singleton "Tom" "cat") (Dict.filter (\k v -> k == "Tom") animals)
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)
23 , test "partition" <| assertEqual (Dict.singleton "Tom" "cat", Dict.singleton "Jerry" "mouse") (Dict.partition (\k v -> k == "Tom") animals)
24 ]
24 ]
25 in
25 in
26− List.concat [ getTests, filterTests ]
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.elm+8−7
@@ -1,26 +1,27 @@
1module Test.Set (tests) where
1module Test.Set (tests) where
2
2
3import Set
3import Set
4+import Set (Set)
4import List
5import List
5
6
6import ElmTest.Assertion (..)
7import ElmTest.Assertion (..)
7import ElmTest.Test (..)
8import ElmTest.Test (..)
8
9
9−set : Set
10+set : Set Int
10set = Set.fromList [1..100]
11set = Set.fromList [1..100]
11
12
12−setPart1 : Set
13+setPart1 : Set Int
13setPart1 = Set.fromList [1..50]
14setPart1 = Set.fromList [1..50]
14
15
15−setPart2 : Set
16+setPart2 : Set Int
16setPart2 = Set.fromList [51..100]
17setPart2 = Set.fromList [51..100]
17
18
18pred : Int -> Bool
19pred : Int -> Bool
19pred x = x <= 50
20pred x = x <= 50
20
21
21−tests : [Test]
22+tests : Test
22tests =
23tests =
23 let
24 let
24− filterTests = [assertEqual setPart1 <| filter pred set]
25+ filterTests = suite "filter Tests" [test "Simple filter" <| assertEqual setPart1 <| Set.filter pred set]
25− partitionTests = [assertEqual (setPart1, setPart2) <| partition pred set]
26+ partitionTests = suite "partition Tests" [test "Simple partition" <| assertEqual (setPart1, setPart2) <| Set.partition pred set]
26− in List.concat [partitionTests, filterTests]
27+ in suite "Set Tests" [partitionTests, filterTests]
tests/elm/Test/String.elm+28−17
@@ -6,21 +6,32 @@ import String (..)
6import ElmTest.Assertion (..)
6import ElmTest.Assertion (..)
7import ElmTest.Test (..)
7import ElmTest.Test (..)
8
8
9−tests : [Test]
9+tests : Test
10tests =
10tests =
11+ let simpleTests = suite "Simple Stuff"
11− let isEmptyTests = [test "empty is empty" <| assert <| isEmpty "",
12+ [ test "is empty" <| assert (isEmpty "")
12− test "not empty" <| assert <| not . isEmpty <| "the world"]
13+ , test "is not empty" <| assert (not (isEmpty ("the world")))
13− lengthTest = test "length of innumerable" <| assertEqual 11 (length "innumerable")
14+ , test "length" <| assertEqual 11 (length "innumerable")
15+ , test "endsWith" (assert <| endsWith "ship" "spaceship")
14− reverseTest = test "reverse test" <| assertEqual "desserts" (reverse "stressed")
16+ , test "reverse" <| assertEqual "desserts" (reverse "stressed")
15− repeatTest = test "repeat test" <| assertEqual "hahaha" (repeat 3 "ha")
17+ , test "repeat" <| assertEqual "hahaha" (repeat 3 "ha")
18+ ]
19+
20+ combiningTests = suite "Combining Strings"
16− unconsTests = [test "nonempty uncons" <| assertEqual (Just ('a',"bc")) (uncons "abc"),
21+ [ test "uncons non-empty" <| assertEqual (Just ('a',"bc")) (uncons "abc")
17− test "empty uncons" <| assertEqual Nothing (uncons "")]
22+ , test "uncons empty" <| assertEqual Nothing (uncons "")
18− appendTest = test "append test" <| assertEqual "butterfly" (append "butter" "fly")
23+ , test "append 1" <| assertEqual "butterfly" (append "butter" "fly")
24+ , test "append 2" <| assertEqual "butter" (append "butter" "")
25+ , test "append 3" <| assertEqual "butter" (append "" "butter")
19− concatTest = test "concat test" <| assertEqual "nevertheless" (concat ["never","the","less"])
26+ , test "concat" <| assertEqual "nevertheless" (concat ["never","the","less"])
20− splitTests = [test "split commas" <| assertEqual ["cat","dog","cow"] (split "," "cat,dog,cow"),
27+ , test "split commas" <| assertEqual ["cat","dog","cow"] (split "," "cat,dog,cow")
21− test "split slashes"<| assertEqual ["home","evan","Desktop", ""] (split "/" "home/evan/Desktop/")]
28+ , test "split slashes"<| assertEqual ["home","steve","Desktop", ""] (split "/" "home/steve/Desktop/")
22− joinTests = [test "join spaces" <| assertEqual "cat dog cow" (join " " ["cat","dog","cow"]),
29+ , test "join spaces" <| assertEqual "cat dog cow" (join " " ["cat","dog","cow"])
23− test "join slashes" <| assertEqual "home/evan/Desktop" (join "/" ["home","evan","Desktop"])]
30+ , test "join slashes" <| assertEqual "home/steve/Desktop" (join "/" ["home","steve","Desktop"])
24−
31+ , test "slice 1" <| assertEqual "c" (slice 2 3 "abcd")
25− endsWithTest = test "endsWith Check" (assert <| endsWith "h" "th")
32+ , test "slice 2" <| assertEqual "abc" (slice 0 3 "abcd")
26− in List.concat [isEmptyTests, [lengthTest, reverseTest, repeatTest], unconsTests, [appendTest, concatTest], splitTests, joinTests, [endsWithTest]]
33+ , test "slice 3" <| assertEqual "abc" (slice 0 -1 "abcd")
34+ , test "slice 4" <| assertEqual "cd" (slice -2 4 "abcd")
35+ ]
36+ in
37+ suite "String" [ simpleTests, combiningTests ]
tests/elm/Test/Trampoline.elm+3−3
@@ -21,9 +21,9 @@ goodSum n =
21 _ -> Continue (\_ -> sumT (x-1) (acc+x))
21 _ -> Continue (\_ -> sumT (x-1) (acc+x))
22 in trampoline <| sumT n 0
22 in trampoline <| sumT n 0
23
23
24−tests : [Test]
24+tests : Test
25tests =
25tests =
26 let mkLoopCheck n = test ("Equivalent Loop Check #"++ show n) (assertEqual (badSum n) (goodSum n))
26 let mkLoopCheck n = test ("Equivalent Loop Check #"++ show n) (assertEqual (badSum n) (goodSum n))
27− loopChecks = map mkLoopCheck [0..25]
27+ loopChecks = suite "Equivalent to untrampolined Tests" <| map mkLoopCheck [0..25]
28 noStackOverflow = test "Trampoline Deep Recursion Test" (assertEqual 500000500000 (goodSum 1000000))
28 noStackOverflow = test "Trampoline Deep Recursion Test" (assertEqual 500000500000 (goodSum 1000000))
29− in noStackOverflow :: loopChecks
29+ in suite "Trampoline Tests" [noStackOverflow, loopChecks]
tests/hs/LibTest.hs+5−2
@@ -1,5 +1,7 @@
1module Main where
1module Main where
2
2
3+import Control.Monad (unless)
4+import Data.List (isInfixOf)
3import System.Directory
5import System.Directory
4import System.Exit
6import System.Exit
5import System.FilePath
7import System.FilePath
@@ -11,8 +13,9 @@ main :: IO ()
11main = do
13main = do
12 top <- getCurrentDirectory
14 top <- getCurrentDirectory
13 let ioScript s = top</>"IO"</>s
15 let ioScript s = top</>"IO"</>s
14− runCmd "git submodule init"
16+ runCmd "git submodule update --init"
17+ out <- readProcess "npm" ["ls", "--parseable"] ""
15− runCmd "npm install jsdom"
18+ unless ("jsdom" `isInfixOf` out) $ runCmd "npm install jsdom"
16 setCurrentDirectory $ top</>"tests"</>"elm"
19 setCurrentDirectory $ top</>"tests"</>"elm"
17 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"]
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"]
18 runCmd $ unwords ["cat ", ioScript "prescript.js", Elm.runtime, "build"</>"Test.js", ioScript "handler.js", "> exe.js"]
21 runCmd $ unwords ["cat ", ioScript "prescript.js", Elm.runtime, "build"</>"Test.js", ioScript "handler.js", "> exe.js"]