on master help sign in
Merge branch 'dev' into webgl
commit9efd173f17f8561ac1506df4fc176304429ec170 authorJohn P Mayer Jr <john.p.mayer.jr@gmail.com> dateTue 28 Jan 2014, 23:00 (13 years ago) parentc9905f4f5c612f
19 files changed+148−62
Elm.cabal+1−1 README.md+1−1 compiler/Build/Dependencies.hs+30−22 compiler/Generate/JavaScript.hs+2−2 compiler/SourceSyntax/Expression.hs+2−2 compiler/SourceSyntax/Helpers.hs+9 compiler/Transform/Canonicalize.hs+3−1 compiler/Transform/SafeNames.hs+8−4 libraries/Basics.elm+1−1 libraries/Date.elm+5−1 libraries/Mouse.elm+1−6 libraries/Native/Date.js+1 libraries/Native/Signal/Mouse.js+2−6 libraries/Native/Signal/Signal.js−9 libraries/Native/Trampoline.js+22 libraries/Signal.elm+7−2 libraries/Trampoline.elm+49 libraries/elm_dependencies.json+3−3 runtime/Utils.js+1−1
Elm.cabal+1−1
@@ -1,5 +1,5 @@
11Name: Elm
2−Version: 0.10.1
2+Version: 0.11
33Synopsis: The Elm language module.
44Description: Elm aims to make client-side web-development more pleasant.
55 It is a statically/strongly typed, functional reactive
README.md+1−1
@@ -7,7 +7,7 @@ Learn about the Elm programming language at [elm-lang.org](http://elm-lang.org/)
77**Arch Linux** &mdash; follow [these directions](https://github.com/evancz/Elm/wiki/Installing-Elm#arch-linux) and then
88jump to the [My First Project](#my-first-project) section.
99<br/>
10−**OS X 10.9** &mdash; follow
10+**OS X 10.9 or XCode 5** &mdash; follow
1111[these directions](http://justtesting.org/post/64947952690/the-glasgow-haskell-compiler-ghc-on-os-x-10-9)
1212before continuing with the platform agnostic directions below.
1313
compiler/Build/Dependencies.hs+30−22
@@ -29,10 +29,7 @@ getSortedDependencies srcDirs builtIns root =
2929 result <- runErrorT $ readAllDeps allSrcDirs builtIns root
3030 case result of
3131 Right deps -> sortDeps deps
32− Left err -> failure $ err ++ if Maybe.isJust extras then "" else msg
33− where msg = "\nYou may need to create a " ++
34− Path.dependencyFile ++
35− " file if you\nare trying to use a 3rd party library."
32+ Left err -> failure err
3633
3734extraDependencies :: IO (Maybe [FilePath])
3835extraDependencies =
@@ -75,20 +72,22 @@ sortDeps depends =
7572 msg = "A cyclical module dependency or was detected in:\n"
7673
7774readAllDeps :: [FilePath] -> Module.Interfaces -> FilePath -> ErrorT String IO [Deps]
78−readAllDeps srcDirs builtIns root =
79− do let ifaces = (Set.fromList . Map.keys) builtIns
80− State.evalStateT (go ifaces root) Set.empty
75+readAllDeps srcDirs rawBuiltIns filePath =
76+ State.evalStateT (go Nothing filePath) Set.empty
8177 where
82− go :: Set.Set String -> FilePath -> State.StateT (Set.Set String) (ErrorT String IO) [Deps]
83− go builtIns root = do
84− root' <- lift $ findSrcFile srcDirs root
85− (name, deps) <- lift $ readDeps root'
78+ builtIns :: Set.Set String
79+ builtIns = Set.fromList $ Map.keys rawBuiltIns
80+
81+ go :: Maybe String -> FilePath -> State.StateT (Set.Set String) (ErrorT String IO) [Deps]
82+ go parentModuleName filePath = do
83+ filePath' <- lift $ findSrcFile parentModuleName srcDirs filePath
84+ (moduleName, deps) <- lift $ readDeps filePath'
8685 seen <- State.get
8786 let realDeps = Set.difference (Set.fromList deps) builtIns
8887 newDeps = Set.difference (Set.filter (not . isNative) realDeps) seen
89− State.put (Set.insert name (Set.union newDeps seen))
90− rest <- mapM (go builtIns . toFilePath) (Set.toList newDeps)
91− return ((makeRelative "." root', name, Set.toList realDeps) : concat rest)
88+ State.put (Set.insert moduleName (Set.union newDeps seen))
89+ rest <- mapM (go (Just moduleName) . toFilePath) (Set.toList newDeps)
90+ return ((makeRelative "." filePath', moduleName, Set.toList realDeps) : concat rest)
9291
9392readDeps :: FilePath -> ErrorT String IO (String, [String])
9493readDeps path = do
@@ -98,15 +97,10 @@ readDeps path = do
9897 where msg = "Error resolving dependencies in " ++ path ++ ":\n"
9998 Right o -> return o
10099
101−findSrcFile :: [FilePath] -> FilePath -> ErrorT String IO FilePath
102−findSrcFile dirs path = foldr tryDir notFound dirs
100+findSrcFile :: Maybe String -> [FilePath] -> FilePath -> ErrorT String IO FilePath
101+findSrcFile parentModuleName dirs path =
102+ foldr tryDir notFound dirs
103103 where
104− notFound = throwError $ unlines
105− [ "Could not find file: " ++ path
106− , " If it is not in the root directory of your project, use"
107− , " --src-dir to declare additional locations for source files."
108− , " If it is part of a 3rd party library, it needs to be declared"
109− , " as a dependency in the " ++ Path.dependencyFile ++ " file." ]
110104 tryDir dir next = do
111105 let path' = dir </> path
112106 exists <- liftIO $ doesFileExist path'
@@ -114,6 +108,20 @@ findSrcFile dirs path = foldr tryDir notFound dirs
114108 then return path'
115109 else next
116110
111+ parentModuleName' =
112+ case parentModuleName of
113+ Just name -> "module '" ++ name ++ "'"
114+ Nothing -> "the main module"
115+
116+ notFound = throwError $ unlines
117+ [ "When finding the imports declared in " ++ parentModuleName' ++ ", could not find file: " ++ path
118+ , " If you created this module, but it is in a subdirectory that does not"
119+ , " exactly match the module name, you may need to use the --src-dir flag."
120+ , ""
121+ , " If it is part of a 3rd party library, it needs to be declared"
122+ , " as a dependency in your project's " ++ Path.dependencyFile ++ " file."
123+ ]
124+
117125isNative :: String -> Bool
118126isNative name = List.isPrefixOf "Native." name
119127
compiler/Generate/JavaScript.hs+2−2
@@ -314,7 +314,7 @@ generate unsafeModule =
314314
315315 jsImport modul = setup Nothing path ++ [ include ]
316316 where
317− path = split modul
317+ path = Help.splitDots modul
318318 include = assign path $ dotSep ("Elm" : path ++ ["make"]) <| ref "_elm"
319319
320320 setup namespace path = map create paths
@@ -354,7 +354,7 @@ binop span op e1 e2 =
354354 func | Help.isOp operator = BracketRef () (dotSep (init parts ++ ["_op"])) (string operator)
355355 | otherwise = dotSep parts
356356 where
357− parts = split op
357+ parts = Help.splitDots op
358358 operator = last parts
359359
360360 opDict = Map.fromList (infixOps ++ specialOps)
compiler/SourceSyntax/Expression.hs+2−2
@@ -1,12 +1,12 @@
11{-# OPTIONS_GHC -Wall #-}
2−module SourceSyntax.Expression where
2+
33{-| The Abstract Syntax Tree (AST) for expressions comes in a couple formats.
44The first is the fully general version and is labeled with a prime (Expr').
55The others are specialized versions of the AST that represent specific phases
66of the compilation process. I expect there to be more phases as we begin to
77enrich the AST with more information.
88-}
9−
9+module SourceSyntax.Expression where
1010
1111import SourceSyntax.PrettyPrint
1212import Text.PrettyPrint as P
compiler/SourceSyntax/Helpers.hs+9
@@ -3,6 +3,15 @@ module SourceSyntax.Helpers where
33
44import qualified Data.Char as Char
55
6+splitDots :: String -> [String]
7+splitDots = go []
8+ where
9+ go vars str =
10+ case break (=='.') str of
11+ (x,_:rest) | isOp x -> vars ++ [x ++ '.' : rest]
12+ | otherwise -> go (vars ++ [x]) rest
13+ (x,[]) -> vars ++ [x]
14+
615brkt :: String -> String
716brkt s = "{ " ++ s ++ " }"
817
compiler/Transform/Canonicalize.hs+3−1
@@ -55,7 +55,9 @@ metadataModule :: Interfaces -> MetadataModule -> Either [Doc] MetadataModule
5555metadataModule ifaces modul =
5656 do case filter (\m -> Map.notMember m ifaces) (map fst realImports) of
5757 [] -> Right ()
58− missings -> Left [ P.text $ "The following imports were not found: " ++ List.intercalate ", " missings ]
58+ missings -> Left [ P.text $ "The following imports were not found: " ++ List.intercalate ", " missings ++
59+ "\n You may need to compile with the --make flag to detect modules you have written."
60+ ]
5961 program' <- rename initialEnv (program modul)
6062 aliases' <- mapM (three3 renameType') (aliases modul)
6163 datatypes' <- mapM (three3 (mapM (two2 (mapM renameType')))) (datatypes modul)
compiler/Transform/SafeNames.hs+8−4
@@ -1,16 +1,20 @@
11{-# OPTIONS_GHC -Wall #-}
22module Transform.SafeNames (metadataModule) where
33
4−import Control.Arrow (first, (***))
4+import Control.Arrow (first, (***))
5+import Data.List (intercalate)
6+
7+import qualified Data.Set as Set
8+
9+import qualified Parse.Helpers as PHelp
510import SourceSyntax.Expression
11+import qualified SourceSyntax.Helpers as SHelp
612import SourceSyntax.Location
713import SourceSyntax.Module
814import SourceSyntax.Pattern
9−import qualified Data.Set as Set
10−import qualified Parse.Helpers as PHelp
1115
1216var :: String -> String
13−var = dereserve . deprime
17+var = intercalate "." . map (dereserve . deprime) . SHelp.splitDots
1418 where
1519 deprime = map (\c -> if c == '\'' then '$' else c)
1620 dereserve x = case Set.member x PHelp.jsReserveds of
libraries/Basics.elm+1−1
@@ -320,7 +320,7 @@ It is defined as:
320320 always a b = a
321321
322322It totally ignores the second argument, so `always 42` is a function that always
323−returns in 42. When you are dealing with higher-order functions, this comes in
323+returns 42. When you are dealing with higher-order functions, this comes in
324324handy more often than you might expect. For example, creating a zeroed out list
325325of length ten would be:
326326
libraries/Date.elm+5−1
@@ -5,7 +5,7 @@ module Date where
55issues with internationalization or locale formatting.
66
77# Conversions
8−@docs read, toTime
8+@docs read, toTime, fromTime
99
1010# Extractions
1111@docs year, month, Month, day, dayOfWeek, Day, hour, minute, second
@@ -36,6 +36,10 @@ read = Native.Date.read
3636toTime : Date -> Time
3737toTime = Native.Date.toTime
3838
39+{-| Take a UNIX time and convert it to a `Date` -}
40+fromTime : Time -> Date
41+fromTime = Native.Date.fromTime
42+
3943{-| Extract the year of a given date. Given the date 23 June 1990 at 11:45AM
4044this returns the integer `1990`. -}
4145year : Date -> Int
libraries/Mouse.elm+1−6
@@ -7,7 +7,7 @@ module Mouse where
77@docs position, x, y
88
99# Button Status
10−@docs isDown, clicks, isClicked
10+@docs isDown, clicks
1111
1212-}
1313
@@ -31,11 +31,6 @@ True when the button is down, and false otherwise. -}
3131isDown : Signal Bool
3232isDown = Native.Mouse.isDown
3333
34−{-| True immediately after the left mouse-button has been clicked,
35−and false otherwise. -}
36−isClicked : Signal Bool
37−isClicked = Native.Mouse.isClicked
38−
3934{-| Always equal to unit. Event triggers on every mouse click. -}
4035clicks : Signal ()
4136clicks = Native.Mouse.clicks
libraries/Native/Date.js+1
@@ -27,6 +27,7 @@ Elm.Native.Date.make = function(elm) {
2727 minute : function(d) { return d.getMinutes(); },
2828 second : function(d) { return d.getSeconds(); },
2929 toTime : function(d) { return d.getTime(); },
30+ fromTime: function(t) { return new window.Date(t); },
3031 dayOfWeek : function(d) { return { ctor:dayTable[d.getDay()] }; }
3132 };
3233
libraries/Native/Signal/Mouse.js+2−6
@@ -20,15 +20,12 @@ Elm.Native.Mouse.make = function(elm) {
2020 y.defaultNumberOfKids = 0;
2121
2222 var isDown = Signal.constant(false);
23− var isClicked = Signal.constant(false);
2423 var clicks = Signal.constant(Utils.Tuple0);
2524
2625 var node = elm.display === ElmRuntime.Display.FULLSCREEN ? document : elm.node;
2726
28− elm.addListener([isClicked.id, clicks.id], node, 'click', function click() {
29− elm.notify(isClicked.id, true);
27+ elm.addListener([clicks.id], node, 'click', function click() {
3028 elm.notify(clicks.id, Utils.Tuple0);
31− elm.notify(isClicked.id, false);
3229 });
3330 elm.addListener([isDown.id], node, 'mousedown', function down() {
3431 elm.notify(isDown.id, true);
@@ -44,8 +41,7 @@ Elm.Native.Mouse.make = function(elm) {
4441 position: position,
4542 x:x,
4643 y:y,
47− isClicked: isClicked,
4844 isDown: isDown,
4945 clicks: clicks
5046 };
51−};
47+};
libraries/Native/Signal/Signal.js−9
@@ -127,12 +127,6 @@ Elm.Native.Signal.make = function(elm) {
127127 input.kids.push(this);
128128 }
129129
130− function dropWhen(s1,b,s2) {
131− var pairs = lift2( F2(function(x,y){return {x:x,y:y};}), s1, s2 );
132− var dropped = new DropIf(function(p){return p.x;},{x:true,y:b},pairs);
133− return lift(function(p){return p.y;}, dropped);
134− }
135−
136130 function timestamp(a) {
137131 function update() { return Utils.Tuple2(Date.now(), a.value); }
138132 return new LiftN(update, [a]);
@@ -225,9 +219,6 @@ Elm.Native.Signal.make = function(elm) {
225219 keepIf : F3(function(pred,base,sig) {
226220 return new DropIf(function(x) {return !pred(x);},base,sig); }),
227221 dropIf : F3(function(pred,base,sig) { return new DropIf(pred,base,sig); }),
228− keepWhen : F3(function(s1,b,s2) {
229− return dropWhen(lift(function(b){return !b;},s1), b, s2); }),
230− dropWhen : F3(dropWhen),
231222 dropRepeats : function(s) { return new DropRepeats(s);},
232223 sampleOn : F2(sampleOn),
233224 timestamp : timestamp
libraries/Native/Trampoline.jsnew file+22
@@ -0,0 +1,22 @@
1+Elm.Native.Trampoline = {};
2+Elm.Native.Trampoline.make = function(elm) {
3+ elm.Native = elm.Native || {};
4+ elm.Native.Trampoline = elm.Native.Trampoline || {};
5+ if (elm.Native.Trampoline.values) return elm.Native.Trampoline.values;
6+
7+ // trampoline : Trampoline a -> a
8+ trampoline = function(t) {
9+ var tramp = t;
10+ while(true) {
11+ switch(tramp.ctor) {
12+ case "Done":
13+ return tramp._0;
14+ case "Continue":
15+ tramp = tramp._0({ctor: "_Tuple0"});
16+ continue;
17+ }
18+ }
19+ }
20+
21+ return elm.Native.Trampoline.values = { trampoline: trampoline };
22+};
libraries/Signal.elm+7−2
@@ -32,6 +32,10 @@ the [`Time`](/docs/Signal/Time.elm) library.
3232import Native.Signal
3333import List (foldr)
3434
35+import Basics (fst, snd, not)
36+import Native.Error
37+import Maybe as M
38+
3539data Signal a = Signal
3640
3741{-| Create a constant signal that never changes. -}
@@ -122,7 +126,8 @@ Until the first signal becomes false again, all events will be propagated. Elm
122126does not allow undefined signals, so a base case must be provided in case the
123127first signal is not true initially. -}
124128keepWhen : Signal Bool -> a -> Signal a -> Signal a
125−keepWhen = Native.Signal.keepWhen
129+keepWhen bs def sig =
130+ snd <~ (keepIf fst (False, def) ((,) <~ (sampleOn sig bs) ~ sig))
126131
127132{-| Drop events when the first signal is true. When the first signal becomes
128133false, the most recent value of the second signal will be propagated. Until the
@@ -130,7 +135,7 @@ first signal becomes true again, all events will be propagated. Elm does not
130135allow undefined signals, s oa base case must be provided in case the first
131136signal is true initially. -}
132137dropWhen : Signal Bool -> a -> Signal a -> Signal a
133−dropWhen = Native.Signal.dropWhen
138+dropWhen bs = keepWhen (not <~ bs)
134139
135140{-| Drop updates that repeat the current value of the signal.
136141
libraries/Trampoline.elmnew file+49
@@ -0,0 +1,49 @@
1+module Trampoline where
2+{-| A [trampoline](http://en.wikipedia.org/wiki/Tail-recursive_function#Through_trampolining)
3+makes it possible to recursively call a function without growing the stack.
4+
5+Popular JavaScript implementations do not perform any tail-call elimination, so
6+recursive functions can cause a stack overflow if they go to deep. Trampolines
7+permit unbounded recursion despite limitations in JavaScript.
8+
9+This strategy may create many intermediate closures, which is very expensive in
10+JavaScript, so use this library only when it is essential that you recurse deeply.
11+
12+# Trampolines
13+@docs trampoline, Trampoline
14+-}
15+
16+import Native.Trampoline
17+
18+{-| A way to build computations that may be deeply recursive. We will take an
19+example of a tail-recursive function and rewrite it in a way that lets us use
20+a trampoline:
21+
22+ length : [a] -> Int
23+ length list = length' 0 list
24+
25+ length' : Int -> [a] -> Int
26+ length' accum list =
27+ case list of
28+ [] -> accum
29+ hd::tl -> length' (accum+1) tl
30+
31+This finds the length of a list, but if the list is too long, it may cause a
32+stack overflow. We can rewrite it as follows:
33+
34+ length : [a] -> Int
35+ length list = trampoline (length' 0 list)
36+
37+ length' : Int -> [a] -> Trampoline Int
38+ length' accum list =
39+ case list of
40+ [] -> Done accum
41+ hd::tl -> Continue (\() -> length' (accum+1) tl)
42+
43+Now it uses a trampoline and can recurse without growing the stack!
44+-}
45+data Trampoline a = Done a | Continue (() -> Trampoline a)
46+
47+{-| Evaluate a trampolined value in constant space. -}
48+trampoline : Trampoline a -> a
49+trampoline = Native.Trampoline.trampoline
libraries/elm_dependencies.json+3−3
@@ -1,9 +1,9 @@
1−{ "version": "0.10.1"
1+{ "version": "0.11"
22, "summary": "Elm's standard libraries"
3−, "description": "The full set of standard libraries for Elm. This library is pegged to the version number of the compiler, so if you are using Elm 0.10.1, you should be using version 0.10.1 of the standard libraries."
3+, "description": "The full set of standard libraries for Elm. This library is pegged to the version number of the compiler, so if you are using Elm 0.11, you should be using version 0.11 of the standard libraries."
44, "license": "BSD3"
55, "repository": "http://github.com/evancz/Elm.git"
6−, "elm-version": "0.10.1"
6+, "elm-version": "0.11"
77, "dependencies": {}
88, "exposed-modules":
99 [ "Basics"
runtime/Utils.js+1−1
@@ -34,7 +34,7 @@ ElmRuntime.filterDeadInputs = function(inputs) {
3434
3535// define the draw function
3636var vendors = ['ms', 'moz', 'webkit', 'o'];
37−var win = window || {};
37+var win = typeof window !== 'undefined' ? window : {};
3838for (var i = 0; i < vendors.length && !win.requestAnimationFrame; ++i) {
3939 win.requestAnimationFrame = win[vendors[i]+'RequestAnimationFrame'];
4040 win.cancelAnimationFrame = win[vendors[i]+'CancelAnimationFrame'] ||