From d629db79c23ea0e87be3f9055e1a1d1e9de7e83e Mon Sep 17 00:00:00 2001 From: evancz Date: Fri, 7 Jun 2013 09:43:58 -0700 Subject: [PATCH 01/81] Fix issue causing build error. --- compiler/Model/Ast.hs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/Model/Ast.hs b/compiler/Model/Ast.hs index 7b4f287..a0e1803 100644 --- a/compiler/Model/Ast.hs +++ b/compiler/Model/Ast.hs @@ -9,6 +9,7 @@ import qualified Text.Pandoc as Pandoc import Data.Data data Module = Module [String] Exports Imports [Statement] + deriving Show type Exports = [String] From 776ef7c3f91b3e6b913dbb0fb5810c741cfeae8b Mon Sep 17 00:00:00 2001 From: evancz Date: Sun, 9 Jun 2013 11:15:37 -0700 Subject: [PATCH 02/81] Fix bug in setting headers. --- libraries/Native/Signal/Http.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/Native/Signal/Http.js b/libraries/Native/Signal/Http.js index 1dda015..7f58bc9 100644 --- a/libraries/Native/Signal/Http.js +++ b/libraries/Native/Signal/Http.js @@ -26,7 +26,7 @@ Elm.Native.Http = function(elm) { } function setHeader(pair) { - request.setRequestHeader( JS.fomString(pair._0), JS.fromString(pair._1) ); + request.setRequestHeader( JS.fromString(pair._0), JS.fromString(pair._1) ); } function sendReq(queue,responses,req) { From 569541e72a3d24afd0b783e27eb9b9c218cd060c Mon Sep 17 00:00:00 2001 From: evancz Date: Sun, 9 Jun 2013 23:36:59 -0700 Subject: [PATCH 03/81] Fix broken build. --- compiler/Compiler.hs | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/compiler/Compiler.hs b/compiler/Compiler.hs index aeb1fc9..65fc6c3 100644 --- a/compiler/Compiler.hs +++ b/compiler/Compiler.hs @@ -67,24 +67,25 @@ compileArgs flags = type Interface = String +file :: Flags -> FilePath -> String -> FilePath +file flags filePath ext = output_directory flags replaceExtension filePath ext + +elmo :: Flags -> FilePath -> FilePath +elmo flags filePath = file flags filePath "elmo" + + buildFile :: Flags -> Int -> Int -> FilePath -> IO Interface buildFile flags moduleNum numModules filePath = do compiled <- alreadyCompiled - if compiled then getInterface else compile + if compiled then readFile (elmo flags filePath) else compile where - file :: String -> FilePath - file ext = output_directory flags replaceExtension filePath ext - - interface :: FilePath - interface = file "elmi" - alreadyCompiled :: IO Bool alreadyCompiled = do - exists <- doesFileExist interface + exists <- doesFileExist (elmo flags filePath) if not exists then return False else do tsrc <- getModificationTime filePath - tint <- getModificationTime interface + tint <- getModificationTime (elmo flags filePath) return (tsrc < tint) number :: String @@ -97,19 +98,16 @@ buildFile flags moduleNum numModules filePath = compile = do putStrLn (number ++ " Compiling " ++ name) source <- readFile filePath - (inter,obj) <- + (interface,obj) <- if takeExtension filePath == ".js" then return ("",source) else case buildFromSource (no_prelude flags) source of Left err -> putStrLn err >> exitFailure - Right modul -> return (show modul, jsModule modul) + Right modul -> do exs <- exportInfo modul + return (exs, jsModule modul) createDirectoryIfMissing True (output_directory flags) - writeFile interface inter - writeFile (file "elmo") obj - return inter + writeFile (elmo flags filePath) obj + return obj - getInterface :: IO Interface - getInterface = do - readFile interface getRuntime :: Flags -> IO FilePath getRuntime flags = @@ -125,19 +123,19 @@ build flags rootFile = do case only_js flags of True -> do putStr "Generating JavaScript ... " - writeFile (replaceExtension rootFile "js") (genJs js) + writeFile (file flags rootFile "js") (genJs js) putStrLn "Done" False -> do putStr "Generating HTML ... " runtime <- getRuntime flags let html = genHtml $ createHtml runtime rootFile (sources js) "" - writeFile (replaceExtension rootFile "html") html + writeFile (file flags rootFile "html") html putStrLn "Done" where appendToOutput :: String -> FilePath -> IO String appendToOutput js filePath = - do src <- readFile (output_directory flags replaceExtension filePath "elmo") + do src <- readFile (elmo flags filePath) return (src ++ js) genHtml = if minify flags then Normal.renderHtml else Pretty.renderHtml @@ -153,3 +151,9 @@ buildFiles flags numModules interfaces (filePath:rest) = do let moduleName = intercalate "." (splitDirectories (dropExtensions filePath)) interfaces' = Map.insert moduleName interface interfaces buildFiles flags numModules interfaces' rest + + +exportInfo :: Module -> IO String +exportInfo (Module names exs ims stmts) = + do print exs + return (show exs) \ No newline at end of file From df667ca0227e2043817e8fd4408575b8e1cf4e23 Mon Sep 17 00:00:00 2001 From: Mads Flensted-Urech Date: Mon, 17 Jun 2013 22:48:05 +0200 Subject: [PATCH 04/81] Replace two '$' with '<|' --- libraries/Automaton.elm | 2 +- libraries/Dict.elm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/Automaton.elm b/libraries/Automaton.elm index 6fee530..955855b 100644 --- a/libraries/Automaton.elm +++ b/libraries/Automaton.elm @@ -33,7 +33,7 @@ g <<< f = f >>> g -- Combine a list of automatons into a single automaton that produces a list. combine : [Automaton a b] -> Automaton a [b] combine autos = - Step (\a -> let (autos', bs) = unzip $ map (step a) autos + Step (\a -> let (autos', bs) = unzip <| map (step a) autos in (combine autos', bs)) -- Create an automaton with no memory. It just applies the given function to diff --git a/libraries/Dict.elm b/libraries/Dict.elm index 33a9ea4..b2319ee 100644 --- a/libraries/Dict.elm +++ b/libraries/Dict.elm @@ -154,7 +154,7 @@ find k t = -- Determine if a key is in a dictionary. member : Comparable k -> Dict (Comparable k) v -> Bool -- Does t contain k? -member k t = Maybe.isJust $ lookup k t +member k t = Maybe.isJust <| lookup k t rotateLeft : Dict k v -> Dict k v rotateLeft t = From 1df206dcc91f0f17ba0d8f21179f07ee2ae873f5 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Sun, 4 Aug 2013 15:44:47 -0700 Subject: [PATCH 05/81] Clean up mistakes from the merge --- compiler/Compiler.hs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/compiler/Compiler.hs b/compiler/Compiler.hs index df37992..b82bbf1 100644 --- a/compiler/Compiler.hs +++ b/compiler/Compiler.hs @@ -194,9 +194,3 @@ buildFiles flags numModules interfaces (filePath:rest) = do let moduleName = List.intercalate "." . splitDirectories $ dropExtensions filePath interfaces' = Map.insert moduleName interface interfaces buildFiles flags numModules interfaces' rest - - -exportInfo :: Module -> IO String -exportInfo (Module names exs ims stmts) = - do print exs - return (show exs) From 555cdc65879a3e4828251c68b3b05294e6579d66 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Sun, 4 Aug 2013 15:58:06 -0700 Subject: [PATCH 06/81] minor clarification --- changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index d6c1f62..94f37ae 100644 --- a/changelog.txt +++ b/changelog.txt @@ -6,7 +6,7 @@ Build Improvements: * Major speed improvements to type-checker * Type-checker should catch _all_ type errors now * Module-level compilation, only re-compile if necessary - * Import type aliases between modules + * Import types and type aliases between modules Error Messages: * Cross-module type errors From 48ee3120e513e62951846a13f16046b7f0dd2508 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Sun, 4 Aug 2013 16:01:18 -0700 Subject: [PATCH 07/81] try to clarify syntax upgrade for infix definitions --- changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 94f37ae..f28bef9 100644 --- a/changelog.txt +++ b/changelog.txt @@ -22,7 +22,7 @@ Syntax: * Record Constructors * Record type aliases can be closed on the zeroth column * (,,) syntax in types - * "(+) = " is permitted + * Allow infix op definitions without args: (*) = add * Unparenthesized if, let, case, lambda at end of binary expressions Libraries: From a446d609f2492a372178d8d2d6c311ae0249de2e Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Tue, 6 Aug 2013 00:36:07 -0700 Subject: [PATCH 08/81] Ensure that binary serialization works on Windows. Previously had issues with line ending conversions messing with binary data. --- Setup.hs | 12 ++++++++++-- compiler/Compiler.hs | 16 +++++++++++++--- compiler/Metadata/Prelude.hs | 12 ++++++++++-- 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/Setup.hs b/Setup.hs index 4169f73..74ff31e 100644 --- a/Setup.hs +++ b/Setup.hs @@ -11,6 +11,7 @@ import System.Process import Control.Monad import qualified Data.Binary as Binary +import qualified Data.ByteString.Lazy as BS -- Part 1 -- ------ @@ -130,8 +131,15 @@ buildInterfaces :: LocalBuildInfo -> [FilePath] -> IO () buildInterfaces lbi elmis = do createDirectoryIfMissing True (rtsDir lbi) let ifaces = interfaces lbi - Binary.encodeFile ifaces (length elmis) - mapM_ (\elmi -> readFile elmi >>= appendFile ifaces) elmis + ifaceHandle <- openBinaryFile ifaces WriteMode + BS.hPut ifaceHandle (Binary.encode (length elmis)) + let append file = do + handle <- openBinaryFile file ReadMode + bits <- hGetContents handle + length bits `seq` hPutStr ifaceHandle bits + hClose handle + mapM_ append elmis + hClose ifaceHandle buildRuntime :: LocalBuildInfo -> [FilePath] -> IO () buildRuntime lbi elmos = do diff --git a/compiler/Compiler.hs b/compiler/Compiler.hs index b82bbf1..74b55c7 100644 --- a/compiler/Compiler.hs +++ b/compiler/Compiler.hs @@ -10,12 +10,14 @@ import System.Console.CmdArgs hiding (program) import System.Directory import System.Exit import System.FilePath +import System.IO import GHC.Conc import qualified Text.Blaze.Html.Renderer.Pretty as Pretty import qualified Text.Blaze.Html.Renderer.String as Normal import qualified Text.Jasmine as JS import qualified Data.ByteString.Lazy.Char8 as BS +import qualified Data.ByteString.Lazy as L import qualified Metadata.Prelude as Prelude import qualified Transform.Canonicalize as Canonical @@ -91,8 +93,14 @@ elmi flags filePath = file flags filePath "elmi" buildFile :: Flags -> Int -> Int -> Interfaces -> FilePath -> IO ModuleInterface buildFile flags moduleNum numModules interfaces filePath = do compiled <- alreadyCompiled - if not compiled then compile - else getInterface `fmap` Binary.decodeFile (elmi flags filePath) + case compiled of + False -> compile + True -> do + handle <- openBinaryFile (elmi flags filePath) ReadMode + bits <- L.hGetContents handle + let iface = getInterface (Binary.decode bits) + L.length bits `seq` hClose handle + return iface where getInterface :: (String, ModuleInterface) -> ModuleInterface getInterface = snd @@ -139,7 +147,9 @@ buildFile flags moduleNum numModules interfaces filePath = iAliases = aliases metaModule } createDirectoryIfMissing True . dropFileName $ elmi flags filePath - Binary.encodeFile (elmi flags filePath) (name,interface) + handle <- openBinaryFile (elmi flags filePath) WriteMode + L.hPut handle (Binary.encode (name,interface)) + hClose handle writeFile (elmo flags filePath) (jsModule metaModule) return interface diff --git a/compiler/Metadata/Prelude.hs b/compiler/Metadata/Prelude.hs index a58fe26..72eae07 100644 --- a/compiler/Metadata/Prelude.hs +++ b/compiler/Metadata/Prelude.hs @@ -6,9 +6,11 @@ import qualified Paths_Elm as Path import System.Directory import System.Exit import System.FilePath +import System.IO import System.IO.Unsafe (unsafePerformIO) import SourceSyntax.Module import qualified Data.Binary as Binary +import qualified Data.ByteString.Lazy as BS add :: Module t v -> Module t v @@ -47,5 +49,11 @@ safeReadDocs name = readDocs :: FilePath -> IO Interfaces readDocs name = do exists <- doesFileExist name - if exists then Map.fromList `fmap` Binary.decodeFile name - else ioError . userError $ "File Not Found" + case exists of + False -> ioError . userError $ "File Not Found" + True -> do + handle <- openBinaryFile name ReadMode + bits <- BS.hGetContents handle + let ifaces = Map.fromList (Binary.decode bits) + BS.length bits `seq` hClose handle + return ifaces \ No newline at end of file From 96835bf598b8ccff9feb74632c3eafcbb2404aae Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Tue, 6 Aug 2013 12:25:17 -0700 Subject: [PATCH 09/81] Update to talk about ElmFiles/ directory --- changelog.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/changelog.txt b/changelog.txt index f28bef9..33be51f 100644 --- a/changelog.txt +++ b/changelog.txt @@ -7,6 +7,10 @@ Build Improvements: * Type-checker should catch _all_ type errors now * Module-level compilation, only re-compile if necessary * Import types and type aliases between modules + * Intermediate files are generated to avoid unneeded recompilation + and shorten compile time. These files go in ElmFiles/ by default + * Generated files are placed in ElmFiles/ by default, replicating + the directory structure of your source code. Error Messages: * Cross-module type errors @@ -30,6 +34,9 @@ Libraries: * Set alpha of arbitrary forms in collages * Switch Text.height to use px instead of em +Bug Fixes: + * Many bug fixes for collage, especially when rendering Elements. + Website: * Hot-swapping * Much faster page load with pre-compiled Elm files (Max New) From 97a462897659c25c6d253d38e6cf41ee0229823c Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Tue, 6 Aug 2013 13:40:54 -0700 Subject: [PATCH 10/81] Get rid of dead code: `showErr` is not used any more --- compiler/Generate/JavaScript.hs | 8 +------- compiler/Language/Elm.hs | 2 +- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/compiler/Generate/JavaScript.hs b/compiler/Generate/JavaScript.hs index b0488b2..3b41b01 100644 --- a/compiler/Generate/JavaScript.hs +++ b/compiler/Generate/JavaScript.hs @@ -1,4 +1,4 @@ -module Generate.JavaScript (showErr, jsModule) where +module Generate.JavaScript (jsModule) where import Control.Arrow (first,second) import Control.Monad (liftM,(<=<),join,ap) @@ -18,12 +18,6 @@ import qualified Transform.SortDefinitions as SD deprime :: String -> String deprime = map (\c -> if c == '\'' then '$' else c) -showErr :: String -> String -showErr err = globalAssign "Elm.Main" (jsFunc "elm" body) - where msg = show . concatMap (++"
") . lines $ err - body = "var T = Elm.Text(elm);\n\ - \return { main : T.text(T.monospace(" ++ msg ++ ")) };" - indent = concatMap f where f '\n' = "\n " f c = [c] diff --git a/compiler/Language/Elm.hs b/compiler/Language/Elm.hs index c74c655..55b721c 100644 --- a/compiler/Language/Elm.hs +++ b/compiler/Language/Elm.hs @@ -14,7 +14,7 @@ module Language.Elm (compile, toHtml, moduleName, runtime, docs) where import qualified Data.List as List import qualified Data.Map as Map import Data.Version (showVersion) -import Generate.JavaScript (showErr, jsModule) +import Generate.JavaScript (jsModule) import Generate.Html (generateHtml) import Initialize (buildFromSource) import Parse.Helpers From 97ab6199bd7a70f8f304b885f1cd447d1406c9c0 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Tue, 6 Aug 2013 13:41:17 -0700 Subject: [PATCH 11/81] Make sure that the user defined module name is used in generated HTML --- compiler/Compiler.hs | 12 ++++++------ compiler/Generate/Html.hs | 26 +++++--------------------- 2 files changed, 11 insertions(+), 27 deletions(-) diff --git a/compiler/Compiler.hs b/compiler/Compiler.hs index 74b55c7..7f0fa46 100644 --- a/compiler/Compiler.hs +++ b/compiler/Compiler.hs @@ -171,7 +171,7 @@ build flags rootFile = do let noPrelude = no_prelude flags files <- if make flags then getSortedDependencies noPrelude rootFile else return [rootFile] let ifaces = if noPrelude then Map.empty else Prelude.interfaces - interfaces <- buildFiles flags (length files) ifaces files + (moduleName, interfaces) <- buildFiles flags (length files) ifaces "" files js <- foldM appendToOutput "" files case only_js flags of True -> do @@ -181,7 +181,7 @@ build flags rootFile = do False -> do putStr "Generating HTML ... " runtime <- getRuntime flags - let html = genHtml $ createHtml runtime (takeBaseName rootFile) (sources js) "" + let html = genHtml $ createHtml runtime (takeBaseName rootFile) (sources js) moduleName "" writeFile (file flags rootFile "html") html putStrLn "Done" @@ -197,10 +197,10 @@ build flags rootFile = do [ Source (if minify flags then Minified else Readable) js ] -buildFiles :: Flags -> Int -> Interfaces -> [FilePath] -> IO Interfaces -buildFiles _ _ interfaces [] = return interfaces -buildFiles flags numModules interfaces (filePath:rest) = do +buildFiles :: Flags -> Int -> Interfaces -> String -> [FilePath] -> IO (String, Interfaces) +buildFiles _ _ interfaces moduleName [] = return (moduleName, interfaces) +buildFiles flags numModules interfaces _ (filePath:rest) = do interface <- buildFile flags (numModules - length rest) numModules interfaces filePath let moduleName = List.intercalate "." . splitDirectories $ dropExtensions filePath interfaces' = Map.insert moduleName interface interfaces - buildFiles flags numModules interfaces' rest + buildFiles flags numModules interfaces' moduleName rest diff --git a/compiler/Generate/Html.hs b/compiler/Generate/Html.hs index 9fa166e..5e244d3 100644 --- a/compiler/Generate/Html.hs +++ b/compiler/Generate/Html.hs @@ -40,27 +40,10 @@ generateHtml :: String -- ^ Location of elm-runtime.js as expected by the browse -> String -- ^ The page title -> String -- ^ The elm source code. -> H.Html -generateHtml libLoc title source = H.span "broken for now" -{-- - case buildFromSource True source of - Right modul -> createHtml libLoc title [] "" title [modul] - Left err -> createHtml Readable libLoc title (Right $ showErr err) - (H.noscript "") "Main" ---} -{-- -modulesToHtml :: FilePath -> String -> [] -modulesToHtml libLoc title scripts nscrpt modules = - createHtml jsStyle libLoc title' js noscript altTitle - where - js = Right $ jss ++ concatMap jsModule modules - noscript = if nscrpt then extractNoscript $ last modules else "" - title' = if null title then altTitle else title - altTitle = intercalate "." names - where Module names _ _ _ = last modules ---} +generateHtml libLoc title source = error "function 'generateHtml' is unimplemented for now" -createHtml :: FilePath -> String -> [JSSource] -> String -> H.Html -createHtml libLoc title scripts noscript = +createHtml :: FilePath -> String -> [JSSource] -> String -> String -> H.Html +createHtml libLoc title scripts moduleName noscript = H.docTypeHtml $ do H.head $ do H.meta ! A.charset "UTF-8" @@ -68,5 +51,6 @@ createHtml libLoc title scripts noscript = makeScript (Link libLoc) mapM_ makeScript scripts H.body $ do - H.script ! A.type_ "text/javascript" $ preEscapedToMarkup ("Elm.fullscreen(Elm.Main)" :: String) + H.script ! A.type_ "text/javascript" $ + preEscapedToMarkup ("Elm.fullscreen(Elm." ++ moduleName ++ ")") H.noscript $ preEscapedToMarkup noscript From 7af7c1f98d4811c5b14fdb6a8f77109dd3b81ee8 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Tue, 6 Aug 2013 15:43:31 -0700 Subject: [PATCH 12/81] Change "line" to "on line" in the string representation of one line `SrcSpan`s --- compiler/SourceSyntax/Location.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/SourceSyntax/Location.hs b/compiler/SourceSyntax/Location.hs index e8b7e40..36bb0fa 100644 --- a/compiler/SourceSyntax/Location.hs +++ b/compiler/SourceSyntax/Location.hs @@ -49,7 +49,7 @@ instance Show SrcSpan where Span start end _ -> case line start == line end of False -> "between lines " ++ show (line start) ++ " and " ++ show (line end) - True -> "line " ++ show (line end) ++ ", column " ++ + True -> "on line " ++ show (line end) ++ ", column " ++ show (column start) ++ " to " ++ show (column end) instance Show e => Show (Located e) where From a3f62c34c3e25464ce250b08b9292e4e70758634 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Tue, 6 Aug 2013 15:43:59 -0700 Subject: [PATCH 13/81] Make errors a little bit better when a type alias gets the wrong number of arguments. --- compiler/Type/Environment.hs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/Type/Environment.hs b/compiler/Type/Environment.hs index 6dec368..4dd46d8 100644 --- a/compiler/Type/Environment.hs +++ b/compiler/Type/Environment.hs @@ -99,7 +99,7 @@ ctorToType env (name, tvars, ctors) = get :: Environment -> (Environment -> Map.Map String a) -> String -> a get env subDict key = Map.findWithDefault err key (subDict env) where - err = error $ "Could not find type constructor '" ++ key ++ "' while checking types." + err = error $ "\nCould not find type constructor '" ++ key ++ "' while checking types." freshDataScheme :: Environment -> String -> IO (Int, [Variable], [Type], Type) @@ -146,9 +146,11 @@ instantiator env sourceType = go sourceType Just t -> return $ foldl (<|) t ts' Nothing -> case Map.lookup name (aliases env) of - Nothing -> error $ "Could not find type constructor '" ++ name ++ "' while checking types." + Nothing -> error $ "\nCould not find type constructor '" ++ name ++ "' while checking types." Just (tvars, t) -> - let msg = "Type alias '" ++ name ++ "' expects " ++ show (length tvars) ++ + let tvarLen = length tvars + msg = "\nType alias '" ++ name ++ "' expects " ++ show tvarLen ++ + " type argument" ++ (if tvarLen == 1 then "" else "s") ++ " but was given " ++ show (length ts') in if length ts' /= length tvars then error msg else do (dict, aliases) <- State.get From 2e38f7b06121a3d70d2a76fce30273f0ef8284d3 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Tue, 6 Aug 2013 15:44:19 -0700 Subject: [PATCH 14/81] Give line numbers when there is a kind error in a pattern --- compiler/Type/Constrain/Expression.hs | 12 ++++++++++-- compiler/Type/Constrain/Pattern.hs | 15 ++++++++------- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/compiler/Type/Constrain/Expression.hs b/compiler/Type/Constrain/Expression.hs index 97af1f7..3b948bd 100644 --- a/compiler/Type/Constrain/Expression.hs +++ b/compiler/Type/Constrain/Expression.hs @@ -6,6 +6,7 @@ import qualified Data.Set as Set import Control.Arrow (second) import Control.Applicative ((<$>),(<*>)) import qualified Control.Monad as Monad +import Control.Monad.Error (ErrorT, runErrorT) import Control.Monad.State import Data.Traversable (traverse) @@ -56,7 +57,7 @@ constrain env (L span expr) tipe = Lambda p e -> exists $ \t1 -> exists $ \t2 -> do - fragment <- Pattern.constrain env p t1 + fragment <- try span $ Pattern.constrain env p t1 c2 <- constrain env e t2 let c = ex (vars fragment) (clet [monoscheme (typeEnv fragment)] (typeConstraint fragment /\ c2 )) @@ -80,7 +81,7 @@ constrain env (L span expr) tipe = exists $ \t -> do ce <- constrain env exp t let branch (p,e) = do - fragment <- Pattern.constrain env p t + fragment <- try span $ Pattern.constrain env p t clet [toScheme fragment] <$> constrain env e tipe and . (:) ce <$> mapM branch branches @@ -213,3 +214,10 @@ collapseDefs = concatMap expandPattern . go [] Map.empty Map.empty go ((pattern, body, Nothing) : output) defs typs ds TypeAnnotation name typ -> go output defs (Map.insert name typ typs) ds + +try :: SrcSpan -> ErrorT String IO a -> IO a +try span computation = do + result <- runErrorT computation + case result of + Left msg -> error $ "\nType error " ++ show span ++ "\n" ++ msg + Right value -> return value \ No newline at end of file diff --git a/compiler/Type/Constrain/Pattern.hs b/compiler/Type/Constrain/Pattern.hs index eab64f5..36381cf 100644 --- a/compiler/Type/Constrain/Pattern.hs +++ b/compiler/Type/Constrain/Pattern.hs @@ -3,6 +3,7 @@ module Type.Constrain.Pattern where import Control.Arrow (second) import Control.Applicative ((<$>)) import qualified Control.Monad as Monad +import Control.Monad.Error import qualified Data.List as List import qualified Data.Maybe as Maybe import qualified Data.Map as Map @@ -17,7 +18,7 @@ import Type.Environment as Env import qualified Type.Constrain.Literal as Literal -constrain :: Environment -> Pattern -> Type -> IO Fragment +constrain :: Environment -> Pattern -> Type -> ErrorT String IO Fragment constrain env pattern tipe = let span = Loc.NoSpan (render $ pretty pattern) t1 === t2 = Loc.L span (CEqual t1 t2) @@ -27,11 +28,11 @@ constrain env pattern tipe = PAnything -> return emptyFragment PLiteral lit -> do - c <- Literal.constrain env span lit tipe + c <- liftIO $ Literal.constrain env span lit tipe return $ emptyFragment { typeConstraint = c } PVar name -> do - v <- var Flexible + v <- liftIO $ var Flexible return $ Fragment { typeEnv = Map.singleton name (VarN v), vars = [v], @@ -46,11 +47,11 @@ constrain env pattern tipe = } PData name patterns -> do - (kind, cvars, args, result) <- freshDataScheme env name + (kind, cvars, args, result) <- liftIO $ freshDataScheme env name let msg = concat [ "Constructor '", name, "' expects ", show kind , " argument", if kind == 1 then "" else "s" , " but was given ", show (length patterns), "." ] - if length patterns /= kind then error msg else do + if length patterns /= kind then throwError msg else do fragment <- Monad.liftM joinFragments (Monad.zipWithM (constrain env) patterns args) return $ fragment { typeConstraint = typeConstraint fragment /\ tipe === result, @@ -58,9 +59,9 @@ constrain env pattern tipe = } PRecord fields -> do - pairs <- mapM (\name -> (,) name <$> var Flexible) fields + pairs <- liftIO $ mapM (\name -> (,) name <$> var Flexible) fields let tenv = Map.fromList (map (second VarN) pairs) - c <- exists $ \t -> return (tipe === record (Map.map (:[]) tenv) t) + c <- liftIO . exists $ \t -> return (tipe === record (Map.map (:[]) tenv) t) return $ Fragment { typeEnv = tenv, vars = map snd pairs, From 43b604e0ca8ea62ec350d44a7f16279144a3289e Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Tue, 6 Aug 2013 18:34:23 -0700 Subject: [PATCH 15/81] Introduce cache/ and build/ directories Switch from using --output-directory for all generated files, to using --cache-dir for .elmo and .elmi files and using --build-dir for .html and .js files. --- Setup.hs | 3 ++- compiler/Compiler.hs | 27 +++++++++++++++++---------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/Setup.hs b/Setup.hs index 74ff31e..d8c2bf8 100644 --- a/Setup.hs +++ b/Setup.hs @@ -113,7 +113,8 @@ compileLibraries lbi = do -- replace 'system' call with 'runProcess' which handles args better -- and allows env variable "Elm_datadir" which is used by LoadLibraries -- to find docs.json - let args = ["--only-js","--make","--no-prelude","--output-directory="++out_c,file] + let args = [ "--only-js", "--make", "--no-prelude" + , "--cache-dir="++out_c, "--build-dir="++out_c, file ] arg = Just [("Elm_datadir", rtd_c)] handle <- runProcess elm_c args Nothing arg Nothing Nothing Nothing exitCode <- waitForProcess handle diff --git a/compiler/Compiler.hs b/compiler/Compiler.hs index 7f0fa46..2c6909a 100644 --- a/compiler/Compiler.hs +++ b/compiler/Compiler.hs @@ -42,7 +42,8 @@ data Flags = , scripts :: [FilePath] , no_prelude :: Bool , minify :: Bool - , output_directory :: FilePath + , cache_dir :: FilePath + , build_dir :: FilePath } deriving (Data,Typeable,Show,Eq) @@ -64,8 +65,10 @@ flags = Flags &= help "Do not import Prelude by default, used only when compiling standard libraries." , minify = False &= help "Minify generated JavaScript and HTML" - , output_directory = "ElmFiles" &= typFile - &= help "Output files to directory specified. Defaults to ElmFiles/ directory." + , cache_dir = "cache" &= typFile + &= help "Directory for files cached to make builds faster. Defaults to cache/ directory." + , build_dir = "build" &= typFile + &= help "Directory for generated HTML and JS files. Defaults to build/ directory." } &= help "Compile Elm programs to HTML, CSS, and JavaScript." &= summary ("The Elm Compiler " ++ showVersion version ++ ", (c) Evan Czaplicki") @@ -80,14 +83,17 @@ compileArgs flags = fs -> mapM_ (build flags) fs -file :: Flags -> FilePath -> String -> FilePath -file flags filePath ext = output_directory flags replaceExtension filePath ext +buildPath :: Flags -> FilePath -> String -> FilePath +buildPath flags filePath ext = build_dir flags replaceExtension filePath ext + +cachePath :: Flags -> FilePath -> String -> FilePath +cachePath flags filePath ext = cache_dir flags replaceExtension filePath ext elmo :: Flags -> FilePath -> FilePath -elmo flags filePath = file flags filePath "elmo" +elmo flags filePath = cachePath flags filePath "elmo" elmi :: Flags -> FilePath -> FilePath -elmi flags filePath = file flags filePath "elmi" +elmi flags filePath = cachePath flags filePath "elmi" buildFile :: Flags -> Int -> Int -> Interfaces -> FilePath -> IO ModuleInterface @@ -127,7 +133,8 @@ buildFile flags moduleNum numModules interfaces filePath = , replicate (max 1 (20 - length name)) ' ' , "( " ++ filePath ++ " )" ] source <- readFile filePath - createDirectoryIfMissing True (output_directory flags) + createDirectoryIfMissing True (cache_dir flags) + createDirectoryIfMissing True (build_dir flags) metaModule <- case buildFromSource (no_prelude flags) interfaces source of Left errors -> do @@ -176,13 +183,13 @@ build flags rootFile = do case only_js flags of True -> do putStr "Generating JavaScript ... " - writeFile (file flags rootFile "js") (genJs js) + writeFile (buildPath flags rootFile "js") (genJs js) putStrLn "Done" False -> do putStr "Generating HTML ... " runtime <- getRuntime flags let html = genHtml $ createHtml runtime (takeBaseName rootFile) (sources js) moduleName "" - writeFile (file flags rootFile "html") html + writeFile (buildPath flags rootFile "html") html putStrLn "Done" where From ed6b255ba55ad1b7d54a33839978fa5b46e2cf15 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Tue, 6 Aug 2013 21:20:08 -0700 Subject: [PATCH 16/81] Properly parse out module names, defaulting to Main if no name is given. --- compiler/Compiler.hs | 31 +++++++++++++++---------------- compiler/Language/Elm.hs | 13 ++----------- compiler/Parse/Module.hs | 13 ++++++++++++- 3 files changed, 29 insertions(+), 28 deletions(-) diff --git a/compiler/Compiler.hs b/compiler/Compiler.hs index 2c6909a..0521913 100644 --- a/compiler/Compiler.hs +++ b/compiler/Compiler.hs @@ -22,6 +22,7 @@ import qualified Data.ByteString.Lazy as L import qualified Metadata.Prelude as Prelude import qualified Transform.Canonicalize as Canonical import SourceSyntax.Module +import Parse.Module (getModuleName) import Initialize (buildFromSource, getSortedDependencies) import Generate.JavaScript (jsModule) import Generate.Html (createHtml, JSStyle(..), JSSource(..)) @@ -96,7 +97,7 @@ elmi :: Flags -> FilePath -> FilePath elmi flags filePath = cachePath flags filePath "elmi" -buildFile :: Flags -> Int -> Int -> Interfaces -> FilePath -> IO ModuleInterface +buildFile :: Flags -> Int -> Int -> Interfaces -> FilePath -> IO (String,ModuleInterface) buildFile flags moduleNum numModules interfaces filePath = do compiled <- alreadyCompiled case compiled of @@ -104,13 +105,11 @@ buildFile flags moduleNum numModules interfaces filePath = True -> do handle <- openBinaryFile (elmi flags filePath) ReadMode bits <- L.hGetContents handle - let iface = getInterface (Binary.decode bits) + let info :: (String, ModuleInterface) + info = Binary.decode bits L.length bits `seq` hClose handle - return iface + return info where - getInterface :: (String, ModuleInterface) -> ModuleInterface - getInterface = snd - alreadyCompiled :: IO Bool alreadyCompiled = do existsi <- doesFileExist (elmi flags filePath) @@ -124,15 +123,16 @@ buildFile flags moduleNum numModules interfaces filePath = number :: String number = "[" ++ show moduleNum ++ " of " ++ show numModules ++ "]" - name :: String - name = List.intercalate "." (splitDirectories (dropExtensions filePath)) - - compile :: IO ModuleInterface + compile :: IO (String,ModuleInterface) compile = do + source <- readFile filePath + let name = case getModuleName source of + Just n -> n + Nothing -> "Name" putStrLn $ concat [ number, " Compiling ", name , replicate (max 1 (20 - length name)) ' ' , "( " ++ filePath ++ " )" ] - source <- readFile filePath + createDirectoryIfMissing True (cache_dir flags) createDirectoryIfMissing True (build_dir flags) metaModule <- @@ -158,7 +158,7 @@ buildFile flags moduleNum numModules interfaces filePath = L.hPut handle (Binary.encode (name,interface)) hClose handle writeFile (elmo flags filePath) (jsModule metaModule) - return interface + return (name,interface) printTypes metaModule = do putStrLn "" @@ -207,7 +207,6 @@ build flags rootFile = do buildFiles :: Flags -> Int -> Interfaces -> String -> [FilePath] -> IO (String, Interfaces) buildFiles _ _ interfaces moduleName [] = return (moduleName, interfaces) buildFiles flags numModules interfaces _ (filePath:rest) = do - interface <- buildFile flags (numModules - length rest) numModules interfaces filePath - let moduleName = List.intercalate "." . splitDirectories $ dropExtensions filePath - interfaces' = Map.insert moduleName interface interfaces - buildFiles flags numModules interfaces' moduleName rest + (name,interface) <- buildFile flags (numModules - length rest) numModules interfaces filePath + let interfaces' = Map.insert name interface interfaces + buildFiles flags numModules interfaces' name rest diff --git a/compiler/Language/Elm.hs b/compiler/Language/Elm.hs index 55b721c..221cfa9 100644 --- a/compiler/Language/Elm.hs +++ b/compiler/Language/Elm.hs @@ -17,11 +17,9 @@ import Data.Version (showVersion) import Generate.JavaScript (jsModule) import Generate.Html (generateHtml) import Initialize (buildFromSource) -import Parse.Helpers -import Parse.Module (moduleDef) +import Parse.Module (getModuleName) import SourceSyntax.Module import Text.Blaze.Html (Html) -import Text.Parsec (option,optional) import qualified Text.PrettyPrint as P import qualified Metadata.Prelude as Prelude import Paths_Elm @@ -36,14 +34,7 @@ compile source = -- |This function extracts the module name of a given source program. moduleName :: String -> Maybe String -moduleName source = case iParse getModuleName "" source of - Right name -> Just name - Left _ -> Nothing - where - getModuleName = do - optional freshLine - (names, _) <- moduleDef - return (List.intercalate "." names) +moduleName = getModuleName -- |This function compiles Elm code into a full HTML page. toHtml :: String -- ^ Location of elm-min.js as expected by the browser diff --git a/compiler/Parse/Module.hs b/compiler/Parse/Module.hs index ca496d1..0c559ef 100644 --- a/compiler/Parse/Module.hs +++ b/compiler/Parse/Module.hs @@ -1,5 +1,5 @@ -module Parse.Module (moduleDef, imports) where +module Parse.Module (moduleDef, getModuleName, imports) where import Control.Applicative ((<$>), (<*>)) import Data.List (intercalate) @@ -11,6 +11,17 @@ import SourceSyntax.Module (Module(..), ImportMethod(..), Imports) varList :: IParser [String] varList = parens $ commaSep1 (var <|> parens symOp) +getModuleName :: String -> Maybe String +getModuleName source = + case iParse getModuleName "" source of + Right name -> Just name + Left _ -> Nothing + where + getModuleName = do + optional freshLine + (names, _) <- moduleDef + return (intercalate "." names) + moduleDef :: IParser ([String], [String]) moduleDef = do try (reserved "module") From 53ef6d33c974757c411739b1fe866f7d978ad0fa Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Tue, 6 Aug 2013 21:20:32 -0700 Subject: [PATCH 17/81] Give a better error message when trying to unify rigid type variables in a bad way --- compiler/Type/Unify.hs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/compiler/Type/Unify.hs b/compiler/Type/Unify.hs index 8d1d230..5a0cc6a 100644 --- a/compiler/Type/Unify.hs +++ b/compiler/Type/Unify.hs @@ -7,6 +7,8 @@ import qualified Type.State as TS import Control.Arrow (first,second) import Control.Monad.State import SourceSyntax.Location +import Type.PrettyPrint +import Text.PrettyPrint (render) unify :: SrcSpan -> Variable -> Variable -> StateT TS.SolverState IO () unify span variable1 variable2 = do @@ -106,6 +108,12 @@ actuallyUnify span variable1 variable2 = do List _ -> flexAndUnify varSuper _ -> comparableError "" + rigidError variable = TS.addError span msg variable1 variable2 + where + msg = concat + [ "Cannot unify rigid type variable '", render (pretty Never variable), "'.\n" + , "It is likely that a type annotation is not general enough." ] + superUnify = case (flex desc1, flex desc2, name desc1, name desc2) of (Is super1, Is super2, _, _) @@ -126,6 +134,8 @@ actuallyUnify span variable1 variable2 = do (Is Appendable, _, _, _) -> unifyAppendable variable1 variable2 (_, Is Appendable, _, _) -> unifyAppendable variable2 variable1 + (Rigid, _, _, _) -> rigidError variable1 + (_, Rigid, _, _) -> rigidError variable2 _ -> TS.addError span "" variable1 variable2 case (structure desc1, structure desc2) of From 50dada1f223cf01c337d4c735279da1da20c311d Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Tue, 6 Aug 2013 21:40:54 -0700 Subject: [PATCH 18/81] Fix very silly error, default module name is "Main" not "Name" --- compiler/Compiler.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/Compiler.hs b/compiler/Compiler.hs index 0521913..acb60a7 100644 --- a/compiler/Compiler.hs +++ b/compiler/Compiler.hs @@ -128,7 +128,7 @@ buildFile flags moduleNum numModules interfaces filePath = source <- readFile filePath let name = case getModuleName source of Just n -> n - Nothing -> "Name" + Nothing -> "Main" putStrLn $ concat [ number, " Compiling ", name , replicate (max 1 (20 - length name)) ' ' , "( " ++ filePath ++ " )" ] From f7db7a3b477dba9d7d1bf695978c7a3da3af75a4 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Tue, 6 Aug 2013 22:12:26 -0700 Subject: [PATCH 19/81] Add a default error message for beginners --- compiler/Type/State.hs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/Type/State.hs b/compiler/Type/State.hs index 50c81f2..8bd1cc7 100644 --- a/compiler/Type/State.hs +++ b/compiler/Type/State.hs @@ -62,9 +62,11 @@ addError span message t1 t2 = NoSpan msg -> display msg Span _ _ msg -> display msg + defaultMessage = "Something is weird is happening with this value:" + makeError pt1 pt2 = P.vcat [ P.text $ "Type error" ++ location ++ ":" - , if null message then empty else P.vcat . map P.text $ lines message + , P.vcat . map P.text . lines $ if null message then defaultMessage else message , P.text src , P.text " Expected Type:" <+> pt1 , P.text " Actual Type:" <+> pt2 <> P.text "\n" From cc81b1e22b25b684d544863d9f4ddeba366e672e Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Tue, 6 Aug 2013 22:51:21 -0700 Subject: [PATCH 20/81] Make sure that all directories in build/ are properly constructed --- compiler/Compiler.hs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/Compiler.hs b/compiler/Compiler.hs index acb60a7..ac31882 100644 --- a/compiler/Compiler.hs +++ b/compiler/Compiler.hs @@ -189,7 +189,9 @@ build flags rootFile = do putStr "Generating HTML ... " runtime <- getRuntime flags let html = genHtml $ createHtml runtime (takeBaseName rootFile) (sources js) moduleName "" - writeFile (buildPath flags rootFile "html") html + htmlFile = buildPath flags rootFile "html" + createDirectoryIfMissing True (takeDirectory htmlFile) + writeFile htmlFile html putStrLn "Done" where From a043b95f0cac24057536801b0df9c71ed4cf010c Mon Sep 17 00:00:00 2001 From: Alexander Date: Wed, 7 Aug 2013 06:12:11 -0300 Subject: [PATCH 21/81] Remove extra "is" from defaultMessage. --- compiler/Type/State.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/Type/State.hs b/compiler/Type/State.hs index 8bd1cc7..0a2cca4 100644 --- a/compiler/Type/State.hs +++ b/compiler/Type/State.hs @@ -62,7 +62,7 @@ addError span message t1 t2 = NoSpan msg -> display msg Span _ _ msg -> display msg - defaultMessage = "Something is weird is happening with this value:" + defaultMessage = "Something weird is happening with this value:" makeError pt1 pt2 = P.vcat [ P.text $ "Type error" ++ location ++ ":" From 9821e12a4ce96c78a3f94395874cd734b83541d2 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Wed, 7 Aug 2013 09:12:53 -0700 Subject: [PATCH 22/81] Strip \r from multiline strings --- compiler/Parse/Literal.hs | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/compiler/Parse/Literal.hs b/compiler/Parse/Literal.hs index 1b04451..aac75c4 100644 --- a/compiler/Parse/Literal.hs +++ b/compiler/Parse/Literal.hs @@ -19,13 +19,25 @@ num = fmap toLit (preNum "number") string "." ('.':) <$> many1 digit +chr :: IParser Literal +chr = Chr <$> betwixt '\'' '\'' (backslashed <|> satisfy (/='\'')) + "character" + str :: IParser Literal -str = choice [ let quote = try (string "\"\"\"") - in quote >> Str <$> manyTill (backslashed <|> anyChar) quote +str = choice [ quote >> str <$> manyTill (backslashed <|> anyChar) quote , liftM Str . expecting "string" . betwixt '"' '"' . many $ backslashed <|> satisfy (/='"') ] + where + quote = try (string "\"\"\"") + str = Str . dewindows -chr :: IParser Literal -chr = Chr <$> betwixt '\'' '\'' (backslashed <|> satisfy (/='\'')) - "character" \ No newline at end of file + -- Remove \r from strings to fix generated JavaScript + dewindows [] = [] + dewindows cs = + let (pre, suf) = break (`elem` ['\r','\n']) cs + in pre ++ case suf of + ('\r':'\n':rest) -> '\n' : dewindows rest + ('\n':rest) -> '\n' : dewindows rest + ('\r':rest) -> '\n' : dewindows rest + _ -> [] From 0b9317124dc208a800189471aa68e898c34bac8b Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Wed, 7 Aug 2013 09:38:30 -0700 Subject: [PATCH 23/81] Give more specific errors when a variable cannot be found during canonicalization --- compiler/Transform/Canonicalize.hs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/compiler/Transform/Canonicalize.hs b/compiler/Transform/Canonicalize.hs index 721c4a3..90f1a47 100644 --- a/compiler/Transform/Canonicalize.hs +++ b/compiler/Transform/Canonicalize.hs @@ -61,7 +61,7 @@ metadataModule ifaces modul = second f (a,b) = (,) a `fmap` f b third f (a,b,c) = (,,) a b `fmap` f c renameType' = - Either.either (\err -> Left [P.text err]) return . renameType (replace initialEnv) + Either.either (\err -> Left [P.text err]) return . renameType (replace "type" initialEnv) get1 (a,_,_) = a canon (name, importMethod) = @@ -92,12 +92,12 @@ extend env pattern = Map.union (Map.fromList (zip xs xs)) env where xs = Set.toList (SD.boundVars pattern) -replace :: Env -> String -> Either String String -replace env v = +replace :: String -> Env -> String -> Either String String +replace variable env v = if List.isPrefixOf "Native." v then return v else case Map.lookup v env of Just v' -> return v' - Nothing -> Left $ "Could not find variable '" ++ v ++ "'." ++ msg + Nothing -> Left $ "Could not find " ++ variable ++ " '" ++ v ++ "'." ++ msg where matches = filter (List.isInfixOf v) (Map.keys env) msg = if null matches then "" else @@ -129,7 +129,7 @@ rename env lexpr@(L s expr) = frnm (f,e) = (,) f `liftM` rename env e Binop op e1 e2 -> - do op' <- format (replace env op) + do op' <- format (replace "variable" env op) Binop op' `liftM` rnm e1 `ap` rnm e2 Lambda pattern e -> @@ -149,9 +149,10 @@ rename env lexpr@(L s expr) = Def p exp -> Def `liftM` format (renamePattern env' p) `ap` rename env' exp TypeAnnotation name tipe -> - TypeAnnotation name `liftM` renameType (format . replace env') tipe + TypeAnnotation name `liftM` + renameType (format . replace "variable" env') tipe - Var x -> Var `liftM` format (replace env x) + Var x -> Var `liftM` format (replace "variable" env x) Data name es -> Data name `liftM` mapM rnm es @@ -173,5 +174,5 @@ renamePattern env pattern = PRecord _ -> return pattern PAnything -> return pattern PAlias x p -> PAlias x `liftM` renamePattern env p - PData name ps -> PData `liftM` replace env name + PData name ps -> PData `liftM` replace "pattern" env name `ap` mapM (renamePattern env) ps From 4d719eb235fb132482b1e827acfee0a4097aae55 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Wed, 7 Aug 2013 16:10:54 -0700 Subject: [PATCH 24/81] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 9251cb5..fbe6a47 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,8 @@ Use [the installer](https://dl.dropboxusercontent.com/u/5850974/Elm/Elm.pkg) and Let us know on [the list](https://groups.google.com/forum/?fromgroups#!forum/elm-discuss) if you have any trouble. +If you do have issues, use the [on any platform](#on-any-platform) instructions which are known to work reliably. + #### On any platform Download the [Haskell Platform 2012.2.0.0](http://hackage.haskell.org/platform/). From fa28e6119848e5eff3562652e0c2edfcec04ce42 Mon Sep 17 00:00:00 2001 From: Zsombor Nagy Date: Thu, 8 Aug 2013 08:24:24 +0200 Subject: [PATCH 25/81] Change foldp example to contain a function which uses both of its arguments --- libraries/Signal.elm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/Signal.elm b/libraries/Signal.elm index 7fddef3..16f3b31 100644 --- a/libraries/Signal.elm +++ b/libraries/Signal.elm @@ -52,7 +52,8 @@ lift8 = Native.Signal.lift8 -- Create a past-dependent signal. Each value given on the input signal will -- be accumulated, producing a new output value. -- --- For instance, `(foldp (\\t acc -> acc + 1) 0 (Time.every second))` increments every second. +-- For instance, `(foldp (\\arrows number -> number + arrows.y) 0 Keyboard.arrows)` +-- increments or decrements the accumulated value (which starts at zero) when the up or down arrow keys are pressed. foldp : (a -> b -> b) -> b -> Signal a -> Signal b foldp = Native.Signal.foldp From 143547e766efe66c007f37e1c4b278edba4ebebc Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Thu, 8 Aug 2013 15:45:22 -0700 Subject: [PATCH 26/81] Fix problem with variable shadowing when instantiating aliased types --- compiler/Type/Environment.hs | 56 ++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/compiler/Type/Environment.hs b/compiler/Type/Environment.hs index 4dd46d8..54177e7 100644 --- a/compiler/Type/Environment.hs +++ b/compiler/Type/Environment.hs @@ -122,40 +122,40 @@ instantiator env sourceType = go sourceType Src.Var x -> do (dict, aliases) <- State.get - case Map.lookup x dict of - Just var -> return (VarN var) - Nothing -> - case Map.lookup x aliases of - Just t -> return t - Nothing -> - do var <- State.liftIO $ namedVar flex x - State.put (Map.insert x var dict, aliases) - return (VarN var) - where - flex | "number" `isPrefixOf` x = Is Number - | "comparable" `isPrefixOf` x = Is Comparable - | "appendable" `isPrefixOf` x = Is Appendable - | otherwise = Flexible + case (Map.lookup x dict, Map.lookup x aliases) of + (_, Just t) -> return t + (Just v, _) -> return (VarN v) + _ -> + do var <- State.liftIO $ namedVar flex x + State.put (Map.insert x var dict, aliases) + return (VarN var) + where + flex | "number" `isPrefixOf` x = Is Number + | "comparable" `isPrefixOf` x = Is Comparable + | "appendable" `isPrefixOf` x = Is Appendable + | otherwise = Flexible Src.Data "String" [] -> return (get env types "_List" <| get env types "Char") Src.Data name ts -> do ts' <- mapM go ts - case Map.lookup name (types env) of - Just t -> return $ foldl (<|) t ts' - Nothing -> - case Map.lookup name (aliases env) of - Nothing -> error $ "\nCould not find type constructor '" ++ name ++ "' while checking types." - Just (tvars, t) -> - let tvarLen = length tvars - msg = "\nType alias '" ++ name ++ "' expects " ++ show tvarLen ++ - " type argument" ++ (if tvarLen == 1 then "" else "s") ++ - " but was given " ++ show (length ts') - in if length ts' /= length tvars then error msg else - do (dict, aliases) <- State.get - State.put (dict, Map.union aliases . Map.fromList $ zip tvars ts') - go t + case (Map.lookup name (types env), Map.lookup name (aliases env)) of + (Just t, _) -> return $ foldl (<|) t ts' + (_, Just (tvars, t)) -> + let tvarLen = length tvars + msg = "\nType alias '" ++ name ++ "' expects " ++ show tvarLen ++ + " type argument" ++ (if tvarLen == 1 then "" else "s") ++ + " but was given " ++ show (length ts') + in if length ts' /= length tvars then error msg else + do (dict, aliases) <- State.get + let aliases' = Map.union (Map.fromList $ zip tvars ts') aliases + State.put (dict, aliases') + t' <- go t + State.put (dict, aliases) + return t' + _ -> error $ "\nCould not find type constructor '" ++ + name ++ "' while checking types." Src.EmptyRecord -> return (TermN EmptyRecord1) From 623741877b3f5cfab1404acb1da42969a3ecc611 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Thu, 8 Aug 2013 16:04:40 -0700 Subject: [PATCH 27/81] Fix problems generating functions with 10 or more arguments Mainly useful for record constructors which are automatically generated. --- compiler/Generate/JavaScript.hs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/Generate/JavaScript.hs b/compiler/Generate/JavaScript.hs index 3b41b01..d22bfa3 100644 --- a/compiler/Generate/JavaScript.hs +++ b/compiler/Generate/JavaScript.hs @@ -191,11 +191,14 @@ instance ToJS (Expr t v) where Record fs -> makeRecord fs Binop op e1 e2 -> binop op e1 e2 - Lambda p e@(L s _) -> liftM (fastFunc . ret) (toJS' body) + Lambda p e@(L s _) -> liftM fastFunc (toJS' body) where fastFunc body - | length args < 2 || length args > 9 = foldr jsFunc body args - | otherwise = "F" ++ show (length args) ++ parens (jsFunc (commaSep args) body) + | length args < 2 || length args > 9 = + foldr (\arg bod -> jsFunc arg (ret bod)) body args + | otherwise = + "F" ++ show (length args) ++ parens (jsFunc (commaSep args) (ret body)) + (args, body) = first reverse $ foldr depattern ([], innerBody) (zip patterns [1..]) depattern (pattern,n) (args, body) = From 0bd875923f71d643ce8d13ed05b5c47d0b31f4e9 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Thu, 8 Aug 2013 16:20:16 -0700 Subject: [PATCH 28/81] Define List.and and List.or --- libraries/List.elm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/List.elm b/libraries/List.elm index 97d3052..0e448f6 100644 --- a/libraries/List.elm +++ b/libraries/List.elm @@ -91,11 +91,11 @@ any = Native.List.any -- Check to see if all elements are True. and : [Bool] -> Bool -and = Native.List.and +and = foldl (&&) True -- Check to see if any elements are True. or : [Bool] -> Bool -or = Native.List.or +or = foldl (||) False -- Concatenate a list of appendable things: -- From d55e9608f80b6cd128bf2f60d28dec8eda700ffa Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Thu, 8 Aug 2013 17:55:18 -0700 Subject: [PATCH 29/81] Make readme more compact --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index fbe6a47..aa40ee1 100644 --- a/README.md +++ b/README.md @@ -7,9 +7,8 @@ Learn about the Elm programming language at [elm-lang.org](http://elm-lang.org/) Use [the installer](https://dl.dropboxusercontent.com/u/5850974/Elm/Elm.pkg) and you are done. Let us know on [the list](https://groups.google.com/forum/?fromgroups#!forum/elm-discuss) -if you have any trouble. - -If you do have issues, use the [on any platform](#on-any-platform) instructions which are known to work reliably. +if you have any trouble. If you do have issues, use the [on any platform](#on-any-platform) +instructions which are known to work reliably. #### On any platform From 5b6773c3ec97a73a2fcd8f786bd5338f6a2a6c61 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Thu, 8 Aug 2013 18:05:21 -0700 Subject: [PATCH 30/81] Fix extra space in error message --- compiler/Transform/Check.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/Transform/Check.hs b/compiler/Transform/Check.hs index 9661811..962736a 100644 --- a/compiler/Transform/Check.hs +++ b/compiler/Transform/Check.hs @@ -39,8 +39,8 @@ duplicates defs = dups = map head . filter ((>1) . length) . List.group msg = "Syntax Error: There can only be one " - defMsg x = msg ++ " definition of '" ++ x ++ "'." - annMsg x = msg ++ " type annotation for '" ++ x ++ "'." + defMsg x = msg ++ "definition of '" ++ x ++ "'." + annMsg x = msg ++ "type annotation for '" ++ x ++ "'." badOrder :: [Def t v] -> [String] From 5e6481ccfd76ae3c6e7691b07302a2d9c189ef9c Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Fri, 9 Aug 2013 00:57:57 -0700 Subject: [PATCH 31/81] Bump to 0.9 --- Elm.cabal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Elm.cabal b/Elm.cabal index f111c12..a43f079 100644 --- a/Elm.cabal +++ b/Elm.cabal @@ -1,5 +1,5 @@ Name: Elm -Version: 0.8.0.3 +Version: 0.9 Synopsis: The Elm language module. Description: Elm aims to make client-side web-development more pleasant. It is a statically/strongly typed, functional reactive From 308c1af433830fe7dcf5ecb673439ee8fef96523 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Fri, 9 Aug 2013 17:44:18 -0700 Subject: [PATCH 32/81] Fix hotswapping on static scenes --- runtime/Init.js | 1 - 1 file changed, 1 deletion(-) diff --git a/runtime/Init.js b/runtime/Init.js index cf959f2..b4ba24c 100644 --- a/runtime/Init.js +++ b/runtime/Init.js @@ -115,7 +115,6 @@ function init(display, container, module, moduleToReplace) { // rerender scene if graphics are enabled. if (typeof graphicsNode !== 'undefined') { - graphicsNode.value = A2( Elm.Graphics.Element(elm).spacer, 0, 0 ); graphicsNode.recv(0, true, 0); } } From b23ff222a0ee204cb3ff8b66496b873f85235cd0 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Fri, 9 Aug 2013 17:44:30 -0700 Subject: [PATCH 33/81] Add some documentation --- libraries/Graphics/Input.elm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libraries/Graphics/Input.elm b/libraries/Graphics/Input.elm index fbc03c9..8ac65cb 100644 --- a/libraries/Graphics/Input.elm +++ b/libraries/Graphics/Input.elm @@ -75,10 +75,14 @@ checkbox b = let cbs = checkboxes b in (lift (cbs.checkbox id) cbs.events, cbs.events) +-- Detect when the mouse is hovering over some elements. This +-- allows you to create and destroy elements dynamically and still +-- detect hover information. hoverables : a -> { events : Signal a, hoverable : (Bool -> a) -> Element -> Element } hoverables = Native.Graphics.Input.hoverables +-- Detect when the mouse is hovering over a specifici `Element`. hoverable : Element -> (Element, Signal Bool) hoverable elem = let pool = hoverables False From e81e0c4424172176448ddd6220a930adfbee383a Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Fri, 9 Aug 2013 23:20:22 -0700 Subject: [PATCH 34/81] move the home of the data files out of dist/ (cabal complained) --- Elm.cabal | 2 +- Setup.hs | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Elm.cabal b/Elm.cabal index a43f079..057d930 100644 --- a/Elm.cabal +++ b/Elm.cabal @@ -21,7 +21,7 @@ Category: Compiler, Language Build-type: Custom Extra-source-files: changelog.txt -Data-dir: dist/data +Data-dir: data Data-files: elm-runtime.js interfaces.data Cabal-version: >=1.9 diff --git a/Setup.hs b/Setup.hs index d8c2bf8..9c600f8 100644 --- a/Setup.hs +++ b/Setup.hs @@ -33,10 +33,10 @@ import qualified Data.ByteString.Lazy as BS -- Elm.cabal expects the generated files to end up in dist/data -- git won't look in dist + cabal will clean it rtsDir :: LocalBuildInfo -> FilePath -rtsDir lbi = buildDir lbi ".." "data" +rtsDir lbi = "data" tempDir :: LocalBuildInfo -> FilePath -tempDir lbi = buildDir lbi ".." "temp" +tempDir lbi = "temp" -- The runtime is called: rts :: LocalBuildInfo -> FilePath @@ -96,18 +96,18 @@ myPostBuild as bfs pd lbi = do buildInterfaces lbi elmis putStrLn "Custom build step: build elm-runtime.js" buildRuntime lbi elmos - removeDirectoryRecursive ("dist" "temp") + removeDirectoryRecursive (tempDir lbi) postBuild simpleUserHooks as bfs pd lbi compileLibraries lbi = do - let temp = tempDir lbi -- dist/temp - rts = rtsDir lbi -- dist/data + let temp = tempDir lbi -- temp + rts = rtsDir lbi -- data createDirectoryIfMissing True temp createDirectoryIfMissing True rts - out_c <- canonicalizePath temp -- dist/temp (root folder) + out_c <- canonicalizePath temp -- temp (root folder) elm_c <- canonicalizePath (elm lbi) -- dist/build/elm/elm - rtd_c <- canonicalizePath rts -- dist/data (for docs.json) + rtd_c <- canonicalizePath rts -- data let make file = do -- replace 'system' call with 'runProcess' which handles args better From 3f6fc1686c7b97e96019679f1b11775630ac89d6 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Fri, 9 Aug 2013 23:21:42 -0700 Subject: [PATCH 35/81] Pull the Mac installer until it is updated to 0.9 --- README.md | 9 --------- 1 file changed, 9 deletions(-) diff --git a/README.md b/README.md index aa40ee1..4a1c0ad 100644 --- a/README.md +++ b/README.md @@ -3,15 +3,6 @@ Learn about the Elm programming language at [elm-lang.org](http://elm-lang.org/) ## Install -#### On Mac OSX - -Use [the installer](https://dl.dropboxusercontent.com/u/5850974/Elm/Elm.pkg) and you are done. -Let us know on [the list](https://groups.google.com/forum/?fromgroups#!forum/elm-discuss) -if you have any trouble. If you do have issues, use the [on any platform](#on-any-platform) -instructions which are known to work reliably. - -#### On any platform - Download the [Haskell Platform 2012.2.0.0](http://hackage.haskell.org/platform/). Elm definitely works with GHC 7.4, so newer versions of the Haskell Platform may work too. Once the Haskell Platform is installed: From c54dbf38afa2bfb0ec106818776e5605fa1333ed Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Fri, 9 Aug 2013 23:21:58 -0700 Subject: [PATCH 36/81] Get rid of dead code and bad exports --- compiler/Language/Elm.hs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/compiler/Language/Elm.hs b/compiler/Language/Elm.hs index 221cfa9..3799eb9 100644 --- a/compiler/Language/Elm.hs +++ b/compiler/Language/Elm.hs @@ -1,15 +1,11 @@ -{-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-} {- | This module exports the functions necessary for compiling Elm code into the respective HTML, CSS, and JS code. The documentation for the Elm language is available at , and many interactive examples are available at - - Example implementations using Yesod and Happstack are available - at -} -module Language.Elm (compile, toHtml, moduleName, runtime, docs) where +module Language.Elm (compile, moduleName, runtime) where import qualified Data.List as List import qualified Data.Map as Map From 77ff8ca3ab994c830f4cd11285fa5fcd6d3d8c36 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Fri, 9 Aug 2013 23:39:34 -0700 Subject: [PATCH 37/81] add the new data dir to ignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 779f803..a502b8e 100644 --- a/.gitignore +++ b/.gitignore @@ -7,5 +7,6 @@ cabal-dev *.aes *.elmi *.elmo +data */ElmFiles/* .DS_Store From 0f400da42f46622715d248d742faefd1aeac4dac Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Sat, 10 Aug 2013 00:51:29 -0700 Subject: [PATCH 38/81] Update elm-server to work with 0.9, compiles multiple files --- server/Server.hs | 37 +++++++++++++++++++++++-------------- server/elm-server.cabal | 8 +++++--- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/server/Server.hs b/server/Server.hs index 930c730..fed497b 100644 --- a/server/Server.hs +++ b/server/Server.hs @@ -7,17 +7,19 @@ import Data.List (isPrefixOf, isSuffixOf, (\\)) import Data.Version (showVersion) import Happstack.Server import Happstack.Server.Compression +import System.Directory import System.Environment import System.FilePath +import System.Process import qualified Language.Elm as Elm import Paths_elm_server -runtime = "/elm-" ++ showVersion version ++ ".js" +runtime = "/elm-runtime.js" serve :: Int -> String -> IO () serve portNumber libLoc = do - putStrLn ("Elm Server " ++ showVersion version ++ - ": running at ") + putStrLn $ "Elm Server " ++ showVersion version ++ + ": running at " putStrLn "Just refresh a page to recompile it!" simpleHTTP httpConf $ do _ <- compressedResponseFilter @@ -30,11 +32,16 @@ serve portNumber libLoc = do pageTitle :: String -> String pageTitle = dropExtension . takeBaseName +serveElm :: FilePath -> ServerPartT IO Response serveElm fp = do guard (takeExtension fp == ".elm") - content <- liftIO (readFile (tail fp)) - length content `seq` (ok . toResponse $ Elm.toHtml runtime (pageTitle fp) content) + let file = tail fp + liftIO $ rawSystem "elm" [ "--make" ,"--runtime=" ++ runtime + , "--cache-dir=elm-server-cache", file ] + liftIO $ removeDirectoryRecursive "elm-server-cache" + serveFile (asContentType "text/html") ("build" replaceExtension file "html") +serveLib :: FilePath -> [Char] -> ServerPartT IO Response serveLib libLoc fp = do guard (fp == runtime) serveFile (asContentType "application/javascript") libLoc @@ -45,16 +52,18 @@ main = getArgs >>= parse parse :: [String] -> IO () parse ("--help":_) = putStrLn usage parse ("--version":_) = putStrLn ("The Elm Server " ++ showVersion version) -parse args = if null remainingArgs - then serve portNumber =<< elmRuntime - else putStrLn usageMini - where runtimeArg = filter (isPrefixOf "--runtime-location=") args - portArg = filter (isPrefixOf "--port=") args - remainingArgs = (args \\ runtimeArg) \\ portArg +parse args = + case null remainingArgs of + True -> serve portNumber =<< elmRuntime + False -> putStrLn usageMini + where + runtimeArg = filter (isPrefixOf "--runtime-location=") args + portArg = filter (isPrefixOf "--port=") args + remainingArgs = (args \\ runtimeArg) \\ portArg - argValue arg = tail $ dropWhile (/= '=') (head arg) - portNumber = if null portArg then 8000 else read (argValue portArg) :: Int - elmRuntime = if null runtimeArg then Elm.runtime else return $ argValue runtimeArg + argValue arg = tail $ dropWhile (/= '=') (head arg) + portNumber = if null portArg then 8000 else read (argValue portArg) :: Int + elmRuntime = if null runtimeArg then Elm.runtime else return $ argValue runtimeArg usageMini :: String usageMini = diff --git a/server/elm-server.cabal b/server/elm-server.cabal index 7c49de3..18d59c3 100644 --- a/server/elm-server.cabal +++ b/server/elm-server.cabal @@ -1,5 +1,5 @@ Name: elm-server -Version: 0.8 +Version: 0.9 Synopsis: The Elm language server. Description: This package provides a standalone, Happstack-based Elm server. @@ -27,12 +27,14 @@ Executable elm-server Main-is: Server.hs Build-depends: base >=4.2 && <5, containers >= 0.3, + directory, transformers >= 0.2, mtl >= 2, parsec >= 3.1.1, blaze-html >= 0.5.1, HTTP >= 4000, - happstack-server == 7.1.1 || == 7.1.7 || == 7.0.2, + happstack-server, deepseq, filepath, - Elm >= 0.8 + Elm >= 0.9.0.1, + process From 9bba47c791441019b7354d9ed4804493bc3ec328 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Sat, 10 Aug 2013 14:18:59 -0700 Subject: [PATCH 39/81] compute a flexibility mark, just so it's easier to turn on and off later --- compiler/Type/Type.hs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/compiler/Type/Type.hs b/compiler/Type/Type.hs index 031962f..aaa53db 100644 --- a/compiler/Type/Type.hs +++ b/compiler/Type/Type.hs @@ -277,7 +277,11 @@ addNames value = do Is Number -> (Just $ "number" ++ replicate a '\'', (vars, a+1, b, c)) Is Comparable -> (Just $ "comparable" ++ replicate b '\'', (vars, a, b+1, c)) Is Appendable -> (Just $ "appendable" ++ replicate c '\'', (vars, a, b, c+1)) - _ -> (Just $ head vars, (tail vars, a, b, c)) + other -> (Just $ head vars, (tail vars, a, b, c)) + where mark = case other of + Flexible -> "" + Rigid -> "!" + Constant -> "#" type CrawlState = ([String], Int, Int, Int) From 3b27395e62783d815edad42d6d1961d95099c4a9 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Sat, 10 Aug 2013 14:20:36 -0700 Subject: [PATCH 40/81] Fix issue unifying comparables brought up by Max on the lists A flexible comparable should be able to unify with another comparable --- compiler/Type/Unify.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/Type/Unify.hs b/compiler/Type/Unify.hs index 5a0cc6a..d201ebb 100644 --- a/compiler/Type/Unify.hs +++ b/compiler/Type/Unify.hs @@ -85,7 +85,7 @@ actuallyUnify span variable1 variable2 = do "Int, Float, Char, or a list or tuple of comparables." unifyComparable var name - | name `elem` ["Int","Float","Char"] = flexAndUnify var + | name `elem` ["Int","Float","Char","comparable"] = flexAndUnify var | otherwise = comparableError "" unifyComparableStructure varSuper varFlex = From 1e0294eea4b08804445fc67c70d929599227cf5e Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Sat, 10 Aug 2013 14:21:34 -0700 Subject: [PATCH 41/81] Move to 0.9.0.2 --- Elm.cabal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Elm.cabal b/Elm.cabal index 057d930..aa69c36 100644 --- a/Elm.cabal +++ b/Elm.cabal @@ -1,5 +1,5 @@ Name: Elm -Version: 0.9 +Version: 0.9.0.2 Synopsis: The Elm language module. Description: Elm aims to make client-side web-development more pleasant. It is a statically/strongly typed, functional reactive From 47aa48d9fdd0b9b618f6975997c594287b86c26d Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Sat, 10 Aug 2013 14:26:01 -0700 Subject: [PATCH 42/81] Preemptively add "number" as a kind of flexible variable that can unify with an (Is Number) This is similar to the recent issue with comparable brought up by Max. --- compiler/Type/Unify.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/Type/Unify.hs b/compiler/Type/Unify.hs index d201ebb..048e16f 100644 --- a/compiler/Type/Unify.hs +++ b/compiler/Type/Unify.hs @@ -77,7 +77,7 @@ actuallyUnify span variable1 variable2 = do unify' variable1 variable2 unifyNumber svar name - | name `elem` ["Int","Float"] = flexAndUnify svar + | name `elem` ["Int","Float","number"] = flexAndUnify svar | otherwise = TS.addError span "Expecting a number (Int or Float)" variable1 variable2 comparableError str = TS.addError span (str ++ msg) variable1 variable2 From 9e58bdbc54704c136e46f827c0ce35ee2550175c Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Sat, 10 Aug 2013 15:48:18 -0700 Subject: [PATCH 43/81] Canonicalize patterns in lambda expressions --- compiler/Transform/Canonicalize.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/Transform/Canonicalize.hs b/compiler/Transform/Canonicalize.hs index 90f1a47..40ee65c 100644 --- a/compiler/Transform/Canonicalize.hs +++ b/compiler/Transform/Canonicalize.hs @@ -134,7 +134,7 @@ rename env lexpr@(L s expr) = Lambda pattern e -> let env' = extend env pattern in - Lambda pattern `liftM` rename env' e + Lambda `liftM` format (renamePattern env' pattern) `ap` rename env' e App e1 e2 -> App `liftM` rnm e1 `ap` rnm e2 From 552fe262c2df9639a995f7261cddb829a088e0bf Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Sat, 10 Aug 2013 20:01:48 -0700 Subject: [PATCH 44/81] Switch back to using `number` instead of `Float` whenever it is appropriate --- libraries/Graphics/Collage.elm | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/libraries/Graphics/Collage.elm b/libraries/Graphics/Collage.elm index b157f86..1813027 100644 --- a/libraries/Graphics/Collage.elm +++ b/libraries/Graphics/Collage.elm @@ -128,27 +128,27 @@ groupTransform matrix fs = form (FGroup matrix fs) -- Rotate a form by a given angle. Rotate takes standard Elm angles (radians) -- and turns things counterclockwise. So to turn `form` 30° to the left -- you would say, `(rotate (degrees 30) form)`. -rotate : Float -> Form -> Form +rotate : number -> Form -> Form rotate t f = { f | theta <- f.theta + t } -- Scale a form by a given factor. Scaling by 2 doubles the size. -scale : Float -> Form -> Form +scale : number -> Form -> Form scale s f = { f | scale <- f.scale * s } -- Move a form by the given amount. This is a relative translation so -- `(move (10,10) form)` would move `form` ten pixels up and ten pixels to the -- right. -move : (Float,Float) -> Form -> Form +move : (number,number) -> Form -> Form move (x,y) f = { f | x <- f.x + x, y <- f.y + y } -- Move a shape in the x direction. This is relative so `(moveX 10 form)` moves -- `form` 10 pixels to the right. -moveX : Float -> Form -> Form +moveX : number -> Form -> Form moveX x f = { f | x <- f.x + x } -- Move a shape in the y direction. This is relative so `(moveY 10 form)` moves -- `form` upwards by 10 pixels. -moveY : Float -> Form -> Form +moveY : number -> Form -> Form moveY y f = { f | y <- f.y + y } -- Set the alpha of a `Form`. The default is 1, and 0 is totally transparent. @@ -161,36 +161,36 @@ collage : Int -> Int -> [Form] -> Element collage = Native.Graphics.Collage.collage -type Path = [(Float,Float)] +type Path = [(number,number)] -- Create a path that follows a sequence of points. -path : [(Float,Float)] -> Path +path : [(number,number)] -> Path path ps = ps -- Create a path along a given line segment. -segment : (Float,Float) -> (Float,Float) -> Path +segment : (number,number) -> (number,number) -> Path segment p1 p2 = [p1,p2] -type Shape = [(Float,Float)] +type Shape = [(number,number)] -- Create an arbitrary polygon by specifying its corners in order. -- `polygon` will automatically close all shapes, so the given list -- of points does not need to start and end with the same position. -polygon : [(Float,Float)] -> Shape +polygon : [(number,number)] -> Shape polygon points = points -- A rectangle with a given width and height. -rect : Float -> Float -> Shape +rect : number -> number -> Shape rect w h = let hw = w/2 hh = h/2 in [ (0-hw,0-hh), (0-hw,hh), (hw,hh), (hw,0-hh) ] -- A square with a given edge length. -square : Float -> Shape +square : number -> Shape square n = rect n n -- An oval with a given width and height. -oval : Float -> Float -> Shape +oval : number -> number -> Shape oval w h = let n = 50 t = 2 * pi / n @@ -200,7 +200,7 @@ oval w h = in List.map f [0..n-1] -- A circle with a given radius. -circle : Float -> Shape +circle : number -> Shape circle r = oval (2*r) (2*r) -- A regular polygon with N sides. The first argument specifies the number @@ -208,7 +208,7 @@ circle r = oval (2*r) (2*r) -- 30 you would say: -- -- ngon 5 30 -ngon : Int -> Float -> Shape +ngon : Int -> number -> Shape ngon n r = let m = toFloat n t = 2 * pi / m From 5a06bba85dcac1e7992ce561cf95febea4c14e8b Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Sat, 10 Aug 2013 20:07:57 -0700 Subject: [PATCH 45/81] Add tiny clarification to `hsv` documentation --- libraries/Color.elm | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/Color.elm b/libraries/Color.elm index 9c796fd..082475d 100644 --- a/libraries/Color.elm +++ b/libraries/Color.elm @@ -67,6 +67,7 @@ hsva = Native.Color.hsva -- Create [HSV colors](http://en.wikipedia.org/wiki/HSL_and_HSV). -- This is very convenient for creating colors that cycle and shift. +-- Hue is an angle and should be given in standard Elm angles (radians). -- -- hsv (degrees 240) 1 1 == blue hsv : Float -> Float -> Float -> Color From 3d570aa01192ad93510816a17c31b3cdc5ef7026 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Sat, 10 Aug 2013 23:01:37 -0700 Subject: [PATCH 46/81] Show error messages in browser with elm-server --- server/Server.hs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/server/Server.hs b/server/Server.hs index fed497b..58e0503 100644 --- a/server/Server.hs +++ b/server/Server.hs @@ -9,8 +9,10 @@ import Happstack.Server import Happstack.Server.Compression import System.Directory import System.Environment +import System.Exit import System.FilePath import System.Process +import GHC.IO.Handle import qualified Language.Elm as Elm import Paths_elm_server @@ -36,10 +38,18 @@ serveElm :: FilePath -> ServerPartT IO Response serveElm fp = do guard (takeExtension fp == ".elm") let file = tail fp - liftIO $ rawSystem "elm" [ "--make" ,"--runtime=" ++ runtime - , "--cache-dir=elm-server-cache", file ] + args = [ "--make" ,"--runtime=" ++ runtime, "--cache-dir=elm-server-cache", file ] + (_, stdout, _, handle) <- liftIO $ createProcess $ (proc "elm" args) { std_out = CreatePipe } + exitCode <- liftIO $ waitForProcess handle liftIO $ removeDirectoryRecursive "elm-server-cache" - serveFile (asContentType "text/html") ("build" replaceExtension file "html") + case (exitCode, stdout) of + (ExitFailure _, Just out) -> + do str <- liftIO $ hGetContents out + badRequest $ toResponse str + (ExitFailure _, Nothing) -> + badRequest $ toResponse "See command line for error message." + (ExitSuccess, _) -> + serveFile (asContentType "text/html") ("build" replaceExtension file "html") serveLib :: FilePath -> [Char] -> ServerPartT IO Response serveLib libLoc fp = do From f5910c4dc943e0f125f993fb6e1a11a3235a2d0a Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Sat, 10 Aug 2013 23:43:36 -0700 Subject: [PATCH 47/81] add `elm-server` to changelog --- changelog.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/changelog.txt b/changelog.txt index 33be51f..a126de1 100644 --- a/changelog.txt +++ b/changelog.txt @@ -29,6 +29,10 @@ Syntax: * Allow infix op definitions without args: (*) = add * Unparenthesized if, let, case, lambda at end of binary expressions +elm-server: + * Build multi-module projects + * Report all errors in browser + Libraries: * Detect hovering over any Element * Set alpha of arbitrary forms in collages From 585107eaed4a73146cf33efd6b1c87eb6da5c41b Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Sun, 11 Aug 2013 12:45:59 -0700 Subject: [PATCH 48/81] Fix variable shadowing when pattern matching on a pattern with only one variable, when it appears in a let-expression --- compiler/Type/Constrain/Expression.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/Type/Constrain/Expression.hs b/compiler/Type/Constrain/Expression.hs index 3b948bd..c07d9be 100644 --- a/compiler/Type/Constrain/Expression.hs +++ b/compiler/Type/Constrain/Expression.hs @@ -195,7 +195,7 @@ expandPattern triple@(pattern, lexpr@(L s _), maybeType) = _ -> (PVar x, lexpr, maybeType) : map toDef vars where vars = Set.toList $ SD.boundVars pattern - x = concat vars + x = "$" ++ concat vars var = L s . Var toDef y = (PVar y, L s $ Case (var x) [(pattern, var y)], Nothing) From a736a28a431e54d38630ab4ff32e47859d7b1757 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Mon, 12 Aug 2013 01:09:26 -0700 Subject: [PATCH 49/81] Properly quantify variables in Data expressions. --- compiler/Type/Constrain/Expression.hs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/compiler/Type/Constrain/Expression.hs b/compiler/Type/Constrain/Expression.hs index c07d9be..606d362 100644 --- a/compiler/Type/Constrain/Expression.hs +++ b/compiler/Type/Constrain/Expression.hs @@ -86,13 +86,11 @@ constrain env (L span expr) tipe = and . (:) ce <$> mapM branch branches Data name exprs -> - do pairs <- mapM pair exprs + do vars <- forM exprs $ \_ -> var Flexible + let pairs = zip exprs (map VarN vars) (ctipe, cs) <- Monad.foldM step (tipe,true) (reverse pairs) - return (cs /\ name t, c /\ c') From 17628a0a26ba85cf717b68ce537b273987c6b656 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Mon, 12 Aug 2013 01:09:45 -0700 Subject: [PATCH 50/81] Fix type error in Automaton library --- libraries/Automaton.elm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/Automaton.elm b/libraries/Automaton.elm index 86b572d..8ce2af4 100644 --- a/libraries/Automaton.elm +++ b/libraries/Automaton.elm @@ -80,12 +80,12 @@ average : Int -> Automaton Float Float average k = let step n (ns,len,sum) = if len == k then stepFull n (ns,len,sum) - else ((enqueue n ns, len+1, sum+n), (sum+n) / (len+1)) + else ((enqueue n ns, len+1, sum+n), (sum+n) / (toFloat len+1)) stepFull n (ns,len,sum) = case dequeue ns of Nothing -> ((ns,len,sum), 0) Just (m,ns') -> let sum' = sum + n - m - in ((enqueue n ns', len, sum'), sum' / len) + in ((enqueue n ns', len, sum'), sum' / toFloat len) in hiddenState (empty,0,0) step From 1609e61cba4584dfcc4bc688ef0c12a47e479555 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Mon, 12 Aug 2013 14:27:42 -0700 Subject: [PATCH 51/81] Fix accidental creation of rigid variables when type-checking mixed record types when a type alias is given Fixes the issue raised by Alexander --- compiler/Type/Unify.hs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/Type/Unify.hs b/compiler/Type/Unify.hs index 048e16f..b5951ab 100644 --- a/compiler/Type/Unify.hs +++ b/compiler/Type/Unify.hs @@ -168,7 +168,7 @@ actuallyUnify span variable1 variable2 = do (Record1 fields1 ext1, Record1 fields2 ext2) -> do sequence . concat . Map.elems $ Map.intersectionWith (zipWith unify') fields1 fields2 - let mkRecord fs ext = liftIO . structuredVar $ Record1 fs ext + let mkRecord fs ext = fresh . Just $ Record1 fs ext case (Map.null fields1', Map.null fields2') of (True , True ) -> unify' ext1 ext2 (True , False) -> do @@ -178,8 +178,8 @@ actuallyUnify span variable1 variable2 = do record1' <- mkRecord fields1' ext1 unify' record1' ext2 (False, False) -> do - record1' <- mkRecord fields1' =<< liftIO (var Flexible) - record2' <- mkRecord fields2' =<< liftIO (var Flexible) + record1' <- mkRecord fields1' =<< fresh Nothing + record2' <- mkRecord fields2' =<< fresh Nothing unify' record1' ext2 unify' ext1 record2' where From a3f62bdd140d76eb1570f41047bc6c25f637d109 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Mon, 12 Aug 2013 14:29:38 -0700 Subject: [PATCH 52/81] style tweaks --- compiler/Type/Solve.hs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/compiler/Type/Solve.hs b/compiler/Type/Solve.hs index 10ab4fb..f75ff1c 100644 --- a/compiler/Type/Solve.hs +++ b/compiler/Type/Solve.hs @@ -49,16 +49,17 @@ generalize youngPool = do -- otherwise generalize let registerIfLowerRank var = do isRedundant <- liftIO $ UF.redundant var - if isRedundant then return () else do + case isRedundant of + True -> return () + False -> do desc <- liftIO $ UF.descriptor var - if rank desc < youngRank - then TS.register var >> return () - else let flex' = if flex desc == Flexible then Rigid else flex desc - in liftIO $ UF.setDescriptor var (desc { rank = noRank, flex = flex' }) - - mapM registerIfLowerRank (Map.findWithDefault [] youngRank rankDict) - - return () + case rank desc < youngRank of + True -> TS.register var >> return () + False -> do + let flex' = case flex desc of { Flexible -> Rigid ; other -> other } + liftIO $ UF.setDescriptor var (desc { rank = noRank, flex = flex' }) + + mapM_ registerIfLowerRank (Map.findWithDefault [] youngRank rankDict) -- adjust the ranks of variables such that ranks never increase as you From e4fc35c90176749dc323cba5c30b83eb2775d658 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Mon, 12 Aug 2013 14:30:32 -0700 Subject: [PATCH 53/81] Make impossible error more specific --- compiler/Type/State.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/Type/State.hs b/compiler/Type/State.hs index 0a2cca4..9568c3b 100644 --- a/compiler/Type/State.hs +++ b/compiler/Type/State.hs @@ -139,7 +139,8 @@ makeCopy alreadyCopied variable = do () | mark desc == alreadyCopied -> case copy desc of Just v -> return v - Nothing -> error "This should be impossible." + Nothing -> error $ "Error copying type variable. This should be impossible." ++ + " Please report an error to the github repo!" | rank desc /= noRank || flex desc == Constant -> return variable From b7eb1335b0a4ecc4f43acb523646f1975c722dc4 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Mon, 12 Aug 2013 14:32:51 -0700 Subject: [PATCH 54/81] Fix subtle bug with rigidVars vs rigidQuantifiers, was quantifing over the wrong variables in a forall --- compiler/Type/Constrain/Expression.hs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/Type/Constrain/Expression.hs b/compiler/Type/Constrain/Expression.hs index 606d362..e3229ec 100644 --- a/compiler/Type/Constrain/Expression.hs +++ b/compiler/Type/Constrain/Expression.hs @@ -151,9 +151,11 @@ constrainDef env info (pattern, expr, maybeTipe) = let qs = [] -- should come from the def, but I'm not sure what would live there... (schemes, rigidQuantifiers, flexibleQuantifiers, headers, c2, c1) = info in - case (pattern, maybeTipe) of - (PVar name, Just tipe) -> - do flexiVars <- mapM (\_ -> var Flexible) qs + do rigidVars <- mapM (\_ -> var Rigid) qs -- Some mistake may be happening here. + -- Currently, qs is always the empty list. + case (pattern, maybeTipe) of + (PVar name, Just tipe) -> do + flexiVars <- mapM (\_ -> var Flexible) qs let inserts = zipWith (\arg typ -> Map.insert arg (VarN typ)) qs flexiVars env' = env { Env.value = List.foldl' (\x f -> f x) (Env.value env) inserts } (vars, typ) <- Env.instantiateType env tipe Map.empty @@ -167,12 +169,10 @@ constrainDef env info (pattern, expr, maybeTipe) = , flexibleQuantifiers , headers , c2 - , fl rigidQuantifiers c /\ c1 ) + , fl rigidVars c /\ c1 ) - (PVar name, Nothing) -> - do v <- var Flexible - rigidVars <- mapM (\_ -> var Rigid) qs -- Some mistake may be happening here. - -- Currently, qs is always the empty list. + (PVar name, Nothing) -> do + v <- var Flexible let tipe = VarN v inserts = zipWith (\arg typ -> Map.insert arg (VarN typ)) qs rigidVars env' = env { Env.value = List.foldl' (\x f -> f x) (Env.value env) inserts } From c87fb860bb916681b590011b2f39f8926441de55 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Mon, 12 Aug 2013 23:16:12 -0700 Subject: [PATCH 55/81] Give minum require ment for elm-server --- server/elm-server.cabal | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/elm-server.cabal b/server/elm-server.cabal index 18d59c3..da567ad 100644 --- a/server/elm-server.cabal +++ b/server/elm-server.cabal @@ -1,5 +1,5 @@ Name: elm-server -Version: 0.9 +Version: 0.9.0.2 Synopsis: The Elm language server. Description: This package provides a standalone, Happstack-based Elm server. @@ -36,5 +36,5 @@ Executable elm-server happstack-server, deepseq, filepath, - Elm >= 0.9.0.1, + Elm >= 0.9.0.2, process From 3d368460558efeabe159e91575ed789d12f6a206 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Tue, 13 Aug 2013 16:16:56 -0700 Subject: [PATCH 56/81] switch to Tango color scheme for default colors Everything looks nicer already :P http://tango.freedesktop.org/Tango_Icon_Theme_Guidelines --- libraries/Color.elm | 57 +++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 31 deletions(-) diff --git a/libraries/Color.elm b/libraries/Color.elm index 082475d..5db81d5 100644 --- a/libraries/Color.elm +++ b/libraries/Color.elm @@ -14,23 +14,35 @@ rgba = Color rgb : Int -> Int -> Int -> Color rgb r g b = Color r g b 1 -red : Color -red = Color 255 0 0 1 -lime : Color -lime = Color 0 255 0 1 -blue : Color -blue = Color 0 0 255 1 +lightYellow = Color 255 233 79 1 +yellow = Color 237 212 0 1 +darkYellow = Color 196 160 0 1 -yellow : Color -yellow = Color 255 255 0 1 -cyan : Color -cyan = Color 0 255 255 1 -magenta : Color -magenta = Color 255 0 255 1 +lightOrange = Color 252 175 62 1 +orange = Color 245 121 0 1 +darkOrange = Color 206 92 0 1 + +lightBrown = Color 233 185 110 1 +brown = Color 193 125 17 1 +darkBrown = Color 143 89 2 1 + +lightGreen = Color 138 226 52 1 +green = Color 115 210 22 1 +darkGreen = Color 78 154 6 1 + +lightBlue = Color 114 159 207 1 +blue = Color 52 101 164 1 +darkBlue = Color 32 74 135 1 + +lightPurple = Color 173 127 168 1 +purple = Color 117 80 123 1 +darkPurple = Color 92 53 102 1 + +lightRed = Color 239 41 41 1 +red = Color 204 0 0 1 +darkRed = Color 164 0 0 1 -black : Color black = Color 0 0 0 1 -white : Color white = Color 255 255 255 1 gray : Color @@ -38,23 +50,6 @@ gray = Color 128 128 128 1 grey : Color grey = Color 128 128 128 1 -maroon : Color -maroon = Color 128 0 0 1 -navy : Color -navy = Color 0 0 128 1 -green : Color -green = Color 0 128 0 1 - -teal : Color -teal = Color 0 128 128 1 -purple : Color -purple = Color 128 0 128 1 - -violet : Color -violet = Color 238 130 238 1 -forestGreen : Color -forestGreen = Color 34 139 34 1 - -- Produce a “complementary color”. -- The two colors will accent each other. complement : Color -> Color From bc0c6a441073b3fac504cf9c192d9ec47c2c1685 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Tue, 13 Aug 2013 18:10:17 -0700 Subject: [PATCH 57/81] Fix #209, bad JS generation for primes in patterns --- compiler/Generate/Cases.hs | 9 ++++++--- compiler/Generate/JavaScript.hs | 5 +---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/Generate/Cases.hs b/compiler/Generate/Cases.hs index 548b55f..b668d21 100644 --- a/compiler/Generate/Cases.hs +++ b/compiler/Generate/Cases.hs @@ -1,4 +1,4 @@ -module Generate.Cases (caseToMatch, Match (..), Clause (..), matchSubst) where +module Generate.Cases (caseToMatch, Match (..), Clause (..), matchSubst, deprime) where import Control.Arrow (first) import Control.Monad (liftM,foldM) @@ -12,6 +12,9 @@ import SourceSyntax.Pattern import SourceSyntax.Expression import Transform.Substitute +deprime :: String -> String +deprime = map (\c -> if c == '\'' then '$' else c) + caseToMatch patterns = do v <- newVar (,) v `liftM` match [v] (map (first (:[])) patterns) Fail @@ -65,7 +68,7 @@ match vs@(v:_) cs def dealias v c@(p:ps, L s e) = case p of - PAlias x pattern -> (pattern:ps, L s $ subst x (Var v) e) + PAlias x pattern -> (pattern:ps, L s $ subst (deprime x) (Var v) e) _ -> c matchVar :: [String] -> [([Pattern],LExpr t v)] -> Match t v @@ -76,7 +79,7 @@ matchVar (v:vs) cs def = match vs (map subVar cs) def where subOnePattern pattern e = case pattern of - PVar x -> subst x (Var v) e + PVar x -> subst (deprime x) (Var v) e PAnything -> e PRecord fs -> foldr (\x -> subst x (Access (L s (Var v)) x)) e fs diff --git a/compiler/Generate/JavaScript.hs b/compiler/Generate/JavaScript.hs index d22bfa3..77df750 100644 --- a/compiler/Generate/JavaScript.hs +++ b/compiler/Generate/JavaScript.hs @@ -10,14 +10,11 @@ import Data.Either (partitionEithers) import qualified Text.Pandoc as Pan import Unique -import Generate.Cases +import Generate.Cases (caseToMatch, deprime, matchSubst, Match(..), Clause(..)) import SourceSyntax.Everything import SourceSyntax.Location import qualified Transform.SortDefinitions as SD -deprime :: String -> String -deprime = map (\c -> if c == '\'' then '$' else c) - indent = concatMap f where f '\n' = "\n " f c = [c] From fbad8eaab26dd5e0265e0611b17f00018a767175 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Tue, 13 Aug 2013 18:31:15 -0700 Subject: [PATCH 58/81] Update tests to cover the bugs that got reported leading up to 0.9 --- tests/good/AliasSubstitution.elm | 6 ++++++ tests/good/Apply.elm | 3 --- tests/good/Soundness.elm | 8 -------- tests/good/Soundness/Apply.elm | 3 +++ tests/good/Soundness/ApplyAnnotated.elm | 4 ++++ tests/good/{Soundness1.elm => Soundness/Id.elm} | 3 ++- .../IdAnnotated.elm} | 3 ++- tests/good/Soundness/TrickyId.elm | 2 ++ tests/good/Soundness/TrickyIdAnnotated.elm | 3 +++ tests/good/Soundness2.elm | 1 - tests/good/Soundness3.elm | 2 -- tests/good/SoundnessAnnotated2.elm | 2 -- tests/good/SoundnessAnnotated3.elm | 3 --- tests/good/Unify/LockedVars.elm | 6 ++++++ tests/good/Unify/NonHomogeneousRecords.elm | 8 ++++++++ 15 files changed, 36 insertions(+), 21 deletions(-) create mode 100644 tests/good/AliasSubstitution.elm delete mode 100644 tests/good/Apply.elm delete mode 100644 tests/good/Soundness.elm create mode 100644 tests/good/Soundness/Apply.elm create mode 100644 tests/good/Soundness/ApplyAnnotated.elm rename tests/good/{Soundness1.elm => Soundness/Id.elm} (72%) rename tests/good/{SoundnessAnnotated1.elm => Soundness/IdAnnotated.elm} (58%) create mode 100644 tests/good/Soundness/TrickyId.elm create mode 100644 tests/good/Soundness/TrickyIdAnnotated.elm delete mode 100644 tests/good/Soundness2.elm delete mode 100644 tests/good/Soundness3.elm delete mode 100644 tests/good/SoundnessAnnotated2.elm delete mode 100644 tests/good/SoundnessAnnotated3.elm create mode 100644 tests/good/Unify/LockedVars.elm create mode 100644 tests/good/Unify/NonHomogeneousRecords.elm diff --git a/tests/good/AliasSubstitution.elm b/tests/good/AliasSubstitution.elm new file mode 100644 index 0000000..336926e --- /dev/null +++ b/tests/good/AliasSubstitution.elm @@ -0,0 +1,6 @@ + +type Vec2Ext a = { a | x:Float, y:Float } +type Vec2 = Vec2Ext {} + +extractVec : Vec2Ext a -> Vec2 +extractVec v = { x = v.x, y = v.y } diff --git a/tests/good/Apply.elm b/tests/good/Apply.elm deleted file mode 100644 index 6fb2de2..0000000 --- a/tests/good/Apply.elm +++ /dev/null @@ -1,3 +0,0 @@ -let apply f x = f x - id x = x - in apply id (apply id (apply id (apply id (apply id (apply id 4))))) diff --git a/tests/good/Soundness.elm b/tests/good/Soundness.elm deleted file mode 100644 index 7d5fbd3..0000000 --- a/tests/good/Soundness.elm +++ /dev/null @@ -1,8 +0,0 @@ - -trickyID x = let y = x in y - -quad f = twice (twice f) -twice f x = f (f x) - -n = quad (quad trickyID) 4 -c = twice trickyID 'a' diff --git a/tests/good/Soundness/Apply.elm b/tests/good/Soundness/Apply.elm new file mode 100644 index 0000000..ae1ea4a --- /dev/null +++ b/tests/good/Soundness/Apply.elm @@ -0,0 +1,3 @@ + +apply f = let g x = f x + in g diff --git a/tests/good/Soundness/ApplyAnnotated.elm b/tests/good/Soundness/ApplyAnnotated.elm new file mode 100644 index 0000000..cc676e7 --- /dev/null +++ b/tests/good/Soundness/ApplyAnnotated.elm @@ -0,0 +1,4 @@ + +apply : (a -> b) -> a -> b +apply f = let g x = f x + in g diff --git a/tests/good/Soundness1.elm b/tests/good/Soundness/Id.elm similarity index 72% rename from tests/good/Soundness1.elm rename to tests/good/Soundness/Id.elm index 46b6e7a..1d324d8 100644 --- a/tests/good/Soundness1.elm +++ b/tests/good/Soundness/Id.elm @@ -1,2 +1,3 @@ -test = + +myId = let id x = x in id diff --git a/tests/good/SoundnessAnnotated1.elm b/tests/good/Soundness/IdAnnotated.elm similarity index 58% rename from tests/good/SoundnessAnnotated1.elm rename to tests/good/Soundness/IdAnnotated.elm index 4224583..9f92cbf 100644 --- a/tests/good/SoundnessAnnotated1.elm +++ b/tests/good/Soundness/IdAnnotated.elm @@ -1,3 +1,4 @@ -test = let id : a -> a + +myId = let id : a -> a id x = x in id diff --git a/tests/good/Soundness/TrickyId.elm b/tests/good/Soundness/TrickyId.elm new file mode 100644 index 0000000..5bfe1c0 --- /dev/null +++ b/tests/good/Soundness/TrickyId.elm @@ -0,0 +1,2 @@ + +myId x = let y = x in y \ No newline at end of file diff --git a/tests/good/Soundness/TrickyIdAnnotated.elm b/tests/good/Soundness/TrickyIdAnnotated.elm new file mode 100644 index 0000000..30db333 --- /dev/null +++ b/tests/good/Soundness/TrickyIdAnnotated.elm @@ -0,0 +1,3 @@ + +myId : a -> a +myId x = let y = x in y diff --git a/tests/good/Soundness2.elm b/tests/good/Soundness2.elm deleted file mode 100644 index 79e0a22..0000000 --- a/tests/good/Soundness2.elm +++ /dev/null @@ -1 +0,0 @@ -test x = let y = x in y \ No newline at end of file diff --git a/tests/good/Soundness3.elm b/tests/good/Soundness3.elm deleted file mode 100644 index 7d72d68..0000000 --- a/tests/good/Soundness3.elm +++ /dev/null @@ -1,2 +0,0 @@ -test f = let g x = f x - in g diff --git a/tests/good/SoundnessAnnotated2.elm b/tests/good/SoundnessAnnotated2.elm deleted file mode 100644 index ca4e721..0000000 --- a/tests/good/SoundnessAnnotated2.elm +++ /dev/null @@ -1,2 +0,0 @@ -test : a -> a -test x = let y = x in y diff --git a/tests/good/SoundnessAnnotated3.elm b/tests/good/SoundnessAnnotated3.elm deleted file mode 100644 index 24f52d7..0000000 --- a/tests/good/SoundnessAnnotated3.elm +++ /dev/null @@ -1,3 +0,0 @@ -test : (a -> b) -> a -> b -test f = let g x = f x - in g diff --git a/tests/good/Unify/LockedVars.elm b/tests/good/Unify/LockedVars.elm new file mode 100644 index 0000000..9fa2887 --- /dev/null +++ b/tests/good/Unify/LockedVars.elm @@ -0,0 +1,6 @@ +-- unify flexible and locked types +import Dict + +multiplyKey ((i,j), _) = (i*j) + +x = map multiplyKey (Dict.toList (Dict.singleton (1,2) 0)) diff --git a/tests/good/Unify/NonHomogeneousRecords.elm b/tests/good/Unify/NonHomogeneousRecords.elm new file mode 100644 index 0000000..c0029d4 --- /dev/null +++ b/tests/good/Unify/NonHomogeneousRecords.elm @@ -0,0 +1,8 @@ + +type Thing = { x:Float, y:Float } + +f : Thing -> Thing +f t = + let x = t.x + y = t.y + in t From 3f4936303d3db3f3a85fbe3fd5bb84c6b2e8d581 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Tue, 13 Aug 2013 18:36:07 -0700 Subject: [PATCH 59/81] Make a proper `Main` module --- tests/{Everything.hs => Main.hs} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename tests/{Everything.hs => Main.hs} (64%) diff --git a/tests/Everything.hs b/tests/Main.hs similarity index 64% rename from tests/Everything.hs rename to tests/Main.hs index d056cb0..5cd9e69 100644 --- a/tests/Everything.hs +++ b/tests/Main.hs @@ -1,4 +1,4 @@ -module Everything where +module Main where import System.Exit From a46432f30aa6a7d6b8aefaea5d575ee2d2955b11 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Tue, 13 Aug 2013 18:38:01 -0700 Subject: [PATCH 60/81] Make the `Main` module runable --- Elm.cabal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Elm.cabal b/Elm.cabal index aa69c36..47f71d2 100644 --- a/Elm.cabal +++ b/Elm.cabal @@ -167,5 +167,5 @@ Executable elm Test-Suite test-elm Type: exitcode-stdio-1.0 Hs-Source-Dirs: tests - Main-is: Everything.hs + Main-is: Main.hs build-depends: base \ No newline at end of file From 47d68d8bf2784235288b44d3a5d3883a5bb2a20e Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Tue, 13 Aug 2013 22:12:45 -0700 Subject: [PATCH 61/81] Succeed on programs that have no expressions --- compiler/Type/Constrain/Expression.hs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/compiler/Type/Constrain/Expression.hs b/compiler/Type/Constrain/Expression.hs index e3229ec..64b8f39 100644 --- a/compiler/Type/Constrain/Expression.hs +++ b/compiler/Type/Constrain/Expression.hs @@ -34,7 +34,8 @@ constrain env (L span expr) tipe = case expr of Literal lit -> Literal.constrain env span lit tipe - Var name -> return (name return (L span CSaveEnv) + | otherwise -> return (name exists $ \x -> do @@ -136,9 +137,7 @@ constrain env (L span expr) tipe = return ("Graphics.Element.markdown" - do c <- case body of - L _ (Var name) | name == saveEnvName -> return (L span CSaveEnv) - _ -> constrain env body tipe + do c <- constrain env body tipe (schemes, rqs, fqs, header, c2, c1) <- Monad.foldM (constrainDef env) ([], [], [], Map.empty, true, true) From cd84e066955e99799c563576ce7edc0069753c61 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Tue, 13 Aug 2013 22:20:00 -0700 Subject: [PATCH 62/81] Make pattern exhaustive, giving parse error when someone uses binops with different associativity --- compiler/Parse/Binop.hs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/compiler/Parse/Binop.hs b/compiler/Parse/Binop.hs index 93535c3..91a834d 100644 --- a/compiler/Parse/Binop.hs +++ b/compiler/Parse/Binop.hs @@ -93,12 +93,14 @@ getAssoc table n eops | all (==L) assocs = return L | all (==R) assocs = return R | all (==N) assocs = case assocs of [_] -> return N - _ -> fail msg + _ -> fail (msg "precedence") + | otherwise = fail (msg "associativity") where levelOps = filter (hasLevel table n) eops assocs = map (opAssoc table . fst) levelOps - msg = concat [ "Conflicting precedence for binary operators (" - , intercalate ", " (map fst eops), "). " - , "Consider adding parentheses to disambiguate." ] + msg problem = + concat [ "Conflicting " ++ problem ++ " for binary operators (" + , intercalate ", " (map fst eops), "). " + , "Consider adding parentheses to disambiguate." ] infixStmt :: IParser (Int, Assoc, String) infixStmt = From 470234ecddc97ad4f434e6ebd02ac6377e0b6e8a Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Tue, 13 Aug 2013 22:20:17 -0700 Subject: [PATCH 63/81] Add test case for programs with no expressions --- tests/good/NoExpressions.elm | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 tests/good/NoExpressions.elm diff --git a/tests/good/NoExpressions.elm b/tests/good/NoExpressions.elm new file mode 100644 index 0000000..a9c0070 --- /dev/null +++ b/tests/good/NoExpressions.elm @@ -0,0 +1,3 @@ + +type Width = Float +type Height = Float \ No newline at end of file From ab83c78d8d068a27b93434b267ff104b5d61d9de Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Tue, 13 Aug 2013 23:09:46 -0700 Subject: [PATCH 64/81] Remove dead code --- compiler/Parse/Pattern.hs | 68 --------------------------------------- 1 file changed, 68 deletions(-) diff --git a/compiler/Parse/Pattern.hs b/compiler/Parse/Pattern.hs index 41a142f..0c25287 100644 --- a/compiler/Parse/Pattern.hs +++ b/compiler/Parse/Pattern.hs @@ -64,71 +64,3 @@ expr :: IParser Pattern expr = do patterns <- consSep1 (patternConstructor <|> term) asPattern (foldr1 Pattern.cons patterns) "pattern" - -{-- -extract :: Pattern -> LExpr t v -> Unique (String, LExpr t v) -extract pattern body@(L t s _) = - let loc = L t s in - let fn x e = (x,e) in - case pattern of - PAnything -> return $ fn "_" body - PVar x -> return $ fn x body - PAlias x PAnything -> return $ fn x body - PAlias x p -> do - (x', body') <- extract p body - return $ fn x (loc $ Let [FnDef x' [] (loc $ Var x)] body') - PData name ps -> do - x <- guid - let a = '_' : show x - return . fn a . loc $ Case (loc (Var a)) [(pattern, body)] - PRecord fs -> do - x <- guid - let a = '_' : show x - toDef f = FnDef f [] (loc $ Access (loc $ Var a) f) - return . fn a . loc $ Let (map toDef fs) body - -extracts :: [Pattern] -> LExpr t v -> Unique ([String], LExpr t v) -extracts ps body = go [] (reverse ps) body - where go args [] body = return (args, body) - go args (p:ps) body = do (x,e) <- extract p body - go (x:args) ps e - -flatten :: [Pattern] -> LExpr t v -> Unique (IParser [Def t v]) -flatten patterns exp@(L t s _) = - let loc = L t s in - case patterns of - PVar f : args -> do - (as,e) <- extracts args exp - return . return $ - if isOp (head f) then let [a,b] = as in [ OpDef f a b e ] - else [ FnDef f as e ] - - [p] -> return `liftM` matchSingle p exp p - - _ -> return . fail $ "Pattern (" ++ unwords (map show patterns) ++ - ") cannot be used on the left-hand side of an assign statement." - -matchSingle :: Pattern -> LExpr t v -> Pattern -> Unique [Def t v] -matchSingle pat exp@(L t s _) p = - let loc = L t s in - case p of - PData _ ps -> do - x <- guid - let v = '_' : show x - dss <- mapM (matchSingle pat . loc $ Var v) ps - return (FnDef v [] exp : concat dss) - - PVar x -> - return [ FnDef x [] (loc $ Case exp [(pat, loc $ Var x)]) ] - - PAlias x p' -> do - subPat <- matchSingle p' (loc $ Var x) p' - return $ (FnDef x [] (loc $ Case exp [(pat, loc $ Var x)])):subPat - - PRecord fs -> do - a <- (\x -> '_' : show x) `liftM` guid - let toDef f = FnDef f [] (loc $ Access (loc $ Var a) f) - return (FnDef a [] exp : map toDef fs) - - PAnything -> return [] ---} \ No newline at end of file From 61b5d8fbfa0a4749fcc71d46514ab03073a67667 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Tue, 13 Aug 2013 23:11:23 -0700 Subject: [PATCH 65/81] Nicer messages on specific parse failures --- compiler/Parse/Binop.hs | 8 ++++---- compiler/Parse/Helpers.hs | 6 ++++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/compiler/Parse/Binop.hs b/compiler/Parse/Binop.hs index 91a834d..edb902d 100644 --- a/compiler/Parse/Binop.hs +++ b/compiler/Parse/Binop.hs @@ -80,21 +80,21 @@ splitLevel table n e eops = joinL :: [LExpr t v] -> [String] -> IParser (LExpr t v) joinL [e] [] = return e joinL (a:b:es) (op:ops) = joinL (merge a b (Binop op a b) : es) ops -joinL _ _ = fail "Ill-formed binary expression. Report a compiler bug." +joinL _ _ = failure "Ill-formed binary expression. Report a compiler bug." joinR :: [LExpr t v] -> [String] -> IParser (LExpr t v) joinR [e] [] = return e joinR (a:b:es) (op:ops) = do e <- joinR (b:es) ops return (merge a e (Binop op a e)) -joinR _ _ = fail "Ill-formed binary expression. Report a compiler bug." +joinR _ _ = failure "Ill-formed binary expression. Report a compiler bug." getAssoc :: OpTable -> Int -> [(String,LExpr t v)] -> IParser Assoc getAssoc table n eops | all (==L) assocs = return L | all (==R) assocs = return R | all (==N) assocs = case assocs of [_] -> return N - _ -> fail (msg "precedence") - | otherwise = fail (msg "associativity") + _ -> failure (msg "precedence") + | otherwise = failure (msg "associativity") where levelOps = filter (hasLevel table n) eops assocs = map (opAssoc table . fst) levelOps msg problem = diff --git a/compiler/Parse/Helpers.hs b/compiler/Parse/Helpers.hs index f2cf9ef..4e3c607 100644 --- a/compiler/Parse/Helpers.hs +++ b/compiler/Parse/Helpers.hs @@ -116,6 +116,12 @@ constrainedSpacePrefix p constraint = indented p +failure msg = do + inp <- getInput + setInput ('x':inp) + anyToken + fail msg + followedBy a b = do x <- a ; b ; return x betwixt a b c = do char a ; out <- c From d9918e0ac2172b4aeefb1bbc22bebe711fe049de Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Tue, 13 Aug 2013 23:41:44 -0700 Subject: [PATCH 66/81] Convince parser to commit to lists, records, and tuples --- compiler/Parse/Helpers.hs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/compiler/Parse/Helpers.hs b/compiler/Parse/Helpers.hs index 4e3c607..aea6889 100644 --- a/compiler/Parse/Helpers.hs +++ b/compiler/Parse/Helpers.hs @@ -110,11 +110,14 @@ spaceSep1 p = (:) <$> p <*> spacePrefix p spacePrefix p = constrainedSpacePrefix p (\_ -> return ()) constrainedSpacePrefix p constraint = - many . try $ do - n <- whitespace - constraint n - indented - p + many $ choice [ try (spacing >> lookAhead (oneOf "[({")) >> p + , try (spacing >> p) + ] + where + spacing = do + n <- whitespace + constraint n + indented failure msg = do inp <- getInput From 9ec51f558d943f1c8757d561bd108813ba0f86d3 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Wed, 14 Aug 2013 00:42:26 -0700 Subject: [PATCH 67/81] deprime on parsing, not on JS generation --- compiler/Generate/Cases.hs | 9 +++------ compiler/Generate/JavaScript.hs | 25 ++++++++++++------------- compiler/Parse/Helpers.hs | 5 ++++- 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/compiler/Generate/Cases.hs b/compiler/Generate/Cases.hs index b668d21..548b55f 100644 --- a/compiler/Generate/Cases.hs +++ b/compiler/Generate/Cases.hs @@ -1,4 +1,4 @@ -module Generate.Cases (caseToMatch, Match (..), Clause (..), matchSubst, deprime) where +module Generate.Cases (caseToMatch, Match (..), Clause (..), matchSubst) where import Control.Arrow (first) import Control.Monad (liftM,foldM) @@ -12,9 +12,6 @@ import SourceSyntax.Pattern import SourceSyntax.Expression import Transform.Substitute -deprime :: String -> String -deprime = map (\c -> if c == '\'' then '$' else c) - caseToMatch patterns = do v <- newVar (,) v `liftM` match [v] (map (first (:[])) patterns) Fail @@ -68,7 +65,7 @@ match vs@(v:_) cs def dealias v c@(p:ps, L s e) = case p of - PAlias x pattern -> (pattern:ps, L s $ subst (deprime x) (Var v) e) + PAlias x pattern -> (pattern:ps, L s $ subst x (Var v) e) _ -> c matchVar :: [String] -> [([Pattern],LExpr t v)] -> Match t v @@ -79,7 +76,7 @@ matchVar (v:vs) cs def = match vs (map subVar cs) def where subOnePattern pattern e = case pattern of - PVar x -> subst (deprime x) (Var v) e + PVar x -> subst x (Var v) e PAnything -> e PRecord fs -> foldr (\x -> subst x (Access (L s (Var v)) x)) e fs diff --git a/compiler/Generate/JavaScript.hs b/compiler/Generate/JavaScript.hs index 77df750..1ab12b8 100644 --- a/compiler/Generate/JavaScript.hs +++ b/compiler/Generate/JavaScript.hs @@ -10,7 +10,7 @@ import Data.Either (partitionEithers) import qualified Text.Pandoc as Pan import Unique -import Generate.Cases (caseToMatch, deprime, matchSubst, Match(..), Clause(..)) +import Generate.Cases import SourceSyntax.Everything import SourceSyntax.Location import qualified Transform.SortDefinitions as SD @@ -75,7 +75,7 @@ jsModule modul = jsExports = setup ("elm" : names modul) ++ ret (assign' ("elm." ++ modName) (brackets exs)) where - exs = indent . commaSep . concatMap (pair . deprime) $ "_op" : exports modul + exs = indent . commaSep . concatMap pair $ "_op" : exports modul pair x | isOp x = [] | otherwise = ["\n" ++ x ++ " : " ++ x] @@ -120,14 +120,13 @@ instance ToJS (Def t v) where -- TODO: Make this handle patterns besides plain variables toJS (Def (PVar x) e) | isOp x = globalAssign ("_op['" ++ x ++ "']") `liftM` toJS' e - | otherwise = assign (deprime x) `liftM` toJS' e + | otherwise = assign x `liftM` toJS' e toJS (Def pattern e@(L s _)) = do n <- guid let x = "_" ++ show n var = L s . Var - toDef y' = let y = deprime y' in - Def (PVar y) (L s $ Case (var x) [(pattern, var y)]) + toDef y = Def (PVar y) (L s $ Case (var x) [(pattern, var y)]) stmt <- assign x `liftM` toJS' e vars <- toJS . map toDef . Set.toList $ SD.boundVars pattern return (stmt ++ vars) @@ -145,18 +144,18 @@ toJS' (L span expr) = Case e cases -> caseToJS span e cases _ -> toJS expr -remove x e = "_N.remove('" ++ deprime x ++ "', " ++ e ++ ")" -addField x v e = "_N.insert('" ++ deprime x ++ "', " ++ v ++ ", " ++ e ++ ")" +remove x e = "_N.remove('" ++ x ++ "', " ++ e ++ ")" +addField x v e = "_N.insert('" ++ x ++ "', " ++ v ++ ", " ++ e ++ ")" setField fs e = "_N.replace(" ++ jsList (map f fs) ++ ", " ++ e ++ ")" - where f (x,v) = "['" ++ deprime x ++ "'," ++ v ++ "]" -access x e = e ++ "." ++ deprime x + where f (x,v) = "['" ++ x ++ "'," ++ v ++ "]" +access x e = e ++ "." ++ x makeRecord kvs = record `liftM` collect kvs where combine r (k,v) = Map.insertWith (++) k v r collect = liftM (List.foldl' combine Map.empty) . mapM prep prep (k, e) = do v <- toJS' e - return (deprime k, [v]) + return (k, [v]) fields fs = brackets ("\n "++List.intercalate ",\n " (map (\(k,v) -> k++":"++v) fs)) hidden = fields . map (second jsList) . @@ -177,7 +176,7 @@ instance ToJS Literal where instance ToJS (Expr t v) where toJS expr = case expr of - Var x -> return (deprime x) + Var x -> return x Literal lit -> toJS lit Range lo hi -> jsRange `liftM` toJS' lo `ap` toJS' hi Access e x -> access x `liftM` toJS' e @@ -200,7 +199,7 @@ instance ToJS (Expr t v) where depattern (pattern,n) (args, body) = case pattern of - PVar x -> (deprime x : args, body) + PVar x -> (x : args, body) _ -> let arg = "arg" ++ show n in (arg:args, L s (Case (L s (Var arg)) [(pattern, body)])) @@ -268,7 +267,7 @@ caseToJS span e ps = do (tempVar,match) <- caseToMatch ps e' <- toJS' e let (match',stmt) = case e of - L _ (Var x) -> (matchSubst [(tempVar,deprime x)] match, "") + L _ (Var x) -> (matchSubst [(tempVar,x)] match, "") _ -> (match, assign tempVar e') matches <- matchToJS span match' return $ jsFunc "" (stmt ++ matches) ++ "()" diff --git a/compiler/Parse/Helpers.hs b/compiler/Parse/Helpers.hs index aea6889..6273c41 100644 --- a/compiler/Parse/Helpers.hs +++ b/compiler/Parse/Helpers.hs @@ -49,10 +49,13 @@ rLabel = lowVar innerVarChar :: IParser Char innerVarChar = alphaNum <|> char '_' <|> char '\'' "" +deprime :: String -> String +deprime = map (\c -> if c == '\'' then '$' else c) + makeVar :: IParser Char -> IParser String makeVar p = do v <- (:) <$> p <*> many innerVarChar guard (v `notElem` reserveds) - return v + return (deprime v) reserved :: String -> IParser String reserved word = From 0e62924aaf00381629bcec0159d2bf78660ef196 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Wed, 14 Aug 2013 00:44:29 -0700 Subject: [PATCH 68/81] reprime when printing expressions and patterns --- compiler/SourceSyntax/Expression.hs | 12 ++++++------ compiler/SourceSyntax/Pattern.hs | 4 ++-- compiler/SourceSyntax/PrettyPrint.hs | 7 ++++++- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/compiler/SourceSyntax/Expression.hs b/compiler/SourceSyntax/Expression.hs index b655689..4c4a47f 100644 --- a/compiler/SourceSyntax/Expression.hs +++ b/compiler/SourceSyntax/Expression.hs @@ -75,24 +75,24 @@ instance Pretty (Expr t v) where Data "::" [hd,tl] -> pretty hd <+> P.text "::" <+> pretty tl Data "[]" [] -> P.text "[]" Data name es -> P.hang (P.text name) 2 (P.sep (map prettyParens es)) - Access e x -> prettyParens e <> P.text "." <> P.text x - Remove e x -> P.braces (pretty e <+> P.text "-" <+> P.text x) + Access e x -> prettyParens e <> P.text "." <> variable x + Remove e x -> P.braces (pretty e <+> P.text "-" <+> variable x) Insert (Location.L _ (Remove e y)) x v -> - P.braces (pretty e <+> P.text "-" <+> P.text y <+> P.text "|" <+> P.text x <+> P.text "=" <+> pretty v) + P.braces (pretty e <+> P.text "-" <+> variable y <+> P.text "|" <+> variable x <+> P.text "=" <+> pretty v) Insert e x v -> - P.braces (pretty e <+> P.text "|" <+> P.text x <+> P.text "=" <+> pretty v) + P.braces (pretty e <+> P.text "|" <+> variable x <+> P.text "=" <+> pretty v) Modify e fs -> P.braces $ P.hang (pretty e <+> P.text "|") 4 (commaSep $ map field fs) where - field (x,e) = P.text x <+> P.text "<-" <+> pretty e + field (x,e) = variable x <+> P.text "<-" <+> pretty e Record fs -> P.braces $ P.nest 2 (commaSep $ map field fs) where - field (x,e) = P.text x <+> P.text "=" <+> pretty e + field (x,e) = variable x <+> P.text "=" <+> pretty e Markdown _ -> P.text "[markdown| ... |]" diff --git a/compiler/SourceSyntax/Pattern.hs b/compiler/SourceSyntax/Pattern.hs index 8f47a94..b1f0455 100644 --- a/compiler/SourceSyntax/Pattern.hs +++ b/compiler/SourceSyntax/Pattern.hs @@ -27,8 +27,8 @@ instance Pretty Pattern where case pattern of PVar x -> variable x PLiteral lit -> pretty lit - PRecord fs -> PP.braces (commaCat $ map PP.text fs) - PAlias x p -> prettyParens p <+> PP.text "as" <+> PP.text x + PRecord fs -> PP.braces (commaCat $ map variable fs) + PAlias x p -> prettyParens p <+> PP.text "as" <+> variable x PAnything -> PP.text "_" PData "::" [hd,tl] -> parensIf isCons (pretty hd) <+> PP.text "::" <+> pretty tl where isCons = case hd of diff --git a/compiler/SourceSyntax/PrettyPrint.hs b/compiler/SourceSyntax/PrettyPrint.hs index 8b30536..24583fa 100644 --- a/compiler/SourceSyntax/PrettyPrint.hs +++ b/compiler/SourceSyntax/PrettyPrint.hs @@ -15,4 +15,9 @@ commaSep docs = sep (punctuate comma docs) parensIf bool doc = if bool then parens doc else doc -variable x = parensIf (Help.isOp x) (text x) \ No newline at end of file +variable x = + if Help.isOp x then parens (text x) + else text (reprime x) + +reprime :: String -> String +reprime = map (\c -> if c == '$' then '\'' else c) From 7c19935d863359fc62a6f59b8ee9dcee2177b4dc Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Wed, 14 Aug 2013 00:44:40 -0700 Subject: [PATCH 69/81] reprime when printing types --- compiler/Type/PrettyPrint.hs | 5 ++++- compiler/Type/Type.hs | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/Type/PrettyPrint.hs b/compiler/Type/PrettyPrint.hs index f45d410..435adbc 100644 --- a/compiler/Type/PrettyPrint.hs +++ b/compiler/Type/PrettyPrint.hs @@ -2,6 +2,7 @@ module Type.PrettyPrint where import Text.PrettyPrint +import qualified SourceSyntax.PrettyPrint as Src data ParensWhen = Fn | App | Never @@ -10,4 +11,6 @@ class PrettyType a where commaSep docs = sep (punctuate comma docs) -parensIf bool doc = if bool then parens doc else doc \ No newline at end of file +parensIf bool doc = if bool then parens doc else doc + +reprime = Src.reprime \ No newline at end of file diff --git a/compiler/Type/Type.hs b/compiler/Type/Type.hs index aaa53db..8aee76d 100644 --- a/compiler/Type/Type.hs +++ b/compiler/Type/Type.hs @@ -176,7 +176,7 @@ instance PrettyType a => PrettyType (Term1 a) where prettyExt = prty ext extend | P.render prettyExt == "{}" = P.empty | otherwise = prettyExt <+> P.text "|" - mkPretty f t = P.text f <+> P.text ":" <+> prty t + mkPretty f t = P.text (reprime f) <+> P.text ":" <+> prty t prettyFields = concatMap (\(f,ts) -> map (mkPretty f) ts) (Map.toList fields) @@ -191,7 +191,7 @@ instance PrettyType Descriptor where pretty when desc = case (structure desc, name desc) of (Just term, _) -> pretty when term - (_, Just name) -> if not (isTuple name) then P.text name else + (_, Just name) -> if not (isTuple name) then P.text (reprime name) else P.parens . P.text $ replicate (read (drop 6 name) - 1) ',' _ -> P.text "?" From efd42c386b3d69a2cda2a106ddd3b4f9abdbac73 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Wed, 14 Aug 2013 17:41:02 -0700 Subject: [PATCH 70/81] Bare minimum framework for testing --- Elm.cabal | 2 +- tests/Main.hs | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Elm.cabal b/Elm.cabal index 47f71d2..1cc3b60 100644 --- a/Elm.cabal +++ b/Elm.cabal @@ -168,4 +168,4 @@ Test-Suite test-elm Type: exitcode-stdio-1.0 Hs-Source-Dirs: tests Main-is: Main.hs - build-depends: base \ No newline at end of file + build-depends: base, HTF \ No newline at end of file diff --git a/tests/Main.hs b/tests/Main.hs index 5cd9e69..71670f4 100644 --- a/tests/Main.hs +++ b/tests/Main.hs @@ -1,7 +1,9 @@ module Main where -import System.Exit +import Test.Framework +import Test.Framework.BlackBoxTest -main = do - putStrLn "This test always fails" - exitFailure \ No newline at end of file +main :: IO () +main = htfMain tests + +tests = blackBoxTests "tests/good" "dist/build/elm/elm" ".elm" defaultBBTArgs \ No newline at end of file From b9abf862dd4d8568669550e4019e040d70bab1b8 Mon Sep 17 00:00:00 2001 From: John P Mayer Jr Date: Thu, 15 Aug 2013 05:24:44 +0000 Subject: [PATCH 71/81] fixed wierd keyboard stuff by factoring out keypress events --- libraries/Native/Signal/Keyboard.js | 91 ++++++++++++++++++++++------- 1 file changed, 70 insertions(+), 21 deletions(-) diff --git a/libraries/Native/Signal/Keyboard.js b/libraries/Native/Signal/Keyboard.js index 77880e1..d945895 100644 --- a/libraries/Native/Signal/Keyboard.js +++ b/libraries/Native/Signal/Keyboard.js @@ -4,29 +4,76 @@ Elm.Native.Keyboard = function(elm) { elm.Native = elm.Native || {}; if (elm.Native.Keyboard) return elm.Native.Keyboard; + // Duplicated from Native.Signal + function send(node, timestep, changed) { + var kids = node.kids; + for (var i = kids.length; i--; ) { + kids[i].recv(timestep, changed, node.id); + } + } + var Signal = Elm.Signal(elm); var NList = Elm.Native.List(elm); + var Utils = Elm.Native.Utils(elm); - var keysDown = Signal.constant(NList.Nil); - var lastKey = Signal.constant('\0'); + var downEvents = Signal.constant(0); + var upEvents = Signal.constant(0); + var blurEvents = Signal.constant(0); - elm.addListener([keysDown.id], document, 'keydown', function down(e) { - if (NList.member(e.keyCode)(keysDown.value)) return; - elm.notify(keysDown.id, NList.Cons(e.keyCode, keysDown.value)); - }); - elm.addListener([keysDown.id], document, 'keyup', function up(e) { - function notEq(kc) { return kc !== e.keyCode; } - elm.notify(keysDown.id, NList.filter(notEq)(keysDown.value)); - }); - elm.addListener([keysDown.id], document, 'blur', function blur(e) { - elm.notify(keysDown.id, NList.Nil); - }); - elm.addListener([lastKey.id], document, 'keypress', function press(e) { - elm.notify(lastKey.id, e.charCode || e.keyCode); - }); + elm.addListener([downEvents.id], document, 'keydown', function down(e) { + elm.notify(downEvents.id, e.keyCode); + }); + + elm.addListener([upEvents.id], document, 'keyup', function up(e) { + elm.notify(upEvents.id, e.keyCode); + }); + + elm.addListener([blurEvents.id], document, 'blur', function blur(e) { + elm.notify(blurEvents.id, NList.Nil); + }); + + function KeyMerge(down, up, blur) { + var args = [down,up,blur]; + this.id = Utils.guid(); + // Ignore starting values here + this.value = NList.Nil + this.kids = []; + + var n = args.length; + var count = 0; + var isChanged = false; + + this.recv = function(timestep, changed, parentID) { + ++count; + if (changed) { + isChanged = true; + // We know that a change must only be one of the following cases + if (parentID = down.id && !(NList.member(down.value)(this.value))) { + this.value = NList.Cons(down.value, this.value); + } else if (parentID = up.id) { + var notEq = function(kc) { return kc !== up.value }; + this.value = NList.filter(notEq)(this.value); + } else if (parentID = blur.id) { + this.value = NList.Nil; + } + } + if (count == n) { + console.log(this.value); + send(this, timestep, isChanged); + isChanged = false; + count = 0; + } + }; + + for (var i = n; i--; ) { args[i].kids.push(this); } + + } + + var keysDown = Signal.dropRepeats(new KeyMerge(downEvents,upEvents,blurEvents)); function keySignal(f) { - var signal = Signal.dropRepeats(A2(Signal.lift, f, keysDown)); + var signal = A2(Signal.lift, f, keysDown); + // what's the significance of these two following lines? -jpm keysDown.defaultNumberOfKids += 1; signal.defaultNumberOfKids = 0; return signal; @@ -51,11 +98,13 @@ Elm.Native.Keyboard = function(elm) { function is(key) { return keySignal(NList.member(key)); } + var lastPressed = Signal.dropRepeats(downEvents); + return elm.Native.Keyboard = { - isDown:is, - directions:F4(dir), - keysDown:keysDown, - lastPressed:lastKey + isDown:is, + directions:F4(dir), + keysDown:keysDown, + lastPressed:lastPressed }; }; From 6821a350f4caf58388c4da78aeb1697b47512f49 Mon Sep 17 00:00:00 2001 From: John P Mayer Jr Date: Thu, 15 Aug 2013 05:55:48 +0000 Subject: [PATCH 72/81] fixed obvious === bug --- libraries/Native/Signal/Keyboard.js | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/libraries/Native/Signal/Keyboard.js b/libraries/Native/Signal/Keyboard.js index d945895..14dc28c 100644 --- a/libraries/Native/Signal/Keyboard.js +++ b/libraries/Native/Signal/Keyboard.js @@ -46,19 +46,22 @@ Elm.Native.Keyboard = function(elm) { this.recv = function(timestep, changed, parentID) { ++count; if (changed) { - isChanged = true; - // We know that a change must only be one of the following cases - if (parentID = down.id && !(NList.member(down.value)(this.value))) { + // We know this a change must only be one of the following cases + if (parentID === down.id && !(NList.member(down.value)(this.value))) { + isChanged = true; this.value = NList.Cons(down.value, this.value); - } else if (parentID = up.id) { + } + if (parentID === up.id) { + isChanged = true; var notEq = function(kc) { return kc !== up.value }; this.value = NList.filter(notEq)(this.value); - } else if (parentID = blur.id) { + } + if (parentID === blur.id) { + isChanged = true; this.value = NList.Nil; } } if (count == n) { - console.log(this.value); send(this, timestep, isChanged); isChanged = false; count = 0; From b8a270e9d409be019b27408013197a031e12bf65 Mon Sep 17 00:00:00 2001 From: John P Mayer Jr Date: Thu, 15 Aug 2013 06:09:13 +0000 Subject: [PATCH 73/81] toCode needs to use uppercase, since keyboard separates key and modifier --- libraries/Native/Char.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/Native/Char.js b/libraries/Native/Char.js index 191a834..e2a8383 100644 --- a/libraries/Native/Char.js +++ b/libraries/Native/Char.js @@ -16,7 +16,7 @@ Elm.Native.Char = function(elm) { return elm.Native.Char = { fromCode : function(c) { return String.fromCharCode(c); }, - toCode : function(c) { return c.charCodeAt(0); }, + toCode : function(c) { return c.toUpperCase().charCodeAt(0); }, toUpper : function(c) { return c.toUpperCase(); }, toLower : function(c) { return c.toLowerCase(); }, toLocaleUpper : function(c) { return c.toLocaleUpperCase(); }, From 5fd85cd9c548a8b7c6c009eb23b8ac8ac5ca1eba Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Thu, 15 Aug 2013 23:29:29 -0700 Subject: [PATCH 74/81] Permit single line comments intermingled with types --- compiler/Parse/Type.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/Parse/Type.hs b/compiler/Parse/Type.hs index 0a76c3f..ab5f225 100644 --- a/compiler/Parse/Type.hs +++ b/compiler/Parse/Type.hs @@ -64,7 +64,7 @@ expr :: IParser T.Type expr = do t1 <- app <|> term whitespace - arr <- optionMaybe arrow + arr <- optionMaybe (try arrow) whitespace case arr of Just _ -> T.Lambda t1 <$> expr From 251c7d7c2de2ab2787a01594cd8b0d48d0db4c94 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Fri, 16 Aug 2013 00:00:39 -0700 Subject: [PATCH 75/81] Avoid extra updates (as recommended by Jeff) --- runtime/Render/Utils.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/Render/Utils.js b/runtime/Render/Utils.js index aa4a6cf..622dc5d 100644 --- a/runtime/Render/Utils.js +++ b/runtime/Render/Utils.js @@ -14,8 +14,8 @@ function addTo(container, elem) { } function extract(c) { - if (c._3 === 1) { return 'rgb(' + c._0 + ',' + c._1 + ',' + c._2 + ')'; } - return 'rgba(' + c._0 + ',' + c._1 + ',' + c._2 + ',' + c._3 + ')'; + if (c._3 === 1) { return 'rgb(' + c._0 + ', ' + c._1 + ', ' + c._2 + ')'; } + return 'rgba(' + c._0 + ', ' + c._1 + ', ' + c._2 + ', ' + c._3 + ')'; } function addTransform(style, trans) { From 560f679d8f71e2923a8a7fb7b2fcb86883cf926d Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Fri, 16 Aug 2013 00:07:32 -0700 Subject: [PATCH 76/81] Fix transparency issue in #210 --- runtime/Render/Element.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/Render/Element.js b/runtime/Render/Element.js index 77884ab..8222820 100644 --- a/runtime/Render/Element.js +++ b/runtime/Render/Element.js @@ -252,9 +252,9 @@ function updateProps(node, curr, next) { e.style.opacity = props.opacity; } var nextColor = (props.color.ctor === 'Just' ? - extract(props.color._0) : 'transparent'); + extract(props.color._0) : ''); if (e.style.backgroundColor !== nextColor) { - e.style.backgroundColor = nextColor; + e.style.backgroundColor = (nextColor === '' ? 'transparent' : nextColor); } if (props.tag !== currP.tag) { e.id = props.tag; } if (props.href !== currP.href) { From 5e02b74a35f7b8d8180c88b31a11111227297156 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Fri, 16 Aug 2013 03:09:53 -0700 Subject: [PATCH 77/81] Actually run tests!!! --- tests/Main.hs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/Main.hs b/tests/Main.hs index 71670f4..2658654 100644 --- a/tests/Main.hs +++ b/tests/Main.hs @@ -4,6 +4,12 @@ import Test.Framework import Test.Framework.BlackBoxTest main :: IO () -main = htfMain tests +main = do + tests <- blackBoxTests "tests/good" "dist/build/elm/elm" ".elm" args + htfMain tests -tests = blackBoxTests "tests/good" "dist/build/elm/elm" ".elm" defaultBBTArgs \ No newline at end of file +args = defaultBBTArgs { bbtArgs_stdoutDiff = ignoreDiff + , bbtArgs_stderrDiff = ignoreDiff } + +ignoreDiff :: Diff +ignoreDiff _ _ = return Nothing \ No newline at end of file From 2dc78fc9046c8286eef9deac4dcb2d392d958819 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Fri, 16 Aug 2013 03:26:51 -0700 Subject: [PATCH 78/81] Clean up after testing --- Elm.cabal | 2 +- tests/Main.hs | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/Elm.cabal b/Elm.cabal index 1cc3b60..1cf620d 100644 --- a/Elm.cabal +++ b/Elm.cabal @@ -168,4 +168,4 @@ Test-Suite test-elm Type: exitcode-stdio-1.0 Hs-Source-Dirs: tests Main-is: Main.hs - build-depends: base, HTF \ No newline at end of file + build-depends: base, directory, HTF \ No newline at end of file diff --git a/tests/Main.hs b/tests/Main.hs index 2658654..90578f0 100644 --- a/tests/Main.hs +++ b/tests/Main.hs @@ -1,15 +1,22 @@ module Main where -import Test.Framework +import System.Directory +import System.Exit (exitWith) +import System.Environment (getArgs) +import Test.Framework.TestManager import Test.Framework.BlackBoxTest main :: IO () main = do - tests <- blackBoxTests "tests/good" "dist/build/elm/elm" ".elm" args - htfMain tests + args <- getArgs + tests <- blackBoxTests "tests/good" "dist/build/elm/elm" ".elm" bbtArgs + code <- runTestWithArgs args tests + removeDirectoryRecursive "cache" + removeDirectoryRecursive "build" + exitWith code -args = defaultBBTArgs { bbtArgs_stdoutDiff = ignoreDiff - , bbtArgs_stderrDiff = ignoreDiff } +bbtArgs = defaultBBTArgs { bbtArgs_stdoutDiff = ignoreDiff + , bbtArgs_stderrDiff = ignoreDiff } ignoreDiff :: Diff ignoreDiff _ _ = return Nothing \ No newline at end of file From c2329d0affc0be3b7c6390ba7223058f4fcd2d62 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Fri, 16 Aug 2013 12:41:30 -0700 Subject: [PATCH 79/81] Fix generation of JS code for pattern matching on literals --- compiler/Generate/JavaScript.hs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/Generate/JavaScript.hs b/compiler/Generate/JavaScript.hs index 1ab12b8..e5a2b24 100644 --- a/compiler/Generate/JavaScript.hs +++ b/compiler/Generate/JavaScript.hs @@ -297,14 +297,14 @@ matchToJS span match = clauseToJS span var (Clause value vars e) = do let vars' = map (\n -> var ++ "._" ++ show n) [0..] s <- matchToJS span $ matchSubst (zip vars vars') e - return $ concat [ "\ncase ", case value of - Right (Boolean True) -> "true" - Right (Boolean False) -> "false" - Right lit -> show lit - Left name -> quoted $ case List.elemIndices '.' name of - [] -> name - is -> drop (last is + 1) name - , ":", indent s ] + pattern <- case value of + Right (Boolean True) -> return "true" + Right (Boolean False) -> return "false" + Right lit -> toJS lit + Left name -> return . quoted $ case List.elemIndices '.' name of + [] -> name + is -> drop (last is + 1) name + return $ concat [ "\ncase ", pattern, ":", indent s ] jsNil = "_L.Nil" jsCons e1 e2 = "_L.Cons(" ++ e1 ++ "," ++ e2 ++ ")" From c608e757a3240c37b70ebf3db7501e1ffed1a502 Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Fri, 16 Aug 2013 16:53:30 -0700 Subject: [PATCH 80/81] Remove scripts that are not used anymore --- tests/test | 7 ------- tests/testRepl | 5 ----- tests/tests/.ghci | 5 ----- 3 files changed, 17 deletions(-) delete mode 100755 tests/test delete mode 100755 tests/testRepl delete mode 100644 tests/tests/.ghci diff --git a/tests/test b/tests/test deleted file mode 100755 index 88a10ff..0000000 --- a/tests/test +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh -( - cd `dirname $0` && - cabal configure --enable-tests && - cabal build && - cabal test -) || exit 1 diff --git a/tests/testRepl b/tests/testRepl deleted file mode 100755 index 12889d6..0000000 --- a/tests/testRepl +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -here=`cd \`dirname $0\` && pwd` -cd "$here/tests" && -ghci diff --git a/tests/tests/.ghci b/tests/tests/.ghci deleted file mode 100644 index 77b779a..0000000 --- a/tests/tests/.ghci +++ /dev/null @@ -1,5 +0,0 @@ -:set -i../src -i. -:l Main Parse.Parser -:m + Test.QuickCheck Main -:set prompt "test>> " -:set -Wall From 26c51bb44a95702264994f2bc6dbd6c0ec0598ff Mon Sep 17 00:00:00 2001 From: Evan Czaplicki Date: Mon, 19 Aug 2013 11:21:08 -0700 Subject: [PATCH 81/81] Get rid of quickcheck stuff for now --- tests/tests/Main.hs | 54 ------------------------------------ tests/tests/Util/Arbs.hs | 45 ------------------------------ tests/tests/Util/CharGens.hs | 19 ------------- tests/tests/Util/String.hs | 13 --------- 4 files changed, 131 deletions(-) delete mode 100644 tests/tests/Main.hs delete mode 100644 tests/tests/Util/Arbs.hs delete mode 100644 tests/tests/Util/CharGens.hs delete mode 100644 tests/tests/Util/String.hs diff --git a/tests/tests/Main.hs b/tests/tests/Main.hs deleted file mode 100644 index 4b1bb68..0000000 --- a/tests/tests/Main.hs +++ /dev/null @@ -1,54 +0,0 @@ -{-# LANGUAGE GeneralizedNewtypeDeriving, TypeSynonymInstances, FlexibleInstances, QuasiQuotes, ExtendedDefaultRules #-} - - -module Main where - -import Test.Framework as TF (defaultMain, testGroup, Test) -import Test.Framework.Providers.QuickCheck2 (testProperty) - -import Text.InterpolatedString.Perl6 (qq) -import Parse.Parser -import Util.Arbs - -import Debug.Trace - -main :: IO () -main = defaultMain tests - -parses :: String -> Bool -parses code = either (const False) (const True) (parseProgram code) - -parseFails :: String -> Bool -parseFails = not . parses - -tests :: [TF.Test] -tests = [ - testGroup "String Assignments" [ - testProperty "prop_assignString" prop_assignString - , testProperty "prop_invalidIdent" prop_invalidIdent - , testProperty "prop_emptyList" prop_emptyList - , testProperty "prop_record" prop_record - ] - ] - -prop_assignString :: ValidIdent -> StringLiteral -> Bool -prop_assignString i s = parses [qq| -{i} = {s} -|] - -prop_invalidIdent :: ValidIdent -> InvalidIdentChar -> StringLiteral -> Bool -prop_invalidIdent i z s = parseFails [qq| -{i}{z} = {s} -|] - -prop_emptyList :: ValidIdent -> Bool -prop_emptyList i = parses [qq| -{i}=[] -|] - -prop_record :: ValidIdent -> ValidIdent -> ValidIdent -> ValidIdent -> StringLiteral -> Bool -prop_record a b c k v = parses [qq| -{a} = \{{k} = {v} \} -{b} = .{k} {a} -{c} = {a}.{k} -|] diff --git a/tests/tests/Util/Arbs.hs b/tests/tests/Util/Arbs.hs deleted file mode 100644 index c44d00d..0000000 --- a/tests/tests/Util/Arbs.hs +++ /dev/null @@ -1,45 +0,0 @@ -module Util.Arbs where - -import Control.Applicative -import Test.QuickCheck -import Util.CharGens -import Util.String - -import Text.InterpolatedString.Perl6 (ShowQ(showQ)) - - -newtype ValidIdent = ValidIdent String deriving (Eq, Show) - -instance ShowQ ValidIdent where - showQ (ValidIdent v) = v - -instance Arbitrary ValidIdent where - arbitrary = ValidIdent <$> ((:) <$> lowerAlpha <*> (listOf alphaNumUnderPrime)) - - -newtype StringLiteral = StringLiteral String deriving (Eq, Show) - -instance ShowQ StringLiteral where - showQ (StringLiteral v) = v - -instance Arbitrary StringLiteral where - arbitrary = StringLiteral <$> (\x -> "\"" ++ x ++ "\"") <$> escape <$> arbitrary - - -newtype InvalidIdentChar = InvalidIdentChar Char deriving (Eq, Show) - -instance ShowQ InvalidIdentChar where - showQ (InvalidIdentChar c) = [c] - -instance Arbitrary InvalidIdentChar where - arbitrary = InvalidIdentChar <$> elements "!@#$%^&*()-=+\\|/?.>,<`~" - - -newtype BuiltinType = BuiltinType String deriving (Eq, Show) - -instance ShowQ BuiltinType where - showQ (BuiltinType v) = v - -instance Arbitrary BuiltinType where - -- TODO: add others - arbitrary = BuiltinType <$> elements ["Char", "String"] diff --git a/tests/tests/Util/CharGens.hs b/tests/tests/Util/CharGens.hs deleted file mode 100644 index f41ca51..0000000 --- a/tests/tests/Util/CharGens.hs +++ /dev/null @@ -1,19 +0,0 @@ -module Util.CharGens where - -import Test.QuickCheck -import Test.QuickCheck.Property - -lowerAlpha :: Gen Char -lowerAlpha = elements ['a'..'z'] - -upperAlpha :: Gen Char -upperAlpha = elements ['A'..'Z'] - -alpha :: Gen Char -alpha = oneof [lowerAlpha, upperAlpha] - -alphaNum :: Gen Char -alphaNum = oneof [alpha, elements ['0'..'9']] - -alphaNumUnderPrime :: Gen Char -alphaNumUnderPrime = oneof [alphaNum, elements ['_', '\'']] diff --git a/tests/tests/Util/String.hs b/tests/tests/Util/String.hs deleted file mode 100644 index e17740b..0000000 --- a/tests/tests/Util/String.hs +++ /dev/null @@ -1,13 +0,0 @@ -module Util.String where - -import qualified Data.Text as T - -replace :: String -> String -> String -> String -replace a b c = T.unpack (T.replace (T.pack a) (T.pack b) (T.pack c)) - -escape :: String -> String -escape = - (replace "\n" "\\n") . - (replace "\t" "\\t") . - (replace "\"" "\\\"") . - (replace "\\" "\\\\")