on master help sign in
Merge branch 'master' into stable
64fb941Evan Czaplicki
Elm.cabal+1−1
@@ -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,
libraries/Array.elm+22−13
@@ -14,7 +14,7 @@ reads, updates, and appends.
14@docs get, getOrElse, getOrFail, 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,7 +122,7 @@ 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− getOrFail 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,
128so it is best to use `get` or `getOrElse` unless you are sure the index will be
128so it is best to use `get` or `getOrElse` unless you are sure the index will be
@@ -133,9 +133,10 @@ 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 =
@@ -146,8 +147,8 @@ get i array =
146{-| Get the element at the index. Or if the index is out of range, a default
147{-| Get the element at the index. Or if the index is out of range, a default
147value is returned.
148value is returned.
148
149
149− getOrElse 0 2 (fromList [3,2,1]) == 1
150+ getOrElse 0 2 (fromList [0,1,2]) == 2
150− getOrElse 0 5 (fromList [3,2,1]) == 0
151+ getOrElse 0 5 (fromList [0,1,2]) == 0
151-}
152-}
152getOrElse : a -> Int -> Array a -> a
153getOrElse : a -> Int -> Array a -> a
153getOrElse default i array =
154getOrElse default i array =
@@ -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/Native/Array.js+46−6
@@ -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 || {};
@@ -262,9 +262,6 @@ Elm.Native.Array.make = function(elm) {
262 return b;
262 return b;
263 }
263 }
264
264
265− // Returns a sliced tree. "to" is inclusive, but this may change,
266− // when I understand, why e.g. JS does not handle it this way. :-)
267− // If "from" or "to" is negative, they will select from the end on.
268 // TODO: currently, it slices the right, then the left. This can be
265 // TODO: currently, it slices the right, then the left. This can be
269 // optimized.
266 // optimized.
270 function slice(from, to, a) {
267 function slice(from, to, a) {
@@ -281,7 +278,7 @@ Elm.Native.Array.make = function(elm) {
281 // Handle leaf level.
278 // Handle leaf level.
282 if (a.height == 0) {
279 if (a.height == 0) {
283 var newA = { ctor:"_Array", height:0 };
280 var newA = { ctor:"_Array", height:0 };
284− newA.table = a.table.slice(0, to + 1);
281+ newA.table = a.table.slice(0, to);
285 return newA;
282 return newA;
286 }
283 }
287
284
@@ -576,6 +573,46 @@ Elm.Native.Array.make = function(elm) {
576 , lengths:[length(a), length(a) + length(b)] };
573 , lengths:[length(a), length(a) + length(b)] };
577 }
574 }
578
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+
579 Elm.Native.Array.values = {
616 Elm.Native.Array.values = {
580 empty:empty,
617 empty:empty,
581 fromList:fromList,
618 fromList:fromList,
@@ -590,7 +627,10 @@ Elm.Native.Array.make = function(elm) {
590 indexedMap:F2(indexedMap),
627 indexedMap:F2(indexedMap),
591 foldl:F3(foldl),
628 foldl:F3(foldl),
592 foldr:F3(foldr),
629 foldr:F3(foldr),
593− length:length
630+ length:length,
631+
632+ toJSArray:toJSArray,
633+ fromJSArray:fromJSArray
594 };
634 };
595
635
596 return elm.Native.Array.values = Elm.Native.Array.values;
636 return elm.Native.Array.values = Elm.Native.Array.values;
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/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
tests/elm/Test/Array.elm+31−23
@@ -2,6 +2,7 @@ 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 (..)
@@ -21,34 +22,41 @@ tests =
21 , test "fromList" <| assertEqual (Array.fromList []) Array.empty
22 , test "fromList" <| assertEqual (Array.fromList []) Array.empty
22 ]
23 ]
23 basicsTests = suite "Basics"
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 = suite "Get and Set"
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 "getOrElse 1" <| assertEqual (Array.getOrElse 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 "getOrElse 2" <| assertEqual (Array.getOrElse 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 "getOrFail" <| assertEqual (Array.getOrFail 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 = suite "Taking Arrays Apart"
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 = suite "Mapping and Folding"
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− suite "Array Tests" [creationTests, basicsTests, getAndSetTests, takingArraysApartTests, mappingAndFoldingTests]
61+ , takingArraysApartTests, mappingAndFoldingTests, nativeTests
62+ ]
tests/elm/Test/String.elm+27−24
@@ -8,27 +8,30 @@ import ElmTest.Test (..)
8
8
9tests : Test
9tests : Test
10tests =
10tests =
11− let isEmptyTests = suite "isEmpty Tests" [
11+ let simpleTests = suite "Simple Stuff"
12− test "empty is empty" <| assert <| isEmpty "",
12+ [ test "is empty" <| assert (isEmpty "")
13− test "not empty" <| assert <| not . isEmpty <| "the world"
13+ , test "is not empty" <| assert (not (isEmpty ("the world")))
14− ]
15− lengthTest = test "length of innumerable" <| assertEqual 11 (length "innumerable")
14+ , test "length" <| assertEqual 11 (length "innumerable")
15+ , test "endsWith" (assert <| endsWith "ship" "spaceship")
16− reverseTest = test "reverse test" <| assertEqual "desserts" (reverse "stressed")
16+ , test "reverse" <| assertEqual "desserts" (reverse "stressed")
17− repeatTest = test "repeat test" <| assertEqual "hahaha" (repeat 3 "ha")
17+ , test "repeat" <| assertEqual "hahaha" (repeat 3 "ha")
18− unconsTests = suite "uncons Tests" [
18+ ]
19+
20+ combiningTests = suite "Combining Strings"
19− test "nonempty uncons" <| assertEqual (Just ('a',"bc")) (uncons "abc"),
21+ [ test "uncons non-empty" <| assertEqual (Just ('a',"bc")) (uncons "abc")
20− test "empty uncons" <| assertEqual Nothing (uncons "")
22+ , test "uncons empty" <| assertEqual Nothing (uncons "")
21− ]
22− 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")
23− concatTest = test "concat test" <| assertEqual "nevertheless" (concat ["never","the","less"])
26+ , test "concat" <| assertEqual "nevertheless" (concat ["never","the","less"])
24− splitTests = suite "split Tests" [
25− test "split commas" <| assertEqual ["cat","dog","cow"] (split "," "cat,dog,cow"),
27+ , test "split commas" <| assertEqual ["cat","dog","cow"] (split "," "cat,dog,cow")
26− test "split slashes"<| assertEqual ["home","evan","Desktop", ""] (split "/" "home/evan/Desktop/")
28+ , test "split slashes"<| assertEqual ["home","steve","Desktop", ""] (split "/" "home/steve/Desktop/")
27− ]
28− joinTests = suite "join Tests" [
29− test "join spaces" <| assertEqual "cat dog cow" (join " " ["cat","dog","cow"]),
29+ , test "join spaces" <| assertEqual "cat dog cow" (join " " ["cat","dog","cow"])
30− test "join slashes" <| assertEqual "home/evan/Desktop" (join "/" ["home","evan","Desktop"])
30+ , test "join slashes" <| assertEqual "home/steve/Desktop" (join "/" ["home","steve","Desktop"])
31− ]
31+ , test "slice 1" <| assertEqual "c" (slice 2 3 "abcd")
32−
32+ , test "slice 2" <| assertEqual "abc" (slice 0 3 "abcd")
33− endsWithTest = test "endsWith Check" (assert <| endsWith "h" "th")
33+ , test "slice 3" <| assertEqual "abc" (slice 0 -1 "abcd")
34− in suite "String Tests" [isEmptyTests, lengthTest, reverseTest, repeatTest, unconsTests, appendTest, concatTest, splitTests, joinTests, endsWithTest]
34+ , test "slice 4" <| assertEqual "cd" (slice -2 4 "abcd")
35+ ]
36+ in
37+ suite "String" [ simpleTests, combiningTests ]