on master help sign in
Merge branch 'master' into debugger
cf895bcEvan Czaplicki
Elm.cabal+89−89
@@ -99,29 +99,29 @@ Library
99 Build.Utils,
99 Build.Utils,
100 Paths_Elm
100 Paths_Elm
101
101
102− Build-depends: aeson,
102+ Build-depends: aeson >= 0.7 && < 0.9,
103− aeson-pretty,
103+ aeson-pretty >= 0.7 && < 0.8,
104 base >=4.2 && <5,
104 base >=4.2 && <5,
105− binary >= 0.7.0.0,
105+ binary >= 0.7.0.0 && < 0.8,
106 blaze-html >= 0.5 && < 0.8,
106 blaze-html >= 0.5 && < 0.8,
107− blaze-markup,
107+ blaze-markup >= 0.5.1 && < 0.7,
108− bytestring,
108+ bytestring >= 0.9 && < 0.11,
109− cheapskate,
109+ cheapskate >= 0.1 && < 0.2,
110− cmdargs,
110+ cmdargs >= 0.7 && < 0.11,
111− containers >= 0.3,
111+ containers >= 0.3 && < 0.6,
112− directory,
112+ directory >= 1.0 && < 2.0,
113− filepath,
113+ filepath >= 1 && < 2.0,
114− highlighting-kate,
114+ highlighting-kate >= 0.5 && < 0.6,
115− indents,
115+ indents >= 0.3 && < 0.4,
116− language-ecmascript >=0.15 && < 1.0,
116+ language-ecmascript >=0.15 && < 0.17,
117− language-glsl >= 0.0.2,
117+ language-glsl >= 0.0.2 && < 0.1,
118− mtl >= 2,
118+ mtl >= 2 && < 3,
119− parsec >= 3.1.1,
119+ parsec >= 3.1.1 && < 3.5,
120− pretty,
120+ pretty >= 1.0 && < 2.0,
121− text,
121+ text >= 1 && < 2,
122− transformers >= 0.2,
122+ transformers >= 0.2 && < 0.5,
123− union-find,
123+ union-find >= 0.2 && < 0.3,
124− unordered-containers
124+ unordered-containers >= 0.1 && < 0.3
125
125
126Executable elm
126Executable elm
127 Main-is: Compiler.hs
127 Main-is: Compiler.hs
@@ -189,29 +189,29 @@ Executable elm
189 Build.Utils,
189 Build.Utils,
190 Paths_Elm
190 Paths_Elm
191
191
192− Build-depends: aeson,
192+ Build-depends: aeson >= 0.7 && < 0.9,
193− aeson-pretty,
193+ aeson-pretty >= 0.7 && < 0.8,
194 base >=4.2 && <5,
194 base >=4.2 && <5,
195− binary >= 0.7.0.0,
195+ binary >= 0.7.0.0 && < 0.8,
196 blaze-html >= 0.5 && < 0.8,
196 blaze-html >= 0.5 && < 0.8,
197− blaze-markup,
197+ blaze-markup >= 0.5.1 && < 0.7,
198− bytestring,
198+ bytestring >= 0.9 && < 0.11,
199− cheapskate,
199+ cheapskate >= 0.1 && < 0.2,
200− cmdargs,
200+ cmdargs >= 0.7 && < 0.11,
201− containers >= 0.3,
201+ containers >= 0.3 && < 0.6,
202− directory,
202+ directory >= 1.0 && < 2.0,
203− filepath,
203+ filepath >= 1 && < 2.0,
204− highlighting-kate,
204+ highlighting-kate >= 0.5 && < 0.6,
205− indents,
205+ indents >= 0.3 && < 0.4,
206− language-ecmascript >=0.15 && < 1.0,
206+ language-ecmascript >=0.15 && < 0.17,
207− language-glsl >= 0.0.2,
207+ language-glsl >= 0.0.2 && < 0.1,
208− mtl >= 2,
208+ mtl >= 2 && < 3,
209− parsec >= 3.1.1,
209+ parsec >= 3.1.1 && < 3.5,
210− pretty,
210+ pretty >= 1.0 && < 2.0,
211− text,
211+ text >= 1 && < 2,
212− transformers >= 0.2,
212+ transformers >= 0.2 && < 0.5,
213− union-find,
213+ union-find >= 0.2 && < 0.3,
214− unordered-containers
214+ unordered-containers >= 0.1 && < 0.3
215
215
216Executable elm-doc
216Executable elm-doc
217 Main-is: Docs.hs
217 Main-is: Docs.hs
@@ -235,23 +235,23 @@ Executable elm-doc
235 Parse.Pattern,
235 Parse.Pattern,
236 Parse.Type
236 Parse.Type
237
237
238− Build-depends: aeson,
238+ Build-depends: aeson >= 0.7 && < 0.9,
239− aeson-pretty,
239+ aeson-pretty >= 0.7 && < 0.8,
240 base >=4.2 && <5,
240 base >=4.2 && <5,
241− binary >= 0.7.0.0,
241+ binary >= 0.7.0.0 && < 0.8,
242− bytestring,
242+ bytestring >= 0.9 && < 0.11,
243− cmdargs,
243+ cmdargs >= 0.7 && < 0.11,
244− containers >= 0.3,
244+ containers >= 0.3 && < 0.6,
245− directory,
245+ directory >= 1.0 && < 2.0,
246− filepath,
246+ filepath >= 1 && < 2.0,
247− indents,
247+ indents >= 0.3 && < 0.4,
248− language-glsl >= 0.0.2,
248+ language-glsl >= 0.0.2 && < 0.1,
249− mtl >= 2,
249+ mtl >= 2 && < 3,
250− parsec >= 3.1.1,
250+ parsec >= 3.1.1 && < 3.5,
251− pretty,
251+ pretty >= 1.0 && < 2.0,
252− text,
252+ text >= 1 && < 2,
253− transformers >= 0.2,
253+ transformers >= 0.2 && < 0.5,
254− union-find
254+ union-find >= 0.2 && < 0.3
255
255
256Test-Suite compiler-tests
256Test-Suite compiler-tests
257 Type: exitcode-stdio-1.0
257 Type: exitcode-stdio-1.0
@@ -263,43 +263,43 @@ Test-Suite compiler-tests
263 AST.Helpers
263 AST.Helpers
264 AST.Literal
264 AST.Literal
265 AST.PrettyPrint
265 AST.PrettyPrint
266− build-depends: test-framework,
266+ build-depends: test-framework > 0.8 && < 0.9,
267− test-framework-hunit,
267+ test-framework-hunit >= 0.3 && < 0.4,
268− test-framework-quickcheck2 >= 0.3,
268+ test-framework-quickcheck2 >= 0.3 && < 0.4,
269− HUnit,
269+ HUnit >= 1.1 && < 2,
270 QuickCheck >= 2 && < 3,
270 QuickCheck >= 2 && < 3,
271− aeson,
271+ aeson >= 0.7 && < 0.9,
272− aeson-pretty,
272+ aeson-pretty >= 0.7 && < 0.8,
273 base >=4.2 && <5,
273 base >=4.2 && <5,
274− binary >= 0.7.0.0,
274+ binary >= 0.7.0.0 && < 0.8,
275− blaze-html,
275+ blaze-html >= 0.5 && < 0.8,
276− blaze-markup,
276+ blaze-markup >= 0.5.1 && < 0.7,
277− bytestring,
277+ bytestring >= 0.9 && < 0.11,
278− cheapskate,
278+ cheapskate >= 0.1 && < 0.2,
279− cmdargs,
279+ cmdargs >= 0.7 && < 0.11,
280− containers >= 0.3,
280+ containers >= 0.3 && < 0.6,
281− directory,
281+ directory >= 1.0 && < 2.0,
282 Elm,
282 Elm,
283− filemanip,
283+ filemanip >= 0.3.5 && < 0.4,
284− filepath,
284+ filepath >= 1 && < 2.0,
285− highlighting-kate,
285+ highlighting-kate >= 0.5 && < 0.6,
286− indents,
286+ indents >= 0.3 && < 0.4,
287− language-ecmascript >=0.15 && < 1.0,
287+ language-ecmascript >=0.15 && < 0.17,
288− language-glsl >= 0.0.2,
288+ language-glsl >= 0.0.2 && < 0.1,
289− mtl >= 2,
289+ mtl >= 2 && < 3,
290− parsec >= 3.1.1,
290+ parsec >= 3.1.1 && < 3.5,
291− pretty,
291+ pretty >= 1.0 && < 2.0,
292− text,
292+ text >= 1 && < 2,
293− transformers >= 0.2,
293+ transformers >= 0.2 && < 0.5,
294− union-find,
294+ union-find >= 0.2 && < 0.3,
295− unordered-containers
295+ unordered-containers >= 0.1 && < 0.3
296
296
297Test-Suite library-tests
297Test-Suite library-tests
298 Type: exitcode-stdio-1.0
298 Type: exitcode-stdio-1.0
299 Hs-Source-Dirs: tests/libraries
299 Hs-Source-Dirs: tests/libraries
300 Main-is: LibraryTest.hs
300 Main-is: LibraryTest.hs
301− build-depends: base,
301+ build-depends: base >= 4.2 && <5,
302− directory,
302+ directory >= 1.0 && < 2.0,
303 Elm,
303 Elm,
304− filepath,
304+ filepath >= 1 && < 2.0,
305− process
305+ process >= 1 && < 2.0
changelog.md+3
@@ -17,6 +17,9 @@
17
17
18#### Breaking Changes:
18#### Breaking Changes:
19
19
20+ * Rename Basics.id to Basics.identity
21+ * Rename Basics.div to (//)
22+ * Rename Basics.mod to (%)
20 * Rename Maybe.maybe to Maybe.extract
23 * Rename Maybe.maybe to Maybe.extract
21 * Rename Either.either to Either.extract
24 * Rename Either.either to Either.extract
22 * Remove Maybe.justs for (List.filterMap id)
25 * Remove Maybe.justs for (List.filterMap id)
compiler/Build/Utils.hs+22−2
@@ -5,6 +5,7 @@ import Control.Monad.Error
5import System.Directory (doesFileExist)
5import System.Directory (doesFileExist)
6import System.Environment (getEnv)
6import System.Environment (getEnv)
7import System.FilePath ((</>), replaceExtension)
7import System.FilePath ((</>), replaceExtension)
8+import System.IO.Error (tryIOError)
8import qualified Build.Flags as Flag
9import qualified Build.Flags as Flag
9import qualified Build.Print as Print
10import qualified Build.Print as Print
10import qualified Paths_Elm as This
11import qualified Paths_Elm as This
@@ -33,8 +34,27 @@ getDataFile name = do
33 if exists
34 if exists
34 then return path
35 then return path
35 else do
36 else do
36− env <- getEnv "ELM_HOME"
37+ environment <- tryIOError (getEnv "ELM_HOME")
38+ case environment of
37− return (env </> name)
39+ Right env -> return (env </> name)
40+ Left _ ->
41+ fail $ unlines
42+ [ "Unable to find the ELM_HOME environment variable when searching"
43+ , "for the " ++ name ++ " file."
44+ , ""
45+ , "If you installed Elm Platform with the Mac or Windows installer, it looks like"
46+ , "ELM_HOME was not set automatically. Look up how to set environment variables"
47+ , "on your platform and set ELM_HOME to the directory that contains Elm's static"
48+ , "files:"
49+ , ""
50+ , " * On Mac it is /usr/local/share/elm"
51+ , " * On Windows it is one of the following:"
52+ , " C:/Program Files/Elm Platform/0.12.3/share"
53+ , " C:/Program Files (x86)/Elm Platform/0.12.3/share"
54+ , ""
55+ , "If it seems like a more complex issue, please report it here:"
56+ , " <https://github.com/elm-lang/elm-platform/issues>"
57+ ]
38
58
39run :: ErrorT String IO a -> IO a
59run :: ErrorT String IO a -> IO a
40run command = do
60run command = do
compiler/Generate/JavaScript.hs+9−9
@@ -418,15 +418,15 @@ binop region func@(Var.Canonical home op) e1 e2 =
418 ]
418 ]
419
419
420 specialOps =
420 specialOps =
421− [ (,) "^" $ \a b -> obj ["Math","pow"] `call` [a,b]
421+ [ (,) "^" $ \a b -> obj ["Math","pow"] `call` [a,b]
422− , (,) "|>" $ flip (<|)
422+ , (,) "|>" $ flip (<|)
423− , (,) "==" $ \a b -> _Utils "eq" `call` [a,b]
423+ , (,) "==" $ \a b -> _Utils "eq" `call` [a,b]
424− , (,) "/=" $ \a b -> PrefixExpr () PrefixLNot (_Utils "eq" `call` [a,b])
424+ , (,) "/=" $ \a b -> PrefixExpr () PrefixLNot (_Utils "eq" `call` [a,b])
425− , (,) "<" $ cmp OpLT 0
425+ , (,) "<" $ cmp OpLT 0
426− , (,) ">" $ cmp OpGT 0
426+ , (,) ">" $ cmp OpGT 0
427− , (,) "<=" $ cmp OpLT 1
427+ , (,) "<=" $ cmp OpLT 1
428− , (,) ">=" $ cmp OpGT (-1)
428+ , (,) ">=" $ cmp OpGT (-1)
429− , (,) "div" $ \a b -> InfixExpr () OpBOr (InfixExpr () OpDiv a b) (IntLit () 0)
429+ , (,) "//" $ \a b -> InfixExpr () OpBOr (InfixExpr () OpDiv a b) (IntLit () 0)
430 ]
430 ]
431
431
432 cmp op n a b = InfixExpr () op (_Utils "cmp" `call` [a,b]) (IntLit () n)
432 cmp op n a b = InfixExpr () op (_Utils "cmp" `call` [a,b]) (IntLit () n)
compiler/Metadata/Prelude.hs+80−28
@@ -2,6 +2,7 @@
2module Metadata.Prelude (interfaces, add) where
2module Metadata.Prelude (interfaces, add) where
3
3
4import qualified Data.Map as Map
4import qualified Data.Map as Map
5+import qualified Data.Set as Set
5import qualified Control.Exception as E
6import qualified Control.Exception as E
6import System.Exit
7import System.Exit
7import System.IO
8import System.IO
@@ -10,37 +11,88 @@ import qualified AST.Variable as Var
10import qualified Build.Interface as Interface
11import qualified Build.Interface as Interface
11import Build.Utils (getDataFile)
12import Build.Utils (getDataFile)
12
13
13−add :: Bool -> Module exs body -> Module exs body
14+
14−add noPrelude (Module name path exs ims decls) =
15+-- DEFINITION OF THE PRELUDE
15− Module name path exs (customIms ++ ims) decls
16+
16− where
17+type ImportDict =
17− customIms = if noPrelude then [] else concatMap addModule prelude
18+ Map.Map String ([String], Var.Listing Var.Value)
18−
19+
19− addModule (n, method) = case lookup n ims of
20+prelude :: ImportDict
20− Nothing -> [(n, method)]
21− Just (As _) -> [(n, method)]
22− Just _ -> []
23−
24−prelude :: [(String, ImportMethod)]
25−prelude = string : text : maybe : map (\n -> (n, Module.open)) modules
21+prelude = Map.unions [ string, text, maybe, openImports ]
26 where
22 where
23+ importing :: String -> [Var.Value] -> ImportDict
24+ importing name values =
25+ Map.singleton name ([], Var.Listing values False)
26+
27+ openImports :: ImportDict
28+ openImports =
29+ Map.fromList $ map (\name -> (name, ([], Var.openListing))) $
27− modules = [ "Basics", "Signal", "List", "Time", "Color"
30+ [ "Basics", "Signal", "List", "Time", "Color"
28− , "Graphics.Element", "Graphics.Collage"
31+ , "Graphics.Element", "Graphics.Collage"
29− , "Native.Ports", "Native.Json"
32+ , "Native.Ports", "Native.Json"
30− ]
31−
32− string = ("String", Module.importing [Var.Value "show"])
33−
34− text = ("Text", Module.importing textImports)
35− textImports =
36− Var.ADT "Text" (Var.Listing [] False) : map Var.Value
37− [ "toText", "leftAligned", "rightAligned", "centered", "justified"
38− , "plainText", "asText", "typeface", "monospace", "bold", "italic"
39 ]
33 ]
40
34
41− maybe =
35+ maybe :: ImportDict
42− let imports = [ Var.ADT "Maybe" (Var.Listing ["Just", "Nothing"] False) ]
36+ maybe = importing "Maybe" [ Var.ADT "Maybe" Var.openListing ]
43− in ("Maybe", Module.importing imports)
37+
38+ string :: ImportDict
39+ string = importing "String" [Var.Value "show"]
40+
41+ text :: ImportDict
42+ text = importing "Text" (Var.ADT "Text" (Var.Listing [] False) : values)
43+ where
44+ values =
45+ map Var.Value
46+ [ "toText", "leftAligned", "rightAligned", "centered", "justified"
47+ , "plainText", "asText", "typeface", "monospace", "bold", "italic"
48+ ]
49+
50+
51+-- ADDING PRELUDE TO A MODULE
52+
53+add :: Bool -> Module exs body -> Module exs body
54+add noPrelude (Module moduleName path exports imports decls) =
55+ Module moduleName path exports ammendedImports decls
56+ where
57+ ammendedImports =
58+ importDictToList $
59+ foldr addImport (if noPrelude then Map.empty else prelude) imports
60+
61+importDictToList :: ImportDict -> [(String, ImportMethod)]
62+importDictToList dict =
63+ concatMap toImports (Map.toList dict)
64+ where
65+ toImports (name, (qualifiers, listing@(Var.Listing explicits open))) =
66+ map (\qualifier -> (name, As qualifier)) qualifiers
67+ ++
68+ if open || not (null explicits)
69+ then [(name, Open listing)]
70+ else []
71+
72+addImport :: (String, ImportMethod) -> ImportDict -> ImportDict
73+addImport (name, method) importDict =
74+ Map.alter mergeMethods name importDict
75+ where
76+ mergeMethods :: Maybe ([String], Var.Listing Var.Value)
77+ -> Maybe ([String], Var.Listing Var.Value)
78+ mergeMethods entry =
79+ let (qualifiers, listing) =
80+ case entry of
81+ Nothing -> ([], Var.Listing [] False)
82+ Just v -> v
83+ in
84+ case method of
85+ As qualifier -> Just (qualifier : qualifiers, listing)
86+ Open newListing ->
87+ Just (qualifiers, mergeListings newListing listing)
88+
89+ mergeListings (Var.Listing explicits1 open1) (Var.Listing explicits2 open2) =
90+ Var.Listing
91+ (Set.toList (Set.fromList (explicits1 ++ explicits2)))
92+ (open1 || open2)
93+
94+
95+-- EXTRACT INTERFACES FROM STATIC FILE
44
96
45interfaces :: Bool -> IO Interfaces
97interfaces :: Bool -> IO Interfaces
46interfaces noPrelude =
98interfaces noPrelude =
libraries/Basics.elm+23−13
@@ -22,7 +22,7 @@ are your tuples so big?
22@docs not, (&&), (||), xor, otherwise
22@docs not, (&&), (||), xor, otherwise
23
23
24# Mathematics
24# Mathematics
25−@docs (+), (-), (*), (/), (^), div, rem, mod, abs, sqrt, clamp, logBase, e
25+@docs (+), (-), (*), (/), (^), (//), rem, (%), abs, sqrt, clamp, logBase, e
26
26
27# Trigonometry
27# Trigonometry
28@docs pi, cos, sin, tan, acos, asin, atan, atan2
28@docs pi, cos, sin, tan, acos, asin, atan, atan2
@@ -46,7 +46,7 @@ which happen to be radians.
46@docs fst, snd
46@docs fst, snd
47
47
48# Higher-Order Helpers
48# Higher-Order Helpers
49−@docs id, always, (<|), (|>), (.), flip, curry, uncurry
49+@docs identity, always, (<|), (|>), (.), flip, curry, uncurry
50
50
51-}
51-}
52
52
@@ -97,21 +97,29 @@ infixl 7 *
97infixl 7 /
97infixl 7 /
98infixl 8 ^
98infixl 8 ^
99
99
100−infixl 7 `div`
100+infixl 7 //
101−infixl 7 `mod`
101+infixl 7 %
102infixl 7 `rem`
102infixl 7 `rem`
103
103
104{-| Integer division, remainder is discarded. -}
104{-| Integer division, remainder is discarded. -}
105−div : Int -> Int -> Int
105+(//) : Int -> Int -> Int
106−div = Native.Basics.div
106+(//) = Native.Basics.div
107
107
108−{-| Finds the remainder after dividing one number by another: ``4 `rem` 3 == 1`` -}
108+{-| Finds the remainder after dividing one number by another:
109+
110+ 7 `rem` 2 == 1
111+ -1 `rem` 4 == 1
112+-}
109rem : Int -> Int -> Int
113rem : Int -> Int -> Int
110rem = Native.Basics.rem
114rem = Native.Basics.rem
111
115
112−{-| Perform modular arithmetic: ``7 `mod` 2 == 1`` -}
116+{-| Perform [modular arithmetic](http://en.wikipedia.org/wiki/Modular_arithmetic):
117+
118+ 7 % 2 == 1
119+ -1 % 4 == 3
120+-}
113−mod : Int -> Int -> Int
121+(%) : Int -> Int -> Int
114−mod = Native.Basics.mod
122+(%) = Native.Basics.mod
115
123
116{-| Exponentiation: `3^2 == 9` -}
124{-| Exponentiation: `3^2 == 9` -}
117(^) : number -> number -> number
125(^) : number -> number -> number
@@ -348,9 +356,11 @@ infixr 9 .
348infixr 0 <|
356infixr 0 <|
349infixl 0 |>
357infixl 0 |>
350
358
351−{-| Given a value, returns exactly the same value. -}
359+{-| Given a value, returns exactly the same value. This is called
352−id : a -> a
360+[the identity function](http://en.wikipedia.org/wiki/Identity_function).
353−id x = x
361+-}
362+identity : a -> a
363+identity x = x
354
364
355{-| Creates a [constant function](http://en.wikipedia.org/wiki/Constant_function),
365{-| Creates a [constant function](http://en.wikipedia.org/wiki/Constant_function),
356a function that *always* returns the same value regardless of what input you give.
366a function that *always* returns the same value regardless of what input you give.
libraries/Color.elm+1−1
@@ -124,7 +124,7 @@ toRgb color =
124fmod : Float -> Int -> Float
124fmod : Float -> Int -> Float
125fmod f n =
125fmod f n =
126 let integer = floor f
126 let integer = floor f
127− in toFloat (integer `mod` n) + f - toFloat integer
127+ in toFloat (integer % n) + f - toFloat integer
128
128
129rgbToHsl : Int -> Int -> Int -> (Float,Float,Float)
129rgbToHsl : Int -> Int -> Int -> (Float,Float,Float)
130rgbToHsl red green blue =
130rgbToHsl red green blue =
libraries/Graphics/Collage.elm+3−2
@@ -33,7 +33,8 @@ it as a single unit.
33import Basics (..)
33import Basics (..)
34import List
34import List
35import Either (Either(Left, Right))
35import Either (Either(Left, Right))
36−import Transform2D (Transform2D, identity)
36+import Transform2D (Transform2D)
37+import Transform2D as T
37import Native.Graphics.Collage
38import Native.Graphics.Collage
38import Graphics.Element (Element)
39import Graphics.Element (Element)
39import Color (Color, black, Gradient)
40import Color (Color, black, Gradient)
@@ -153,7 +154,7 @@ toForm e = form (FElement e)
153as a single unit, making it possible to build small, modular components.
154as a single unit, making it possible to build small, modular components.
154-}
155-}
155group : [Form] -> Form
156group : [Form] -> Form
156−group fs = form (FGroup identity fs)
157+group fs = form (FGroup T.identity fs)
157
158
158{-| Flatten many forms into a single `Form` and then apply a matrix
159{-| Flatten many forms into a single `Form` and then apply a matrix
159transformation.
160transformation.
libraries/Maybe.elm+1−3
@@ -12,8 +12,6 @@ module Maybe (Maybe(..), maybe, isJust, isNothing, map) where
12@docs map
12@docs map
13-}
13-}
14
14
15−import Basics (not, (.))
16−
17{-| The Maybe datatype. Useful when a computation may or may not
15{-| The Maybe datatype. Useful when a computation may or may not
18result in a value (e.g. logarithm is defined only for positive
16result in a value (e.g. logarithm is defined only for positive
19numbers).
17numbers).
@@ -49,7 +47,7 @@ isJust = maybe False (\_ -> True)
49 isNothing Nothing == True
47 isNothing Nothing == True
50-}
48-}
51isNothing : Maybe a -> Bool
49isNothing : Maybe a -> Bool
52−isNothing = not . isJust
50+isNothing = maybe True (\_ -> False)
53
51
54{-| Transform the contents of a `Maybe` with a given function:
52{-| Transform the contents of a `Maybe` with a given function:
55
53
libraries/Native/Array.js+101−49
@@ -35,8 +35,10 @@ Elm.Native.Array.make = function(elm) {
35 function unsafeGet(i, array) {
35 function unsafeGet(i, array) {
36 for (var x = array.height; x > 0; x--) {
36 for (var x = array.height; x > 0; x--) {
37 var slot = i >> (x * 5);
37 var slot = i >> (x * 5);
38+ while (array.lengths[slot] <= i) {
39+ slot++;
40+ }
38 if (slot > 0) {
41 if (slot > 0) {
39− while (array.lengths[slot - 1] > i) { slot--; }
40 i -= array.lengths[slot - 1];
42 i -= array.lengths[slot - 1];
41 }
43 }
42 array = array.table[slot];
44 array = array.table[slot];
@@ -311,10 +313,12 @@ Elm.Native.Array.make = function(elm) {
311
313
312 // Create new node.
314 // Create new node.
313 var newA = { ctor:"_Array", height:a.height
315 var newA = { ctor:"_Array", height:a.height
314− , table:a.table.slice(0, right + 1)
316+ , table:a.table.slice(0, right)
315− , lengths:a.lengths.slice(0, right + 1) };
317+ , lengths:a.lengths.slice(0, right) };
318+ if (sliced.table.length > 0) {
316− newA.table[right] = sliced;
319+ newA.table[right] = sliced;
317− newA.lengths[right] = length(sliced) + (right > 0 ? newA.lengths[right - 1] : 0);
320+ newA.lengths[right] = length(sliced) + (right > 0 ? newA.lengths[right - 1] : 0);
321+ }
318 return newA;
322 return newA;
319 }
323 }
320
324
@@ -343,7 +347,7 @@ Elm.Native.Array.make = function(elm) {
343 var newA = { ctor:"_Array", height:a.height
347 var newA = { ctor:"_Array", height:a.height
344 , table:a.table.slice(left, a.table.length + 1)
348 , table:a.table.slice(left, a.table.length + 1)
345 , lengths:new Array(a.table.length - left) };
349 , lengths:new Array(a.table.length - left) };
346− newA.table[left] = sliced;
350+ newA.table[0] = sliced;
347 var len = 0;
351 var len = 0;
348 for (var i = 0; i < newA.table.length; i++) {
352 for (var i = 0; i < newA.table.length; i++) {
349 len += length(newA.table[i]);
353 len += length(newA.table[i]);
@@ -354,70 +358,116 @@ Elm.Native.Array.make = function(elm) {
354 }
358 }
355
359
356 // Appends two trees.
360 // Appends two trees.
357− // TODO: Add support for appending trees of different sizes. Current
358− // behavior will just rise the lower tree and then append them.
359 function append(a,b) {
361 function append(a,b) {
360− if (a.table.length == 0) return b;
362+ if (a.table.length === 0) {
363+ return b;
364+ }
361− if (b.table.length == 0) return a;
365+ if (b.table.length === 0) {
362− if (b.height > a.height) return append(parentise(a, b.height), b);
366+ return a;
363− if (a.height > b.height) return append(a, parentise(b, a.height));
367+ }
364− if (a.height == 0) return append(parentise(a, 1), parentise(b, 1));
365
368
366 var c = append_(a, b);
369 var c = append_(a, b);
370+
371+ // Check if both nodes can be crunshed together.
372+ if (c[0].table.length + c[1].table.length <= M) {
373+ if (c[0].table.length === 0) {
374+ return c[1];
375+ }
367− if (c[1].table.length > 0) {
376+ if (c[1].table.length === 0) {
368− return siblise(c[0], c[1]);
377+ return c[0];
369− } else {
378+ }
379+
380+ // Adjust .table and .lengths
381+ c[0].table = c[0].table.concat(c[1].table);
382+ if (c[0].height > 0) {
383+ var len = length(c[0]);
384+ for (var i = 0; i < c[1].lengths.length; i++) {
385+ c[1].lengths[i] += len;
386+ }
387+ c[0].lengths = c[0].lengths.concat(c[1].lengths);
388+ }
389+
370 return c[0];
390 return c[0];
371 }
391 }
392+
393+ var toRemove = calcToRemove(a, b);
394+ if (toRemove > E) {
395+ c = shuffle(c[0], c[1], toRemove);
396+ }
397+
398+ return siblise(c[0], c[1]);
372 }
399 }
373
400
374− // Returns an array of two nodes. The second node _may_ be empty. This case
401+ // Returns an array of two nodes; right and left. One node _may_ be empty.
375− // needs to be handled by the function, that called append_. May be only
376− // called for trees with an minimal height of 1.
377 function append_(a, b) {
402 function append_(a, b) {
378− if (a.height == 1) {
403+ if (a.height === 0 && b.height === 0) {
379− // Check if balancing is needed and return based on that.
380− var toRemove = calcToRemove(a, b);
381− if (toRemove <= E) {
382− return [a,b];
404+ return [a, b];
383− }
384−
385− return shuffle(a, b, toRemove);
386 }
405 }
387
406
407+ if (a.height !== 1 || b.height !== 1) {
408+ if (a.height === b.height) {
409+ a = nodeCopy(a);
410+ b = nodeCopy(b);
388− var appended = append_(botRight(a), botLeft(b));
411+ var appended = append_(botRight(a), botLeft(b));
389− a = nodeCopy(a), b = nodeCopy(b);
390
412
391− // Adjust the bottom right side of the new tree.
413+ insertRight(a, appended[1]);
392− a.table[a.table.length - 1] = appended[0];
414+ insertLeft(b, appended[0]);
393− a.lengths[a.lengths.length - 1] = length(appended[0])
415+ } else if (a.height > b.height) {
394− a.lengths[a.lengths.length - 1] += a.lengths.length > 1 ? a.lengths[a.lengths.length - 2] : 0;
416+ a = nodeCopy(a);
417+ var appended = append_(botRight(a), b);
395
418
396− // Adjust the bottom left side of the new tree.
397− if (appended[1].table.length > 0) {
398− b.table[0] = appended[1];
419+ insertRight(a, appended[0]);
399− b.lengths[0] = length(appended[1]);
420+ b = parentise(appended[1], appended[1].height + 1);
400− for (var i = 1, len = length(b.table[0]); i < b.lengths.length; i++) {
401− len += length(b.table[i]);
402− b.lengths[i] = len;
403− }
404− } else {
421+ } else {
405− b.table.shift();
422+ b = nodeCopy(b);
406− for (var i = 1; i < b.lengths.length; i++) {
423+ var appended = append_(a, botLeft(b));
407− b.lengths[i] = b.lengths[i] - b.lengths[0];
424+
425+ var left = appended[0].table.length === 0 ? 0 : 1;
426+ var right = left === 0 ? 1 : 0;
427+ insertLeft(b, appended[left]);
428+ a = parentise(appended[right], appended[right].height + 1);
408 }
429 }
409− b.lengths.shift();
410 }
430 }
411
431
412 // Check if balancing is needed and return based on that.
432 // Check if balancing is needed and return based on that.
413− var toRemove = calcToRemove(a, b);
414− if (toRemove <= E || b.table.length == 0) {
433+ if (a.table.length === 0 || b.table.length === 0) {
415 return [a,b];
434 return [a,b];
416 }
435 }
417
436
437+ var toRemove = calcToRemove(a, b);
438+ if (toRemove <= E) {
439+ return [a,b];
440+ }
418 return shuffle(a, b, toRemove);
441 return shuffle(a, b, toRemove);
419 }
442 }
420
443
444+ // Helperfunctions for append_. Replaces a child node at the side of the parent.
445+ function insertRight(parent, node) {
446+ var index = parent.table.length - 1;
447+ parent.table[index] = node;
448+ parent.lengths[index] = length(node)
449+ parent.lengths[index] += index > 0 ? parent.lengths[index - 1] : 0;
450+ }
451+
452+ function insertLeft(parent, node) {
453+ if (node.table.length > 0) {
454+ parent.table[0] = node;
455+ parent.lengths[0] = length(node);
456+
457+ var len = length(parent.table[0]);
458+ for (var i = 1; i < parent.lengths.length; i++) {
459+ len += length(parent.table[i]);
460+ parent.lengths[i] = len;
461+ }
462+ } else {
463+ parent.table.shift();
464+ for (var i = 1; i < parent.lengths.length; i++) {
465+ parent.lengths[i] = parent.lengths[i] - parent.lengths[0];
466+ }
467+ parent.lengths.shift();
468+ }
469+ }
470+
421 // Returns the extra search steps for E. Refer to the paper.
471 // Returns the extra search steps for E. Refer to the paper.
422 function calcToRemove(a, b) {
472 function calcToRemove(a, b) {
423 var subLengths = 0;
473 var subLengths = 0;
@@ -558,7 +608,9 @@ Elm.Native.Array.make = function(elm) {
558 // find the exact slot via forward searching in "lengths". Returns the index.
608 // find the exact slot via forward searching in "lengths". Returns the index.
559 function getSlot(i, a) {
609 function getSlot(i, a) {
560 var slot = i >> (5 * a.height);
610 var slot = i >> (5 * a.height);
561− while (a.lengths[slot - 1] > i) { slot--; }
611+ while (a.lengths[slot] <= i) {
612+ slot++;
613+ }
562 return slot;
614 return slot;
563 }
615 }
564
616
tests/compiler/test-files/good/OverlappingImports.elmnew file+5
@@ -0,0 +1,5 @@
1+import Text
2+import Text (..)
3+import Text (leftAligned)
4+
5+main = leftAligned (toText "hello")
tests/libraries/Test/Array.elm+14−3
@@ -7,14 +7,23 @@ import Native.Array
7import ElmTest.Assertion (..)
7import ElmTest.Assertion (..)
8import ElmTest.Test (..)
8import ElmTest.Test (..)
9
9
10+mergeSplit : Int -> Array.Array a -> Array.Array a
11+mergeSplit n arr =
12+ let left = Array.slice 0 n arr
13+ right = Array.slice n (Array.length arr) arr
14+ in Array.append left right
15+
16+holeArray : Array.Array Int
17+holeArray = foldl mergeSplit (Array.fromList [0..100]) [0..100]
18+
10tests : Test
19tests : Test
11tests =
20tests =
12 let creationTests = suite "Creation"
21 let creationTests = suite "Creation"
13 [ test "empty" <| assertEqual Array.empty (Array.fromList [])
22 [ test "empty" <| assertEqual Array.empty (Array.fromList [])
14− , test "initialize" <| assertEqual (Array.initialize 4 id) (Array.fromList [0,1,2,3])
23+ , test "initialize" <| assertEqual (Array.initialize 4 identity) (Array.fromList [0,1,2,3])
15 , test "initialize 2" <| assertEqual (Array.initialize 4 (\n -> n*n)) (Array.fromList [0,1,4,9])
24 , test "initialize 2" <| assertEqual (Array.initialize 4 (\n -> n*n)) (Array.fromList [0,1,4,9])
16 , test "initialize 3" <| assertEqual (Array.initialize 4 (always 0)) (Array.fromList [0,0,0,0])
25 , test "initialize 3" <| assertEqual (Array.initialize 4 (always 0)) (Array.fromList [0,0,0,0])
17− , test "initialize Empty" <| assertEqual (Array.initialize 0 id) Array.empty
26+ , test "initialize Empty" <| assertEqual (Array.initialize 0 identity) Array.empty
18 , test "initialize 4" <| assertEqual (Array.initialize 2 (always 0)) (Array.fromList [0,0])
27 , test "initialize 4" <| assertEqual (Array.initialize 2 (always 0)) (Array.fromList [0,0])
19 , test "repeat" <| assertEqual (Array.repeat 5 40) (Array.fromList [40,40,40,40,40])
28 , test "repeat" <| assertEqual (Array.repeat 5 40) (Array.fromList [40,40,40,40,40])
20 , test "repeat 2" <| assertEqual (Array.repeat 5 0) (Array.fromList [0,0,0,0,0])
29 , test "repeat 2" <| assertEqual (Array.repeat 5 0) (Array.fromList [0,0,0,0,0])
@@ -28,6 +37,7 @@ tests =
28 , test "append" <| assertEqual [42,42,81,81,81] (Array.toList (Array.append (Array.repeat 2 42) (Array.repeat 3 81)))
37 , test "append" <| assertEqual [42,42,81,81,81] (Array.toList (Array.append (Array.repeat 2 42) (Array.repeat 3 81)))
29 , test "appendEmpty 1" <| assertEqual [1..33] (Array.toList (Array.append Array.empty (Array.fromList [1..33])))
38 , test "appendEmpty 1" <| assertEqual [1..33] (Array.toList (Array.append Array.empty (Array.fromList [1..33])))
30 , test "appendEmpty 2" <| assertEqual [1..33] (Array.toList (Array.append (Array.fromList [1..33]) Array.empty))
39 , test "appendEmpty 2" <| assertEqual [1..33] (Array.toList (Array.append (Array.fromList [1..33]) Array.empty))
40+ , test "appendAndSlice" <| assertEqual [0..100] (Array.toList holeArray)
31 ]
41 ]
32 getAndSetTests = suite "Get and Set"
42 getAndSetTests = suite "Get and Set"
33 [ test "get" <| assertEqual (Just 2) (Array.get 1 (Array.fromList [3,2,1]))
43 [ test "get" <| assertEqual (Just 2) (Array.get 1 (Array.fromList [3,2,1]))
@@ -45,6 +55,7 @@ tests =
45 , test "slice 2" <| assertEqual (Array.fromList [1,2,3]) (Array.slice 1 4 (Array.fromList [0,1,2,3,4]))
55 , test "slice 2" <| assertEqual (Array.fromList [1,2,3]) (Array.slice 1 4 (Array.fromList [0,1,2,3,4]))
46 , test "slice 3" <| assertEqual (Array.fromList [1,2,3]) (Array.slice 1 -1 (Array.fromList [0,1,2,3,4]))
56 , test "slice 3" <| assertEqual (Array.fromList [1,2,3]) (Array.slice 1 -1 (Array.fromList [0,1,2,3,4]))
47 , test "slice 4" <| assertEqual (Array.fromList [2]) (Array.slice -3 -2 (Array.fromList [0,1,2,3,4]))
57 , test "slice 4" <| assertEqual (Array.fromList [2]) (Array.slice -3 -2 (Array.fromList [0,1,2,3,4]))
58+ , test "slice 5" <| assertEqual 63 (Array.length <| Array.slice 65 (65 + 63) <| Array.fromList [1..200])
48 ]
59 ]
49 mappingAndFoldingTests = suite "Mapping and Folding"
60 mappingAndFoldingTests = suite "Mapping and Folding"
50 [ test "map" <| assertEqual (Array.fromList [1,2,3]) (Array.map sqrt (Array.fromList [1,4,9]))
61 [ test "map" <| assertEqual (Array.fromList [1,2,3]) (Array.map sqrt (Array.fromList [1,4,9]))
@@ -55,7 +66,7 @@ tests =
55 , test "foldr 1" <| assertEqual 15 (Array.foldr (+) 0 (Array.repeat 3 5))
66 , test "foldr 1" <| assertEqual 15 (Array.foldr (+) 0 (Array.repeat 3 5))
56 , test "foldr 2" <| assertEqual [1,2,3] (Array.foldr (::) [] (Array.fromList [1,2,3]))
67 , test "foldr 2" <| assertEqual [1,2,3] (Array.foldr (::) [] (Array.fromList [1,2,3]))
57 , test "foldr 3" <| assertEqual 53 (Array.foldr (-) 54 (Array.fromList [10,11]))
68 , test "foldr 3" <| assertEqual 53 (Array.foldr (-) 54 (Array.fromList [10,11]))
58− , test "filter" <| assertEqual (Array.fromList [2,4,6]) (Array.filter (\x -> x `mod` 2 == 0) (Array.fromList [1..6]))
69+ , test "filter" <| assertEqual (Array.fromList [2,4,6]) (Array.filter (\x -> x % 2 == 0) (Array.fromList [1..6]))
59 ]
70 ]
60 nativeTests = suite "Conversion to JS Arrays"
71 nativeTests = suite "Conversion to JS Arrays"
61 [ test "jsArrays" <| assertEqual (Array.fromList [1..1100]) (Native.Array.fromJSArray (Native.Array.toJSArray (Array.fromList [1..1100])))
72 [ test "jsArrays" <| assertEqual (Array.fromList [1..1100]) (Native.Array.fromJSArray (Native.Array.toJSArray (Array.fromList [1..1100])))
tests/libraries/Test/List.elm+27−28
@@ -5,34 +5,33 @@ import List
5import ElmTest.Assertion (..)
5import ElmTest.Assertion (..)
6import ElmTest.Test (..)
6import ElmTest.Test (..)
7
7
8+largeNumber = 100000
9+trueList = repeat largeNumber True
10+falseList = repeat largeNumber False
11+
12+lessThanThree x = x < 3
13+isEven n = n % 2 == 0
14+
8tests : Test
15tests : Test
9tests =
16tests =
10− let partitionTests =
17+ let partitionTests = suite "partition Tests"
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]),
18+ [ test "simple partition" <| assertEqual ([True],[False]) (List.partition identity [False, True])
15− test "order check" <| assertEqual ([2,1], [5,6]) (List.partition p2 [2,5,6,1]),
19+ , test "order check" <| assertEqual ([2,1], [5,6]) (List.partition lessThanThree [2,5,6,1])
16− test "partition doc check 1" <| assertEqual ([0,1,2], [3,4,5]) (partition p2 [0..5]),
20+ , test "partition doc check 1" <| assertEqual ([0,1,2], [3,4,5]) (partition lessThanThree [0..5])
17− test "partition doc check 2" <| assertEqual ([0,2,4], [1,3,5]) (partition isEven [0..5]),
21+ , 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+ , test "partition stress test" <| assertEqual (trueList, falseList) (partition identity (falseList ++ trueList))
22− ]
23+ ]
23− unzipTests = suite "unzip Tests" [
24+ unzipTests = suite "unzip Tests"
24− test "unzip doc check" <| assertEqual ([0,17,1337],[True,False,True]) (unzip [(0, True), (17, False), (1337, True)]),
25+ [ 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))
26+ , test "unzip stress test" <| assertEqual (trueList, falseList) (unzip (zip trueList falseList))
29− ]
27+ ]
30− intersperseTests = suite "intersperse Tests" [
28+ intersperseTests = suite "intersperse Tests"
31− test "intersperse doc check" <| assertEqual ["turtles","on","turtles","on","turtles"] (intersperse "on" ["turtles","turtles","turtles"]),
29+ [ 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)
30+ , test "intersperse stress test" <| assertEqual (tail . List.concat <| zipWith (\x y -> [x,y]) falseList trueList) (intersperse False trueList)
36− (intersperse False ts)
31+ ]
32+ in
33+ suite "List Tests"
34+ [ partitionTests
35+ , unzipTests
36+ , intersperseTests
37 ]
37 ]
38− in suite "List Tests" [partitionTests, unzipTests, intersperseTests]