on master help sign in
Merge branch 'master' into stable
commit64fb941bf4fef1516b78e356fc60ea4f0a389313 authorEvan Czaplicki <info@elm-lang.org> dateWed 30 Apr 2014, 18:52 (13 years ago) parent8060970fd05744
7 files changed+137−77
Elm.cabal+1−1 libraries/Array.elm+22−13 libraries/Native/Array.js+46−6 libraries/Native/String.js+2−2 libraries/String.elm+8−8 tests/elm/Test/Array.elm+31−23 tests/elm/Test/String.elm+27−24
Elm.cabal+1−1
@@ -27,7 +27,7 @@ Cabal-version: >=1.9
2727
2828source-repository head
2929 type: git
30− location: git://github.com/evancz/Elm.git
30+ location: git://github.com/elm-lang/Elm.git
3131
3232Library
3333 exposed-modules: Elm.Internal.Dependencies,
libraries/Array.elm+22−13
@@ -14,7 +14,7 @@ reads, updates, and appends.
1414@docs get, getOrElse, getOrFail, set
1515
1616# Taking Arrays Apart
17−@docs toList, toIndexedList, slice
17+@docs slice, toList, toIndexedList
1818
1919# Mapping and Folding
2020@docs map, indexedMap, foldl, foldr
@@ -122,7 +122,7 @@ push = Native.Array.push
122122
123123{-| Get the element at a particular index.
124124
125− getOrFail 2 (A.fromList [3,2,1]) == 1
125+ getOrFail 0 (A.fromList [0,1,2]) == 0
126126
127127Warning: this function will result in a runtime error if the index is not found,
128128so it is best to use `get` or `getOrElse` unless you are sure the index will be
@@ -133,9 +133,10 @@ getOrFail = Native.Array.get
133133
134134{-| Return Just the element at the index or Nothing if the index is out of range.
135135
136− get 2 (fromList [3,2,1]) == Just 2
137− get 5 (fromList [3,2,1]) == Nothing
138− get -1 (fromList [3,2,1]) == Nothing
136+ get 0 (fromList [0,1,2]) == Just 0
137+ get 2 (fromList [0,1,2]) == Just 2
138+ get 5 (fromList [0,1,2]) == Nothing
139+ get -1 (fromList [0,1,2]) == Nothing
139140-}
140141get : Int -> Array a -> Maybe a
141142get i array =
@@ -146,8 +147,8 @@ get i array =
146147{-| Get the element at the index. Or if the index is out of range, a default
147148value is returned.
148149
149− getOrElse 0 2 (fromList [3,2,1]) == 1
150− getOrElse 0 5 (fromList [3,2,1]) == 0
150+ getOrElse 0 2 (fromList [0,1,2]) == 2
151+ getOrElse 0 5 (fromList [0,1,2]) == 0
151152-}
152153getOrElse : a -> Int -> Array a -> a
153154getOrElse default i array =
@@ -163,13 +164,21 @@ If the index is out of range, the array is unaltered.
163164set : Int -> a -> Array a -> Array a
164165set = Native.Array.set
165166
166−{-| Slice an array given a range. The selection is inclusive, so the last
167−element in the selection will also be in the new array. This may change in the
168−future. You can select from the end by giving a negative Int.
167+{-| Get a sub-section of an array: `(slice start end array)`. The `start` is a
168+zero-based index where we will start our slice. The `end` is a zero-based index
169+that indicates the end of the slice. The slice extracts up to but not including
170+`end`.
169171
170− slice 1 2 (fromList [0,1,2,3,4]) == fromList [1,2]
171− slice 1 -2 (fromList [0,1,2,3,4]) == fromList [1,2,3]
172− slice -3 -2 (fromList [0,1,2,3,4]) == fromList [2,3]
172+ slice 0 3 (fromList [0,1,2,3,4]) == fromList [0,1,2]
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]
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`
173182-}
174183slice : Int -> Int -> Array a -> Array a
175184slice = Native.Array.slice
libraries/Native/Array.js+46−6
@@ -1,4 +1,4 @@
1−Elm.Native.Array = {};
1+Elm.Native.Array = {};
22Elm.Native.Array.make = function(elm) {
33 elm.Native = elm.Native || {};
44 elm.Native.Array = elm.Native.Array || {};
@@ -262,9 +262,6 @@ Elm.Native.Array.make = function(elm) {
262262 return b;
263263 }
264264
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.
268265 // TODO: currently, it slices the right, then the left. This can be
269266 // optimized.
270267 function slice(from, to, a) {
@@ -281,7 +278,7 @@ Elm.Native.Array.make = function(elm) {
281278 // Handle leaf level.
282279 if (a.height == 0) {
283280 var newA = { ctor:"_Array", height:0 };
284− newA.table = a.table.slice(0, to + 1);
281+ newA.table = a.table.slice(0, to);
285282 return newA;
286283 }
287284
@@ -576,6 +573,46 @@ Elm.Native.Array.make = function(elm) {
576573 , lengths:[length(a), length(a) + length(b)] };
577574 }
578575
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+
579616 Elm.Native.Array.values = {
580617 empty:empty,
581618 fromList:fromList,
@@ -590,7 +627,10 @@ Elm.Native.Array.make = function(elm) {
590627 indexedMap:F2(indexedMap),
591628 foldl:F3(foldl),
592629 foldr:F3(foldr),
593− length:length
630+ length:length,
631+
632+ toJSArray:toJSArray,
633+ fromJSArray:fromJSArray
594634 };
595635
596636 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) {
7373 return result;
7474 }
7575
76− function sub(start, end, str) {
76+ function slice(start, end, str) {
7777 return str.slice(start,end);
7878 }
7979 function left(n, str) {
@@ -216,7 +216,7 @@ Elm.Native.String.make = function(elm) {
216216 join: F2(join),
217217 repeat: F2(repeat),
218218
219− sub: F3(sub),
219+ slice: F3(slice),
220220 left: F2(left),
221221 right: F2(right),
222222 dropLeft: F2(dropLeft),
libraries/String.elm+8−8
@@ -6,10 +6,10 @@ are enclosed in `"double quotes"`. Strings are *not* lists of characters.
66@docs isEmpty, length, reverse, repeat
77
88# Building and Splitting
9−@docs cons, uncons, append, concat, split, join, words, lines
9+@docs cons, uncons, append, concat, split, join, words, lines
1010
1111# Get Substrings
12−@docs sub, left, right, dropLeft, dropRight
12+@docs slice, left, right, dropLeft, dropRight
1313
1414# Check for Substrings
1515@docs contains, startsWith, endsWith, indexes, indices
@@ -139,13 +139,13 @@ repeat = Native.String.repeat
139139{-| Take a substring given a start and end index. Negative indexes
140140are taken starting from the *end* of the list.
141141
142− sub 7 9 "snakes on a plane!" == "on"
143− sub 0 6 "snakes on a plane!" == "snakes"
144− sub 0 -7 "snakes on a plane!" == "snakes on a"
145− sub -6 -1 "snakes on a plane!" == "plane"
142+ slice 7 9 "snakes on a plane!" == "on"
143+ slice 0 6 "snakes on a plane!" == "snakes"
144+ slice 0 -7 "snakes on a plane!" == "snakes on a"
145+ slice -6 -1 "snakes on a plane!" == "plane"
146146-}
147−sub : Int -> Int -> String -> String
148−sub = Native.String.sub
147+slice : Int -> Int -> String -> String
148+slice = Native.String.slice
149149
150150{-| Take N characters from the left side of a string. -}
151151left : Int -> String -> String
tests/elm/Test/Array.elm+31−23
@@ -2,6 +2,7 @@ module Test.Array (tests) where
22
33import List
44import Array
5+import Native.Array
56
67import ElmTest.Assertion (..)
78import ElmTest.Test (..)
@@ -21,34 +22,41 @@ tests =
2122 , test "fromList" <| assertEqual (Array.fromList []) Array.empty
2223 ]
2324 basicsTests = suite "Basics"
24− [ test "length" <| assertEqual (Array.length (Array.fromList [1,2,3])) 3
25− , test "length - Long" <| assertEqual (Array.length (Array.repeat 10000 0)) 10000
26− , test "push" <| assertEqual (Array.push 3 (Array.fromList [1,2])) (Array.fromList [1,2,3])
27− , test "append" <| assertEqual (Array.toList <| Array.append (Array.repeat 2 42) (Array.repeat 3 81)) ([42,42,81,81,81])
25+ [ test "length" <| assertEqual 3 (Array.length (Array.fromList [1,2,3]))
26+ , test "length - Long" <| assertEqual 10000 (Array.length (Array.repeat 10000 0))
27+ , test "push" <| assertEqual (Array.fromList [1,2,3]) (Array.push 3 (Array.fromList [1,2]))
28+ , test "append" <| assertEqual [42,42,81,81,81] (Array.toList (Array.append (Array.repeat 2 42) (Array.repeat 3 81)))
2829 ]
2930 getAndSetTests = suite "Get and Set"
30− [ test "get" <| assertEqual (Array.get 1 (Array.fromList [3,2,1])) (Just 2)
31− , test "get 2" <| assertEqual (Array.get 5 (Array.fromList [3,2,1])) Nothing
32− , test "get 3" <| assertEqual (Array.get -1 (Array.fromList [3,2,1])) Nothing
33− , test "getOrElse 1" <| assertEqual (Array.getOrElse 0 2 (Array.fromList [3,2,1])) 1
34− , test "getOrElse 2" <| assertEqual (Array.getOrElse 0 5 (Array.fromList [3,2,1])) 0
35− , test "getOrFail" <| assertEqual (Array.getOrFail 2 (Array.fromList [3,2,1])) 1
36− , test "set" <| assertEqual (Array.set 1 7 (Array.fromList [1,2,3])) (Array.fromList [1,7,3])
31+ [ test "get" <| assertEqual (Just 2) (Array.get 1 (Array.fromList [3,2,1]))
32+ , test "get 2" <| assertEqual Nothing (Array.get 5 (Array.fromList [3,2,1]))
33+ , test "get 3" <| assertEqual Nothing (Array.get -1 (Array.fromList [3,2,1]))
34+ , test "getOrElse 1" <| assertEqual 1 (Array.getOrElse 0 2 (Array.fromList [3,2,1]))
35+ , test "getOrElse 2" <| assertEqual 0 (Array.getOrElse 0 5 (Array.fromList [3,2,1]))
36+ , test "getOrFail" <| assertEqual 1 (Array.getOrFail 2 (Array.fromList [3,2,1]))
37+ , test "set" <| assertEqual (Array.fromList [1,7,3]) (Array.set 1 7 (Array.fromList [1,2,3]))
3738 ]
3839 takingArraysApartTests = suite "Taking Arrays Apart"
39− [ test "toList" <| assertEqual (Array.toList (Array.fromList [3,5,8])) [3,5,8]
40− , test "toIndexedList" <| assertEqual (Array.toIndexedList (Array.fromList ["cat","dog"])) [(0,"cat"), (1,"dog")]
41− , test "slice" <| assertEqual (Array.slice 1 2 (Array.fromList [0,1,2,3,4])) (Array.fromList [1,2])
42− , test "slice 2" <| assertEqual (Array.slice 1 -2 (Array.fromList [0,1,2,3,4])) (Array.fromList [1,2,3])
43− , test "slice 3" <| assertEqual (Array.slice -3 -2 (Array.fromList [0,1,2,3,4])) (Array.fromList [2,3])
40+ [ test "toList" <| assertEqual [3,5,8] (Array.toList (Array.fromList [3,5,8]))
41+ , test "toIndexedList" <| assertEqual [(0,"cat"), (1,"dog")] (Array.toIndexedList (Array.fromList ["cat","dog"]))
42+ , test "slice 1" <| assertEqual (Array.fromList [0,1,2]) (Array.slice 0 3 (Array.fromList [0,1,2,3,4]))
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]))
45+ , test "slice 4" <| assertEqual (Array.fromList [2]) (Array.slice -3 -2 (Array.fromList [0,1,2,3,4]))
4446 ]
4547 mappingAndFoldingTests = suite "Mapping and Folding"
46− [ test "map" <| assertEqual (Array.map sqrt (Array.fromList [1,4,9])) (Array.fromList [1,2,3])
47− , test "indexedMap" <| assertEqual (Array.indexedMap (*) (Array.fromList [5,5,5])) (Array.fromList [0,5,10])
48− , test "foldl" <| assertEqual (Array.foldl (::) [] (Array.fromList [1,2,3])) [3,2,1]
49− , test "foldr" <| assertEqual (Array.foldr (+) 0 (Array.repeat 3 5)) 15
50− , test "foldr 2" <| assertEqual (Array.foldr (::) [] (Array.fromList [1,2,3])) [1,2,3]
51− , test "filter" <| assertEqual (Array.filter (\x -> x `mod` 2 == 0) (Array.fromList [1..6])) (Array.fromList [2,4,6])
48+ [ test "map" <| assertEqual (Array.fromList [1,2,3]) (Array.map sqrt (Array.fromList [1,4,9]))
49+ , test "indexedMap" <| assertEqual (Array.fromList [0,5,10]) (Array.indexedMap (*) (Array.fromList [5,5,5]))
50+ , test "foldl" <| assertEqual [3,2,1] (Array.foldl (::) [] (Array.fromList [1,2,3]))
51+ , test "foldr 1" <| assertEqual 15 (Array.foldr (+) 0 (Array.repeat 3 5))
52+ , test "foldr 2" <| assertEqual [1,2,3] (Array.foldr (::) [] (Array.fromList [1,2,3]))
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])))
5257 ]
5358 in
54− suite "Array Tests" [creationTests, basicsTests, getAndSetTests, takingArraysApartTests, mappingAndFoldingTests]
59+ suite "Array"
60+ [ creationTests, basicsTests, getAndSetTests
61+ , takingArraysApartTests, mappingAndFoldingTests, nativeTests
62+ ]
tests/elm/Test/String.elm+27−24
@@ -8,27 +8,30 @@ import ElmTest.Test (..)
88
99tests : Test
1010tests =
11− let isEmptyTests = suite "isEmpty Tests" [
12− test "empty is empty" <| assert <| isEmpty "",
13− test "not empty" <| assert <| not . isEmpty <| "the world"
14− ]
15− lengthTest = test "length of innumerable" <| assertEqual 11 (length "innumerable")
16− reverseTest = test "reverse test" <| assertEqual "desserts" (reverse "stressed")
17− repeatTest = test "repeat test" <| assertEqual "hahaha" (repeat 3 "ha")
18− unconsTests = suite "uncons Tests" [
19− test "nonempty uncons" <| assertEqual (Just ('a',"bc")) (uncons "abc"),
20− test "empty uncons" <| assertEqual Nothing (uncons "")
21− ]
22− appendTest = test "append test" <| assertEqual "butterfly" (append "butter" "fly")
23− concatTest = test "concat test" <| assertEqual "nevertheless" (concat ["never","the","less"])
24− splitTests = suite "split Tests" [
25− test "split commas" <| assertEqual ["cat","dog","cow"] (split "," "cat,dog,cow"),
26− test "split slashes"<| assertEqual ["home","evan","Desktop", ""] (split "/" "home/evan/Desktop/")
27− ]
28− joinTests = suite "join Tests" [
29− test "join spaces" <| assertEqual "cat dog cow" (join " " ["cat","dog","cow"]),
30− test "join slashes" <| assertEqual "home/evan/Desktop" (join "/" ["home","evan","Desktop"])
31− ]
32−
33− endsWithTest = test "endsWith Check" (assert <| endsWith "h" "th")
34− in suite "String Tests" [isEmptyTests, lengthTest, reverseTest, repeatTest, unconsTests, appendTest, concatTest, splitTests, joinTests, endsWithTest]
11+ let simpleTests = suite "Simple Stuff"
12+ [ test "is empty" <| assert (isEmpty "")
13+ , test "is not empty" <| assert (not (isEmpty ("the world")))
14+ , test "length" <| assertEqual 11 (length "innumerable")
15+ , test "endsWith" (assert <| endsWith "ship" "spaceship")
16+ , test "reverse" <| assertEqual "desserts" (reverse "stressed")
17+ , test "repeat" <| assertEqual "hahaha" (repeat 3 "ha")
18+ ]
19+
20+ combiningTests = suite "Combining Strings"
21+ [ test "uncons non-empty" <| assertEqual (Just ('a',"bc")) (uncons "abc")
22+ , test "uncons empty" <| assertEqual Nothing (uncons "")
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")
26+ , test "concat" <| assertEqual "nevertheless" (concat ["never","the","less"])
27+ , test "split commas" <| assertEqual ["cat","dog","cow"] (split "," "cat,dog,cow")
28+ , test "split slashes"<| assertEqual ["home","steve","Desktop", ""] (split "/" "home/steve/Desktop/")
29+ , test "join spaces" <| assertEqual "cat dog cow" (join " " ["cat","dog","cow"])
30+ , test "join slashes" <| assertEqual "home/steve/Desktop" (join "/" ["home","steve","Desktop"])
31+ , test "slice 1" <| assertEqual "c" (slice 2 3 "abcd")
32+ , test "slice 2" <| assertEqual "abc" (slice 0 3 "abcd")
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 ]