on master help sign in
Merge branch 'master' of https://github.com/evancz/Elm
commit44fecefde6c186037da1241c4634b1bb9dc19e88 authorevancz <info@elm-lang.org> dateWed 5 Jun 2013, 14:22 (13 years ago) parent212d19c8d13b0b
17 files changed+132−108
Elm.cabal+2 README.md+15−15 compiler/Gen/CompileToJS.hs+9−6 compiler/Gen/ExtractNoscript.hs+1 compiler/Model/Ast.hs+9−7 compiler/Model/Located.hs+5−5 compiler/Parse/Expr.hs+6−2 compiler/Parse/Parser.hs+1−1 compiler/Parse/Types.hs+1−1 compiler/Transform/LetBoundVars.hs+1 compiler/Transform/Optimize.hs+1 compiler/Transform/Rename.hs+3−2 compiler/Transform/Substitute.hs+1 compiler/Types/Alias.hs+49−50 compiler/Types/Constrain.hs+4−4 compiler/Types/Types.hs+5−4 server/Server.hs+19−11
Elm.cabal+2
@@ -65,6 +65,7 @@ Library
6565
6666 Build-depends: base >=4.2 && <5,
6767 containers >= 0.3,
68+ uniplate >= 1.6,
6869 transformers >= 0.2,
6970 mtl >= 2,
7071 deepseq,
@@ -119,6 +120,7 @@ Executable elm
119120
120121 Build-depends: base >=4.2 && <5,
121122 containers >= 0.3,
123+ uniplate >= 1.6,
122124 transformers >= 0.2,
123125 mtl >= 2,
124126 deepseq,
README.md+15−15
@@ -1,26 +1,27 @@
11Learn about the Elm programming language at [elm-lang.org](http://elm-lang.org/).
22
33
4−## Installing everything on Mac OSX
4+## Install
55
6−Use [the installer](https://dl.dropboxusercontent.com/u/5850974/Elm/Elm.pkg).
6+#### On Mac OSX
77
8−### Installing the Compiler
8+Use [the installer](https://dl.dropboxusercontent.com/u/5850974/Elm/Elm.pkg) and you are done.
9+Let us know on [the list](https://groups.google.com/forum/?fromgroups#!forum/elm-discuss)
10+if you have any trouble.
11+
12+#### On any platform
913
1014Download the [Haskell Platform 2012.2.0.0](http://hackage.haskell.org/platform/).
1115Elm definitely works with GHC 7.4, so newer versions of the Haskell Platform may work too.
12−
1316Once the Haskell Platform is installed:
1417
15− cabal update ; cabal install elm
16−
17−### Installing the Server
18−
18+ cabal update
19+ cabal install elm
1920 cabal install elm-server
2021
21−### Using the executables
22+## Use
2223
23−To use `elm` and `elm-server` you need to add a new directory to your PATH.
24+To use `elm` and `elm-server` you may need to add a new directory to your PATH.
2425
2526Cabal should tell you where your executables are located upon
2627successful installation.
@@ -31,20 +32,19 @@ appended to the end of my PATH variable in my .bashrc file.
3132See this tutorial if you are new to changing your PATH in
3233[Unix/Linux](http://www.cyberciti.biz/faq/unix-linux-adding-path/).
3334
34−## A Test project
35+## My First Project
3536
3637Now we will create a simple Elm project.
3738The following commands will set-up a very basic project and start the Elm server.
3839
3940 mkdir helloElm
4041 cd helloElm
41− echo import Mouse > Main.elm
42− echo main = lift asText Mouse.position >> Main.elm
42+ printf "import Mouse\n\nmain = lift asText Mouse.position" > Main.elm
4343 elm-server
4444
45−The first two commands create a new directory and navigate into it. The `echo`
45+The first two commands create a new directory and navigate into it. The `printf`
4646commands place a simple program into `Main.elm`. Do this manually if you do not
47−have `echo`. The final command starts the Elm server at [localhost:8000](http://localhost:8000/),
47+have `printf`. The final command starts the Elm server at [localhost:8000](http://localhost:8000/),
4848allowing you to navigate to `Main.elm` and see your first program in action.
4949
5050#### Wrap up
compiler/Gen/CompileToJS.hs+9−6
@@ -7,6 +7,7 @@ import Data.List (intercalate,sortBy,inits,foldl')
77import qualified Data.Map as Map
88import Data.Either (partitionEithers)
99import qualified Text.Pandoc as Pan
10+import Data.Maybe (maybeToList)
1011
1112import Ast
1213import Located
@@ -82,14 +83,14 @@ getExports names stmts = "\n"++ intercalate ";\n" (op : map fnPair fns)
8283
8384 op = ("_.$op = "++) . jsObj $ map opPair ops
8485
85− get' (FnDef x _ _) = Left x
86− get' (OpDef op _ _ _) = Right op
87− get s = case s of Definition d -> [ get' d ]
86+ get' (FnDef x _ _) = Just (Left x)
87+ get' (OpDef op _ _ _) = Just (Right op)
88+ get' (TypeAnnotation _ _) = Nothing
89+ get s = case s of Definition d -> maybeToList (get' d)
8890 Datatype _ _ tcs -> map (Left . fst) tcs
8991 ImportEvent _ _ x _ -> [ Left x ]
9092 ExportEvent _ _ _ -> []
9193 TypeAlias _ _ _ -> []
92− TypeAnnotation _ _ -> []
9394
9495
9596jsImport (modul, how) =
@@ -129,10 +130,10 @@ stmtsToJS stmts = run $ do program <- mapM toJS (sortBy cmpStmt stmts)
129130 ImportEvent _ _ _ _ -> 2
130131 Definition (FnDef f [] _) ->
131132 if derename f == "main" then 5 else 4
133+ Definition (TypeAnnotation _ _) -> 0
132134 Definition _ -> 3
133135 ExportEvent _ _ _ -> 6
134136 TypeAlias _ _ _ -> 0
135− TypeAnnotation _ _ -> 0
136137
137138class ToJS a where
138139 toJS :: a -> GuidCounter String
@@ -148,6 +149,8 @@ instance ToJS Def where
148149 do body <- toJS' e
149150 let func = "F2" ++ parens (jsFunc (a1 ++ ", " ++ a2) (ret body))
150151 return (globalAssign ("$op['" ++ op ++ "']") func)
152+ toJS (TypeAnnotation _ _) = return ""
153+
151154
152155instance ToJS Statement where
153156 toJS stmt =
@@ -170,7 +173,6 @@ instance ToJS Statement where
170173 , "e.initEvent('", js, "_' + elm.id, true, true);"
171174 , "e.value = v;"
172175 , "document.dispatchEvent(e); return v; })(", elm, ");" ]
173− TypeAnnotation _ _ -> return ""
174176 TypeAlias n _ t -> return ""
175177
176178toJS' :: CExpr -> GuidCounter String
@@ -275,6 +277,7 @@ jsLet defs e' = do ds <- jsDefs defs
275277 valueOf (FnDef _ [] _) = 2
276278 valueOf (FnDef _ _ _) = 1
277279 valueOf (OpDef _ _ _ _) = 1
280+ valueOf (TypeAnnotation _ _) = 0
278281
279282caseToJS span e ps = do
280283 match <- caseToMatch ps
compiler/Gen/ExtractNoscript.hs+1
@@ -21,6 +21,7 @@ instance Extract Statement where
2121instance Extract Def where
2222 extract (FnDef _ _ e) = extract e
2323 extract (OpDef _ _ _ e) = extract e
24+ extract _ = []
2425
2526instance Extract e => Extract (Located e) where
2627 extract (L _ _ e) = extract e
compiler/Model/Ast.hs+9−7
@@ -1,4 +1,4 @@
1−
1+{-# LANGUAGE DeriveDataTypeable #-}
22module Ast where
33
44import Located
@@ -6,6 +6,7 @@ import Data.Char (isDigit, isSymbol)
66import Data.List (intercalate)
77import Types.Types
88import qualified Text.Pandoc as Pandoc
9+import Data.Data
910
1011data Module = Module [String] Exports Imports [Statement]
1112
@@ -13,14 +14,14 @@ type Exports = [String]
1314
1415type Imports = [(String, ImportMethod)]
1516data ImportMethod = As String | Importing [String] | Hiding [String]
16− deriving (Eq, Ord, Show)
17+ deriving (Eq, Ord, Show, Data, Typeable)
1718
1819
1920data Pattern = PData String [Pattern]
2021 | PRecord [String]
2122 | PVar String
2223 | PAnything
23− deriving (Eq)
24+ deriving (Eq, Data, Typeable)
2425
2526type CExpr = Located Expr
2627data Expr = IntNum Int
@@ -44,19 +45,19 @@ data Expr = IntNum Int
4445 | Case CExpr [(Pattern,CExpr)]
4546 | Data String [CExpr]
4647 | Markdown Pandoc.Pandoc
47− deriving (Eq)
48+ deriving (Eq, Data, Typeable)
4849
4950data Def = FnDef String [String] CExpr
5051 | OpDef String String String CExpr
51− deriving (Eq)
52+ | TypeAnnotation String Type
53+ deriving (Eq, Data, Typeable)
5254
5355data Statement = Definition Def
5456 | Datatype String [X] [(String,[Type])]
5557 | TypeAlias String [X] Type
56− | TypeAnnotation String Type
5758 | ImportEvent String CExpr String Type
5859 | ExportEvent String String Type
59− deriving (Eq,Show)
60+ deriving (Eq, Show, Data, Typeable)
6061
6162cons h t = epos h t (Data "Cons" [h,t])
6263nil = L (Just "[]") NoSpan (Data "Nil" [])
@@ -136,6 +137,7 @@ instance Show Def where
136137 FnDef v [] e -> v ++ " = " ++ show e
137138 FnDef f args e -> f ++ concatMap (' ':) args ++ " = " ++ show e
138139 OpDef op a1 a2 e -> intercalate " " [a1,op,a2] ++ " = " ++ show e
140+ TypeAnnotation n t -> n ++ " : " ++ show t
139141
140142getLambdas (L _ _ (Lambda x e)) = (x:xs,e')
141143 where (xs,e') = getLambdas e
compiler/Model/Located.hs+5−5
@@ -1,16 +1,16 @@
1−
1+{-# LANGUAGE DeriveDataTypeable #-}
22module Located where
33
44import Text.Parsec.Pos
5−
5+import Data.Data
66
77data SrcPos = Pos Int Int
8− deriving (Eq,Ord)
8+ deriving (Eq, Ord, Data, Typeable)
99
1010data SrcSpan = Span SrcPos SrcPos | NoSpan
11− deriving (Eq,Ord)
11+ deriving (Eq, Ord, Data, Typeable)
1212
13−data Located e = L (Maybe String) SrcSpan e deriving (Eq,Ord)
13+data Located e = L (Maybe String) SrcSpan e deriving (Eq,Ord, Data, Typeable)
1414
1515
1616instance Show SrcPos where
compiler/Parse/Expr.hs+6−2
@@ -13,6 +13,7 @@ import qualified Text.Pandoc as Pan
1313import Parse.Library
1414import Parse.Patterns
1515import Parse.Binops
16+import Parse.Types
1617
1718import Guid
1819import Types.Types (Type (VarT), Scheme (Forall))
@@ -164,7 +165,7 @@ lambdaExpr = do char '\\' <|> char '\x03BB' <?> "anonymous function"
164165 return . run $ makeLambda pats e
165166
166167defSet :: IParser [Def]
167−defSet = concat <$> block (do d <- assignExpr ; whitespace ; return d)
168+defSet = concat <$> block (do d <- anyDef ; whitespace ; return d)
168169
169170letExpr :: IParser Expr
170171letExpr = do
@@ -207,8 +208,11 @@ assignExpr = withPos $ do
207208 n <- sourceLine <$> getPosition
208209 runAt (1000 * n) $ flattenPatterns fDefs e
209210
210−def = map Definition <$> assignExpr
211+anyDef =
212+ ((\d -> [d]) <$> typeAnnotation) <|>
213+ assignExpr
211214
215+def = map Definition <$> anyDef
212216
213217parseDef str =
214218 case iParse def "" str of
compiler/Parse/Parser.hs+1−1
@@ -16,7 +16,7 @@ import Parse.Foreign
1616
1717
1818statement = choice (typeAlias:defs) <|> def <?> "datatype or variable definition"
19− where defs = map ((:[]) <$>) [ foreignDef, datatype, typeAnnotation ]
19+ where defs = map ((:[]) <$>) [ foreignDef, datatype ]
2020
2121freshDef = commitIf (freshLine >> (letter <|> char '_')) $ do
2222 freshLine
compiler/Parse/Types.hs+1−1
@@ -95,7 +95,7 @@ toConstructor start end alias kvs =
9595 rec = map (\a -> (a, [], loc (Var a))) args
9696
9797
98−typeAnnotation :: IParser Statement
98+typeAnnotation :: IParser Def
9999typeAnnotation = TypeAnnotation <$> try start <*> (toType <$> typeExpr)
100100 where start = do v <- lowVar <|> parens symOp
101101 whitespace ; hasType ; whitespace ; return v
compiler/Transform/LetBoundVars.hs+1
@@ -22,6 +22,7 @@ instance LetBoundVars Statement where
2222instance LetBoundVars Def where
2323 letBoundVars (FnDef n _ e) = n : letBoundVars e
2424 letBoundVars (OpDef _ _ _ e) = letBoundVars e
25+ letBoundVars _ = []
2526
2627instance LetBoundVars e => LetBoundVars (Context e) where
2728 letBoundVars (C _ _ e) = letBoundVars e
compiler/Transform/Optimize.hs+1
@@ -23,6 +23,7 @@ instance Simplify Statement where
2323instance Simplify Def where
2424 simp (FnDef func args e) = FnDef func args (simp e)
2525 simp (OpDef op a1 a2 e) = OpDef op a1 a2 (simp e)
26+ simp x = x
2627
2728instance Simplify e => Simplify (Located e) where
2829 simp (L t s e) = L t s (simp e)
compiler/Transform/Rename.hs+3−2
@@ -30,6 +30,8 @@ instance Rename Def where
3030 rename env (FnDef f args e) =
3131 do env' <- extends env args
3232 FnDef (env f) (map env' args) `liftM` rename env' e
33+ rename env (TypeAnnotation n t) = return (TypeAnnotation (env n) t)
34+
3335
3436instance Rename Statement where
3537 rename env stmt =
@@ -38,7 +40,6 @@ instance Rename Statement where
3840 Datatype name args tcs ->
3941 return $ Datatype name args $ map (first env) tcs
4042 TypeAlias n xs t -> return (TypeAlias n xs t)
41− TypeAnnotation n t -> return (TypeAnnotation (env n) t)
4243 ImportEvent js base elm tipe ->
4344 do base' <- rename env base
4445 return $ ImportEvent js base' (env elm) tipe
@@ -146,4 +147,4 @@ renameLet env defs e = do env' <- extends env $ concatMap getNames defs
146147 defs' <- mapM (rename env') defs
147148 Let defs' `liftM` rename env' e
148149 where getNames (FnDef n _ _) = [n]
149− getNames (OpDef _ _ _ _) = []
150+ getNames _ = []
compiler/Transform/Substitute.hs+1
@@ -22,6 +22,7 @@ subst old new expr =
2222 Let defs e -> Let (map substDef defs) (f e)
2323 where substDef (FnDef name vs e) = FnDef name vs (f e)
2424 substDef (OpDef op a1 a2 e) = OpDef op a1 a2 (f e)
25+ substDef x = x
2526 Var x -> if x == old then new else expr
2627 Case e cases -> Case (f e) $ map (second f) cases
2728 Data name es -> Data name (map f es)
compiler/Types/Alias.hs+49−50
@@ -1,13 +1,16 @@
1−
1+{-# LANGUAGE PatternGuards #-}
22module Types.Alias (dealias, get, mistakes) where
33
44import Ast
5+import Located
56import Control.Arrow (second)
67import Data.List (group,sort)
8+import Data.Maybe (mapMaybe)
79import qualified Data.Map as Map
810import qualified Data.Set as Set
911import Types.Substitutions (subst)
1012import Types.Types
13+import Data.Generics.Uniplate.Data
1114
1215builtins :: [(String,([X],Type))]
1316builtins =
@@ -48,68 +51,59 @@ mistakes :: [Statement] -> [String]
4851mistakes stmts = badKinds stmts ++ dups stmts ++ badOrder stmts
4952
5053badKinds :: [Statement] -> [String]
51−badKinds stmts = map msg (concatMap badS stmts)
54+badKinds stmts = [msg tname | t <- universeBi stmts, tname <- badT t]
5255 where
5356 msg x = "Type Error: Type alias '" ++ x ++
5457 "' was given the wrong number of arguments."
5558
5659 badT :: Type -> [String]
57− badT t =
58− case t of
59− ADT name ts ->
60− case Map.lookup name (get stmts) of
61− Just (xs,t) | length xs == length ts -> []
62− | otherwise -> [name]
63− Nothing -> concatMap badT ts
64− LambdaT t u -> badT t ++ badT u
65− RecordT r t -> badT t ++ concatMap badT (concat (Map.elems r))
66− _ -> []
67−
68− badS :: Statement -> [String]
69− badS s =
70− case s of
71− Datatype _ _ tcs -> concatMap badT (concatMap snd tcs)
72− ExportEvent _ _ tipe -> badT tipe
73− ImportEvent _ _ _ tipe -> badT tipe
74− TypeAnnotation _ tipe -> badT tipe
75− TypeAlias _ _ tipe -> badT tipe
76− Definition _ -> []
77−
78−annotation :: Statement -> [String]
60+ badT (ADT name ts)
61+ | Just (xs, _) <- Map.lookup name (get stmts),
62+ length xs /= length ts = [name]
63+ badT _ = []
64+
65+annotation :: Def -> Maybe String
7966annotation s =
8067 case s of
81− TypeAnnotation name _ -> [name]
82− _ -> []
68+ TypeAnnotation name _ -> Just name
69+ _ -> Nothing
8370
84−definition :: Statement -> [String]
71+definition :: Def -> Maybe String
8572definition s =
8673 case s of
87− Definition d -> [defName d]
88− _ -> []
89−
90−defName :: Def -> String
91−defName d =
92− case d of
93− FnDef n _ _ -> n
94− OpDef n _ _ _ -> n
74+ FnDef name _ _ -> Just name
75+ OpDef name _ _ _ -> Just name
76+ _ -> Nothing
77+
78+checkTopLevelAndLets :: [Statement] -> (String -> [Def] -> [a]) -> [a]
79+checkTopLevelAndLets stmts fcheck =
80+ fcheck "at top-level" topLevelDefs ++
81+ concatMap (fcheck "in let binding") allLetDefs
82+ where
83+ topLevelDefs = mapMaybe maybeDef stmts
84+ maybeDef (Definition d) = Just d
85+ maybeDef _ = Nothing
86+ allLetDefs = [defList | Let defList _ <- universeBi stmts]
9587
9688dups :: [Statement] -> [String]
97−dups stmts = map defMsg (dup definition) ++ map annMsg (dup annotation)
98− where
99− dup :: (Statement -> [String]) -> [String]
100− dup f = map head . filter ((>1) . length) . group . sort $ concatMap f stmts
89+dups stmts = checkTopLevelAndLets stmts $ \ctxt defs ->
90+ let
91+ dup :: (Def -> Maybe String) -> [String]
92+ dup f = map head . filter ((>1) . length) . group . sort $ mapMaybe f defs
10193
10294 msg = "Syntax Error: There can only be one "
103− defMsg x = msg ++ "top-level definition of '" ++ x ++ "'."
104− annMsg x = msg ++ "type annotation for '" ++ x ++ "'."
95+ defMsg x = msg ++ "definition of '" ++ x ++ "' " ++ ctxt ++ "."
96+ annMsg x = msg ++ "type annotation for '" ++ x ++ "'" ++ ctxt ++ "."
97+ in
98+ map defMsg (dup definition) ++ map annMsg (dup annotation)
10599
106100badOrder :: [Statement] -> [String]
107−badOrder stmts = map msg $ missings (sort $ expectedPairs as ds) (sort $ actualPairs stmts)
108− where
101+badOrder stmts = checkTopLevelAndLets stmts $ \ctxt defs ->
102+ let
109103 msg x = "Syntax Error: The type annotation for '" ++ x ++
110− "' must be directly above its definition."
111− as = sort $ concatMap annotation stmts
112− ds = sort $ concatMap definition stmts
104+ "' must be directly above its definition in " ++ ctxt ++ "."
105+ as = sort $ mapMaybe annotation defs
106+ ds = sort $ mapMaybe definition defs
113107
114108 expectedPairs :: [String] -> [String] -> [String]
115109 expectedPairs as ds =
@@ -120,11 +114,14 @@ badOrder stmts = map msg $ missings (sort $ expectedPairs as ds) (sort $ actualP
120114 GT -> expectedPairs (x:xs) ys
121115 ( _ , _ ) -> []
122116
123− actualPairs :: [Statement] -> [String]
117+ actualPairs :: [Def] -> [String]
124118 actualPairs stmts =
125119 case stmts of
126− TypeAnnotation n _ : Definition d : rest ->
127− (if n == defName d then [n] else []) ++ actualPairs rest
120+ TypeAnnotation n _ : rest@(d : _) ->
121+ (if Just n == definition d
122+ then [n]
123+ else []
124+ ) ++ actualPairs rest
128125 t:s:rest -> actualPairs (s:rest)
129126 _ -> []
130127
@@ -136,4 +133,6 @@ badOrder stmts = map msg $ missings (sort $ expectedPairs as ds) (sort $ actualP
136133 EQ -> missings es as
137134 GT -> a : missings (e:es) as
138135 ( [] , _ ) -> actual
139− ( _ , [] ) -> expected
136+ ( _ , [] ) -> expected
137+ in
138+ map msg $ missings (sort $ expectedPairs as ds) (sort $ actualPairs defs)
compiler/Types/Constrain.hs+4−4
@@ -128,6 +128,7 @@ gen (L _ span expr) =
128128 let assumptions = unionsA (as:ass)
129129 getName d = case d of FnDef f _ _ -> f
130130 OpDef op _ _ _ -> op
131+ TypeAnnotation n _ -> n
131132 names = map getName defs
132133 genCs name s = do
133134 v <- guid
@@ -286,6 +287,9 @@ defScheme def = do (as,cs,hint) <- defGen def
286287defGen def = case def of
287288 FnDef f args e -> defGenHelp f args e
288289 OpDef op a1 a2 e -> defGenHelp op [a1,a2] e
290+ TypeAnnotation name tipe -> do
291+ schm <- Subs.generalize [] =<< Subs.superize name tipe
292+ return (Map.empty, Set.empty, (name, schm))
289293
290294defGenHelp name args e = do
291295 argDict <- mapM (\a -> liftM ((,) a) guid) args
@@ -325,8 +329,4 @@ stmtGen stmt =
325329 , Set.insert (L txt span (signalOf t :=: tipe)) cs
326330 , Map.singleton elm (Forall [] [] tipe) )
327331
328− TypeAnnotation name tipe ->
329− do schm <- Subs.generalize [] =<< Subs.superize name tipe
330− return (Map.empty, Set.empty, Map.singleton name schm)
331−
332332 TypeAlias _ _ _ -> return (Map.empty, Set.empty, Map.empty)
compiler/Types/Types.hs+5−4
@@ -1,4 +1,4 @@
1−
1+{-# LANGUAGE DeriveDataTypeable #-}
22module Types.Types where
33
44import Located
@@ -6,6 +6,7 @@ import Data.Char (isDigit)
66import Data.List (intercalate,isPrefixOf)
77import qualified Data.Set as Set
88import qualified Data.Map as Map
9+import Data.Data
910
1011type X = Int
1112
@@ -15,14 +16,14 @@ data Type = LambdaT Type Type
1516 | EmptyRecord
1617 | RecordT (Map.Map String [Type]) Type
1718 | Super (Set.Set Type)
18− deriving (Eq, Ord)
19+ deriving (Eq, Ord, Data, Typeable)
1920
20−data Scheme = Forall [X] [Located Constraint] Type deriving (Eq, Ord, Show)
21+data Scheme = Forall [X] [Located Constraint] Type deriving (Eq, Ord, Show, Data, Typeable)
2122
2223data Constraint = Type :=: Type
2324 | Type :<: Type
2425 | X :<<: Scheme
25− deriving (Eq, Ord, Show)
26+ deriving (Eq, Ord, Show, Data, Typeable)
2627
2728recordT :: [(String,Type)] -> Map.Map String [Type]
2829recordT fields =
server/Server.hs+19−11
@@ -3,7 +3,7 @@ module Main where
33
44import Control.Monad (msum,guard)
55import Control.Monad.Trans (MonadIO(liftIO))
6−import Data.List (isPrefixOf, isSuffixOf)
6+import Data.List (isPrefixOf, isSuffixOf, (\\))
77import Data.Version (showVersion)
88import Happstack.Server
99import Happstack.Server.Compression
@@ -14,17 +14,18 @@ import Paths_elm_server
1414
1515runtime = "/elm-" ++ showVersion version ++ ".js"
1616
17−serve :: String -> IO ()
18−serve libLoc = do
17+serve :: Int -> String -> IO ()
18+serve portNumber libLoc = do
1919 putStrLn ("Elm Server " ++ showVersion version ++
20− ": running at <http://localhost:8000>")
20+ ": running at <http://localhost:" ++ (show portNumber) ++ ">")
2121 putStrLn "Just refresh a page to recompile it!"
22− simpleHTTP nullConf $ do
22+ simpleHTTP httpConf $ do
2323 _ <- compressedResponseFilter
2424 msum [ uriRest serveElm
2525 , uriRest (serveLib libLoc)
2626 , serveDirectory EnableBrowsing [] "."
2727 ]
28+ where httpConf = nullConf { port = portNumber }
2829
2930pageTitle :: String -> String
3031pageTitle = dropExtension . takeBaseName
@@ -44,12 +45,16 @@ main = getArgs >>= parse
4445parse :: [String] -> IO ()
4546parse ("--help":_) = putStrLn usage
4647parse ("--version":_) = putStrLn ("The Elm Server " ++ showVersion version)
47−parse [] = serve =<< Elm.runtime
48−parse [arg]
49− | "--runtime-location=" `isPrefixOf` arg =
50− serve . tail $ dropWhile (/='=') arg
51− | otherwise = putStrLn usageMini
52−parse _ = putStrLn usageMini
48+parse args = if null remainingArgs
49+ then serve portNumber =<< elmRuntime
50+ else putStrLn usageMini
51+ where runtimeArg = filter (isPrefixOf "--runtime-location=") args
52+ portArg = filter (isPrefixOf "--port=") args
53+ remainingArgs = (args \\ runtimeArg) \\ portArg
54+
55+ argValue arg = tail $ dropWhile (/= '=') (head arg)
56+ portNumber = if null portArg then 8000 else read (argValue portArg) :: Int
57+ elmRuntime = if null runtimeArg then Elm.runtime else return $ argValue runtimeArg
5358
5459usageMini :: String
5560usageMini =
@@ -62,6 +67,9 @@ usage =
6267 \Compiles and serves .elm files from the current directory.\n\
6368 \Example: elm-server\n\
6469 \\n\
70+ \Server configuration:\n\
71+ \ --port set the port to listen on (default: 8000)\n\
72+ \\n\
6573 \Resource Locations:\n\
6674 \ --runtime-location set the location of the Elm runtime\n\
6775 \\n\