on master help sign in
Merge branch 'master' into webgl
commit7f7b545dc35d73049d3f00f55be9b05b8bd80300 authorJohn P Mayer Jr <john.p.mayer.jr@gmail.com> dateTue 15 Apr 2014, 15:41 (13 years ago) parent42ae81a97c9475
43 files changed+440−228
.gitignore+4 .gitmodules+9 CONTRIBUTING.md+20−19 Elm-Test+1 Elm.cabal+20−13 IO+1 README.md+11−46 automaton+1 libraries/Array.elm+61−75 libraries/Graphics/Input.elm+1−1 libraries/Native/Array.js+133−32 libraries/Native/Graphics/Input.js−29 libraries/Native/Utils.js+13−8 libraries/Signal.elm−3 runtime/Render/Element.js+8−2 tests/elm/Test.elm+28 tests/elm/Test/Array.elm+47 tests/elm/Test/String.elm+26 tests/elm/Test/Trampoline.elm+29 tests/Main.hs → tests/hs/CompilerTest.hs tests/hs/LibTest.hs+27 tests/Tests/Compiler.hs → tests/hs/Tests/Compiler.hs tests/Tests/Property.hs → tests/hs/Tests/Property.hs tests/Tests/Property/Arbitrary.hs → tests/hs/Tests/Property/Arbitrary.hs tests/test-files/bad/BBTArgs → tests/hs/test-files/bad/BBTArgs tests/test-files/bad/InfiniteType.elm → tests/hs/test-files/bad/InfiniteType.elm tests/test-files/bad/NonElementMain.elm → tests/hs/test-files/bad/NonElementMain.elm tests/test-files/bad/Strings/ExtraClose.elm → tests/hs/test-files/bad/Strings/ExtraClose.elm tests/test-files/good/AliasSubstitution.elm → tests/hs/test-files/good/AliasSubstitution.elm tests/test-files/good/NoExpressions.elm → tests/hs/test-files/good/NoExpressions.elm tests/test-files/good/Otherwise.elm → tests/hs/test-files/good/Otherwise.elm tests/test-files/good/Ports.elm → tests/hs/test-files/good/Ports.elm tests/test-files/good/QuotesAndComments.elm → tests/hs/test-files/good/QuotesAndComments.elm tests/test-files/good/Soundness/Apply.elm → tests/hs/test-files/good/Soundness/Apply.elm tests/test-files/good/Soundness/ApplyAnnotated.elm → tests/hs/test-files/good/Soundness/ApplyAnnotated.elm tests/test-files/good/Soundness/Id.elm → tests/hs/test-files/good/Soundness/Id.elm tests/test-files/good/Soundness/IdAnnotated.elm → tests/hs/test-files/good/Soundness/IdAnnotated.elm tests/test-files/good/Soundness/TrickyId.elm → tests/hs/test-files/good/Soundness/TrickyId.elm tests/test-files/good/Soundness/TrickyIdAnnotated.elm → tests/hs/test-files/good/Soundness/TrickyIdAnnotated.elm tests/test-files/good/Strings/Multiline.elm → tests/hs/test-files/good/Strings/Multiline.elm tests/test-files/good/Strings/MultilineNormal.elm → tests/hs/test-files/good/Strings/MultilineNormal.elm tests/test-files/good/Unify/LockedVars.elm → tests/hs/test-files/good/Unify/LockedVars.elm tests/test-files/good/Unify/NonHomogeneousRecords.elm → tests/hs/test-files/good/Unify/NonHomogeneousRecords.elm
.gitignore+4
@@ -13,3 +13,7 @@ data
1313build
1414cache
1515*~
16+tests/elm/build/
17+tests/elm/cache/
18+tests/elm/exe.js
19+node_modules/
.gitmodulesnew file+9
@@ -0,0 +1,9 @@
1+[submodule "IO"]
2+ path = IO
3+ url = https://github.com/maxsnew/IO.git
4+[submodule "automaton"]
5+ path = automaton
6+ url = https://github.com/evancz/automaton.git
7+[submodule "Elm-Test"]
8+ path = Elm-Test
9+ url = https://github.com/deadfoxygrandpa/Elm-Test.git
CONTRIBUTING.md+20−19
@@ -5,31 +5,32 @@ describes the basic standards for opening pull requests:
55
66## Branches
77
8− * The master branch of Elm is for tagging previous releases
9− and non-breaking changes, like bug fixes. This branch is
10− handy for folks who want to build the most recent public
11− release from source.
8+ * [The master branch](https://github.com/elm-lang/Elm/tree/master) is the
9+ home of the next release of the compiler so new features and improvements
10+ get merged there. Most pull requests should target this branch!
1211
13− * The dev branch is where the most active development occurs.
14− It is the home of the next release of the compiler so new
15− features and improvements get merged there.
12+ * [The stable branch](https://github.com/elm-lang/Elm/tree/stable) is for
13+ tagging previous releases and critical bug fixes. This branch is handy for
14+ folks who want to build the most recent public release from source.
15+
16+If you are working on a fairly large feature, we will probably want to merge it
17+in as its own branch and do some testing before bringing it into the master
18+branch. This way we can keep releases of the master branch independent of new
19+features.
1620
1721## Opening a pull request
1822
19−**Please open PRs against the [dev branch of
20−Elm](http://github.com/evancz/elm/tree/dev) whenever possible.** Changes that
21−are compatible with the API of master will be merged to master as soon as
22−possible. Changes that affect Elm's API will be merged to master with a future
23−release of the compiler.
23+**Please open PRs against the [master branch of
24+Elm](http://github.com/elm-lang/elm/tree/master) whenever possible.**
2425
25−Note that changes in the master branch of [Elm](https://github.com/evancz/Elm/)
26+Note that changes in the master branch of [Elm](https://github.com/elm-lang/Elm/)
2627are able to be compiled against the master branch of the [elm-lang.org
27−repo](https://github.com/evancz/elm-lang.org), and the dev branch of
28−[Elm](https://github.com/evancz/Elm/) is able to be built with the dev branch of
29−the [elm-lang.org repo](https://github.com/evancz/elm-lang.org). Please make
30−sure that your changes maintain this compatibility.
28+repo](https://github.com/elm-lang/elm-lang.org), and the stable branch of
29+[Elm](https://github.com/elm-lang/Elm/) is able to be built with the stable
30+branch of the [elm-lang.org repo](https://github.com/elm-lang/elm-lang.org).
31+Please make sure that your changes maintain this compatibility.
3132
3233## Licensing
3334
34−You should sign the [contributor agreement](ContributorAgreement.pdf)
35−and send it to <info@elm-lang.org> before opening your pull request.
35+You need to sign the [contributor agreement](ContributorAgreement.pdf)
36+and send it to <info@elm-lang.org> before opening your pull request.
Elm-Testnew file+1

Submodule changed.

Elm.cabal+20−13
@@ -96,7 +96,7 @@ Library
9696
9797 Build-depends: aeson,
9898 base >=4.2 && <5,
99− binary >= 0.6.4.0,
99+ binary >= 0.7.0.0,
100100 blaze-html >= 0.5 && < 0.8,
101101 blaze-markup,
102102 bytestring,
@@ -179,7 +179,7 @@ Executable elm
179179
180180 Build-depends: aeson,
181181 base >=4.2 && <5,
182− binary >= 0.6.4.0,
182+ binary >= 0.7.0.0,
183183 blaze-html >= 0.5 && < 0.8,
184184 blaze-markup,
185185 bytestring,
@@ -224,7 +224,7 @@ Executable elm-doc
224224 Build-depends: aeson,
225225 aeson-pretty,
226226 base >=4.2 && <5,
227− binary >= 0.6.4.0,
227+ binary >= 0.7.0.0,
228228 bytestring,
229229 cmdargs,
230230 containers >= 0.3,
@@ -239,35 +239,32 @@ Executable elm-doc
239239 text,
240240 union-find
241241
242−Test-Suite test-elm
242+Test-Suite compiler-tests
243243 Type: exitcode-stdio-1.0
244− Hs-Source-Dirs: tests, compiler
245− Main-is: Main.hs
244+ Hs-Source-Dirs: tests/hs, compiler
245+ Main-is: CompilerTest.hs
246246 other-modules: Tests.Compiler
247247 Tests.Property
248248 Tests.Property.Arbitrary
249249 SourceSyntax.Helpers
250250 SourceSyntax.Literal
251251 SourceSyntax.PrettyPrint
252− build-depends: base,
253− directory,
254− Elm,
255− test-framework,
252+ build-depends: test-framework,
256253 test-framework-hunit,
257254 test-framework-quickcheck2 >= 0.3,
258255 HUnit,
259− pretty,
260256 QuickCheck >= 2 && < 3,
261− filemanip,
262257 aeson,
263258 base >=4.2 && <5,
264− binary >= 0.6.4.0,
259+ binary >= 0.7.0.0,
265260 blaze-html == 0.5.* || == 0.6.*,
266261 blaze-markup == 0.5.1.*,
267262 bytestring,
268263 cmdargs,
269264 containers >= 0.3,
270265 directory,
266+ Elm,
267+ filemanip,
271268 filepath,
272269 indents,
273270 language-ecmascript >=0.15 && < 1.0,
@@ -280,3 +277,13 @@ Test-Suite test-elm
280277 transformers >= 0.2,
281278 union-find,
282279 unordered-containers
280+
281+Test-Suite lib-tests
282+ Type: exitcode-stdio-1.0
283+ Hs-Source-Dirs: tests/hs
284+ Main-is: LibTest.hs
285+ build-depends: base,
286+ directory,
287+ Elm,
288+ filepath,
289+ process >= 1.2
IOnew file+1

Submodule changed.

README.md+11−46
@@ -4,55 +4,20 @@ Learn about the Elm programming language at [elm-lang.org](http://elm-lang.org/)
44
55## Install
66
7−**Arch Linux** &mdash; follow [these directions](https://github.com/elm-lang/Elm/wiki/Installing-Elm#arch-linux) and then
8−jump to the [My First Project](#my-first-project) section.
9−<br/>
10−**OS X 10.9 or XCode 5** &mdash; follow
11−[these directions](http://justtesting.org/post/64947952690/the-glasgow-haskell-compiler-ghc-on-os-x-10-9)
12−before continuing with the platform agnostic directions below.
7+Follow [these instructions][installer] if you just want to use Elm. To build
8+the compiler from source, run the following commands:
139
14−**Platform Agnostic** &mdash;
15−download the [Haskell Platform 2012.2.0.0 or later](http://hackage.haskell.org/platform/).
16−Once the Haskell Platform is installed:
10+ [installer]: https://github.com/elm-lang/elm-platform/blob/master/README.md#elm-platform
1711
18− cabal update
19− cabal install elm
20− cabal install elm-server
12+```bash
13+git clone https://github.com/elm-lang/Elm.git
14+cd Elm
15+cabal configure
16+cabal build
17+```
2118
22−## Use
23−
24−To use `elm` and `elm-server` you may need to add a new directory to your PATH.
25−
26−Cabal should tell you where your executables are located upon
27−successful installation. It'll be something like `/home/evan/.cabal/bin`
28−which you should append to your PATH variable.
29−See this tutorial if you are new to changing your PATH in
30−[Unix/Linux](http://www.cyberciti.biz/faq/unix-linux-adding-path/).
31−
32−## My First Project
33−
34−Now we will create a simple Elm project.
35−The following commands will set-up a very basic project and start the Elm server.
36−
37− mkdir helloElm
38− cd helloElm
39− printf "import Mouse\n\nmain = lift asText Mouse.position" > Main.elm
40− elm-server
41−
42−The first two commands create a new directory and navigate into it. The `printf`
43−commands place a simple program into `Main.elm`. Do this manually if you do not
44−have `printf`. The final command starts the Elm server at [localhost:8000](http://localhost:8000/),
45−allowing you to navigate to `Main.elm` and see your first program in action.
46−
47−#### Final Notes
48−
49−The `elm` package provides
50−[some utility functions](http://hackage.haskell.org/package/Elm) for
51−working with Elm in Haskell. This can be useful for creating tooling
52−for Elm, and has been useful for projects like
53−[the website](http://elm-lang.org/) and
54−[`elm-get`](https://github.com/elm-lang/elm-get). Email the list if you
55−want to rely on these functions!
19+This will build the compiler in `/dist/build/elm/elm` but it will not be on
20+your PATH.
5621
5722If you are stuck, email
5823[the list](https://groups.google.com/forum/?fromgroups#!forum/elm-discuss)
automatonnew file+1

Submodule changed.

libraries/Array.elm+61−75
@@ -1,23 +1,23 @@
11module Array where
22
3−{-| A library for immutable arrays. The elements in an array must have the same
4−type. The arrays are implemented in Relaxed Radix Balanced-Trees for fast
5−reads, updates, and concatenation.
3+{-| A library for fast immutable arrays. The elements in an array must have the
4+same type. The arrays are implemented in Relaxed Radix Balanced-Trees for fast
5+reads, updates, and appends.
66
7−If you use more then one map or zip function on an array, consider turning it
8−into a list before operating on it, and then turning it back into an array.
7+# Creating Arrays
8+@docs empty, repeat, initialize, fromList
99
1010# Basics
11−@docs empty, length, get, getMaybe, getSafe
11+@docs length, push, append
1212
13−# Putting Arrays Together
14−@docs fill, fromList, concat, set, updates, push
13+# Get and Set
14+@docs get, getMaybe, getWithDefault, set
1515
1616# Taking Arrays Apart
17−@docs toList, toIndexedList, indices, slice
17+@docs toList, toIndexedList, slice
1818
19−# Mapping, folding, zipping
20−@docs map, indexedMap, foldl, foldr, zip, zipWith
19+# Mapping and Folding
20+@docs map, indexedMap, foldl, foldr
2121-}
2222
2323import Native.Array
@@ -27,17 +27,29 @@ import List
2727
2828data Array a = Array
2929
30−{-| Fills an array with a given length and a default element.
30+{-| Initialize an array. `initialize n f` creates an array of length `n` with
31+the element at index `i` initialized to the result of `(f i)`.
3132
32− fill 3 5 == fromList [5,5,5]
33+ initialize 4 id == fromList [0,1,2,3]
34+ initialize 4 (\n -> n*n) == fromList [0,1,4,9]
35+ initialize 4 (always 0) == fromList [0,0,0,0]
3336-}
34−fill : Int -> a -> Array a
35−fill len e = fromList <| List.map (always e) [1..len]
37+initialize : Int -> (Int -> a) -> Array a
38+initialize = Native.Array.initialize
39+
40+{-| Creates an array with a given length, filled with a default element.
41+
42+ repeat 5 0 == fromList [0,0,0,0,0]
43+ repeat 3 "cat" == fromList ["cat","cat","cat"]
44+
45+Notice that `repeat 3 x` is the same as `initialize 3 (always x)`.
46+-}
47+repeat : Int -> a -> Array a
48+repeat n e = initialize n (always e)
3649
37−-- TODO: make this a native function.
3850{-| Create an array from a list. -}
3951fromList : [a] -> Array a
40−fromList = List.foldl (Native.Array.push) Native.Array.empty
52+fromList = Native.Array.fromList
4153
4254{-| Create a list of elements from an array.
4355
@@ -46,24 +58,19 @@ fromList = List.foldl (Native.Array.push) Native.Array.empty
4658toList : Array a -> [a]
4759toList = Native.Array.toList
4860
49−{-| Create a list of the possible indices of an array.
50−
51− indices (fromList [3,5,8] == [0,1,2])
52−-}
53−indices : Array a -> [Int]
54−indices a = [0..Native.Array.length a - 1]
55−
5661-- TODO: make this a native function.
57−{-| Create a list of tuples (Index, Element) from an array.
62+{-| Create an indexed list from an array. Each element of the array will be
63+paired with its index.
5864
59− toIndexedList (fromList [3,5,8]) == [(0,3), (1,5), (2,8)]
65+ toIndexedList (fromList ["cat","dog"]) == [(0,"cat"), (1,"dog")]
6066-}
6167toIndexedList : Array a -> [(Int, a)]
62−toIndexedList a = List.zip (indices a) (Native.Array.toList a)
68+toIndexedList array =
69+ List.zip [ 0 .. Native.Array.length array - 1 ] (Native.Array.toList array)
6370
6471{-| Apply a function on every element in an array.
6572
66− map (\x -> x*x) (fromList [1,2,3]) == fromList [1,4,9]
73+ map sqrt (fromList [1,4,9]) == fromList [1,2,3]
6774-}
6875map : (a -> b) -> Array a -> Array b
6976map = Native.Array.map
@@ -77,35 +84,18 @@ indexedMap = Native.Array.indexedMap
7784
7885{-| Reduce an array from the left.
7986
80− foldl (+) 0 (fill 3 5) == 15
87+ foldl (::) [] (fromList [1,2,3]) == [3,2,1]
8188-}
8289foldl : (a -> b -> b) -> b -> Array a -> b
8390foldl = Native.Array.foldl
8491
8592{-| Reduce an array from the right.
8693
87− foldr (::) [] (fromList [1,2,3]) == [3,2,1]
94+ foldr (+) 0 (repeat 3 5) == 15
8895-}
8996foldr : (a -> b -> b) -> b -> Array a -> b
9097foldr = Native.Array.foldr
9198
92−{-| Zip the elements of two arrays via a tuple into a new array. If one array is
93−longer, the extra elements are dropped.
94−
95− zip (fromList [1,2,3,4]) (fromList [0,0,0]) = fromList [(1,0), (2,0), (3,0)]
96−-}
97−zip : Array a -> Array b -> Array (a,b)
98−zip = zipWith (,)
99−
100−{-| Zips the elements of two arrays via a function into a new array. If one array
101−is longer, the extra elements are dropped.
102−
103− zipWith (+) (fill 3 5) (fill 5 8) == fill 3 13
104−-}
105−zipWith : (a -> b -> c) -> Array a -> Array b -> Array c
106−zipWith f a b =
107− fromList <| List.zipWith f (Native.Array.toList a) (Native.Array.toList b)
108−
10999{-| Return an empty array.
110100
111101 length empty == 0
@@ -121,7 +111,7 @@ push : a -> Array a -> Array a
121111push = Native.Array.push
122112
123113{-| Return the element at the index. Breaks, if index is out of range. If the
124−array length is unkown, use safeGet oder getWithDefault.
114+array length is unkown, use withDefaultGet oder getWithDefault.
125115
126116 get 2 (A.fromList [3,2,1]) == 1
127117-}
@@ -130,46 +120,42 @@ get = Native.Array.get
130120
131121{-| Return Just the element at the index or Nothing if the index is out of range.
132122
133− getMaybe 2 (A.fromList [3,2,1]) == Just 2
134− getMaybe 5 (A.fromList [3,2,1]) == Nothing
123+ getMaybe 2 (fromList [3,2,1]) == Just 2
124+ getMaybe 5 (fromList [3,2,1]) == Nothing
125+ getMaybe -1 (fromList [3,2,1]) == Nothing
135126-}
136127getMaybe : Int -> Array a -> Maybe a
137−getMaybe i array = if Native.Array.length array > i
138− then Just (Native.Array.get i array)
139− else Nothing
128+getMaybe i array =
129+ if 0 <= i && i < Native.Array.length array
130+ then Just (Native.Array.get i array)
131+ else Nothing
140132
141133{-| Get the element at the index. If the index is out of range, the given default
142134element is returned.
143135
144− getSafe 0 2 (A.fromList [3,2,1]) == 1
145− getSafe 0 5 (A.fromList [3,2,1]) == 0
136+ getWithDefault 0 2 (fromList [3,2,1]) == 1
137+ getWithDefault 0 5 (fromList [3,2,1]) == 0
146138-}
147−getSafe : a -> Int -> Array a -> a
148−getSafe default i array = if Native.Array.length array > i
149− then Native.Array.get i array else default
139+getWithDefault : a -> Int -> Array a -> a
140+getWithDefault default i array =
141+ if 0 <= i && i < Native.Array.length array
142+ then Native.Array.get i array
143+ else default
150144
151−{-| Set the element at the index. Returns the updated array, or if the index is
152−out of range, the unaltered array.
145+{-| Set the element at a particular index. Returns an updated array.
146+If the index is out of range, the array is unaltered.
153147
154148 set 1 7 (fromList [1,2,3]) == fromList [1,7,3]
155149-}
156150set : Int -> a -> Array a -> Array a
157151set = Native.Array.set
158152
159−{-| Update an array with a a list tuples, wherein the first Int is the index.
160−
161− updates [(1,7),(2,8)] (fill 3 1) == fromList [1,7,8]
162−-}
163−updates : [(Int, a)] -> Array a -> Array a
164−updates us array = List.foldl (uncurry Native.Array.set) array us
165−
166153{-| Slice an array given a range. The selection is inclusive, so the last
167154element in the selection will also be in the new array. This may change in the
168−future.
169−You can select from the end by giving a negative Int.
155+future. You can select from the end by giving a negative Int.
170156
171− slice 1 2 (fromList [0,1,2,3,4]) == fromList [1,2]
172− slice 1 -2 (fromList [0,1,2,3,4]) == fromList [1,2,3]
157+ slice 1 2 (fromList [0,1,2,3,4]) == fromList [1,2]
158+ slice 1 -2 (fromList [0,1,2,3,4]) == fromList [1,2,3]
173159 slice -3 -2 (fromList [0,1,2,3,4]) == fromList [2,3]
174160-}
175161slice : Int -> Int -> Array a -> Array a
@@ -182,9 +168,9 @@ slice = Native.Array.slice
182168length : Array a -> Int
183169length = Native.Array.length
184170
185−{-| Concat two arrays to a new one.
171+{-| Append two arrays to a new one.
186172
187− concat (fill 3 1) (fill 4 2) == fromList [1,1,1,2,2,2,2]
173+ append (array 2 42) (array 3 81) == fromList [42,42,81,81,81]
188174-}
189−concat : Array a -> Array a -> Array a
190−concat = Native.Array.concat
175+append : Array a -> Array a -> Array a
176+append = Native.Array.append
libraries/Graphics/Input.elm+1−1
@@ -89,7 +89,7 @@ button = Native.Graphics.Input.button
8989
9090 prettyButton : Element
9191 prettyButton =
92− customButton click.handle
92+ customButton click.handle ()
9393 (image 100 40 "/button_up.jpg")
9494 (image 100 40 "/button_hover.jpg")
9595 (image 100 40 "/button_down.jpg")
libraries/Native/Array.js+133−32
@@ -25,18 +25,21 @@ Elm.Native.Array.make = function(elm) {
2525 var empty = { ctor:"_Array", height:0, table:new Array() };
2626
2727 // Gets the value at index i recursively.
28− function get(i, a) {
29− if (a.height == 0) {
30− if (i < a.table.length) {
31− return a.table[i];
32− } else {
33− throw new Error("Index "+ i +" is out of range. Check the length of your array first or use getSafe or getMaybe.");
28+ function get(i, array) {
29+ if (i < 0 || i >= length(array)) {
30+ throw new Error("Index " + i + " is out of range. Check the length of " +
31+ "your array first or use getMaybe or getWithDefault.");
3432 }
35− }
33+ return unsafeGet(i, array);
34+ }
3635
37− var slot = getSlot(i, a);
38− var sub = slot > 0 ? a.lengths[slot-1] : 0;
39− return get(i - sub, a.table[slot]);
36+ function unsafeGet(i, array) {
37+ if (array.height == 0) {
38+ return array.table[i];
39+ }
40+ var slot = getSlot(i, array);
41+ var offset = slot > 0 ? array.lengths[slot-1] : 0;
42+ return unsafeGet(i - offset, array.table[slot]);
4043 }
4144
4245 // Sets the value at the index i. Only the nodes leading to i will get
@@ -58,6 +61,102 @@ Elm.Native.Array.make = function(elm) {
5861 return newA;
5962 }
6063
64+ function initialize(len, f) {
65+ if (len == 0) { return empty; }
66+ var h = Math.floor(Math.log(len)/Math.log(M));
67+ return initialize_(f, h, 0, len);
68+ }
69+
70+ function initialize_(f, h, from, to) {
71+ if (h == 0) {
72+ var table = new Array((to - from) % (M + 1));
73+ for (var i = 0; i < table.length; i++) {
74+ table[i] = f(from + i);
75+ }
76+ return { ctor:"_Array", height:0, table:table };
77+ }
78+
79+ var step = Math.pow(M, h);
80+ var table = new Array(Math.ceil((to - from) / step));
81+ var lengths = new Array(table.length);
82+ for (var i = 0; i < table.length; i++) {
83+ table[i] = initialize_( f, h - 1, from + (i * step)
84+ , Math.min(from + ((i + 1) * step), to));
85+ lengths[i] = length(table[i]) + (i > 0 ? lengths[i-1] : 0);
86+ }
87+ return { ctor:"_Array", height:h, table:table, lengths:lengths };
88+ }
89+
90+ function fromList(list) {
91+ if (list == List.Nil) { return empty; }
92+
93+ // Allocate M sized blocks (table) and write list elements to it.
94+ var table = new Array(M);
95+ var nodes = new Array();
96+ var i = 0;
97+
98+ while (list.ctor !== '[]') {
99+ table[i] = list._0;
100+ list = list._1;
101+ i++;
102+
103+ // table is full, so we can push a leaf containing it into the
104+ // next node.
105+ if (i == M) {
106+ fromListPush({ ctor:"_Array", height:0, table:table }
107+ , nodes);
108+ table = new Array(M);
109+ i = 0;
110+ }
111+ }
112+
113+ // Maybe there is something left on the table.
114+ if (i > 0) {
115+ fromListPush({ ctor:"_Array", height:0, table:table.splice(0,i) }
116+ , nodes);
117+ }
118+
119+ // Go through all of the nodes and eventually push them into higher nodes.
120+ for (var h = 0; h < nodes.length - 1; h++) {
121+ if (nodes[h].table.length > 0) {
122+ fromListPush(nodes[h], nodes);
123+ }
124+ }
125+
126+ var head = nodes[nodes.length - 1];
127+ if (head.height > 0 && head.table.length == 1) {
128+ return head.table[0];
129+ } else {
130+ return head;
131+ }
132+ }
133+
134+ // Push a node into a higher node as a child.
135+ function fromListPush(toPush, nodes) {
136+ var h = toPush.height;
137+
138+ // Maybe the node on this height does not exist.
139+ if (nodes.length == h) {
140+ nodes.push({ ctor:"_Array", height:h + 1
141+ , table:new Array()
142+ , lengths:new Array() });
143+ }
144+
145+ nodes[h].table.push(toPush);
146+ var len = length(toPush);
147+ if (nodes[h].lengths.length > 0) {
148+ len += nodes[h].lengths[nodes[h].lengths.length - 1];
149+ }
150+ nodes[h].lengths.push(len);
151+
152+ if (nodes[h].table.length == M) {
153+ fromListPush(nodes[h], nodes);
154+ nodes[h] = { ctor:"_Array", height:h + 1
155+ , table:new Array()
156+ , lengths:new Array() };
157+ }
158+ }
159+
61160 // Pushes an item via push_ to the bottom right of a tree.
62161 function push(item, a) {
63162 var pushed = push_(item, a);
@@ -65,7 +164,7 @@ Elm.Native.Array.make = function(elm) {
65164 return pushed;
66165 }
67166
68− newTree = create(item, a.height);
167+ var newTree = create(item, a.height);
69168 return siblise(a, newTree);
70169 }
71170
@@ -232,15 +331,15 @@ Elm.Native.Array.make = function(elm) {
232331 return newA;
233332 }
234333
235− // Concats two trees.
236− // TODO: Add support for concatting trees of different sizes. Current
237− // behavior will just rise the lower tree and then concat them.
238− function concat(a, b) {
239− if (b.height > a.height) { return concat(parentise(a, b.height), b); }
240− if (a.height > b.height) { return concat(a, parentise(b, a.height)); }
241− if (a.height == 0) { return concat(parentise(a, 1), parentise(b, 1)); }
334+ // Appends two trees.
335+ // TODO: Add support for appending trees of different sizes. Current
336+ // behavior will just rise the lower tree and then append them.
337+ function append(a,b) {
338+ if (b.height > a.height) { return append(parentise(a, b.height), b); }
339+ if (a.height > b.height) { return append(a, parentise(b, a.height)); }
340+ if (a.height == 0) { return append(parentise(a, 1), parentise(b, 1)); }
242341
243− var c = concat_(a, b);
342+ var c = append_(a, b);
244343 if (c[1].table.length > 0) {
245344 return siblise(c[0], c[1]);
246345 } else {
@@ -249,9 +348,9 @@ Elm.Native.Array.make = function(elm) {
249348 }
250349
251350 // Returns an array of two nodes. The second node _may_ be empty. This case
252− // needs to be handled by the function, that called concat_. May be only
351+ // needs to be handled by the function, that called append_. May be only
253352 // called for trees with an minimal height of 1.
254− function concat_(a, b) {
353+ function append_(a, b) {
255354 if (a.height == 1) {
256355 // Check if balancing is needed and return based on that.
257356 var toRemove = calcToRemove(a, b);
@@ -262,18 +361,18 @@ Elm.Native.Array.make = function(elm) {
262361 return shuffle(a, b, toRemove);
263362 }
264363
265− var concated = concat_(botRight(a), botLeft(b));
364+ var appended = append_(botRight(a), botLeft(b));
266365 a = nodeCopy(a), b = nodeCopy(b);
267366
268367 // Adjust the bottom right side of the new tree.
269− a.table[a.table.length - 1] = concated[0];
270− a.lengths[a.lengths.length - 1] = length(concated[0])
368+ a.table[a.table.length - 1] = appended[0];
369+ a.lengths[a.lengths.length - 1] = length(appended[0])
271370 a.lengths[a.lengths.length - 1] += a.lengths.length > 1 ? a.lengths[a.lengths.length - 2] : 0;
272371
273372 // Adjust the bottom left side of the new tree.
274− if (concated[1].table.length > 0) {
275− b.table[0] = concated[1];
276− b.lengths[0] = length(concated[1]);
373+ if (appended[1].table.length > 0) {
374+ b.table[0] = appended[1];
375+ b.lengths[0] = length(appended[1]);
277376 for (var i = 1, len = length(b.table[0]); i < b.lengths.length; i++) {
278377 len += length(b.table[i]);
279378 b.lengths[i] = len;
@@ -423,11 +522,11 @@ Elm.Native.Array.make = function(elm) {
423522 }
424523
425524 // Returns how many items are in the tree.
426− function length(a) {
427− if (a.height == 0) {
428− return a.table.length;
525+ function length(array) {
526+ if (array.height == 0) {
527+ return array.table.length;
429528 } else {
430− return a.lengths[a.lengths.length - 1];
529+ return array.lengths[array.lengths.length - 1];
431530 }
432531 }
433532
@@ -474,8 +573,10 @@ Elm.Native.Array.make = function(elm) {
474573
475574 Elm.Native.Array.values = {
476575 empty:empty,
576+ fromList:fromList,
477577 toList:toList,
478− concat:F2(concat),
578+ initialize:F2(initialize),
579+ append:F2(append),
479580 push:F2(push),
480581 slice:F3(slice),
481582 get:F2(get),
libraries/Native/Graphics/Input.js−29
@@ -134,13 +134,6 @@ Elm.Native.Graphics.Input.make = function(elm) {
134134
135135 btn.appendChild(btn.elm_up);
136136
137− var clicker = newNode('div');
138− clicker.style.width = btn.elm_up.style.width;
139− clicker.style.height = btn.elm_up.style.height;
140− clicker.style.position = 'absolute';
141− clicker.style.top = 0;
142− btn.appendChild(clicker);
143−
144137 return btn;
145138 }
146139
@@ -297,29 +290,7 @@ Elm.Native.Graphics.Input.make = function(elm) {
297290 }));
298291 }
299292
300− function mouseUpdate(event) {
301− var direction = field.selectionDirection === 'forward' ? 'Forward' : 'Backward';
302− elm.notify(field.elm_signal.id, field.elm_handler({
303− _:{},
304− string: field.value,
305− selection: {
306− _:{},
307− start: field.selectionStart,
308− end: field.selectionEnd,
309− direction: { ctor: direction }
310− },
311− }));
312− }
313− function mousedown(event) {
314− mouseUpdate(event);
315− elm.node.addEventListener('mouseup', mouseup);
316− }
317− function mouseup(event) {
318− mouseUpdate(event);
319− elm.node.removeEventListener('mouseup', mouseup)
320− }
321293 field.addEventListener('input', inputUpdate);
322− field.addEventListener('mousedown', mousedown);
323294 field.addEventListener('focus', function() {
324295 field.elm_hasFocus = true;
325296 });
libraries/Native/Utils.js+13−8
@@ -30,11 +30,15 @@ Elm.Native.Utils.make = function(elm) {
3030 function compare(x,y) { return { ctor: ord[cmp(x,y)+1] } }
3131 function cmp(x,y) {
3232 var ord;
33− if (typeof x !== 'object' || x instanceof String){
33+ if (typeof x !== 'object'){
3434 return x === y ? EQ : x < y ? LT : GT;
3535 }
36−
37− if (x.ctor === "::" || x.ctor === "[]") {
36+ else if (x.isChar){
37+ var a = x.toString();
38+ var b = y.toString();
39+ return a === b ? EQ : a < b ? LT : GT;
40+ }
41+ else if (x.ctor === "::" || x.ctor === "[]") {
3842 while (true) {
3943 if (x.ctor === "[]" && y.ctor === "[]") return EQ;
4044 if (x.ctor !== y.ctor) return x.ctor === '[]' ? LT : GT;
@@ -44,8 +48,7 @@ Elm.Native.Utils.make = function(elm) {
4448 y = y._1;
4549 }
4650 }
47−
48− if (x.ctor.slice(0,6) === '_Tuple') {
51+ else if (x.ctor.slice(0,6) === '_Tuple') {
4952 var n = x.ctor.slice(6) - 0;
5053 var err = 'cannot compare tuples with more than 6 elements.';
5154 if (n === 0) return EQ;
@@ -58,9 +61,11 @@ Elm.Native.Utils.make = function(elm) {
5861 if (n >= 7) throw new Error('Comparison error: ' + err); } } } } } }
5962 return EQ;
6063 }
61− throw new Error('Comparison error: comparison is only defined on ints, ' +
62− 'floats, times, chars, strings, lists of comparable values, ' +
63− 'and tuples of comparable values.')
64+ else {
65+ throw new Error('Comparison error: comparison is only defined on ints, ' +
66+ 'floats, times, chars, strings, lists of comparable values, ' +
67+ 'and tuples of comparable values.');
68+ }
6469 }
6570
6671
libraries/Signal.elm−3
@@ -31,10 +31,7 @@ the `Time` library.
3131
3232import Native.Signal
3333import List (foldr)
34−
3534import Basics (fst, snd, not)
36−import Native.Error
37−import Maybe as M
3835
3936data Signal a = Signal
4037
runtime/Render/Element.js+8−2
@@ -31,6 +31,7 @@ function setProps(elem, e) {
3131 a.style.display = 'block';
3232 a.style.position = 'absolute';
3333 e.style.position = 'relative';
34+ a.style.pointerEvents = 'auto';
3435 e.appendChild(a);
3536 }
3637 if (props.hover.ctor !== '_Tuple0') {
@@ -45,8 +46,9 @@ function setProps(elem, e) {
4546function addClick(e, handler) {
4647 e.style.pointerEvents = 'auto';
4748 e.elm_click_handler = handler;
48− function trigger() {
49+ function trigger(ev) {
4950 e.elm_click_handler(Utils.Tuple0);
51+ ev.stopPropagation();
5052 }
5153 e.elm_click_trigger = trigger;
5254 e.addEventListener('click', trigger);
@@ -63,14 +65,16 @@ function addHover(e, handler) {
6365 e.elm_hover_handler = handler;
6466 e.elm_hover_count = 0;
6567
66− function over() {
68+ function over(evt) {
6769 if (e.elm_hover_count++ > 0) return;
6870 e.elm_hover_handler(true);
71+ evt.stopPropagation();
6972 }
7073 function out(evt) {
7174 if (e.contains(evt.toElement || evt.relatedTarget)) return;
7275 e.elm_hover_count = 0;
7376 e.elm_hover_handler(false);
77+ evt.stopPropagation();
7478 }
7579 e.elm_hover_over = over;
7680 e.elm_hover_out = out;
@@ -232,6 +236,7 @@ function rawHtml(elem) {
232236 }
233237 document.body.removeChild(div);
234238 div.style.visibility = 'visible';
239+ div.style.pointerEvents = 'auto';
235240 return div;
236241}
237242
@@ -375,6 +380,7 @@ function updateProps(node, curr, next) {
375380 a.style.display = 'block';
376381 a.style.position = 'absolute';
377382 e.style.position = 'relative';
383+ a.style.pointerEvents = 'auto';
378384 e.appendChild(a);
379385 } else {
380386 node.lastNode.href = props.href;
tests/elm/Test.elmnew file+28
@@ -0,0 +1,28 @@
1+module Main where
2+
3+import ElmTest.Assertion as A
4+import ElmTest.Run as R
5+import ElmTest.Runner.Console (runDisplay)
6+import ElmTest.Test (..)
7+
8+import IO.IO (..)
9+import IO.Runner (Request, Response)
10+import IO.Runner as Run
11+
12+import Test.String as String
13+import Test.Trampoline as Trampoline
14+import Test.Array as Array
15+
16+tests : [Test]
17+tests = String.tests ++ Trampoline.tests ++ Array.tests
18+
19+console : IO ()
20+console = runDisplay tests
21+
22+port requests : Signal [{ mPut : Maybe String
23+ , mExit : Maybe Int
24+ , mGet : Bool
25+ }]
26+port requests = Run.run responses console
27+
28+port responses : Signal (Maybe String)
tests/elm/Test/Array.elmnew file+47
@@ -0,0 +1,47 @@
1+module Test.Array (tests) where
2+
3+import List
4+import Array
5+
6+import ElmTest.Assertion (..)
7+import ElmTest.Test (..)
8+
9+tests : [Test]
10+tests =
11+ let creationTests = [ test "empty" <| assertEqual Array.empty (Array.fromList [])
12+ , test "initialize" <| assertEqual (Array.initialize 4 id) (Array.fromList [0,1,2,3])
13+ , test "initialize 2" <| assertEqual (Array.initialize 4 (\n -> n*n)) (Array.fromList [0,1,4,9])
14+ , test "initialize 3" <| assertEqual (Array.initialize 4 (always 0)) (Array.fromList [0,0,0,0])
15+ , test "initialize Empty" <| assertEqual (Array.initialize 0 id) Array.empty
16+ , test "initialize 4" <| assertEqual (Array.initialize 2 (always 0)) (Array.fromList [0,0])
17+ , test "repeat" <| assertEqual (Array.repeat 5 40) (Array.fromList [40,40,40,40,40])
18+ , test "repeat 2" <| assertEqual (Array.repeat 5 0) (Array.fromList [0,0,0,0,0])
19+ , test "repeat 3" <| assertEqual (Array.repeat 3 "cat") (Array.fromList ["cat","cat","cat"])
20+ , test "fromList" <| assertEqual (Array.fromList []) Array.empty
21+ ]
22+ basicsTests = [ test "length" <| assertEqual (Array.length (Array.fromList [1,2,3])) 3
23+ , test "length - Long" <| assertEqual (Array.length (Array.repeat 10000 0)) 10000
24+ , test "push" <| assertEqual (Array.push 3 (Array.fromList [1,2])) (Array.fromList [1,2,3])
25+ , test "append" <| assertEqual (Array.toList <| Array.append (Array.repeat 2 42) (Array.repeat 3 81)) ([42,42,81,81,81])
26+ ]
27+ getAndSetTests = [ test "get" <| assertEqual (Array.get 2 (Array.fromList [3,2,1])) 1
28+ , test "getMaybe" <| assertEqual (Array.getMaybe 1 (Array.fromList [3,2,1])) (Just 2)
29+ , test "getMaybe 2" <| assertEqual (Array.getMaybe 5 (Array.fromList [3,2,1])) Nothing
30+ , test "getMaybe 3" <| assertEqual (Array.getMaybe -1 (Array.fromList [3,2,1])) Nothing
31+ , test "getWithDefault" <| assertEqual (Array.getWithDefault 0 2 (Array.fromList [3,2,1])) 1
32+ , test "getWithDefault 2" <| assertEqual (Array.getWithDefault 0 5 (Array.fromList [3,2,1])) 0
33+ , test "set" <| assertEqual (Array.set 1 7 (Array.fromList [1,2,3])) (Array.fromList [1,7,3])
34+ ]
35+ takingArraysApartTests = [ test "toList" <| assertEqual (Array.toList (Array.fromList [3,5,8])) [3,5,8]
36+ , test "toIndexedList" <| assertEqual (Array.toIndexedList (Array.fromList ["cat","dog"])) [(0,"cat"), (1,"dog")]
37+ , test "slice" <| assertEqual (Array.slice 1 2 (Array.fromList [0,1,2,3,4])) (Array.fromList [1,2])
38+ , test "slice 2" <| assertEqual (Array.slice 1 -2 (Array.fromList [0,1,2,3,4])) (Array.fromList [1,2,3])
39+ , test "slice 3" <| assertEqual (Array.slice -3 -2 (Array.fromList [0,1,2,3,4])) (Array.fromList [2,3])
40+ ]
41+ mappingAndFoldingTests = [ test "map" <| assertEqual (Array.map sqrt (Array.fromList [1,4,9])) (Array.fromList [1,2,3])
42+ , test "indexedMap" <| assertEqual (Array.indexedMap (*) (Array.fromList [5,5,5])) (Array.fromList [0,5,10])
43+ , test "foldl" <| assertEqual (Array.foldl (::) [] (Array.fromList [1,2,3])) [1,2,3]
44+ , test "foldr" <| assertEqual (Array.foldr (+) 0 (Array.repeat 3 5)) 15
45+ , test "foldl 2" <| assertEqual (Array.foldr (::) [] (Array.fromList [1,2,3])) [3,2,1]
46+ ]
47+ in List.concat [creationTests, basicsTests, getAndSetTests, takingArraysApartTests, mappingAndFoldingTests]
tests/elm/Test/String.elmnew file+26
@@ -0,0 +1,26 @@
1+module Test.String (tests) where
2+
3+import List
4+import String (..)
5+
6+import ElmTest.Assertion (..)
7+import ElmTest.Test (..)
8+
9+tests : [Test]
10+tests =
11+ let isEmptyTests = [test "empty is empty" <| assert <| isEmpty "",
12+ test "not empty" <| assert <| not . isEmpty <| "the world"]
13+ lengthTest = test "length of innumerable" <| assertEqual 11 (length "innumerable")
14+ reverseTest = test "reverse test" <| assertEqual "desserts" (reverse "stressed")
15+ repeatTest = test "repeat test" <| assertEqual "hahaha" (repeat 3 "ha")
16+ unconsTests = [test "nonempty uncons" <| assertEqual (Just ('a',"bc")) (uncons "abc"),
17+ test "empty uncons" <| assertEqual Nothing (uncons "")]
18+ appendTest = test "append test" <| assertEqual "butterfly" (append "butter" "fly")
19+ concatTest = test "concat test" <| assertEqual "nevertheless" (concat ["never","the","less"])
20+ splitTests = [test "split commas" <| assertEqual ["cat","dog","cow"] (split "," "cat,dog,cow"),
21+ test "split slashes"<| assertEqual ["home","evan","Desktop", ""] (split "/" "home/evan/Desktop/")]
22+ joinTests = [test "join spaces" <| assertEqual "cat dog cow" (join " " ["cat","dog","cow"]),
23+ test "join slashes" <| assertEqual "home/evan/Desktop" (join "/" ["home","evan","Desktop"])]
24+
25+ endsWithTest = test "endsWith Check" (assert <| endsWith "h" "th")
26+ in List.concat [isEmptyTests, [lengthTest, reverseTest, repeatTest], unconsTests, [appendTest, concatTest], splitTests, joinTests, [endsWithTest]]
tests/elm/Test/Trampoline.elmnew file+29
@@ -0,0 +1,29 @@
1+module Test.Trampoline (tests) where
2+
3+import Trampoline (..)
4+
5+import ElmTest.Assertion (..)
6+import ElmTest.Test (..)
7+
8+badSum : Int -> Int
9+badSum n =
10+ let loop x acc =
11+ case x of
12+ 0 -> acc
13+ _ -> loop (x-1) (acc+x)
14+ in loop n 0
15+
16+goodSum : Int -> Int
17+goodSum n =
18+ let sumT x acc =
19+ case x of
20+ 0 -> Done acc
21+ _ -> Continue (\_ -> sumT (x-1) (acc+x))
22+ in trampoline <| sumT n 0
23+
24+tests : [Test]
25+tests =
26+ let mkLoopCheck n = test ("Equivalent Loop Check #"++ show n) (assertEqual (badSum n) (goodSum n))
27+ loopChecks = map mkLoopCheck [0..25]
28+ noStackOverflow = test "Trampoline Deep Recursion Test" (assertEqual 500000500000 (goodSum 1000000))
29+ in noStackOverflow :: loopChecks
tests/Main.hs → tests/hs/CompilerTest.hsrenamed

The content is the same.

tests/hs/LibTest.hsnew file+27
@@ -0,0 +1,27 @@
1+module Main where
2+
3+import System.Directory
4+import System.Exit
5+import System.FilePath
6+import System.Process
7+
8+import Elm.Internal.Paths as Elm
9+
10+main :: IO ()
11+main = do
12+ top <- getCurrentDirectory
13+ let ioScript s = top</>"IO"</>s
14+ runCmd "git submodule init"
15+ runCmd "npm install jsdom"
16+ setCurrentDirectory $ top</>"tests"</>"elm"
17+ runCmd $ concat [top</>"dist"</>"build"</>"elm"</>"elm --make --only-js --src-dir=" , top</>"automaton", " --src-dir=", top</>"IO", " --src-dir=", top</>"Elm-Test", " Test.elm"]
18+ runCmd $ unwords ["cat ", ioScript "prescript.js", Elm.runtime, "build"</>"Test.js", ioScript "handler.js", "> exe.js"]
19+ exitWith =<< waitForProcess =<< (runCommand "node exe.js")
20+ where runCmd cmd = do
21+ putStrLn cmd
22+ exitCode <- waitForProcess =<< runCommand cmd
23+ case exitCode of
24+ ExitSuccess -> return ()
25+ ExitFailure _ -> error "something went wrong"
26+
27+
tests/Tests/Compiler.hs → tests/hs/Tests/Compiler.hsrenamed

The content is the same.

tests/Tests/Property.hs → tests/hs/Tests/Property.hsrenamed

The content is the same.

tests/Tests/Property/Arbitrary.hs → tests/hs/Tests/Property/Arbitrary.hsrenamed

The content is the same.

tests/test-files/bad/BBTArgs → tests/hs/test-files/bad/BBTArgsrenamed

The content is the same.

tests/test-files/bad/InfiniteType.elm → tests/hs/test-files/bad/InfiniteType.elmrenamed

The content is the same.

tests/test-files/bad/NonElementMain.elm → tests/hs/test-files/bad/NonElementMain.elmrenamed

The content is the same.

tests/test-files/bad/Strings/ExtraClose.elm → tests/hs/test-files/bad/Strings/ExtraClose.elmrenamed

The content is the same.

tests/test-files/good/AliasSubstitution.elm → tests/hs/test-files/good/AliasSubstitution.elmrenamed

The content is the same.

tests/test-files/good/NoExpressions.elm → tests/hs/test-files/good/NoExpressions.elmrenamed

The content is the same.

tests/test-files/good/Otherwise.elm → tests/hs/test-files/good/Otherwise.elmrenamed

The content is the same.

tests/test-files/good/Ports.elm → tests/hs/test-files/good/Ports.elmrenamed

The content is the same.

tests/test-files/good/QuotesAndComments.elm → tests/hs/test-files/good/QuotesAndComments.elmrenamed

The content is the same.

tests/test-files/good/Soundness/Apply.elm → tests/hs/test-files/good/Soundness/Apply.elmrenamed

The content is the same.

tests/test-files/good/Soundness/ApplyAnnotated.elm → tests/hs/test-files/good/Soundness/ApplyAnnotated.elmrenamed

The content is the same.

tests/test-files/good/Soundness/Id.elm → tests/hs/test-files/good/Soundness/Id.elmrenamed

The content is the same.

tests/test-files/good/Soundness/IdAnnotated.elm → tests/hs/test-files/good/Soundness/IdAnnotated.elmrenamed

The content is the same.

tests/test-files/good/Soundness/TrickyId.elm → tests/hs/test-files/good/Soundness/TrickyId.elmrenamed

The content is the same.

tests/test-files/good/Soundness/TrickyIdAnnotated.elm → tests/hs/test-files/good/Soundness/TrickyIdAnnotated.elmrenamed

The content is the same.

tests/test-files/good/Strings/Multiline.elm → tests/hs/test-files/good/Strings/Multiline.elmrenamed

The content is the same.

tests/test-files/good/Strings/MultilineNormal.elm → tests/hs/test-files/good/Strings/MultilineNormal.elmrenamed

The content is the same.

tests/test-files/good/Unify/LockedVars.elm → tests/hs/test-files/good/Unify/LockedVars.elmrenamed

The content is the same.

tests/test-files/good/Unify/NonHomogeneousRecords.elm → tests/hs/test-files/good/Unify/NonHomogeneousRecords.elmrenamed

The content is the same.