on master help sign in
Merge branch 'master' into debugger
commitcf895bc09b75da614fe23278c876d5be96b23d96 authorEvan Czaplicki <info@elm-lang.org> dateThu 14 Aug 2014, 17:42 (12 years ago) parent28685dd489e5cc
13 files changed+378−227
Elm.cabal+89−89 changelog.md+3 compiler/Build/Utils.hs+22−2 compiler/Generate/JavaScript.hs+9−9 compiler/Metadata/Prelude.hs+80−28 libraries/Basics.elm+23−13 libraries/Color.elm+1−1 libraries/Graphics/Collage.elm+3−2 libraries/Maybe.elm+1−3 libraries/Native/Array.js+101−49 tests/compiler/test-files/good/OverlappingImports.elm+5 tests/libraries/Test/Array.elm+14−3 tests/libraries/Test/List.elm+27−28
Elm.cabal+89−89
@@ -99,29 +99,29 @@ Library
9999 Build.Utils,
100100 Paths_Elm
101101
102− Build-depends: aeson,
103− aeson-pretty,
102+ Build-depends: aeson >= 0.7 && < 0.9,
103+ aeson-pretty >= 0.7 && < 0.8,
104104 base >=4.2 && <5,
105− binary >= 0.7.0.0,
105+ binary >= 0.7.0.0 && < 0.8,
106106 blaze-html >= 0.5 && < 0.8,
107− blaze-markup,
108− bytestring,
109− cheapskate,
110− cmdargs,
111− containers >= 0.3,
112− directory,
113− filepath,
114− highlighting-kate,
115− indents,
116− language-ecmascript >=0.15 && < 1.0,
117− language-glsl >= 0.0.2,
118− mtl >= 2,
119− parsec >= 3.1.1,
120− pretty,
121− text,
122− transformers >= 0.2,
123− union-find,
124− unordered-containers
107+ blaze-markup >= 0.5.1 && < 0.7,
108+ bytestring >= 0.9 && < 0.11,
109+ cheapskate >= 0.1 && < 0.2,
110+ cmdargs >= 0.7 && < 0.11,
111+ containers >= 0.3 && < 0.6,
112+ directory >= 1.0 && < 2.0,
113+ filepath >= 1 && < 2.0,
114+ highlighting-kate >= 0.5 && < 0.6,
115+ indents >= 0.3 && < 0.4,
116+ language-ecmascript >=0.15 && < 0.17,
117+ language-glsl >= 0.0.2 && < 0.1,
118+ mtl >= 2 && < 3,
119+ parsec >= 3.1.1 && < 3.5,
120+ pretty >= 1.0 && < 2.0,
121+ text >= 1 && < 2,
122+ transformers >= 0.2 && < 0.5,
123+ union-find >= 0.2 && < 0.3,
124+ unordered-containers >= 0.1 && < 0.3
125125
126126Executable elm
127127 Main-is: Compiler.hs
@@ -189,29 +189,29 @@ Executable elm
189189 Build.Utils,
190190 Paths_Elm
191191
192− Build-depends: aeson,
193− aeson-pretty,
192+ Build-depends: aeson >= 0.7 && < 0.9,
193+ aeson-pretty >= 0.7 && < 0.8,
194194 base >=4.2 && <5,
195− binary >= 0.7.0.0,
195+ binary >= 0.7.0.0 && < 0.8,
196196 blaze-html >= 0.5 && < 0.8,
197− blaze-markup,
198− bytestring,
199− cheapskate,
200− cmdargs,
201− containers >= 0.3,
202− directory,
203− filepath,
204− highlighting-kate,
205− indents,
206− language-ecmascript >=0.15 && < 1.0,
207− language-glsl >= 0.0.2,
208− mtl >= 2,
209− parsec >= 3.1.1,
210− pretty,
211− text,
212− transformers >= 0.2,
213− union-find,
214− unordered-containers
197+ blaze-markup >= 0.5.1 && < 0.7,
198+ bytestring >= 0.9 && < 0.11,
199+ cheapskate >= 0.1 && < 0.2,
200+ cmdargs >= 0.7 && < 0.11,
201+ containers >= 0.3 && < 0.6,
202+ directory >= 1.0 && < 2.0,
203+ filepath >= 1 && < 2.0,
204+ highlighting-kate >= 0.5 && < 0.6,
205+ indents >= 0.3 && < 0.4,
206+ language-ecmascript >=0.15 && < 0.17,
207+ language-glsl >= 0.0.2 && < 0.1,
208+ mtl >= 2 && < 3,
209+ parsec >= 3.1.1 && < 3.5,
210+ pretty >= 1.0 && < 2.0,
211+ text >= 1 && < 2,
212+ transformers >= 0.2 && < 0.5,
213+ union-find >= 0.2 && < 0.3,
214+ unordered-containers >= 0.1 && < 0.3
215215
216216Executable elm-doc
217217 Main-is: Docs.hs
@@ -235,23 +235,23 @@ Executable elm-doc
235235 Parse.Pattern,
236236 Parse.Type
237237
238− Build-depends: aeson,
239− aeson-pretty,
238+ Build-depends: aeson >= 0.7 && < 0.9,
239+ aeson-pretty >= 0.7 && < 0.8,
240240 base >=4.2 && <5,
241− binary >= 0.7.0.0,
242− bytestring,
243− cmdargs,
244− containers >= 0.3,
245− directory,
246− filepath,
247− indents,
248− language-glsl >= 0.0.2,
249− mtl >= 2,
250− parsec >= 3.1.1,
251− pretty,
252− text,
253− transformers >= 0.2,
254− union-find
241+ binary >= 0.7.0.0 && < 0.8,
242+ bytestring >= 0.9 && < 0.11,
243+ cmdargs >= 0.7 && < 0.11,
244+ containers >= 0.3 && < 0.6,
245+ directory >= 1.0 && < 2.0,
246+ filepath >= 1 && < 2.0,
247+ indents >= 0.3 && < 0.4,
248+ language-glsl >= 0.0.2 && < 0.1,
249+ mtl >= 2 && < 3,
250+ parsec >= 3.1.1 && < 3.5,
251+ pretty >= 1.0 && < 2.0,
252+ text >= 1 && < 2,
253+ transformers >= 0.2 && < 0.5,
254+ union-find >= 0.2 && < 0.3
255255
256256Test-Suite compiler-tests
257257 Type: exitcode-stdio-1.0
@@ -263,43 +263,43 @@ Test-Suite compiler-tests
263263 AST.Helpers
264264 AST.Literal
265265 AST.PrettyPrint
266− build-depends: test-framework,
267− test-framework-hunit,
268− test-framework-quickcheck2 >= 0.3,
269− HUnit,
266+ build-depends: test-framework > 0.8 && < 0.9,
267+ test-framework-hunit >= 0.3 && < 0.4,
268+ test-framework-quickcheck2 >= 0.3 && < 0.4,
269+ HUnit >= 1.1 && < 2,
270270 QuickCheck >= 2 && < 3,
271− aeson,
272− aeson-pretty,
271+ aeson >= 0.7 && < 0.9,
272+ aeson-pretty >= 0.7 && < 0.8,
273273 base >=4.2 && <5,
274− binary >= 0.7.0.0,
275− blaze-html,
276− blaze-markup,
277− bytestring,
278− cheapskate,
279− cmdargs,
280− containers >= 0.3,
281− directory,
274+ binary >= 0.7.0.0 && < 0.8,
275+ blaze-html >= 0.5 && < 0.8,
276+ blaze-markup >= 0.5.1 && < 0.7,
277+ bytestring >= 0.9 && < 0.11,
278+ cheapskate >= 0.1 && < 0.2,
279+ cmdargs >= 0.7 && < 0.11,
280+ containers >= 0.3 && < 0.6,
281+ directory >= 1.0 && < 2.0,
282282 Elm,
283− filemanip,
284− filepath,
285− highlighting-kate,
286− indents,
287− language-ecmascript >=0.15 && < 1.0,
288− language-glsl >= 0.0.2,
289− mtl >= 2,
290− parsec >= 3.1.1,
291− pretty,
292− text,
293− transformers >= 0.2,
294− union-find,
295− unordered-containers
283+ filemanip >= 0.3.5 && < 0.4,
284+ filepath >= 1 && < 2.0,
285+ highlighting-kate >= 0.5 && < 0.6,
286+ indents >= 0.3 && < 0.4,
287+ language-ecmascript >=0.15 && < 0.17,
288+ language-glsl >= 0.0.2 && < 0.1,
289+ mtl >= 2 && < 3,
290+ parsec >= 3.1.1 && < 3.5,
291+ pretty >= 1.0 && < 2.0,
292+ text >= 1 && < 2,
293+ transformers >= 0.2 && < 0.5,
294+ union-find >= 0.2 && < 0.3,
295+ unordered-containers >= 0.1 && < 0.3
296296
297297Test-Suite library-tests
298298 Type: exitcode-stdio-1.0
299299 Hs-Source-Dirs: tests/libraries
300300 Main-is: LibraryTest.hs
301− build-depends: base,
302− directory,
301+ build-depends: base >= 4.2 && <5,
302+ directory >= 1.0 && < 2.0,
303303 Elm,
304− filepath,
305− process
304+ filepath >= 1 && < 2.0,
305+ process >= 1 && < 2.0
changelog.md+3
@@ -17,6 +17,9 @@
1717
1818#### Breaking Changes:
1919
20+ * Rename Basics.id to Basics.identity
21+ * Rename Basics.div to (//)
22+ * Rename Basics.mod to (%)
2023 * Rename Maybe.maybe to Maybe.extract
2124 * Rename Either.either to Either.extract
2225 * Remove Maybe.justs for (List.filterMap id)
compiler/Build/Utils.hs+22−2
@@ -5,6 +5,7 @@ import Control.Monad.Error
55import System.Directory (doesFileExist)
66import System.Environment (getEnv)
77import System.FilePath ((</>), replaceExtension)
8+import System.IO.Error (tryIOError)
89import qualified Build.Flags as Flag
910import qualified Build.Print as Print
1011import qualified Paths_Elm as This
@@ -33,8 +34,27 @@ getDataFile name = do
3334 if exists
3435 then return path
3536 else do
36− env <- getEnv "ELM_HOME"
37− return (env </> name)
37+ environment <- tryIOError (getEnv "ELM_HOME")
38+ case environment of
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+ ]
3858
3959run :: ErrorT String IO a -> IO a
4060run command = do
compiler/Generate/JavaScript.hs+9−9
@@ -418,15 +418,15 @@ binop region func@(Var.Canonical home op) e1 e2 =
418418 ]
419419
420420 specialOps =
421− [ (,) "^" $ \a b -> obj ["Math","pow"] `call` [a,b]
422− , (,) "|>" $ flip (<|)
423− , (,) "==" $ \a b -> _Utils "eq" `call` [a,b]
424− , (,) "/=" $ \a b -> PrefixExpr () PrefixLNot (_Utils "eq" `call` [a,b])
425− , (,) "<" $ cmp OpLT 0
426− , (,) ">" $ cmp OpGT 0
427− , (,) "<=" $ cmp OpLT 1
428− , (,) ">=" $ cmp OpGT (-1)
429− , (,) "div" $ \a b -> InfixExpr () OpBOr (InfixExpr () OpDiv a b) (IntLit () 0)
421+ [ (,) "^" $ \a b -> obj ["Math","pow"] `call` [a,b]
422+ , (,) "|>" $ flip (<|)
423+ , (,) "==" $ \a b -> _Utils "eq" `call` [a,b]
424+ , (,) "/=" $ \a b -> PrefixExpr () PrefixLNot (_Utils "eq" `call` [a,b])
425+ , (,) "<" $ cmp OpLT 0
426+ , (,) ">" $ cmp OpGT 0
427+ , (,) "<=" $ cmp OpLT 1
428+ , (,) ">=" $ cmp OpGT (-1)
429+ , (,) "//" $ \a b -> InfixExpr () OpBOr (InfixExpr () OpDiv a b) (IntLit () 0)
430430 ]
431431
432432 cmp op n a b = InfixExpr () op (_Utils "cmp" `call` [a,b]) (IntLit () n)
compiler/Metadata/Prelude.hs+80−28
@@ -2,6 +2,7 @@
22module Metadata.Prelude (interfaces, add) where
33
44import qualified Data.Map as Map
5+import qualified Data.Set as Set
56import qualified Control.Exception as E
67import System.Exit
78import System.IO
@@ -10,37 +11,88 @@ import qualified AST.Variable as Var
1011import qualified Build.Interface as Interface
1112import Build.Utils (getDataFile)
1213
13−add :: Bool -> Module exs body -> Module exs body
14−add noPrelude (Module name path exs ims decls) =
15− Module name path exs (customIms ++ ims) decls
16− where
17− customIms = if noPrelude then [] else concatMap addModule prelude
18−
19− addModule (n, method) = case lookup n ims of
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
14+
15+-- DEFINITION OF THE PRELUDE
16+
17+type ImportDict =
18+ Map.Map String ([String], Var.Listing Var.Value)
19+
20+prelude :: ImportDict
21+prelude = Map.unions [ string, text, maybe, openImports ]
2622 where
27− modules = [ "Basics", "Signal", "List", "Time", "Color"
28− , "Graphics.Element", "Graphics.Collage"
29− , "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"
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))) $
30+ [ "Basics", "Signal", "List", "Time", "Color"
31+ , "Graphics.Element", "Graphics.Collage"
32+ , "Native.Ports", "Native.Json"
3933 ]
4034
41− maybe =
42− let imports = [ Var.ADT "Maybe" (Var.Listing ["Just", "Nothing"] False) ]
43− in ("Maybe", Module.importing imports)
35+ maybe :: ImportDict
36+ maybe = importing "Maybe" [ Var.ADT "Maybe" Var.openListing ]
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
4496
4597interfaces :: Bool -> IO Interfaces
4698interfaces noPrelude =
libraries/Basics.elm+23−13
@@ -22,7 +22,7 @@ are your tuples so big?
2222@docs not, (&&), (||), xor, otherwise
2323
2424# Mathematics
25−@docs (+), (-), (*), (/), (^), div, rem, mod, abs, sqrt, clamp, logBase, e
25+@docs (+), (-), (*), (/), (^), (//), rem, (%), abs, sqrt, clamp, logBase, e
2626
2727# Trigonometry
2828@docs pi, cos, sin, tan, acos, asin, atan, atan2
@@ -46,7 +46,7 @@ which happen to be radians.
4646@docs fst, snd
4747
4848# Higher-Order Helpers
49−@docs id, always, (<|), (|>), (.), flip, curry, uncurry
49+@docs identity, always, (<|), (|>), (.), flip, curry, uncurry
5050
5151-}
5252
@@ -97,21 +97,29 @@ infixl 7 *
9797infixl 7 /
9898infixl 8 ^
9999
100−infixl 7 `div`
101−infixl 7 `mod`
100+infixl 7 //
101+infixl 7 %
102102infixl 7 `rem`
103103
104104{-| Integer division, remainder is discarded. -}
105−div : Int -> Int -> Int
106−div = Native.Basics.div
105+(//) : Int -> Int -> Int
106+(//) = Native.Basics.div
107107
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+-}
109113rem : Int -> Int -> Int
110114rem = Native.Basics.rem
111115
112−{-| Perform modular arithmetic: ``7 `mod` 2 == 1`` -}
113−mod : Int -> Int -> Int
114−mod = Native.Basics.mod
116+{-| Perform [modular arithmetic](http://en.wikipedia.org/wiki/Modular_arithmetic):
117+
118+ 7 % 2 == 1
119+ -1 % 4 == 3
120+-}
121+(%) : Int -> Int -> Int
122+(%) = Native.Basics.mod
115123
116124{-| Exponentiation: `3^2 == 9` -}
117125(^) : number -> number -> number
@@ -348,9 +356,11 @@ infixr 9 .
348356infixr 0 <|
349357infixl 0 |>
350358
351−{-| Given a value, returns exactly the same value. -}
352−id : a -> a
353−id x = x
359+{-| Given a value, returns exactly the same value. This is called
360+[the identity function](http://en.wikipedia.org/wiki/Identity_function).
361+-}
362+identity : a -> a
363+identity x = x
354364
355365{-| Creates a [constant function](http://en.wikipedia.org/wiki/Constant_function),
356366a function that *always* returns the same value regardless of what input you give.
libraries/Color.elm+1−1
@@ -124,7 +124,7 @@ toRgb color =
124124fmod : Float -> Int -> Float
125125fmod f n =
126126 let integer = floor f
127− in toFloat (integer `mod` n) + f - toFloat integer
127+ in toFloat (integer % n) + f - toFloat integer
128128
129129rgbToHsl : Int -> Int -> Int -> (Float,Float,Float)
130130rgbToHsl red green blue =
libraries/Graphics/Collage.elm+3−2
@@ -33,7 +33,8 @@ it as a single unit.
3333import Basics (..)
3434import List
3535import Either (Either(Left, Right))
36−import Transform2D (Transform2D, identity)
36+import Transform2D (Transform2D)
37+import Transform2D as T
3738import Native.Graphics.Collage
3839import Graphics.Element (Element)
3940import Color (Color, black, Gradient)
@@ -153,7 +154,7 @@ toForm e = form (FElement e)
153154as a single unit, making it possible to build small, modular components.
154155-}
155156group : [Form] -> Form
156−group fs = form (FGroup identity fs)
157+group fs = form (FGroup T.identity fs)
157158
158159{-| Flatten many forms into a single `Form` and then apply a matrix
159160transformation.
libraries/Maybe.elm+1−3
@@ -12,8 +12,6 @@ module Maybe (Maybe(..), maybe, isJust, isNothing, map) where
1212@docs map
1313-}
1414
15−import Basics (not, (.))
16−
1715{-| The Maybe datatype. Useful when a computation may or may not
1816result in a value (e.g. logarithm is defined only for positive
1917numbers).
@@ -49,7 +47,7 @@ isJust = maybe False (\_ -> True)
4947 isNothing Nothing == True
5048-}
5149isNothing : Maybe a -> Bool
52−isNothing = not . isJust
50+isNothing = maybe True (\_ -> False)
5351
5452{-| Transform the contents of a `Maybe` with a given function:
5553
libraries/Native/Array.js+101−49
@@ -35,8 +35,10 @@ Elm.Native.Array.make = function(elm) {
3535 function unsafeGet(i, array) {
3636 for (var x = array.height; x > 0; x--) {
3737 var slot = i >> (x * 5);
38+ while (array.lengths[slot] <= i) {
39+ slot++;
40+ }
3841 if (slot > 0) {
39− while (array.lengths[slot - 1] > i) { slot--; }
4042 i -= array.lengths[slot - 1];
4143 }
4244 array = array.table[slot];
@@ -311,10 +313,12 @@ Elm.Native.Array.make = function(elm) {
311313
312314 // Create new node.
313315 var newA = { ctor:"_Array", height:a.height
314− , table:a.table.slice(0, right + 1)
315− , lengths:a.lengths.slice(0, right + 1) };
316− newA.table[right] = sliced;
317− newA.lengths[right] = length(sliced) + (right > 0 ? newA.lengths[right - 1] : 0);
316+ , table:a.table.slice(0, right)
317+ , lengths:a.lengths.slice(0, right) };
318+ if (sliced.table.length > 0) {
319+ newA.table[right] = sliced;
320+ newA.lengths[right] = length(sliced) + (right > 0 ? newA.lengths[right - 1] : 0);
321+ }
318322 return newA;
319323 }
320324
@@ -343,7 +347,7 @@ Elm.Native.Array.make = function(elm) {
343347 var newA = { ctor:"_Array", height:a.height
344348 , table:a.table.slice(left, a.table.length + 1)
345349 , lengths:new Array(a.table.length - left) };
346− newA.table[left] = sliced;
350+ newA.table[0] = sliced;
347351 var len = 0;
348352 for (var i = 0; i < newA.table.length; i++) {
349353 len += length(newA.table[i]);
@@ -354,70 +358,116 @@ Elm.Native.Array.make = function(elm) {
354358 }
355359
356360 // 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.
359361 function append(a,b) {
360− if (a.table.length == 0) return b;
361− if (b.table.length == 0) return a;
362− if (b.height > a.height) return append(parentise(a, b.height), b);
363− if (a.height > b.height) return append(a, parentise(b, a.height));
364− if (a.height == 0) return append(parentise(a, 1), parentise(b, 1));
362+ if (a.table.length === 0) {
363+ return b;
364+ }
365+ if (b.table.length === 0) {
366+ return a;
367+ }
365368
366369 var c = append_(a, b);
367− if (c[1].table.length > 0) {
368− return siblise(c[0], c[1]);
369− } else {
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+ }
376+ if (c[1].table.length === 0) {
377+ return c[0];
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+
370390 return c[0];
371391 }
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]);
372399 }
373400
374− // Returns an array of two nodes. The second node _may_ be empty. This case
375− // needs to be handled by the function, that called append_. May be only
376− // called for trees with an minimal height of 1.
401+ // Returns an array of two nodes; right and left. One node _may_ be empty.
377402 function append_(a, b) {
378− if (a.height == 1) {
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];
383− }
384−
385− return shuffle(a, b, toRemove);
403+ if (a.height === 0 && b.height === 0) {
404+ return [a, b];
386405 }
387406
388− var appended = append_(botRight(a), botLeft(b));
389− a = nodeCopy(a), b = nodeCopy(b);
407+ if (a.height !== 1 || b.height !== 1) {
408+ if (a.height === b.height) {
409+ a = nodeCopy(a);
410+ b = nodeCopy(b);
411+ var appended = append_(botRight(a), botLeft(b));
390412
391− // Adjust the bottom right side of the new tree.
392− a.table[a.table.length - 1] = appended[0];
393− a.lengths[a.lengths.length - 1] = length(appended[0])
394− a.lengths[a.lengths.length - 1] += a.lengths.length > 1 ? a.lengths[a.lengths.length - 2] : 0;
413+ insertRight(a, appended[1]);
414+ insertLeft(b, appended[0]);
415+ } else if (a.height > b.height) {
416+ a = nodeCopy(a);
417+ var appended = append_(botRight(a), b);
395418
396− // Adjust the bottom left side of the new tree.
397− if (appended[1].table.length > 0) {
398− b.table[0] = appended[1];
399− b.lengths[0] = length(appended[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 {
405− b.table.shift();
406− for (var i = 1; i < b.lengths.length; i++) {
407− b.lengths[i] = b.lengths[i] - b.lengths[0];
419+ insertRight(a, appended[0]);
420+ b = parentise(appended[1], appended[1].height + 1);
421+ } else {
422+ b = nodeCopy(b);
423+ var appended = append_(a, botLeft(b));
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);
408429 }
409− b.lengths.shift();
410430 }
411431
412432 // 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) {
415434 return [a,b];
416435 }
417436
437+ var toRemove = calcToRemove(a, b);
438+ if (toRemove <= E) {
439+ return [a,b];
440+ }
418441 return shuffle(a, b, toRemove);
419442 }
420443
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+
421471 // Returns the extra search steps for E. Refer to the paper.
422472 function calcToRemove(a, b) {
423473 var subLengths = 0;
@@ -558,7 +608,9 @@ Elm.Native.Array.make = function(elm) {
558608 // find the exact slot via forward searching in "lengths". Returns the index.
559609 function getSlot(i, a) {
560610 var slot = i >> (5 * a.height);
561− while (a.lengths[slot - 1] > i) { slot--; }
611+ while (a.lengths[slot] <= i) {
612+ slot++;
613+ }
562614 return slot;
563615 }
564616
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
77import ElmTest.Assertion (..)
88import ElmTest.Test (..)
99
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+
1019tests : Test
1120tests =
1221 let creationTests = suite "Creation"
1322 [ 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])
1524 , test "initialize 2" <| assertEqual (Array.initialize 4 (\n -> n*n)) (Array.fromList [0,1,4,9])
1625 , 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
1827 , test "initialize 4" <| assertEqual (Array.initialize 2 (always 0)) (Array.fromList [0,0])
1928 , test "repeat" <| assertEqual (Array.repeat 5 40) (Array.fromList [40,40,40,40,40])
2029 , test "repeat 2" <| assertEqual (Array.repeat 5 0) (Array.fromList [0,0,0,0,0])
@@ -28,6 +37,7 @@ tests =
2837 , test "append" <| assertEqual [42,42,81,81,81] (Array.toList (Array.append (Array.repeat 2 42) (Array.repeat 3 81)))
2938 , test "appendEmpty 1" <| assertEqual [1..33] (Array.toList (Array.append Array.empty (Array.fromList [1..33])))
3039 , 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)
3141 ]
3242 getAndSetTests = suite "Get and Set"
3343 [ test "get" <| assertEqual (Just 2) (Array.get 1 (Array.fromList [3,2,1]))
@@ -45,6 +55,7 @@ tests =
4555 , test "slice 2" <| assertEqual (Array.fromList [1,2,3]) (Array.slice 1 4 (Array.fromList [0,1,2,3,4]))
4656 , test "slice 3" <| assertEqual (Array.fromList [1,2,3]) (Array.slice 1 -1 (Array.fromList [0,1,2,3,4]))
4757 , 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])
4859 ]
4960 mappingAndFoldingTests = suite "Mapping and Folding"
5061 [ test "map" <| assertEqual (Array.fromList [1,2,3]) (Array.map sqrt (Array.fromList [1,4,9]))
@@ -55,7 +66,7 @@ tests =
5566 , test "foldr 1" <| assertEqual 15 (Array.foldr (+) 0 (Array.repeat 3 5))
5667 , test "foldr 2" <| assertEqual [1,2,3] (Array.foldr (::) [] (Array.fromList [1,2,3]))
5768 , 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]))
5970 ]
6071 nativeTests = suite "Conversion to JS Arrays"
6172 [ 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
55import ElmTest.Assertion (..)
66import ElmTest.Test (..)
77
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+
815tests : Test
916tests =
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)
17+ let partitionTests = suite "partition Tests"
18+ [ test "simple partition" <| assertEqual ([True],[False]) (List.partition identity [False, True])
19+ , test "order check" <| assertEqual ([2,1], [5,6]) (List.partition lessThanThree [2,5,6,1])
20+ , test "partition doc check 1" <| assertEqual ([0,1,2], [3,4,5]) (partition lessThanThree [0..5])
21+ , test "partition doc check 2" <| assertEqual ([0,2,4], [1,3,5]) (partition isEven [0..5])
22+ , test "partition stress test" <| assertEqual (trueList, falseList) (partition identity (falseList ++ trueList))
23+ ]
24+ unzipTests = suite "unzip Tests"
25+ [ test "unzip doc check" <| assertEqual ([0,17,1337],[True,False,True]) (unzip [(0, True), (17, False), (1337, True)])
26+ , test "unzip stress test" <| assertEqual (trueList, falseList) (unzip (zip trueList falseList))
27+ ]
28+ intersperseTests = suite "intersperse Tests"
29+ [ test "intersperse doc check" <| assertEqual ["turtles","on","turtles","on","turtles"] (intersperse "on" ["turtles","turtles","turtles"])
30+ , test "intersperse stress test" <| assertEqual (tail . List.concat <| zipWith (\x y -> [x,y]) falseList trueList) (intersperse False trueList)
31+ ]
32+ in
33+ suite "List Tests"
34+ [ partitionTests
35+ , unzipTests
36+ , intersperseTests
3737 ]
38− in suite "List Tests" [partitionTests, unzipTests, intersperseTests]