on master help sign in
Merge branch 'dev'
commite0b0cc0ab5804f8184f8dff100215a5bf74ce405 authorEvan Czaplicki <info@elm-lang.org> dateThu 17 Oct 2013, 23:55 (13 years ago) parent0db34a583406ff
101 files changed+4421−3047
Elm.cabal+44−8 LICENSE+1−1 Setup.hs+37−23 changelog.txt+3 compiler/Compiler.hs+40−39 compiler/Docs.hs+146−59 compiler/Generate/Cases.hs+20−23 compiler/Generate/Html.hs+4−22 compiler/Generate/JavaScript.hs+380−330 compiler/Generate/Noscript.hs+1−1 compiler/Initialize.hs+30−11 compiler/Language/Elm.hs+3−11 compiler/Parse/Binop.hs+7−36 compiler/Parse/Declaration.hs+7−21 compiler/Parse/Expression.hs+45−44 compiler/Parse/Helpers.hs+102−19 compiler/Parse/Literal.hs+4−1 compiler/Parse/Module.hs+1−1 compiler/Parse/Parse.hs+27−4 compiler/Parse/Pattern.hs+1−6 compiler/Parse/Type.hs+3−12 compiler/SourceSyntax/Declaration.hs+8−1 compiler/SourceSyntax/Expression.hs+4−2 compiler/SourceSyntax/Literal.hs+2−2 compiler/SourceSyntax/Module.hs+17−5 compiler/Transform/Canonicalize.hs+17−7 compiler/Transform/LetBoundVars.hs−54 compiler/Transform/Replace.hs−60 compiler/Transform/SortDefinitions.hs+1−1 compiler/Transform/Substitute.hs+19−6 compiler/Type/Alias.hs+20−4 compiler/Type/Constrain/Expression.hs+22−18 compiler/Type/Constrain/Literal.hs+5−5 compiler/Type/Constrain/Pattern.hs+16−3 compiler/Type/Environment.hs+13−8 compiler/Type/Inference.hs+24−18 compiler/Type/Type.hs+3−2 compiler/Type/Unify.hs+6−4 compiler/Unique.hs−19 libraries/Automaton.elm+49−27 libraries/AutomatonV2.elm+149 libraries/Basics.elm+165−85 libraries/Char.elm+23−11 libraries/Color.elm+121−47 libraries/Date.elm+32−25 libraries/Dict.elm+198−253 libraries/Either.elm+42−14 libraries/Graphics/Collage.elm+103−58 libraries/Graphics/Element.elm+95−51 libraries/Graphics/Input.elm+115−76 libraries/Http.elm+28−17 libraries/JavaScript.elm+22−8 libraries/JavaScript/Experimental.elm+31−22 libraries/Json.elm+51−39 libraries/Keyboard.elm+42−22 libraries/List.elm+105−66 libraries/Maybe.elm+28−10 libraries/Mouse.elm+19−9 libraries/Native/Basics.js+8−47 libraries/Native/Char.js+26−28 libraries/Native/Color.js+56−58 libraries/Native/Date.js+7−8 libraries/Native/Error.js+6−6 libraries/Native/Graphics/Collage.js+6−6 libraries/Native/Graphics/Input.js+9−9 libraries/Native/JavaScript.js+13−18 libraries/Native/Json.js+11−8 libraries/Native/List.js+272−315 libraries/Native/Prelude.js+10−9 libraries/Native/Show.js+35−40 libraries/Native/Signal/Http.js+9−8 libraries/Native/Signal/Keyboard.js+14−10 libraries/Native/Signal/Mouse.js+50−65 libraries/Native/Signal/Random.js+32−16 libraries/Native/Signal/Signal.js+8−7 libraries/Native/Signal/Time.js+10−7 libraries/Native/Signal/Touch.js+135−132 libraries/Native/Signal/WebSocket.js+8−8 libraries/Native/Signal/Window.js+7−7 libraries/Native/String.js+232 libraries/Native/Text.js+122−122 libraries/Native/Transform2D.js+5−5 libraries/Native/Utils.js+172−149 libraries/Prelude.elm+1 libraries/Random.elm+21−7 libraries/Set.elm+38−14 libraries/Signal.elm+84−59 libraries/String.elm+274 libraries/Text.elm+50−24 libraries/Time.elm+46−28 libraries/Touch.elm+22−12 libraries/Transform2D.elm+40−27 libraries/WebSocket.elm+11−5 libraries/Window.elm+13−4 runtime/Init.js+6−9 runtime/Render/Collage.js+9−5 runtime/Render/Element.js+8−16 runtime/Render/Utils.js+2−3 server/LICENSE+1−1 server/Server.hs+30−13 server/elm-server.cabal+1−1
Elm.cabal+44−8
@@ -14,7 +14,7 @@ License-file: LICENSE
1414
1515Author: Evan Czaplicki
1616Maintainer: info@elm-lang.org
17−Copyright: Copyright: (c) 2011-2012 Evan Czaplicki
17+Copyright: Copyright: (c) 2011-2013 Evan Czaplicki
1818
1919Category: Compiler, Language
2020
@@ -22,7 +22,7 @@ Build-type: Custom
2222
2323Extra-source-files: changelog.txt
2424Data-dir: data
25−Data-files: elm-runtime.js interfaces.data
25+Data-files: elm-runtime.js interfaces.data docs.json
2626Cabal-version: >=1.9
2727
2828source-repository head
@@ -32,8 +32,7 @@ source-repository head
3232Library
3333 exposed-modules: Language.Elm
3434 Hs-Source-Dirs: compiler
35− other-modules: Unique,
36− SourceSyntax.Declaration,
35+ other-modules: SourceSyntax.Declaration,
3736 SourceSyntax.Expression,
3837 SourceSyntax.Everything,
3938 SourceSyntax.Helpers,
@@ -88,8 +87,8 @@ Library
8887 containers >= 0.3,
8988 directory,
9089 filepath,
91− hjsmin,
9290 indents,
91+ language-ecmascript,
9392 mtl >= 2,
9493 pandoc >= 1.10,
9594 parsec >= 3.1.1,
@@ -102,8 +101,7 @@ Executable elm
102101 Main-is: Compiler.hs
103102 ghc-options: -threaded -O2
104103 Hs-Source-Dirs: compiler
105− other-modules: Unique,
106− SourceSyntax.Declaration,
104+ other-modules: SourceSyntax.Declaration,
107105 SourceSyntax.Expression,
108106 SourceSyntax.Everything,
109107 SourceSyntax.Helpers,
@@ -158,8 +156,8 @@ Executable elm
158156 containers >= 0.3,
159157 directory,
160158 filepath,
161− hjsmin,
162159 indents,
160+ language-ecmascript,
163161 mtl >= 2,
164162 pandoc >= 1.10,
165163 parsec >= 3.1.1,
@@ -168,6 +166,44 @@ Executable elm
168166 union-find,
169167 uniplate
170168
169+Executable elm-doc
170+ Main-is: Docs.hs
171+ Hs-Source-Dirs: compiler
172+ other-modules: SourceSyntax.Declaration,
173+ SourceSyntax.Everything,
174+ SourceSyntax.Expression,
175+ SourceSyntax.Helpers,
176+ SourceSyntax.Literal,
177+ SourceSyntax.Location,
178+ SourceSyntax.Module,
179+ SourceSyntax.Pattern,
180+ SourceSyntax.PrettyPrint,
181+ SourceSyntax.Type,
182+ Parse.Binop,
183+ Parse.Declaration,
184+ Parse.Expression,
185+ Parse.Helpers,
186+ Parse.Literal,
187+ Parse.Module,
188+ Parse.Pattern,
189+ Parse.Type
190+
191+ Build-depends: aeson,
192+ aeson-pretty,
193+ base >=4.2 && <5,
194+ binary,
195+ bytestring,
196+ cmdargs,
197+ containers >= 0.3,
198+ directory,
199+ filepath,
200+ indents,
201+ mtl >= 2,
202+ pandoc >= 1.10,
203+ parsec >= 3.1.1,
204+ pretty,
205+ text
206+
171207Test-Suite test-elm
172208 Type: exitcode-stdio-1.0
173209 Hs-Source-Dirs: tests
LICENSE+1−1
@@ -1,4 +1,4 @@
1−Copyright (c)2012, Evan Czaplicki
1+Copyright (c) 2012-2013, Evan Czaplicki
22
33All rights reserved.
44
Setup.hs+37−23
@@ -12,6 +12,7 @@ import System.Process
1212import Control.Monad
1313import qualified Data.Binary as Binary
1414import qualified Data.ByteString.Lazy as BS
15+import qualified Data.List as List
1516
1617-- Part 1
1718-- ------
@@ -42,13 +43,20 @@ tempDir lbi = "temp"
4243rts :: LocalBuildInfo -> FilePath
4344rts lbi = rtsDir lbi </> "elm-runtime.js"
4445
46+-- The runtime is called:
47+docs :: LocalBuildInfo -> FilePath
48+docs lbi = rtsDir lbi </> "docs.json"
49+
4550-- The interfaces for the Standard Libraries live in:
4651interfaces :: LocalBuildInfo -> FilePath
4752interfaces lbi = rtsDir lbi </> "interfaces.data"
4853
49−-- buildDir with LocalBuildInfo points to "dist/build" (usually)
54+elm :: LocalBuildInfo -> FilePath
5055elm lbi = buildDir lbi </> "elm" </> "elm"
5156
57+document :: LocalBuildInfo -> FilePath
58+document lbi = buildDir lbi </> "elm-doc" </> "elm-doc"
59+
5260-- Care! This appears to be based on an unstable API
5361-- See: http://www.haskell.org/cabal/release/cabal-latest/doc/API/Cabal/Distribution-Simple.html#2
5462
@@ -75,16 +83,6 @@ filterExe name pd = pd {
7583 executables = filter (\x -> (exeName x == name)) (executables pd)
7684 }
7785
78−-- It's not enough to fix the PackageDescription, we also have to fix the
79−-- LocalBuildInfo. This includes the component build order (data ComponentName)
80−-- which is horribly internal.
81−filterLBI :: String -> LocalBuildInfo -> LocalBuildInfo
82−filterLBI name lbi = lbi {
83− libraryConfig = Nothing,
84− compBuildOrder = [CExeName name],
85− executableConfigs = filter (\a -> (fst a == name)) (executableConfigs lbi)
86− }
87−
8886
8987-- Post Build
9088
@@ -96,7 +94,10 @@ myPostBuild as bfs pd lbi = do
9694 buildInterfaces lbi elmis
9795 putStrLn "Custom build step: build elm-runtime.js"
9896 buildRuntime lbi elmos
97+ putStrLn "Custom build step: build docs.json"
98+ buildDocs lbi
9999 removeDirectoryRecursive (tempDir lbi)
100+ removeDirectoryRecursive ("libraries" </> "docs")
100101 postBuild simpleUserHooks as bfs pd lbi
101102
102103
@@ -107,6 +108,7 @@ compileLibraries lbi = do
107108 createDirectoryIfMissing True rts
108109 out_c <- canonicalizePath temp -- temp (root folder)
109110 elm_c <- canonicalizePath (elm lbi) -- dist/build/elm/elm
111+ doc_c <- canonicalizePath (document lbi) -- dist/build/elm-doc/elm-doc
110112 rtd_c <- canonicalizePath rts -- data
111113
112114 let make file = do
@@ -122,9 +124,9 @@ compileLibraries lbi = do
122124 , out_c </> replaceExtension file "elmi")
123125
124126 setCurrentDirectory "libraries"
125− print =<< getCurrentDirectory
126− files <- getFiles ".elm" "."
127− files <- unzip `fmap` mapM make files
127+ paths <- getFiles ".elm" "."
128+ files <- unzip `fmap` mapM make paths
129+ mapM_ (\path -> rawSystem doc_c [path]) paths
128130 setCurrentDirectory ".."
129131 return files
130132
@@ -145,11 +147,23 @@ buildInterfaces lbi elmis = do
145147buildRuntime :: LocalBuildInfo -> [FilePath] -> IO ()
146148buildRuntime lbi elmos = do
147149 createDirectoryIfMissing True (rtsDir lbi)
148− writeFile (rts lbi) "Elm = {}; Elm.Native = {}; Elm.Native.Graphics = {};\n\
149− \Elm.Graphics = {}; ElmRuntime = {}; ElmRuntime.Render = {};\n"
150− mapM_ (appendJS lbi) =<< getFiles ".js" "libraries"
151− mapM_ (appendJS lbi) elmos
152− mapM_ (appendJS lbi) =<< getFiles ".js" "runtime"
150+ let rts' = rts lbi
151+ writeFile rts' "var Elm = {}; Elm.Native = {}; Elm.Native.Graphics = {};\n\
152+ \var ElmRuntime = {}; ElmRuntime.Render = {};\n"
153+ mapM_ (appendTo rts') =<< getFiles ".js" "libraries"
154+ mapM_ (appendTo rts') elmos
155+ mapM_ (appendTo rts') =<< getFiles ".js" "runtime"
156+
157+buildDocs :: LocalBuildInfo -> IO ()
158+buildDocs lbi = do
159+ createDirectoryIfMissing True (rtsDir lbi)
160+ let docs' = docs lbi
161+ writeFile docs' "[\n"
162+ json <- getFiles ".json" ("libraries" </> "docs")
163+ let appends = map (appendTo docs') json
164+ addCommas = List.intersperse (appendFile docs' ",\n")
165+ sequence_ (addCommas appends)
166+ appendFile docs' "\n]"
153167
154168getFiles ext dir = do
155169 contents <- map (dir </>) `fmap` getDirectoryContents dir
@@ -158,8 +172,8 @@ getFiles ext dir = do
158172 filess <- mapM (getFiles ext) dirs
159173 return (files ++ concat filess)
160174
161−appendJS lbi file = do
162− putStrLn (dropExtension file)
163− str <- readFile file
175+appendTo :: FilePath -> FilePath -> IO ()
176+appendTo destination source = do
177+ str <- readFile source
164178 length str `seq` return ()
165− appendFile (rts lbi) str
179+ appendFile destination str
changelog.txt+3
@@ -2,8 +2,11 @@
22Release 0.9.1
33=============
44
5+ * Allow custom precedence and associativity for user-defined infix ops
6+ * Realias types before printing
57 * Switch to Tango color scheme, adding a bunch of nice colors
68 * add the greyscale function for easily producing greys
9+ * Check the type of main
710 * Fix miscellaneous bugs in type checker
811 * Switch name of Matrix2D to Transform2D
912
compiler/Compiler.hs+40−39
@@ -13,9 +13,7 @@ import System.FilePath
1313import System.IO
1414import GHC.Conc
1515
16−import qualified Text.Blaze.Html.Renderer.Pretty as Pretty
17−import qualified Text.Blaze.Html.Renderer.String as Normal
18−import qualified Text.Jasmine as JS
16+import Text.Blaze.Html.Renderer.Pretty (renderHtml)
1917import qualified Data.ByteString.Lazy.Char8 as BS
2018import qualified Data.ByteString.Lazy as L
2119
@@ -25,7 +23,7 @@ import SourceSyntax.Module
2523import Parse.Module (getModuleName)
2624import Initialize (buildFromSource, getSortedDependencies)
2725import Generate.JavaScript (jsModule)
28−import Generate.Html (createHtml, JSStyle(..), JSSource(..))
26+import Generate.Html (createHtml, JSSource(..))
2927import Paths_Elm
3028
3129import SourceSyntax.PrettyPrint (pretty, variable)
@@ -42,36 +40,38 @@ data Flags =
4240 , print_program :: Bool
4341 , scripts :: [FilePath]
4442 , no_prelude :: Bool
45− , minify :: Bool
4643 , cache_dir :: FilePath
4744 , build_dir :: FilePath
45+ , src_dir :: [FilePath]
4846 }
4947 deriving (Data,Typeable,Show,Eq)
5048
5149flags = Flags
52− { make = False
50+ { files = def &= args &= typ "FILES"
51+ , make = False
5352 &= help "automatically compile dependencies."
54− , files = def &= args &= typ "FILES"
55− , runtime = Nothing &= typFile
56− &= help "Specify a custom location for Elm's runtime system."
5753 , only_js = False
5854 &= help "Compile only to JavaScript."
59− , print_types = False
60− &= help "Print out infered types of top-level definitions."
61− , print_program = False
62− &= help "Print out an internal representation of a program."
63− , scripts = [] &= typFile
64− &= help "Load JavaScript files in generated HTML. Files will be included in the given order."
6555 , no_prelude = False
6656 &= help "Do not import Prelude by default, used only when compiling standard libraries."
67− , minify = False
68− &= help "Minify generated JavaScript and HTML"
57+ , scripts = [] &= typFile
58+ &= help "Load JavaScript files in generated HTML. Files will be included in the given order."
59+ , runtime = Nothing &= typFile
60+ &= help "Specify a custom location for Elm's runtime system."
6961 , cache_dir = "cache" &= typFile
7062 &= help "Directory for files cached to make builds faster. Defaults to cache/ directory."
7163 , build_dir = "build" &= typFile
7264 &= help "Directory for generated HTML and JS files. Defaults to build/ directory."
65+ , src_dir = ["."] &= typFile
66+ &= help "Additional source directories besides project root. Searched when using --make"
67+ , print_types = False
68+ &= help "Print out infered types of top-level definitions."
69+ , print_program = False
70+ &= help "Print out an internal representation of a program."
7371 } &= help "Compile Elm programs to HTML, CSS, and JavaScript."
74− &= summary ("The Elm Compiler " ++ showVersion version ++ ", (c) Evan Czaplicki")
72+ &= helpArg [explicit, name "help", name "h"]
73+ &= versionArg [explicit, name "version", name "v", summary (showVersion version)]
74+ &= summary ("The Elm Compiler " ++ showVersion version ++ ", (c) Evan Czaplicki 2011-2013")
7575
7676main :: IO ()
7777main = do setNumCapabilities =<< getNumProcessors
@@ -118,7 +118,7 @@ buildFile flags moduleNum numModules interfaces filePath =
118118 then return False
119119 else do tsrc <- getModificationTime filePath
120120 tint <- getModificationTime (elmo flags filePath)
121− return (tsrc < tint)
121+ return (tsrc <= tint)
122122
123123 number :: String
124124 number = "[" ++ show moduleNum ++ " of " ++ show numModules ++ "]"
@@ -146,11 +146,12 @@ buildFile flags moduleNum numModules interfaces filePath =
146146 True -> print . pretty $ program modul
147147 return modul
148148
149− if print_types flags then printTypes interfaces metaModule else return ()
149+ when (print_types flags) (printTypes interfaces metaModule)
150150 let interface = Canonical.interface name $ ModuleInterface {
151151 iTypes = types metaModule,
152152 iAdts = datatypes metaModule,
153− iAliases = aliases metaModule
153+ iAliases = aliases metaModule,
154+ iFixities = fixities metaModule
154155 }
155156 createDirectoryIfMissing True . dropFileName $ elmi flags filePath
156157 handle <- openBinaryFile (elmi flags filePath) WriteMode
@@ -175,34 +176,34 @@ getRuntime flags =
175176build :: Flags -> FilePath -> IO ()
176177build flags rootFile = do
177178 let noPrelude = no_prelude flags
178− files <- if make flags then getSortedDependencies noPrelude rootFile else return [rootFile]
179+ files <- if make flags then getSortedDependencies (src_dir flags) noPrelude rootFile
180+ else return [rootFile]
179181 let ifaces = if noPrelude then Map.empty else Prelude.interfaces
180182 (moduleName, interfaces) <- buildFiles flags (length files) ifaces "" files
181− js <- foldM appendToOutput "" files
182− case only_js flags of
183+ js <- foldM appendToOutput BS.empty files
184+
185+ (extension, code) <- case only_js flags of
183186 True -> do
184187 putStr "Generating JavaScript ... "
185− writeFile (buildPath flags rootFile "js") (genJs js)
186− putStrLn "Done"
188+ return ("js", js)
187189 False -> do
188190 putStr "Generating HTML ... "
189− runtime <- getRuntime flags
190− let html = genHtml $ createHtml runtime (takeBaseName rootFile) (sources js) moduleName ""
191− htmlFile = buildPath flags rootFile "html"
192− createDirectoryIfMissing True (takeDirectory htmlFile)
193− writeFile htmlFile html
194− putStrLn "Done"
191+ rtsPath <- getRuntime flags
192+ return ("html", BS.pack . renderHtml $
193+ createHtml rtsPath (takeBaseName rootFile) (sources js) moduleName "")
194+
195+ let targetFile = buildPath flags rootFile extension
196+ createDirectoryIfMissing True (takeDirectory targetFile)
197+ BS.writeFile targetFile code
198+ putStrLn "Done"
195199
196200 where
197− appendToOutput :: String -> FilePath -> IO String
201+ appendToOutput :: BS.ByteString -> FilePath -> IO BS.ByteString
198202 appendToOutput js filePath =
199− do src <- readFile (elmo flags filePath)
200− return (src ++ js)
203+ do src <- BS.readFile (elmo flags filePath)
204+ return (BS.append src js)
201205
202− genHtml = if minify flags then Normal.renderHtml else Pretty.renderHtml
203− genJs = if minify flags then BS.unpack . JS.minify . BS.pack else id
204− sources js = map Link (scripts flags) ++
205− [ Source (if minify flags then Minified else Readable) js ]
206+ sources js = map Link (scripts flags) ++ [ Source js ]
206207
207208
208209buildFiles :: Flags -> Int -> Interfaces -> String -> [FilePath] -> IO (String, Interfaces)
compiler/Docs.hs+146−59
@@ -1,75 +1,162 @@
1−
1+{-# LANGUAGE OverloadedStrings, DeriveDataTypeable #-}
22module Main where
33
4−import SourceSyntax.Declaration (Declaration(Datatype))
4+import System.Console.CmdArgs
5+import System.Directory
6+import System.FilePath
7+import System.Exit
8+
59import Control.Applicative ((<$>), (<*>))
6−import Data.List (intercalate)
7−import Parse.Type
10+import Data.Aeson
11+import Data.Aeson.Encode.Pretty
12+import qualified Data.List as List
13+import qualified Data.Map as Map
14+import qualified Data.ByteString.Lazy as BS
15+import qualified Data.Text as Text
16+
17+import SourceSyntax.Helpers (isSymbol)
18+import SourceSyntax.Type (Type(..))
19+import SourceSyntax.Declaration (Declaration(..), Assoc(..))
20+import SourceSyntax.Expression (Def(..))
21+
22+import Text.Parsec hiding (newline,spaces)
23+import Parse.Declaration (alias,datatype,infixDecl)
24+import Parse.Expression (typeAnnotation)
825import Parse.Helpers
926import Parse.Module (moduleDef)
10−import Text.Parsec hiding (newline,spaces)
11−import System.Environment
12−import System.Exit
27+
28+data Flags = Flags
29+ { files :: [FilePath] }
30+ deriving (Data,Typeable,Show,Eq)
31+
32+defaultFlags = Flags
33+ { files = def &= args &= typ "FILES"
34+ } &= help "Generate documentation for Elm"
35+ &= summary ("Generate documentation for Elm, (c) Evan Czaplicki")
1336
1437main = do
15− srcs <- mapM readFile =<< getArgs
16− case mapM docParse srcs of
17− Left err -> putStrLn err >> exitFailure
18− Right ms -> putStrLn (toModules ms)
19−
20−toModules ms = wrap (intercalate ",\n " (map toModule ms))
21− where wrap s = "{ \"modules\" : [\n " ++ s ++ "\n ]\n}"
22−
23−toModule (name, values) =
24− "{ \"name\" : " ++ show name ++ ",\n " ++
25− "\"values\" : [\n " ++ vs ++ "\n ]\n }"
26− where vs = intercalate ",\n " (map toValue values)
27−
28−toValue (name, tipe, desc) =
29− "{ \"name\" : " ++ show name ++
30− ",\n \"type\" : " ++ show tipe ++
31− ",\n \"desc\" : " ++ show desc ++ "\n }"
32−
33−docParse :: String -> Either String (String, [(String, String, String)])
34−docParse = setupParser $ do
38+ flags <- cmdArgs defaultFlags
39+ mapM parseFile (files flags)
40+
41+config = Config { confIndent = 2, confCompare = keyOrder keys }
42+ where
43+ keys = ["name","document","comment","raw","aliases","datatypes"
44+ ,"values","typeVariables","type","constructors"]
45+
46+parseFile path = do
47+ source <- readFile path
48+ case iParse docs source of
49+ Right json -> do
50+ putStrLn $ "Documenting " ++ path
51+ let docPath = "docs" </> replaceExtension path ".json"
52+ createDirectoryIfMissing True (dropFileName docPath)
53+ BS.writeFile docPath (encodePretty' config json)
54+ Left err -> do
55+ putStrLn $ "Parse error in " ++ path ++ " at " ++ show err
56+ exitFailure
57+
58+docs :: IParser Value
59+docs = do
60+ (name, exports, structure) <- moduleDocs
61+ things <- document
62+ return $ documentToJson name exports structure things
63+
64+docComment :: IParser String
65+docComment = do
66+ try (string "{-|")
67+ contents <- closeComment
68+ let reversed = dropWhile (`elem` " \n\r") . drop 2 $ reverse contents
69+ return $ dropWhile (==' ') (reverse reversed)
70+
71+moduleDocs = do
3572 optional freshLine
36− (names, exports) <- option (["Main"],[]) moduleDef
37− info <- many (try (annotation exports) <|> try skip <|> end)
38− return (intercalate "." names, concat info)
73+ (names,exports) <- moduleDef
74+ manyTill (string " " <|> newline <?> "more whitespace")
75+ (lookAhead (string "{-|") <?> "module documentation comment")
76+ structure <- docComment
77+ return (List.intercalate "." names, exports, structure)
78+
79+document :: IParser [(String, Declaration t v, String)]
80+document = onFreshLines (\t ts -> ts ++ [t]) [] docThing
81+
82+docThing :: IParser (String, Declaration t v, String)
83+docThing = uncommentable <|> commented <|> uncommented ""
3984 where
40− skip = manyTill anyChar simpleNewline >> return []
41− end = many1 anyChar >> return []
42−
43−annotation :: [String] -> IParser [(String, String, String)]
44−annotation exports =
45− do description <- comment
46− extras <- option [] (lookAhead adt)
47− varName <- try typeDef <|> name
48− varType <- tipe
49− return $ extras ++ export varName varType description
85+ uncommentable = do
86+ ifx <- infixDecl
87+ return ("", ifx, "")
88+
89+ commented = do
90+ comment <- docComment
91+ freshLine
92+ uncommented comment
93+
94+ uncommented comment = do
95+ (src,def) <- withSource $ choice [ alias, datatype, Definition <$> typeAnnotation ]
96+ return (comment, def, src)
97+
98+
99+documentToJson name exports structure things =
100+ object $ [ "name" .= name
101+ , "document" .= structure
102+ , "values" .= toList values
103+ , "aliases" .= toList aliases
104+ , "datatypes" .= toList adts
105+ ]
50106 where
51− comment = concatMap clip <$> many lineComment
52− clip str = case str of { ' ':rest -> rest ; _ -> str } ++ "\n"
107+ (values, aliases, adts) = collect Map.empty Map.empty Map.empty Map.empty things
108+
109+ toList dict = map object . Map.elems $ filterPublics dict
53110
54− name = do v <- lowVar <|> parens symOp
55− whitespace ; hasType ; whitespace ; return v
111+ exportMap = Map.fromList (zip exports exports)
112+ filterPublics dict =
113+ case Map.null exportMap of
114+ True -> dict
115+ False -> Map.filterWithKey (\k _ -> Map.member k exportMap) dict
56116
57− tipe = manyTill anyChar (try (simpleNewline >> notFollowedBy (string " ")))
117+collect infixes types aliases adts things =
118+ case things of
119+ [] -> (Map.union customOps nonCustomOps, aliases, adts)
120+ where
121+ nonCustomOps = Map.mapWithKey addDefaultInfix $ Map.difference types infixes
122+ addDefaultInfix name pairs
123+ | all isSymbol name = addInfix (L, 9 :: Int) pairs
124+ | otherwise = pairs
58125
59− export name tipe desc =
60− if null exports || name `elem` exports then [(name,tipe,desc)] else []
126+ customOps = Map.intersectionWith addInfix infixes types
127+ addInfix (assoc,prec) pairs =
128+ [ "associativity" .= show assoc, "precedence" .= prec ] ++ pairs
61129
62− typeDef = lookAhead ((string "data" <|> string "type") >> whitespace >> capVar)
130+ (comment, decl, source) : rest ->
131+ case decl of
132+ Fixity assoc prec name ->
133+ collect (Map.insert name (assoc,prec) infixes) types aliases adts rest
134+ Definition (TypeAnnotation name tipe) ->
135+ collect infixes (insert name [ "type" .= tipe ] types) aliases adts rest
136+ TypeAlias name vars tipe ->
137+ let fields = ["typeVariables" .= vars, "type" .= tipe ]
138+ in collect infixes types (insert name fields aliases) adts rest
139+ Datatype name vars ctors ->
140+ let tipe = Data name (map Var vars)
141+ fields = ["typeVariables" .= vars, "constructors" .= map (ctorToJson tipe) ctors ]
142+ in collect infixes types aliases (insert name fields adts) rest
143+ where
144+ insert name fields dict = Map.insert name (obj name fields) dict
145+ obj name fields =
146+ [ "name" .= name, "raw" .= source, "comment" .= comment ] ++ fields
63147
64− adt = do undefined
65−{-- TODO: reimplement this
66− (Datatype name tvs constructors) <- datatype
67− let toType (cName, typeArgs) =
68− (cName, show $ foldr (==>) (kADT name $ map kVarT tvs) typeArgs, "")
69− return $ map toType constructors
70−--}
148+instance ToJSON Type where
149+ toJSON tipe =
150+ case tipe of
151+ Lambda t1 t2 -> toJSON [ "->", toJSON t1, toJSON t2 ]
152+ Var x -> toJSON x
153+ Data name ts -> toJSON (toJSON name : map toJSON ts)
154+ EmptyRecord -> object []
155+ Record fields ext -> object $ map (\(n,t) -> Text.pack n .= toJSON t) fields'
156+ where fields' = case ext of
157+ EmptyRecord -> fields
158+ _ -> ("_",ext) : fields
71159
72−setupParser p source =
73− case iParse p "" source of
74− Right result -> Right result
75− Left err -> Left $ "Parse error at " ++ show err
160+ctorToJson tipe (ctor, tipes) =
161+ object [ "name" .= ctor
162+ , "type" .= foldr Lambda tipe tipes ]
compiler/Generate/Cases.hs+20−23
@@ -1,23 +1,27 @@
1−module Generate.Cases (caseToMatch, Match (..), Clause (..), matchSubst) where
1+module Generate.Cases (toMatch, Match (..), Clause (..), matchSubst) where
22
3−import Control.Arrow (first)
4−import Control.Monad (liftM,foldM)
3+import Control.Applicative ((<$>),(<*>))
4+import Control.Arrow (first,second)
5+import Control.Monad.State
56import Data.List (groupBy,sortBy,lookup)
67import Data.Maybe (fromMaybe)
78
8−import Unique
99import SourceSyntax.Location
1010import SourceSyntax.Literal
1111import SourceSyntax.Pattern
1212import SourceSyntax.Expression
1313import Transform.Substitute
1414
15−caseToMatch patterns = do
15+
16+toMatch :: [(Pattern, LExpr t v)] -> State Int (String, Match t v)
17+toMatch patterns = do
1618 v <- newVar
17− (,) v `liftM` match [v] (map (first (:[])) patterns) Fail
19+ (,) v <$> match [v] (map (first (:[])) patterns) Fail
1820
19−newVar = do n <- guid
20− return $ "case" ++ show n
21+newVar :: State Int String
22+newVar = do n <- get
23+ modify (+1)
24+ return $ "_case" ++ show n
2125
2226data Match t v
2327 = Match String [Clause t v] (Match t v)
@@ -51,7 +55,7 @@ isCon (p:ps, e) =
5155
5256isVar p = not (isCon p)
5357
54−match :: [String] -> [([Pattern],LExpr t v)] -> Match t v -> Unique (Match t v)
58+match :: [String] -> [([Pattern],LExpr t v)] -> Match t v -> State Int (Match t v)
5559match [] [] def = return def
5660match [] [([],e)] Fail = return $ Other e
5761match [] [([],e)] Break = return $ Other e
@@ -68,8 +72,7 @@ dealias v c@(p:ps, L s e) =
6872 PAlias x pattern -> (pattern:ps, L s $ subst x (Var v) e)
6973 _ -> c
7074
71−matchVar :: [String] -> [([Pattern],LExpr t v)] -> Match t v
72− -> Unique (Match t v)
75+matchVar :: [String] -> [([Pattern],LExpr t v)] -> Match t v -> State Int (Match t v)
7376matchVar (v:vs) cs def = match vs (map subVar cs) def
7477 where
7578 subVar (p:ps, ce@(L s e)) = (ps, L s $ subOnePattern p e)
@@ -81,9 +84,8 @@ matchVar (v:vs) cs def = match vs (map subVar cs) def
8184 PRecord fs ->
8285 foldr (\x -> subst x (Access (L s (Var v)) x)) e fs
8386
84−matchCon :: [String] -> [([Pattern],LExpr t v)] -> Match t v
85− -> Unique (Match t v)
86−matchCon (v:vs) cs def = (flip (Match v) def) `liftM` mapM toClause css
87+matchCon :: [String] -> [([Pattern],LExpr t v)] -> Match t v -> State Int (Match t v)
88+matchCon (v:vs) cs def = (flip (Match v) def) <$> mapM toClause css
8789 where
8890 css = groupBy eq (sortBy cmp cs)
8991
@@ -102,14 +104,10 @@ matchCon (v:vs) cs def = (flip (Match v) def) `liftM` mapM toClause css
102104 (PData name _ : _, _) -> matchClause (Left name) (v:vs) cs Break
103105 (PLiteral lit : _, _) -> matchClause (Right lit) (v:vs) cs Break
104106
105−matchClause :: Either String Literal
106− -> [String]
107− -> [([Pattern],LExpr t v)]
108− -> Match t v
109− -> Unique (Clause t v)
107+--matchClause :: Either String Literal -> [String] -> [([Pattern],LExpr t v)] -> Match t v -> State Int (Clause a)
110108matchClause c (v:vs) cs def =
111109 do vs' <- getVars
112− Clause c vs' `liftM` match (vs' ++ vs) (map flatten cs) def
110+ Clause c vs' <$> match (vs' ++ vs) (map flatten cs) def
113111 where
114112
115113 flatten (p:ps, e) =
@@ -119,10 +117,9 @@ matchClause c (v:vs) cs def =
119117
120118 getVars =
121119 case head cs of
122− (PData _ ps : _, _) -> mapM (\_ -> newVar) ps
120+ (PData _ ps : _, _) -> forM ps (const newVar)
123121 (PLiteral _ : _, _) -> return []
124122
125−matchMix :: [String] -> [([Pattern],LExpr t v)] -> Match t v
126− -> Unique (Match t v)
123+matchMix :: [String] -> [([Pattern],LExpr t v)] -> Match t v -> State Int (Match t v)
127124matchMix vs cs def = foldM (flip $ match vs) def (reverse css)
128125 where css = groupBy (\p1 p2 -> isCon p1 == isCon p2) cs
compiler/Generate/Html.hs+4−22
@@ -1,8 +1,6 @@
11{-# LANGUAGE OverloadedStrings #-}
22module Generate.Html
3− (generateHtml,
4− createHtml,
5− JSStyle (..),
3+ (createHtml,
64 JSSource (..)
75 ) where
86
@@ -10,37 +8,21 @@ import Text.Blaze (preEscapedToMarkup)
108import qualified Text.Blaze.Html5 as H
119import Text.Blaze.Html5 ((!))
1210import qualified Text.Blaze.Html5.Attributes as A
13−
14−import Text.Jasmine (minify)
1511import qualified Data.ByteString.Lazy.Char8 as BS
1612
1713import Initialize (buildFromSource)
1814import Generate.JavaScript
1915import Generate.Noscript
2016
21−data JSStyle = Minified | Readable
22−data JSSource = Link String | Source JSStyle String
17+data JSSource = Link String | Source BS.ByteString
2318
2419makeScript :: JSSource -> H.Html
2520makeScript source =
2621 case source of
2722 Link src -> H.script ! A.type_ "text/javascript" ! A.src (H.toValue src) $ ""
28− Source style src ->
23+ Source src ->
2924 H.script ! A.type_ "text/javascript" $
30− preEscapedToMarkup $ case style of
31− Minified -> BS.unpack . minify . BS.pack $ src
32− Readable -> src
33−
34−-- |This function compiles Elm code into simple HTML.
35−--
36−-- Usage example:
37−--
38−-- > generateHtml "/elm-min.js" "Some title" [elmFile|elm-source/somePage.elm|]
39−generateHtml :: String -- ^ Location of elm-runtime.js as expected by the browser
40− -> String -- ^ The page title
41− -> String -- ^ The elm source code.
42− -> H.Html
43−generateHtml libLoc title source = error "function 'generateHtml' is unimplemented for now"
25+ preEscapedToMarkup $ BS.unpack src
4426
4527createHtml :: FilePath -> String -> [JSSource] -> String -> String -> H.Html
4628createHtml libLoc title scripts moduleName noscript =
compiler/Generate/JavaScript.hs+380−330
@@ -1,361 +1,411 @@
1−module Generate.JavaScript (jsModule) where
1+module Generate.JavaScript where
22
3−import Control.Arrow (first,second)
4−import Control.Monad (liftM,(<=<),join,ap)
5−import Data.Char (isAlpha,isDigit)
3+import Control.Arrow (first,(***))
4+import Control.Applicative ((<$>),(<*>))
5+import Control.Monad.State
66import qualified Data.List as List
77import qualified Data.Map as Map
88import qualified Data.Set as Set
9−import Data.Either (partitionEithers)
109import qualified Text.Pandoc as Pan
1110
12−import Unique
13−import Generate.Cases
11+import qualified Generate.Cases as Case
1412import SourceSyntax.Everything
1513import SourceSyntax.Location
1614import qualified Transform.SortDefinitions as SD
15+import Language.ECMAScript3.Syntax
16+import Language.ECMAScript3.PrettyPrint
17+import Parse.Helpers (jsReserveds)
1718
18−indent = concatMap f
19− where f '\n' = "\n "
20− f c = [c]
19+makeSafe :: String -> String
20+makeSafe = List.intercalate "." . map dereserve . split . deprime
21+ where
22+ deprime = map (\c -> if c == '\'' then '$' else c)
23+ dereserve x = case Set.member x jsReserveds of
24+ False -> x
25+ True -> "$" ++ x
26+
27+split = go []
28+ where
29+ go vars str =
30+ case break (=='.') str of
31+ (x,'.':rest) | isOp x -> vars ++ [x ++ '.' : rest]
32+ | otherwise -> go (vars ++ [x]) rest
33+ (x,[]) -> vars ++ [x]
34+
35+var name = Id () (makeSafe name)
36+ref name = VarRef () (var name)
37+prop name = PropId () (var name)
38+f <| x = CallExpr () f [x]
39+args ==> e = FuncExpr () Nothing (map var args) [ ReturnStmt () (Just e) ]
40+function args stmts = FuncExpr () Nothing (map var args) stmts
41+call = CallExpr ()
42+string = StringLit ()
43+
44+dotSep (x:xs) = foldl (DotRef ()) (ref x) (map var xs)
45+obj = dotSep . split
46+
47+varDecl x expr =
48+ VarDecl () (var x) (Just expr)
49+
50+include alias moduleName =
51+ varDecl alias (obj (moduleName ++ ".make") <| ref "elm")
2152
2253internalImports name =
23− [ ("N" , "Elm.Native"),
24− ("_N", "N.Utils(elm)"),
25− ("_L", "N.List(elm)"),
26− ("_E", "N.Error(elm)"),
27− ("_J", "N.JavaScript(elm)"),
28− ("_str", "_J.toString"),
29− ("$moduleName", quoted name)
54+ VarDeclStmt ()
55+ [ varDecl "N" (obj "Elm.Native")
56+ , include "_N" "N.Utils"
57+ , include "_L" "N.List"
58+ , include "_E" "N.Error"
59+ , include "_J" "N.JavaScript"
60+ , varDecl "$moduleName" (string name)
3061 ]
3162
32−parens s = "(" ++ s ++ ")"
33−brackets s = "{" ++ s ++ "}"
34−commaSep = List.intercalate ", "
35−dotSep = List.intercalate "."
36−jsObj = brackets . commaSep
37−jsList ss = "["++ List.intercalate "," ss ++"]"
38−jsFunc args body = "function(" ++ args ++ "){" ++ indent body ++ "}"
39−assign x e = "\nvar " ++ x ++ " = " ++ e ++ ";"
40−ret e = "\nreturn "++ e ++";"
41−quoted s = "'" ++ concatMap f s ++ "'"
42− where f '\n' = "\\n"
43− f '\'' = "\\'"
44− f '\t' = "\\t"
45− f '\"' = "\\\""
46− f '\\' = "\\\\"
47− f c = [c]
48−
49−globalAssign n e = "\n" ++ assign' n e ++ ";"
50−assign' n e = n ++ " = " ++ e
51−
52−jsModule :: MetadataModule t v -> String
63+literal lit =
64+ case lit of
65+ Chr c -> obj "_N.chr" <| string [c]
66+ Str s -> string s
67+ IntNum n -> IntLit () n
68+ FloatNum n -> NumLit () n
69+ Boolean b -> BoolLit () b
70+
71+expression :: LExpr () () -> State Int (Expression ())
72+expression (L span expr) =
73+ case expr of
74+ Var x -> return $ ref x
75+ Literal lit -> return $ literal lit
76+
77+ Range lo hi ->
78+ do lo' <- expression lo
79+ hi' <- expression hi
80+ return $ obj "_L.range" `call` [lo',hi']
81+
82+ Access e x ->
83+ do e' <- expression e
84+ return $ DotRef () e' (var x)
85+
86+ Remove e x ->
87+ do e' <- expression e
88+ return $ obj "_N.remove" `call` [string x, e']
89+
90+ Insert e x v ->
91+ do v' <- expression v
92+ e' <- expression e
93+ return $ obj "_N.insert" `call` [string x, v', e']
94+
95+ Modify e fs ->
96+ do e' <- expression e
97+ fs' <- forM fs $ \(f,v) -> do
98+ v' <- expression v
99+ return $ ArrayLit () [string f, v']
100+ return $ obj "_N.replace" `call` [ArrayLit () fs', e']
101+
102+ Record fields ->
103+ do fields' <- forM fields $ \(f,e) -> do
104+ (,) f <$> expression e
105+ let fieldMap = List.foldl' combine Map.empty fields'
106+ return $ ObjectLit () $ (PropId () (var "_"), hidden fieldMap) : visible fieldMap
107+ where
108+ combine r (k,v) = Map.insertWith (++) k [v] r
109+ prop = PropId () . var
110+ hidden fs = ObjectLit () . map (prop *** ArrayLit ()) .
111+ Map.toList . Map.filter (not . null) $ Map.map tail fs
112+ visible fs = map (first prop) . Map.toList $ Map.map head fs
113+
114+ Binop op e1 e2 -> binop span op e1 e2
115+
116+ Lambda p e@(L s _) ->
117+ do body' <- expression body
118+ return $ case length args < 2 || length args > 9 of
119+ True -> foldr (==>) body' (map (:[]) args)
120+ False -> ref ("F" ++ show (length args)) <| (args ==> body')
121+ where
122+ (args, body) = foldr depattern ([], innerBody) (zip patterns [0..])
123+
124+ depattern (pattern,n) (args, body) =
125+ case pattern of
126+ PVar x -> (args ++ [x], body)
127+ _ -> let arg = "arg" ++ show n
128+ in (args ++ [arg], L s (Case (L s (Var arg)) [(pattern, body)]))
129+
130+ (patterns, innerBody) = collect [p] e
131+
132+ collect patterns lexpr@(L _ expr) =
133+ case expr of
134+ Lambda p e -> collect (p:patterns) e
135+ _ -> (patterns, lexpr)
136+
137+ App e1 e2 ->
138+ do func' <- expression func
139+ args' <- mapM expression args
140+ return $ case args' of
141+ [arg] -> func' <| arg
142+ _ | length args' <= 9 -> ref aN `call` (func':args')
143+ | otherwise -> foldl1 (<|) (func':args')
144+ where
145+ aN = "A" ++ show (length args)
146+ (func, args) = getArgs e1 [e2]
147+ getArgs func args =
148+ case func of
149+ (L _ (App f arg)) -> getArgs f (arg : args)
150+ _ -> (func, args)
151+
152+ Let defs e ->
153+ do let (defs',e') = SD.flattenLets defs e
154+ stmts <- concat <$> mapM definition defs'
155+ exp <- expression e'
156+ return $ function [] (stmts ++ [ ReturnStmt () (Just exp) ]) `call` []
157+
158+ MultiIf branches ->
159+ do branches' <- forM branches $ \(b,e) -> (,) <$> expression b <*> expression e
160+ return $ case last branches of
161+ (L _ (Var "Basics.otherwise"), e) -> ifs (init branches') (snd (last branches'))
162+ _ -> ifs branches'
163+ (obj "_E.If" `call` [ ref "$moduleName", string (show span) ])
164+ where
165+ ifs branches finally = foldr iff finally branches
166+ iff (if', then') else' = CondExpr () if' then' else'
167+
168+ Case e cases ->
169+ do (tempVar,initialMatch) <- Case.toMatch cases
170+ (revisedMatch, stmt) <-
171+ case e of
172+ L _ (Var x) -> return (Case.matchSubst [(tempVar,x)] initialMatch, [])
173+ _ -> do e' <- expression e
174+ return (initialMatch, [VarDeclStmt () [varDecl tempVar e']])
175+ match' <- match span revisedMatch
176+ return (function [] (stmt ++ match') `call` [])
177+
178+ ExplicitList es ->
179+ do es' <- mapM expression es
180+ return $ obj "_J.toList" <| ArrayLit () es'
181+
182+ Data name es ->
183+ do es' <- mapM expression es
184+ return $ ObjectLit () (ctor : fields es')
185+ where
186+ ctor = (prop "ctor", string (makeSafe name))
187+ fields = zipWith (\n e -> (prop ("_" ++ show n), e)) [0..]
188+
189+ Markdown doc _ -> return $ obj "Text.text" <| string (pad ++ md ++ pad)
190+ where pad = "<div style=\"height:0;width:0;\">&nbsp;</div>"
191+ md = Pan.writeHtmlString Pan.def doc
192+
193+definition :: Def () () -> State Int [Statement ()]
194+definition def =
195+ case def of
196+ TypeAnnotation _ _ -> return []
197+
198+ Def pattern expr@(L span _) -> do
199+ expr' <- expression expr
200+ let assign x = varDecl x expr'
201+ case pattern of
202+ PVar x
203+ | isOp x ->
204+ let op = LBracket () (ref "_op") (string x) in
205+ return [ ExprStmt () $ AssignExpr () OpAssign op expr' ]
206+ | otherwise ->
207+ return [ VarDeclStmt () [ assign x ] ]
208+
209+ PRecord fields ->
210+ let setField f = varDecl f (dotSep ["$",f]) in
211+ return [ VarDeclStmt () (assign "$" : map setField fields) ]
212+
213+ PData name patterns | vars /= Nothing ->
214+ case vars of
215+ Just vs -> return [ VarDeclStmt () (setup (zipWith decl vs [0..])) ]
216+ where
217+ vars = getVars patterns
218+ getVars patterns =
219+ case patterns of
220+ PVar x : rest -> (x:) `fmap` getVars rest
221+ [] -> Just []
222+ _ -> Nothing
223+
224+ decl x n = varDecl x (dotSep ["$","_" ++ show n])
225+ setup vars
226+ | isTuple name = assign "$" : vars
227+ | otherwise = safeAssign : vars
228+
229+ safeAssign = varDecl "$" (CondExpr () if' expr' exception)
230+ if' = InfixExpr () OpStrictEq (obj "$.ctor") (string name)
231+ exception = obj "_E.Case" `call` [ref "$moduleName", string (show span)]
232+
233+ _ ->
234+ do defs' <- concat <$> mapM toDef vars
235+ return (VarDeclStmt () [assign "$"] : defs')
236+ where
237+ vars = Set.toList $ SD.boundVars pattern
238+ mkVar = L span . Var
239+ toDef y = definition $
240+ Def (PVar y) (L span $ Case (mkVar "$") [(pattern, mkVar y)])
241+
242+match :: (Show a) => a -> Case.Match () () -> State Int [Statement ()]
243+match span mtch =
244+ case mtch of
245+ Case.Match name clauses mtch' ->
246+ do clauses' <- mapM (clause span name) clauses
247+ mtch'' <- match span mtch'
248+ return (SwitchStmt () (access name) clauses' : mtch'')
249+ where
250+ isLiteral p = case p of
251+ Case.Clause (Right _) _ _ -> True
252+ _ -> False
253+ access name = if any isLiteral clauses then ref name else dotSep [name,"ctor"]
254+
255+ Case.Fail ->
256+ return [ ExprStmt () (obj "_E.Case" `call` [ref "$moduleName", string (show span)]) ]
257+
258+ Case.Break -> return [BreakStmt () Nothing]
259+ Case.Other e ->
260+ do e' <- expression e
261+ return [ ReturnStmt () (Just e') ]
262+ Case.Seq ms -> concat <$> mapM (match span) (dropEnd [] ms)
263+ where
264+ dropEnd acc [] = acc
265+ dropEnd acc (m:ms) =
266+ case m of
267+ Case.Other _ -> acc ++ [m]
268+ _ -> dropEnd (acc ++ [m]) ms
269+
270+clause span variable (Case.Clause value vars mtch) =
271+ CaseClause () pattern <$> match span (Case.matchSubst (zip vars vars') mtch)
272+ where
273+ vars' = map (\n -> variable ++ "._" ++ show n) [0..]
274+ pattern = case value of
275+ Right (Boolean b) -> BoolLit () b
276+ Right lit -> literal lit
277+ Left name -> string $ case List.elemIndices '.' name of
278+ [] -> name
279+ is -> drop (last is + 1) name
280+
281+
282+jsModule :: MetadataModule () () -> String
53283jsModule modul =
54− run $ do
55− body <- toJS . fst . SD.flattenLets [] $ program modul
56− foreignImport <- mapM importEvent (foreignImports modul)
57− return $ concat [ setup ("Elm": names modul)
58− , globalAssign ("Elm." ++ modName)
59− (jsFunc "elm" $ makeProgram body foreignImport) ]
284+ show . prettyPrint $ setup (Just "Elm") (names modul ++ ["make"]) ++
285+ [ assign ("Elm" : names modul ++ ["make"]) (function ["elm"] programStmts) ]
60286 where
61− modName = dotSep (names modul)
62− makeProgram body foreignImport =
63− concat [ "\nvar " ++ usefulFuncs ++ ";"
287+ thisModule = dotSep ("elm" : names modul ++ ["values"])
288+ programStmts =
289+ concat [ setup (Just "elm") (names modul ++ ["values"])
290+ , [ IfSingleStmt () thisModule (ReturnStmt () (Just thisModule)) ]
291+ , [ internalImports (List.intercalate "." (names modul)) ]
64292 , concatMap jsImport (imports modul)
65− , concat foreignImport
66− , assign "_op" "{}"
67− , body
68− , concatMap exportEvent $ foreignExports modul
69− , jsExports
293+ , concatMap importEvent (foreignImports modul)
294+ , [ assign ["_op"] (ObjectLit () []) ]
295+ , concat $ evalState (mapM definition . fst . SD.flattenLets [] $ program modul) 0
296+ , map exportEvent $ foreignExports modul
297+ , [ jsExports ]
298+ , [ ReturnStmt () (Just thisModule) ]
70299 ]
71− setup names = concatMap (\n -> globalAssign n $ n ++ " || {}") .
72− map dotSep . drop 2 . List.inits $ init names
73− usefulFuncs = commaSep (map (uncurry assign') (internalImports modName))
74300
75− jsExports = setup ("elm" : names modul) ++
76− ret (assign' ("elm." ++ modName) (brackets exs))
301+ jsExports = assign ("elm" : names modul ++ ["values"]) (ObjectLit () exs)
302+ where
303+ exs = map entry . filter (not . isOp) $ "_op" : exports modul
304+ entry x = (PropId () (var x), ref x)
305+
306+ assign path expr =
307+ case path of
308+ [x] -> VarDeclStmt () [ varDecl x expr ]
309+ _ -> ExprStmt () $
310+ AssignExpr () OpAssign (LDot () (dotSep (init path)) (last path)) expr
311+
312+ jsImport (modul,_) = setup Nothing path ++ [ include ]
313+ where
314+ path = split modul
315+ include = assign path $ dotSep ("Elm" : path ++ ["make"]) <| ref "elm"
316+
317+ setup namespace path = map create paths
77318 where
78− exs = indent . commaSep . concatMap pair $ "_op" : exports modul
79− pair x | isOp x = []
80− | otherwise = ["\n" ++ x ++ " : " ++ x]
319+ create name = assign name (InfixExpr () OpLOr (dotSep name) (ObjectLit () []))
320+ paths = case namespace of
321+ Nothing -> tail . init $ List.inits path
322+ Just nmspc -> drop 2 . init . List.inits $ nmspc : path
81323
324+ addId js = InfixExpr () OpAdd (string (js++"_")) (obj "elm.id")
82325
83326 importEvent (js,base,elm,_) =
84− do v <- toJS' base
85− return $ concat [ "\nvar " ++ elm ++ "=Signal.constant(" ++ v ++ ");"
86− , "\ndocument.addEventListener('", js
87− , "_' + elm.id, function(e) { elm.notify(", elm
88− , ".id, e.value); });" ]
327+ [ VarDeclStmt () [ varDecl elm $ obj "Signal.constant" <| evalState (expression base) 0 ]
328+ , ExprStmt () $
329+ obj "document.addEventListener" `call`
330+ [ addId js
331+ , function ["e"]
332+ [ ExprStmt () $ obj "elm.notify" `call` [dotSep [elm,"id"], obj "e.value"] ]
333+ ]
334+ ]
89335
90336 exportEvent (js,elm,_) =
91− concat [ "\nA2( Signal.lift, function(v) { "
92− , "var e = document.createEvent('Event');"
93− , "e.initEvent('", js, "_' + elm.id, true, true);"
94− , "e.value = v;"
95− , "document.dispatchEvent(e); return v; }, ", elm, ");" ]
96−
97−jsImport (modul, method) =
98− concat $ zipWith3 (\s n v -> s ++ assign' n v ++ ";") starters subnames values
99− where
100− starters = "\nvar " : repeat "\n"
101− values = map (\name -> name ++ " || {}") (init subnames) ++
102− ["Elm." ++ modul ++ parens "elm"]
103− subnames = map dotSep . tail . List.inits $ split modul
104−
105− split names = case go [] names of
106− (name, []) -> [name]
107− (name, ns) -> name : split ns
108− go name str = case str of
109− '.':rest -> (reverse name, rest)
110− c:rest -> go (c:name) rest
111− [] -> (reverse name, [])
112−
113−
114−class ToJS a where
115− toJS :: a -> Unique String
116−
117−
118−instance ToJS (Def t v) where
119−
120− -- TODO: Make this handle patterns besides plain variables
121− toJS (Def (PVar x) e)
122− | isOp x = globalAssign ("_op['" ++ x ++ "']") `liftM` toJS' e
123− | otherwise = assign x `liftM` toJS' e
124−
125− toJS (Def pattern e@(L s _)) =
126− do n <- guid
127− let x = "_" ++ show n
128− var = L s . Var
129− toDef y = Def (PVar y) (L s $ Case (var x) [(pattern, var y)])
130− stmt <- assign x `liftM` toJS' e
131− vars <- toJS . map toDef . Set.toList $ SD.boundVars pattern
132− return (stmt ++ vars)
133−
134− toJS (TypeAnnotation _ _) = return ""
135−
136−
137−instance ToJS a => ToJS [a] where
138− toJS xs = concat `liftM` mapM toJS xs
139−
140−toJS' :: LExpr t v -> Unique String
141−toJS' (L span expr) =
142− case expr of
143− MultiIf ps -> multiIfToJS span ps
144− Case e cases -> caseToJS span e cases
145− _ -> toJS expr
146−
147−remove x e = "_N.remove('" ++ x ++ "', " ++ e ++ ")"
148−addField x v e = "_N.insert('" ++ x ++ "', " ++ v ++ ", " ++ e ++ ")"
149−setField fs e = "_N.replace(" ++ jsList (map f fs) ++ ", " ++ e ++ ")"
150− where f (x,v) = "['" ++ x ++ "'," ++ v ++ "]"
151−access x e = e ++ "." ++ x
152−makeRecord kvs = record `liftM` collect kvs
153− where
154− combine r (k,v) = Map.insertWith (++) k v r
155− collect = liftM (List.foldl' combine Map.empty) . mapM prep
156− prep (k, e) =
157− do v <- toJS' e
158− return (k, [v])
159− fields fs =
160− brackets ("\n "++List.intercalate ",\n " (map (\(k,v) -> k++":"++v) fs))
161− hidden = fields . map (second jsList) .
162− filter (not . null . snd) . Map.toList . Map.map tail
163− record kvs = fields . (("_", hidden kvs) :) . Map.toList . Map.map head $ kvs
164−
165−
166−instance ToJS Literal where
167− toJS lit =
168− case lit of
169− Chr c -> return $ quoted [c]
170− Str s -> return $ "_str" ++ parens (quoted s)
171− IntNum n -> return $ show n
172− FloatNum n -> return $ show n
173− Boolean b -> return $ if b then "true" else "false"
174−
175−
176−instance ToJS (Expr t v) where
177− toJS expr =
178− case expr of
179− Var x -> return x
180− Literal lit -> toJS lit
181− Range lo hi -> jsRange `liftM` toJS' lo `ap` toJS' hi
182− Access e x -> access x `liftM` toJS' e
183− Remove e x -> remove x `liftM` toJS' e
184− Insert e x v -> addField x `liftM` toJS' v `ap` toJS' e
185− Modify e fs -> do fs' <- (mapM (\(x,v) -> (,) x `liftM` toJS' v) fs)
186− setField fs' `liftM` toJS' e
187− Record fs -> makeRecord fs
188− Binop op e1 e2 -> binop op e1 e2
189−
190− Lambda p e@(L s _) -> liftM fastFunc (toJS' body)
191− where
192− fastFunc body
193− | length args < 2 || length args > 9 =
194− foldr (\arg bod -> jsFunc arg (ret bod)) body args
195− | otherwise =
196− "F" ++ show (length args) ++ parens (jsFunc (commaSep args) (ret body))
197−
198− (args, body) = first reverse $ foldr depattern ([], innerBody) (zip patterns [1..])
199−
200− depattern (pattern,n) (args, body) =
201− case pattern of
202− PVar x -> (x : args, body)
203− _ -> let arg = "arg" ++ show n
204− in (arg:args, L s (Case (L s (Var arg)) [(pattern, body)]))
205−
206− (patterns, innerBody) = collect [p] e
207−
208− collect patterns lexpr@(L _ expr) =
209− case expr of
210− Lambda p e -> collect (p:patterns) e
211− _ -> (patterns, lexpr)
212−
213− App e1 e2 -> jsApp e1 e2
214− Let defs e -> jsLet $ SD.flattenLets defs e
215−
216− ExplicitList es ->
217− do es' <- mapM toJS' es
218− return $ "_J.toList" ++ parens (jsList es')
219−
220− Data name es ->
221− do fs <- mapM toJS' es
222− return $ case name of
223− "[]" -> jsNil
224− "::" -> jsCons (head fs) ((head . tail) fs)
225− _ -> jsObj $ ("ctor:" ++ show name) : fields
226− where fields = zipWith (\n e -> "_" ++ show n ++ ":" ++ e) [0..] fs
227−
228− Markdown doc -> return $ "Text.text('" ++ pad ++ md ++ pad ++ "')"
229− where pad = "<div style=\"height:0;width:0;\">&nbsp;</div>"
230− md = formatMarkdown $ Pan.writeHtmlString Pan.def doc
231−
232−jsApp e1 e2 =
233− do f <- toJS' func
234− as <- mapM toJS' args
235− return $ case as of
236− [a] -> f ++ parens a
237− _ -> "A" ++ show (length as) ++ parens (commaSep (f:as))
238− where
239− (func, args) = go [e2] e1
240− go args e =
241− case e of
242− (L _ (App e1 e2)) -> go (e2 : args) e1
243− _ -> (e, args)
244−
245−formatMarkdown = concatMap f
246− where f '\'' = "\\'"
247− f '\n' = "\\n"
248− f '"' = "\""
249− f c = [c]
250−
251−multiIfToJS span ps =
252− case last ps of
253− (L _ (Var "otherwise"), e) -> toJS' e >>= \b -> format b (init ps)
254− _ -> format ("_E.If" ++ parens ("$moduleName," ++ quoted (show span))) ps
337+ ExprStmt () $
338+ ref "A2" `call`
339+ [ obj "Signal.lift"
340+ , function ["v"]
341+ [ VarDeclStmt () [varDecl "e" $ obj "document.createEvent" <| string "Event"]
342+ , ExprStmt () $
343+ obj "e.initEvent" `call` [ addId js, BoolLit () True, BoolLit () True ]
344+ , ExprStmt () $ AssignExpr () OpAssign (LDot () (ref "e") "value") (ref "v")
345+ , ExprStmt () $ obj "document.dispatchEvent" <| ref "e"
346+ , ReturnStmt () (Just $ ref "v")
347+ ]
348+ , ref elm ]
349+
350+binop span op e1 e2 =
351+ case op of
352+ "Basics.." ->
353+ do es <- mapM expression (e1 : collect [] e2)
354+ return $ ["$"] ==> foldr (<|) (ref "$") es
355+ "Basics.<|" ->
356+ do e2' <- expression e2
357+ es <- mapM expression (collect [] e1)
358+ return $ foldr (<|) e2' es
359+ "List.++" ->
360+ do e1' <- expression e1
361+ e2' <- expression e2
362+ return $ obj "_L.append" `call` [e1', e2']
363+ "::" -> expression (L span (Data "::" [e1,e2]))
364+ _ ->
365+ do e1' <- expression e1
366+ e2' <- expression e2
367+ return $ case Map.lookup op opDict of
368+ Just f -> f e1' e2'
369+ Nothing -> ref "A2" `call` [ func, e1', e2' ]
255370 where
256− format base ps =
257− foldr (\c e -> parens $ c ++ " : " ++ e) base `liftM` mapM f ps
258− f (b,e) = do b' <- toJS' b
259− e' <- toJS' e
260− return (b' ++ " ? " ++ e')
261−
262−jsLet (defs,e') = do ds <- mapM toJS defs
263− e <- toJS' e'
264− return $ jsFunc "" (concat ds ++ ret e) ++ "()"
265−
266−caseToJS span e ps = do
267− (tempVar,match) <- caseToMatch ps
268− e' <- toJS' e
269− let (match',stmt) = case e of
270− L _ (Var x) -> (matchSubst [(tempVar,x)] match, "")
271− _ -> (match, assign tempVar e')
272− matches <- matchToJS span match'
273− return $ jsFunc "" (stmt ++ matches) ++ "()"
274−
275−matchToJS span match =
276− case match of
277− Match name clauses def ->
278− do cases <- concat `liftM` mapM (clauseToJS span name) clauses
279− finally <- matchToJS span def
280− let isLiteral p = case p of
281− Clause (Right _) _ _ -> True
282− _ -> False
283− access = if any isLiteral clauses then "" else ".ctor"
284− return $ concat [ "\nswitch (", name, access, ") {"
285− , indent cases, "\n}", finally ]
286− Fail -> return ("_E.Case" ++ parens ("$moduleName," ++ quoted (show span)))
287− Break -> return "break;"
288− Other e -> ret `liftM` toJS' e
289− Seq ms -> concat `liftM` mapM (matchToJS span) (dropEnd [] ms)
290− where
291− dropEnd acc [] = acc
292− dropEnd acc (m:ms) =
293− case m of
294− Other _ -> acc ++ [m]
295− _ -> dropEnd (acc ++ [m]) ms
296−
297−clauseToJS span var (Clause value vars e) = do
298− let vars' = map (\n -> var ++ "._" ++ show n) [0..]
299− s <- matchToJS span $ matchSubst (zip vars vars') e
300− pattern <- case value of
301− Right (Boolean True) -> return "true"
302− Right (Boolean False) -> return "false"
303− Right lit -> toJS lit
304− Left name -> return . quoted $ case List.elemIndices '.' name of
305− [] -> name
306− is -> drop (last is + 1) name
307− return $ concat [ "\ncase ", pattern, ":", indent s ]
308−
309−jsNil = "_L.Nil"
310−jsCons e1 e2 = "_L.Cons(" ++ e1 ++ "," ++ e2 ++ ")"
311−jsRange e1 e2 = "_L.range" ++ parens (e1 ++ "," ++ e2)
312−jsCompare e1 e2 op = parens ("_N.cmp(" ++ e1 ++ "," ++ e2 ++ ")" ++ op)
313−
314−
315−binop op e1 e2
316− | op == "Basics.." =
317− do ss <- mapM toJS' (e1 : collect [] e2)
318− return . jsFunc "$" . ret $ apply "$" ss
319− | op == "Basics.<|" =
320− do arg <- toJS' e2
321− funcs <- mapM toJS' (collect [] e1)
322− return (apply arg funcs)
323− | otherwise =
324− binopNormal op `liftM` toJS' e1 `ap` toJS' e2
325− where
326− apply = foldr (\f arg-> f ++ parens arg)
327−
328371 collect es e =
329372 case e of
330373 L _ (Binop op e1 e2) | op == "Basics.." -> collect (es ++ [e1]) e2
331374 _ -> es ++ [e]
332375
333−binopNormal op s1 s2 =
334− case Map.lookup op opDict of
335− Just e -> e
336− Nothing -> "A2" ++ parens (commaSep [ prefix ++ func, s1, s2 ])
337− where
338− func | isOp op' = "_op['" ++ op' ++ "']"
339− | otherwise = op'
340− (prefix, op') = case List.elemIndices '.' op of
341− [] -> ("", op)
342− xs -> splitAt (last xs + 1) op
343−
344− opDict = Map.fromList $ basics ++
345− [ ("::", jsCons s1 s2)
346− , ("List.++", "_L.append" ++ parens (s1 ++ "," ++ s2)) ]
347−
348− ops = pow : map (\op -> (op, parens (s1 ++ op ++ s2))) ["+","-","*","/","&&","||"]
349− where pow = ("^" , "Math.pow(" ++ s1 ++ "," ++ s2 ++ ")")
350−
351− basics = ops ++ map (\(op,e) -> ("Basics." ++ op, e))
352− (ops ++ [ ("<|", s1 ++ parens s2)
353− , ("|>", s2 ++ parens s1)
354− , ("==", "_N.eq(" ++ s1 ++ "," ++ s2 ++ ")")
355− , ("/=", "!_N.eq(" ++ s1 ++ "," ++ s2 ++ ")")
356− , ("<" , jsCompare s1 s2 "<0")
357− , (">" , jsCompare s1 s2 ">0")
358− , ("<=", jsCompare s1 s2 "<1")
359− , (">=", jsCompare s1 s2 ">-1")
360− , ("div", parens (s1 ++ "/" ++ s2 ++ "|0"))
361− ])
376+ js1 = expression e1
377+ js2 = expression e2
378+
379+ func | isOp operator = BracketRef () (dotSep (init parts ++ ["_op"])) (string operator)
380+ | otherwise = dotSep parts
381+ where
382+ parts = split op
383+ operator = last parts
384+
385+ opDict = Map.fromList (infixOps ++ specialOps)
386+
387+ specialOp str func = [ (str, func), ("Basics." ++ str, func) ]
388+ infixOp str op = specialOp str (InfixExpr () op)
389+
390+ infixOps = concat
391+ [ infixOp "+" OpAdd
392+ , infixOp "-" OpSub
393+ , infixOp "*" OpMul
394+ , infixOp "/" OpDiv
395+ , infixOp "&&" OpLAnd
396+ , infixOp "||" OpLOr
397+ ]
398+
399+ specialOps = concat
400+ [ specialOp "^" $ \a b -> obj "Math.pow" `call` [a,b]
401+ , specialOp "|>" $ flip (<|)
402+ , specialOp "==" $ \a b -> obj "_N.eq" `call` [a,b]
403+ , specialOp "/=" $ \a b -> PrefixExpr () PrefixLNot (obj "_N.eq" `call` [a,b])
404+ , specialOp "<" $ cmp OpLT 0
405+ , specialOp ">" $ cmp OpGT 0
406+ , specialOp "<=" $ cmp OpLT 1
407+ , specialOp ">=" $ cmp OpGT (-1)
408+ , specialOp "div" $ \a b -> InfixExpr () OpBOr (InfixExpr () OpDiv a b) (IntLit () 0)
409+ ]
410+
411+ cmp op n a b = InfixExpr () op (obj "_N.cmp" `call` [a,b]) (IntLit () n)
compiler/Generate/Noscript.hs+1−1
@@ -49,7 +49,7 @@ instance Extract (Expr t v) where
4949 Case e cases -> concatMap (f . snd) cases
5050 Data _ es -> concatMap f es
5151 MultiIf es -> concatMap (f . snd) es
52− Markdown doc -> [ Pan.writeHtmlString Pan.def doc ]
52+ Markdown doc _ -> [ Pan.writeHtmlString Pan.def doc ]
5353 _ -> []
5454
5555extractLink src txt =
compiler/Initialize.hs+30−11
@@ -6,11 +6,13 @@ import qualified Data.Graph as Graph
66import qualified Data.List as List
77import qualified Data.Map as Map
88import qualified Data.Set as Set
9+import System.Directory
910import System.Exit
1011import System.FilePath as FP
1112import Text.PrettyPrint (Doc)
1213
1314import SourceSyntax.Everything
15+import qualified SourceSyntax.Type as Type
1416import qualified Parse.Parse as Parse
1517import qualified Metadata.Prelude as Prelude
1618import qualified Transform.Check as Check
@@ -22,7 +24,10 @@ import qualified Transform.Canonicalize as Canonical
2224buildFromSource :: Bool -> Interfaces -> String -> Either [Doc] (MetadataModule () ())
2325buildFromSource noPrelude interfaces source =
2426 do let add = if noPrelude then id else Prelude.add
25− modul@(Module _ _ _ decls') <- add `fmap` Parse.program source
27+ infixes = Map.fromList . map (\(assoc,lvl,op) -> (op,(lvl,assoc)))
28+ . concatMap iFixities $ Map.elems interfaces
29+
30+ modul@(Module _ _ _ decls') <- add `fmap` Parse.program infixes source
2631
2732 -- check for structural errors
2833 Module names exs ims decls <-
@@ -34,7 +39,8 @@ buildFromSource noPrelude interfaces source =
3439 | null exs =
3540 let get = Set.toList . SD.boundVars in
3641 concat [ get pattern | Definition (Def pattern _) <- decls ] ++
37− concat [ map fst ctors | Datatype _ _ ctors <- decls ]
42+ concat [ map fst ctors | Datatype _ _ ctors <- decls ] ++
43+ [ name | TypeAlias name _ (Type.Record _ _) <- decls ]
3844 | otherwise = exs
3945
4046 metaModule <- Canonical.metadataModule interfaces $ MetadataModule {
@@ -57,9 +63,9 @@ buildFromSource noPrelude interfaces source =
5763 return $ metaModule { types = types }
5864
5965
60−getSortedDependencies :: Bool -> FilePath -> IO [String]
61−getSortedDependencies noPrelude root =
62− sortDeps =<< readDeps noPrelude root
66+getSortedDependencies :: [FilePath] -> Bool -> FilePath -> IO [String]
67+getSortedDependencies srcDirs noPrelude root =
68+ sortDeps =<< readDeps srcDirs noPrelude root
6369
6470type Deps = (FilePath, String, [String])
6571
@@ -74,18 +80,18 @@ sortDeps depends =
7480 mistakes = filter (\scc -> length scc > 1) sccs
7581 msg = "A cyclical module dependency or was detected in: "
7682
77−readDeps :: Bool -> FilePath -> IO [Deps]
78−readDeps noPrelude root = evalStateT (go root) Set.empty
83+readDeps :: [FilePath] -> Bool -> FilePath -> IO [Deps]
84+readDeps srcDirs noPrelude root = evalStateT (go root) Set.empty
7985 where
8086 builtIns = if noPrelude then Set.empty
8187 else Set.fromList (Map.keys Prelude.interfaces)
8288
8389 go :: FilePath -> StateT (Set.Set String) IO [Deps]
8490 go root = do
85− txt <- liftIO $ readFile root
91+ (root', txt) <- liftIO $ getFile srcDirs root
8692 case Parse.dependencies txt of
8793 Left err -> liftIO (putStrLn msg >> print err >> exitFailure)
88− where msg = "Error resolving dependencies in " ++ root ++ ":"
94+ where msg = "Error resolving dependencies in " ++ root' ++ ":"
8995
9096 Right (name,deps) ->
9197 do seen <- get
@@ -93,8 +99,21 @@ readDeps noPrelude root = evalStateT (go root) Set.empty
9399 newDeps = Set.difference (Set.filter (not . isNative) realDeps) seen
94100 put (Set.insert name (Set.union newDeps seen))
95101 rest <- mapM (go . toFilePath) (Set.toList newDeps)
96− return ((makeRelative "." root, name, Set.toList realDeps) : concat rest)
97−
102+ return ((makeRelative "." root', name, Set.toList realDeps) : concat rest)
103+
104+getFile :: [FilePath] -> FilePath -> IO (FilePath,String)
105+getFile [] path = do
106+ putStrLn $ unlines [ "Could not find file: " ++ path
107+ , " If it is not in the root directory of your project, use"
108+ , " --src-dir to declare additional locations for source files." ]
109+ exitFailure
110+
111+getFile (dir:dirs) path = do
112+ let path' = dir </> path
113+ exists <- doesFileExist path'
114+ case exists of
115+ True -> (,) path' `fmap` readFile path'
116+ False -> getFile dirs path
98117
99118isNative name = List.isPrefixOf "Native." name
100119
compiler/Language/Elm.hs+3−11
@@ -1,17 +1,16 @@
1−{- | This module exports the functions necessary for compiling Elm code into the
2− respective HTML, CSS, and JS code.
1+{- | This module exports the functions necessary for compiling Elm to JS,
2+ and some utilities for making it easier to find some Elm-related files.
33
44 The documentation for the Elm language is available at
55 <http://elm-lang.org/Documentation.elm>, and many interactive examples are
66 available at <http://elm-lang.org/Examples.elm>
77-}
8−module Language.Elm (compile, moduleName, runtime) where
8+module Language.Elm (compile, moduleName, runtime, docs) where
99
1010import qualified Data.List as List
1111import qualified Data.Map as Map
1212import Data.Version (showVersion)
1313import Generate.JavaScript (jsModule)
14−import Generate.Html (generateHtml)
1514import Initialize (buildFromSource)
1615import Parse.Module (getModuleName)
1716import SourceSyntax.Module
@@ -32,13 +31,6 @@ compile source =
3231moduleName :: String -> Maybe String
3332moduleName = getModuleName
3433
35−-- |This function compiles Elm code into a full HTML page.
36−toHtml :: String -- ^ Location of elm-min.js as expected by the browser
37− -> String -- ^ The page title
38− -> String -- ^ The elm source code
39− -> Html
40−toHtml = generateHtml
41−
4234-- |The absolute path to Elm's runtime system.
4335runtime :: IO FilePath
4436runtime = getDataFileName "elm-runtime.js"
compiler/Parse/Binop.hs+7−36
@@ -1,4 +1,4 @@
1−module Parse.Binop (binops, infixStmt, OpTable) where
1+module Parse.Binop (binops, OpTable) where
22
33import Control.Applicative ((<$>))
44import Control.Monad.Error
@@ -11,42 +11,23 @@ import SourceSyntax.Declaration (Assoc(..))
1111import Text.Parsec
1212import Parse.Helpers
1313
14−type OpTable = [(Int, Assoc, String)]
15−
16−preludeTable :: OpTable
17−preludeTable =
18− [ (9, R, ".")
19− , (8, R, "^")
20− , (7, L, "*"), (7, L, "/"), (7, L, "mod"), (7, L, "div"), (7, L, "rem")
21− , (6, L, "+"), (6, L, "-")
22− , (5, R, "::"), (5, R, "++")
23− , (4, N, "<="), (4, N, ">="), (4, N, "<")
24− , (4, N, "=="), (4, N, "/="), (4, N, ">")
25− , (4, L, "~"), (4, L, "<~")
26− , (3, R, "&&")
27− , (2, R, "||")
28− , (0, R, "<|"), (0, L, "|>")
29− ]
30−
3114opLevel :: OpTable -> String -> Int
32−opLevel table op = Map.findWithDefault 9 op dict
33− where dict = Map.fromList (map (\(lvl,_,op) -> (op,lvl)) table)
15+opLevel table op = fst $ Map.findWithDefault (9,L) op table
3416
3517opAssoc :: OpTable -> String -> Assoc
36−opAssoc table op = Map.findWithDefault R op dict
37− where dict = Map.fromList (map (\(_,assoc,op) -> (op,assoc)) table)
18+opAssoc table op = snd $ Map.findWithDefault (9,L) op table
3819
3920hasLevel :: OpTable -> Int -> (String, LExpr t v) -> Bool
4021hasLevel table n (op,_) = opLevel table op == n
4122
42−binops :: OpTable
43− -> IParser (LExpr t v)
23+binops :: IParser (LExpr t v)
4424 -> IParser (LExpr t v)
4525 -> IParser String
4626 -> IParser (LExpr t v)
47−binops table term last anyOp =
27+binops term last anyOp =
4828 do e <- term
49− split (table ++ preludeTable) 0 e =<< nextOps
29+ table <- getState
30+ split table 0 e =<< nextOps
5031 where
5132 nextOps = choice [ commitIf (whitespace >> anyOp) $ do
5233 whitespace ; op <- anyOp ; whitespace
@@ -101,13 +82,3 @@ getAssoc table n eops
10182 concat [ "Conflicting " ++ problem ++ " for binary operators ("
10283 , intercalate ", " (map fst eops), "). "
10384 , "Consider adding parentheses to disambiguate." ]
104−
105−infixStmt :: IParser (Int, Assoc, String)
106−infixStmt =
107− let infx str assoc = try (reserved ("infix" ++ str) >> return assoc) in
108− do assoc <- choice [ infx "l" L, infx "r" R, infx "" N ]
109− whitespace
110− prec <- do n <- digit ; return (read [n] :: Int)
111− whitespace
112− op <- anyOp
113− return (prec, assoc, op)
compiler/Parse/Declaration.hs+7−21
@@ -3,6 +3,7 @@ module Parse.Declaration where
33
44import Control.Applicative ((<$>), (<*>))
55import qualified Data.List as List
6+import qualified Data.Set as Set
67import Text.Parsec hiding (newline,spaces)
78import Text.Parsec.Indent
89import qualified Text.Pandoc as Pan
@@ -13,7 +14,6 @@ import qualified SourceSyntax.Type as T
1314import qualified Parse.Type as Type
1415import SourceSyntax.Declaration (Declaration(..), Assoc(..))
1516
16−import Unique
1717
1818declaration :: IParser (Declaration t v)
1919declaration = alias <|> datatype <|> infixDecl <|> foreignDef <|> definition
@@ -71,8 +71,8 @@ exportEvent = do
7171 T.Data "Signal" [t] ->
7272 case isExportable t of
7373 Nothing -> return (ExportEvent eventName elmVar tipe)
74− Just err -> error err
75− _ -> error "When importing foreign events, the imported value must have type Signal."
74+ Just err -> fail err
75+ _ -> fail "When importing foreign events, the imported value must have type Signal."
7676
7777importEvent :: IParser (Declaration t v)
7878importEvent = do
@@ -88,30 +88,16 @@ importEvent = do
8888 T.Data "Signal" [t] ->
8989 case isExportable t of
9090 Nothing -> return (ImportEvent eventName baseValue elmVar tipe)
91− Just err -> error err
92− _ -> error "When importing foreign events, the imported value must have type Signal."
91+ Just err -> fail err
92+ _ -> fail "When importing foreign events, the imported value must have type Signal."
9393
9494jsVar :: IParser String
9595jsVar = betwixt '"' '"' $ do
9696 v <- (:) <$> (letter <|> char '_') <*> many (alphaNum <|> char '_')
97− if v `notElem` jsReserveds then return v else
98− error $ "'" ++ v ++
97+ if Set.notMember v jsReserveds then return v else
98+ fail $ "'" ++ v ++
9999 "' is not a good name for a importing or exporting JS values."
100100
101−jsReserveds :: [String]
102−jsReserveds =
103− [ "null", "undefined", "Nan", "Infinity", "true", "false", "eval"
104− , "arguments", "int", "byte", "char", "goto", "long", "final", "float"
105− , "short", "double", "native", "throws", "boolean", "abstract", "volatile"
106− , "transient", "synchronized", "function", "break", "case", "catch"
107− , "continue", "debugger", "default", "delete", "do", "else", "finally"
108− , "for", "function", "if", "in", "instanceof", "new", "return", "switch"
109− , "this", "throw", "try", "typeof", "var", "void", "while", "with", "class"
110− , "const", "enum", "export", "extends", "import", "super", "implements"
111− , "interface", "let", "package", "private", "protected", "public"
112− , "static", "yield"
113− ]
114−
115101isExportable tipe =
116102 case tipe of
117103 T.Lambda _ _ ->
compiler/Parse/Expression.hs+45−44
@@ -1,5 +1,6 @@
1−module Parse.Expression (def,term) where
1+module Parse.Expression (def,term,typeAnnotation) where
22
3+import Control.Arrow ((***))
34import Control.Applicative ((<$>), (<*>))
45import Data.List (foldl')
56import Text.Parsec hiding (newline,spaces)
@@ -18,8 +19,6 @@ import qualified SourceSyntax.Literal as Literal
1819import SourceSyntax.Expression
1920import SourceSyntax.Declaration (Declaration(Definition))
2021
21−import Unique
22−
2322
2423-------- Basic Terms --------
2524
@@ -33,17 +32,14 @@ toVar v = case v of "True" -> Literal (Literal.Boolean True)
3332
3433accessor :: IParser (Expr t v)
3534accessor = do
36− start <- getPosition
37− lbl <- try (string "." >> rLabel)
38− end <- getPosition
35+ (start, lbl, end) <- located (try (string "." >> rLabel))
3936 let loc e = Location.at start end e
4037 return (Lambda (PVar "_") (loc $ Access (loc $ Var "_") lbl))
4138
4239negative :: IParser (Expr t v)
4340negative = do
44− start <- getPosition
45− nTerm <- try (char '-' >> notFollowedBy (char '.' <|> char '-')) >> term
46− end <- getPosition
41+ (start, nTerm, end) <-
42+ located (try (char '-' >> notFollowedBy (char '.' <|> char '-')) >> term)
4743 let loc e = Location.at start end e
4844 return (Binop "-" (loc $ Literal (Literal.IntNum 0)) nTerm)
4945
@@ -51,43 +47,51 @@ negative = do
5147-------- Complex Terms --------
5248
5349listTerm :: IParser (Expr t v)
54−listTerm =
55− (do { try $ string "[markdown|"
56− ; md <- filter (/='\r') <$> manyTill anyChar (try $ string "|]")
57− ; return . Markdown $ Pan.readMarkdown Pan.def md })
58− <|> (braces $ choice
59− [ try $ do { lo <- expr; whitespace; string ".." ; whitespace
60− ; Range lo <$> expr }
61− , ExplicitList <$> commaSep expr
62− ])
50+listTerm = markdown' <|> braces (try range <|> ExplicitList <$> commaSep expr)
51+ where
52+ range = do
53+ lo <- expr
54+ whitespace >> string ".." >> whitespace
55+ Range lo <$> expr
56+
57+ markdown' = do
58+ (rawText, exprs) <- markdown interpolation
59+ let md = Pan.readMarkdown Pan.def (filter (/='\r') rawText)
60+ return (Markdown md exprs)
61+
62+ span xs = "<span id=\"md" ++ show (length xs) ++
63+ "\" style=\"font-family:monospace;\">{{ ... }}</span>"
64+
65+ interpolation md exprs = do
66+ try (string "{{")
67+ whitespace
68+ e <- expr
69+ whitespace
70+ string "}}"
71+ return (md ++ span exprs, exprs ++ [e])
6372
6473parensTerm :: IParser (LExpr t v)
6574parensTerm = try (parens opFn) <|> parens (tupleFn <|> parened)
6675 where
6776 opFn = do
68− start <- getPosition
69− op <- anyOp
70− end <- getPosition
77+ (start, op, end) <- located anyOp
7178 let loc = Location.at start end
7279 return . loc . Lambda (PVar "x") . loc . Lambda (PVar "y") . loc $
7380 Binop op (loc $ Var "x") (loc $ Var "y")
7481
7582 tupleFn = do
76− start <- getPosition
7783 let comma = char ',' <?> "comma ','"
78− commas <- comma >> many (whitespace >> comma)
79− end <- getPosition
84+ (start, commas, end) <- located (comma >> many (whitespace >> comma))
8085 let vars = map (('v':) . show) [ 0 .. length commas + 1 ]
8186 loc = Location.at start end
8287 return $ foldr (\x e -> loc $ Lambda x e)
8388 (loc . tuple $ map (loc . Var) vars) (map PVar vars)
8489
8590 parened = do
86− start <- getPosition
87− es <- commaSep expr
88− end <- getPosition
89− return $ case es of [e] -> e
90− _ -> Location.at start end (tuple es)
91+ (start, es, end) <- located (commaSep expr)
92+ return $ case es of
93+ [e] -> e
94+ _ -> Location.at start end (tuple es)
9195
9296recordTerm :: IParser (LExpr t v)
9397recordTerm = brackets $ choice [ misc, addLocation record ]
@@ -144,7 +148,7 @@ appExpr = do
144148-------- Normal Expressions --------
145149
146150binaryExpr :: IParser (LExpr t v)
147−binaryExpr = binops [] appExpr lastExpr anyOp
151+binaryExpr = binops appExpr lastExpr anyOp
148152 where lastExpr = addLocation (choice [ ifExpr, letExpr, caseExpr ])
149153 <|> lambdaExpr
150154
@@ -196,7 +200,8 @@ expr = addLocation (choice [ ifExpr, letExpr, caseExpr ])
196200 <|> binaryExpr
197201 <?> "an expression"
198202
199−funcDef =
203+defStart :: IParser [Pattern]
204+defStart =
200205 choice [ do p1 <- try Pattern.term
201206 infics p1 <|> func p1
202207 , func =<< (PVar <$> parens symOp)
@@ -219,24 +224,20 @@ makeFunction :: [Pattern] -> LExpr t v -> LExpr t v
219224makeFunction args body@(L s _) =
220225 foldr (\arg body' -> L s $ Lambda arg body') body args
221226
222−assignExpr :: IParser (Def t v)
223−assignExpr = withPos $ do
224− (name:args) <- funcDef
227+definition :: IParser (Def t v)
228+definition = withPos $ do
229+ (name:args) <- defStart
225230 whitespace >> string "=" >> whitespace
226231 body <- expr
227232 return . Def name $ makeFunction args body
228233
229234typeAnnotation :: IParser (Def t v)
230235typeAnnotation = TypeAnnotation <$> try start <*> Type.expr
231− where
232− start = do v <- lowVar <|> parens symOp
233− whitespace ; hasType ; whitespace
234− return v
236+ where
237+ start = do
238+ v <- lowVar <|> parens symOp
239+ whitespace ; hasType ; whitespace
240+ return v
235241
236242def :: IParser (Def t v)
237−def = typeAnnotation <|> assignExpr
238−
239−attempt f parser str =
240− case iParse parser "" str of
241− Right result -> f result
242− Left err -> error $ "Parse error at " ++ show err
243+def = typeAnnotation <|> definition
compiler/Parse/Helpers.hs+102−19
@@ -1,12 +1,17 @@
11module Parse.Helpers where
22
3+import Prelude hiding (until)
34import Control.Applicative ((<$>),(<*>))
45import Control.Monad
56import Control.Monad.State
67import Data.Char (isUpper)
8+import qualified Data.Set as Set
9+import qualified Data.Map as Map
710import SourceSyntax.Helpers as Help
811import SourceSyntax.Location as Location
912import SourceSyntax.Expression
13+import SourceSyntax.PrettyPrint
14+import SourceSyntax.Declaration (Assoc)
1015import Text.Parsec hiding (newline,spaces,State)
1116import Text.Parsec.Indent
1217
@@ -18,13 +23,31 @@ reserveds = [ "if", "then", "else"
1823 , "import", "as", "hiding", "open"
1924 , "export", "foreign" ]
2025
26+jsReserveds :: Set.Set String
27+jsReserveds = Set.fromList
28+ [ "null", "undefined", "Nan", "Infinity", "true", "false", "eval"
29+ , "arguments", "int", "byte", "char", "goto", "long", "final", "float"
30+ , "short", "double", "native", "throws", "boolean", "abstract", "volatile"
31+ , "transient", "synchronized", "function", "break", "case", "catch"
32+ , "continue", "debugger", "default", "delete", "do", "else", "finally"
33+ , "for", "function", "if", "in", "instanceof", "new", "return", "switch"
34+ , "this", "throw", "try", "typeof", "var", "void", "while", "with", "class"
35+ , "const", "enum", "export", "extends", "import", "super", "implements"
36+ , "interface", "let", "package", "private", "protected", "public"
37+ , "static", "yield"
38+ ]
39+
2140expecting = flip (<?>)
2241
23−type IParser a = ParsecT String () (State SourcePos) a
42+type OpTable = Map.Map String (Int, Assoc)
43+type IParser a = ParsecT String OpTable (State SourcePos) a
44+
45+iParse :: IParser a -> String -> Either ParseError a
46+iParse = iParseWithTable "" Map.empty
2447
25−iParse :: IParser a -> SourceName -> String -> Either ParseError a
26−iParse aParser source_name input =
27− runIndent source_name $ runParserT aParser () source_name input
48+iParseWithTable :: SourceName -> OpTable -> IParser a -> String -> Either ParseError a
49+iParseWithTable sourceName table aParser input =
50+ runIndent sourceName $ runParserT aParser table sourceName input
2851
2952backslashed :: IParser Char
3053backslashed = do { char '\\'; c <- anyChar
@@ -49,13 +72,10 @@ rLabel = lowVar
4972innerVarChar :: IParser Char
5073innerVarChar = alphaNum <|> char '_' <|> char '\'' <?> ""
5174
52−deprime :: String -> String
53−deprime = map (\c -> if c == '\'' then '$' else c)
54−
5575makeVar :: IParser Char -> IParser String
5676makeVar p = do v <- (:) <$> p <*> many innerVarChar
5777 guard (v `notElem` reserveds)
58− return (deprime v)
78+ return v
5979
6080reserved :: String -> IParser String
6181reserved word =
@@ -147,12 +167,17 @@ parens = surround '(' ')' "paren"
147167brackets :: IParser a -> IParser a
148168brackets = surround '{' '}' "bracket"
149169
150−addLocation :: IParser (Expr t v) -> IParser (LExpr t v)
170+addLocation :: (Pretty a) => IParser a -> IParser (Location.Located a)
151171addLocation expr = do
172+ (start, e, end) <- located expr
173+ return (Location.at start end e)
174+
175+located :: IParser a -> IParser (SourcePos, a, SourcePos)
176+located p = do
152177 start <- getPosition
153− e <- expr
178+ e <- p
154179 end <- getPosition
155− return (Location.at start end e)
180+ return (start, e, end)
156181
157182accessible :: IParser (LExpr t v) -> IParser (LExpr t v)
158183accessible expr = do
@@ -200,16 +225,74 @@ simpleNewline = try (string "\r\n") <|> string "\n"
200225lineComment :: IParser String
201226lineComment = do
202227 try (string "--")
203− comment <- manyTill anyChar $ simpleNewline <|> (eof >> return "\n")
228+ comment <- anyUntil $ simpleNewline <|> (eof >> return "\n")
204229 return ("--" ++ comment)
205230
206231multiComment :: IParser String
207−multiComment = do { try (string "{-"); closeComment }
232+multiComment = (++) <$> try (string "{-") <*> closeComment
208233
209234closeComment :: IParser String
210−closeComment = do
211− comment <- manyTill anyChar . choice $
212− [ try (string "-}") <?> "close comment"
213− , do { try $ string "{-"; closeComment; closeComment }
214− ]
215− return ("{-" ++ comment ++ "-}")
235+closeComment =
236+ anyUntil . choice $
237+ [ try (string "-}") <?> "close comment"
238+ , concat <$> sequence [ try (string "{-"), closeComment, closeComment ]
239+ ]
240+
241+until :: IParser a -> IParser b -> IParser b
242+until p end = go
243+ where
244+ go = end <|> (p >> go)
245+
246+anyUntil :: IParser String -> IParser String
247+anyUntil end = go
248+ where
249+ go = end <|> (:) <$> anyChar <*> go
250+
251+ignoreUntil :: IParser a -> IParser (Maybe a)
252+ignoreUntil end = go
253+ where
254+ ignore p = const () <$> p
255+ filler = choice [ ignore multiComment
256+ , ignore (markdown (\_ _ -> mzero))
257+ , ignore anyChar
258+ ]
259+ go = choice [ Just <$> end
260+ , filler `until` choice [ const Nothing <$> eof, newline >> go ]
261+ ]
262+
263+onFreshLines :: (a -> b -> b) -> b -> IParser a -> IParser b
264+onFreshLines insert init thing = go init
265+ where
266+ go values = do
267+ optionValue <- ignoreUntil thing
268+ case optionValue of
269+ Nothing -> return values
270+ Just v -> go (insert v values)
271+
272+withSource :: IParser a -> IParser (String, a)
273+withSource p = do
274+ start <- getParserState
275+ result <- p
276+ endPos <- getPosition
277+ setParserState start
278+ raw <- anyUntilPos endPos
279+ return (raw, result)
280+
281+anyUntilPos :: SourcePos -> IParser String
282+anyUntilPos pos = go
283+ where
284+ go = do currentPos <- getPosition
285+ case currentPos == pos of
286+ True -> return []
287+ False -> (:) <$> anyChar <*> go
288+
289+markdown :: (String -> [a] -> IParser (String, [a])) -> IParser (String, [a])
290+markdown interpolation = try (string "[markdown|") >> closeMarkdown "" []
291+ where
292+ closeMarkdown md stuff =
293+ choice [ do try (string "|]")
294+ return (md, stuff)
295+ , uncurry closeMarkdown =<< interpolation md stuff
296+ , do c <- anyChar
297+ closeMarkdown (md ++ [c]) stuff
298+ ]
compiler/Parse/Literal.hs+4−1
@@ -14,10 +14,13 @@ num :: IParser Literal
1414num = fmap toLit (preNum <?> "number")
1515 where toLit n | '.' `elem` n = FloatNum (read n)
1616 | otherwise = IntNum (read n)
17− preNum = (++) <$> many1 digit <*> option "" postNum
17+ preNum = concat <$> sequence [ option "" minus, many1 digit, option "" postNum ]
1818 postNum = do try $ lookAhead (string "." >> digit)
1919 string "."
2020 ('.':) <$> many1 digit
21+ minus = try $ do string "-"
22+ lookAhead digit
23+ return "-"
2124
2225chr :: IParser Literal
2326chr = Chr <$> betwixt '\'' '\'' (backslashed <|> satisfy (/='\''))
compiler/Parse/Module.hs+1−1
@@ -13,7 +13,7 @@ varList = parens $ commaSep1 (var <|> parens symOp)
1313
1414getModuleName :: String -> Maybe String
1515getModuleName source =
16− case iParse getModuleName "" source of
16+ case iParse getModuleName source of
1717 Right name -> Just name
1818 Left _ -> Nothing
1919 where
compiler/Parse/Parse.hs+27−4
@@ -4,13 +4,16 @@ import Control.Applicative ((<$>), (<*>))
44import Control.Monad
55import Data.Char (isSymbol, isDigit)
66import Data.List (foldl',intercalate)
7+import qualified Data.Map as Map
78import Text.Parsec hiding (newline,spaces)
89import qualified Text.PrettyPrint as P
910
1011import qualified SourceSyntax.Module as S
12+import SourceSyntax.Declaration (Declaration(Fixity))
1113import Parse.Helpers
12−import Parse.Binop (infixStmt, OpTable)
14+import Parse.Binop (OpTable)
1315import Parse.Expression
16+import Parse.Declaration (infixDecl)
1417import Parse.Type
1518import Parse.Module
1619import qualified Parse.Declaration as Decl
@@ -22,8 +25,8 @@ freshDef = commitIf (freshLine >> (letter <|> char '_')) $ do
2225decls = do d <- Decl.declaration <?> "at least one datatype or variable definition"
2326 (d:) <$> many freshDef
2427
25−program :: String -> Either [P.Doc] (S.Module t v)
26−program = setupParser $ do
28+program :: OpTable -> String -> Either [P.Doc] (S.Module t v)
29+program table = setupParserWithTable table $ do
2730 optional freshLine
2831 (names,exports) <- option (["Main"],[]) (moduleDef `followedBy` freshLine)
2932 is <- (do try (lookAhead $ reserved "import")
@@ -40,8 +43,28 @@ dependencies =
4043 (,) <$> option "Main" (getName <$> moduleDef `followedBy` freshLine)
4144 <*> option [] (map fst <$> imports `followedBy` freshLine)
4245
46+setupParserWithTable :: OpTable -> IParser a -> String -> Either [P.Doc] a
47+setupParserWithTable table p source =
48+ do localTable <- setupParser parseFixities source
49+ case Map.intersection table localTable of
50+ overlap | not (Map.null overlap) -> Left [ msg overlap ]
51+ | otherwise ->
52+ flip setupParser source $ do
53+ putState (Map.union table localTable)
54+ p
55+ where
56+ msg overlap =
57+ P.vcat [ P.text "Parse error:"
58+ , P.text $ "Overlapping definitions for infix operators: " ++
59+ intercalate " " (Map.keys overlap)
60+ ]
61+
62+parseFixities = do
63+ decls <- onFreshLines (:) [] infixDecl
64+ return $ Map.fromList [ (op,(lvl,assoc)) | Fixity assoc lvl op <- decls ]
65+
4366setupParser :: IParser a -> String -> Either [P.Doc] a
4467setupParser p source =
45− case iParse p "" source of
68+ case iParse p source of
4669 Right result -> Right result
4770 Left err -> Left [ P.text $ "Parse error at " ++ show err ]
compiler/Parse/Pattern.hs+1−6
@@ -6,7 +6,6 @@ import Control.Monad
66import Control.Monad.State
77import Data.Char (isUpper)
88import Data.List (intercalate)
9−import Unique
109import Text.Parsec hiding (newline,spaces,State)
1110import Text.Parsec.Indent
1211
@@ -24,11 +23,7 @@ basic = choice
2423 "True" -> PLiteral (Boolean True)
2524 "False" -> PLiteral (Boolean False)
2625 c : _ -> if isUpper c then PData v [] else PVar v
27− , do lit <- literal
28− return $ case lit of
29− Str s -> foldr combine (PData "[]" []) s
30− where combine h t = PData "::" [PLiteral (Chr h),t]
31− _ -> PLiteral lit
26+ , PLiteral <$> literal
3227 ]
3328
3429asPattern :: Pattern -> IParser Pattern
compiler/Parse/Type.hs+3−12
@@ -9,7 +9,6 @@ import Text.Parsec.Indent
99
1010import SourceSyntax.Type as T
1111import Parse.Helpers
12−import Unique
1312
1413tvar :: IParser T.Type
1514tvar = T.Var <$> lowVar <?> "type variable"
@@ -35,7 +34,7 @@ record =
3534 t <- tvar
3635 whitespace >> string "|" >> whitespace
3736 return t
38− fields = commaSep $ do
37+ fields = commaSep1 $ do
3938 lbl <- rLabel
4039 whitespace >> hasType >> whitespace
4140 (,) lbl <$> expr
@@ -63,19 +62,11 @@ app =
6362expr :: IParser T.Type
6463expr =
6564 do t1 <- app <|> term
66− whitespace
67− arr <- optionMaybe (try arrow)
68− whitespace
65+ arr <- optionMaybe $ try (whitespace >> arrow)
6966 case arr of
70− Just _ -> T.Lambda t1 <$> expr
67+ Just _ -> T.Lambda t1 <$> (whitespace >> expr)
7168 Nothing -> return t1
7269
7370constructor :: IParser (String, [T.Type])
7471constructor = (,) <$> (capTypeVar <?> "another type constructor")
7572 <*> spacePrefix term
76−
77−readType :: String -> Type
78−readType str =
79− case iParse expr "" str of
80− Left err -> error (show err)
81− Right tipe -> tipe
compiler/SourceSyntax/Declaration.hs+8−1
@@ -15,4 +15,11 @@ data Declaration tipe var
1515 deriving (Eq, Show)
1616
1717data Assoc = L | N | R
18− deriving (Eq, Show)
18+ deriving (Eq)
19+
20+instance Show Assoc where
21+ show assoc =
22+ case assoc of
23+ L -> "left"
24+ N -> "non"
25+ R -> "right"
compiler/SourceSyntax/Expression.hs+4−2
@@ -30,7 +30,7 @@ data Expr t v
3030 | Insert (LExpr t v) String (LExpr t v)
3131 | Modify (LExpr t v) [(String, LExpr t v)]
3232 | Record [(String, LExpr t v)]
33− | Markdown Pandoc.Pandoc
33+ | Markdown Pandoc.Pandoc [LExpr t v]
3434 deriving (Eq, Show, Data, Typeable)
3535
3636data Def tipe var
@@ -55,6 +55,8 @@ instance Pretty (Expr t v) where
5555 Var x -> variable x
5656 Range e1 e2 -> P.brackets (pretty e1 <> P.text ".." <> pretty e2)
5757 ExplicitList es -> P.brackets (commaCat (map pretty es))
58+ Binop "-" (Location.L _ (Literal (Literal.IntNum 0))) e ->
59+ P.text "-" <> prettyParens e
5860 Binop op e1 e2 -> P.sep [ prettyParens e1 <+> P.text op', prettyParens e2 ]
5961 where op' = if Help.isOp op then op else "`" ++ op ++ "`"
6062 Lambda p e -> let (ps,body) = collectLambdas (Location.none $ Lambda p e)
@@ -94,7 +96,7 @@ instance Pretty (Expr t v) where
9496 where
9597 field (x,e) = variable x <+> P.text "=" <+> pretty e
9698
97− Markdown _ -> P.text "[markdown| ... |]"
99+ Markdown _ _ -> P.text "[markdown| ... |]"
98100
99101instance Pretty (Def t v) where
100102 pretty def =
compiler/SourceSyntax/Literal.hs+2−2
@@ -6,7 +6,7 @@ import SourceSyntax.PrettyPrint
66import qualified Text.PrettyPrint as PP
77
88data Literal = IntNum Int
9− | FloatNum Float
9+ | FloatNum Double
1010 | Chr Char
1111 | Str String
1212 | Boolean Bool
@@ -16,7 +16,7 @@ instance Pretty Literal where
1616 pretty literal =
1717 case literal of
1818 IntNum n -> PP.int n
19− FloatNum n -> PP.float n
19+ FloatNum n -> PP.double n
2020 Chr c -> PP.quotes (PP.char c)
2121 Str s -> PP.text (show s)
2222 Boolean bool -> PP.text (show bool)
compiler/SourceSyntax/Module.hs+17−5
@@ -41,11 +41,23 @@ type Interfaces = Map.Map String ModuleInterface
4141type ADT = (String, [String], [(String,[Type])])
4242
4343data ModuleInterface = ModuleInterface {
44− iTypes :: Map.Map String Type,
45− iAdts :: [ADT],
46− iAliases :: [(String, [String], Type)]
44+ iTypes :: Map.Map String Type,
45+ iAdts :: [ADT],
46+ iAliases :: [(String, [String], Type)],
47+ iFixities :: [(Assoc, Int, String)]
4748} deriving Show
4849
4950instance Binary ModuleInterface where
50− put modul = put (iTypes modul) >> put (iAdts modul) >> put (iAliases modul)
51− get = ModuleInterface <$> get <*> get <*> get
51+ get = ModuleInterface <$> get <*> get <*> get <*> get
52+ put modul = do
53+ put (iTypes modul)
54+ put (iAdts modul)
55+ put (iAliases modul)
56+ put (iFixities modul)
57+
58+
59+instance Binary Assoc where
60+ get = do n <- getWord8
61+ return $ case n of { 0 -> L ; 1 -> N ; 2 -> R }
62+
63+ put assoc = putWord8 $ case assoc of { L -> 0 ; N -> 1 ; R -> 2 }
compiler/Transform/Canonicalize.hs+17−7
@@ -18,10 +18,11 @@ import Text.PrettyPrint as P
1818
1919interface :: String -> ModuleInterface -> ModuleInterface
2020interface moduleName iface =
21− ModuleInterface {
22− iTypes = Map.mapKeys prefix (Map.map renameType' (iTypes iface)),
23− iAdts = map (both prefix renameCtors) (iAdts iface),
24− iAliases = map (both prefix renameType') (iAliases iface)
21+ ModuleInterface
22+ { iTypes = Map.mapKeys prefix (Map.map renameType' (iTypes iface))
23+ , iAdts = map (both prefix renameCtors) (iAdts iface)
24+ , iAliases = map (both prefix renameType') (iAliases iface)
25+ , iFixities = iFixities iface -- cannot have canonicalized operators while parsing
2526 }
2627 where
2728 both f g (a,b,c) = (f a, b, g c)
@@ -56,10 +57,19 @@ metadataModule ifaces modul =
5657 program' <- rename initialEnv (program modul)
5758 aliases' <- mapM (third renameType') (aliases modul)
5859 datatypes' <- mapM (third (mapM (second (mapM renameType')))) (datatypes modul)
59− return $ modul { program = program', aliases = aliases', datatypes = datatypes' }
60+ exports' <- mapM (third renameType') (foreignExports modul)
61+ imports' <- mapM (twoAndFour (rename initialEnv) renameType') (foreignImports modul)
62+ return $ modul { program = program'
63+ , aliases = aliases'
64+ , datatypes = datatypes'
65+ , foreignExports = exports'
66+ , foreignImports = imports' }
6067 where
6168 second f (a,b) = (,) a `fmap` f b
6269 third f (a,b,c) = (,,) a b `fmap` f c
70+ twoAndFour f g (a,b,c,d) = do b' <- f b
71+ d' <- g d
72+ return (a,b',c,d')
6373 renameType' =
6474 Either.either (\err -> Left [P.text err]) return . renameType (replace "type" initialEnv)
6575
@@ -79,7 +89,7 @@ metadataModule ifaces modul =
7989
8090 pair n = (n,n)
8191 localEnv = map pair (map get1 (aliases modul) ++ map get1 (datatypes modul))
82− globalEnv = map pair $ ["_List",saveEnvName,"::","[]","Int","Float","Char","Bool"] ++
92+ globalEnv = map pair $ ["_List",saveEnvName,"::","[]","Int","Float","Char","Bool","String"] ++
8393 map (\n -> "_Tuple" ++ show n) [0..9]
8494 realImports = filter (not . List.isPrefixOf "Native." . fst) (imports modul)
8595 initialEnv = Map.fromList (concatMap canon realImports ++ localEnv ++ globalEnv)
@@ -163,7 +173,7 @@ rename env lexpr@(L s expr) =
163173 branch (pattern,e) = (,) `liftM` format (renamePattern env pattern)
164174 `ap` rename (extend env pattern) e
165175
166− Markdown _ -> return expr
176+ Markdown md es -> Markdown md `liftM` mapM rnm es
167177
168178
169179renamePattern :: Env -> Pattern -> Either String Pattern
compiler/Transform/LetBoundVars.hsdeleted−54
@@ -1,54 +0,0 @@
1−module LetBoundVars (letBoundVars) where
2−
3−import Context
4−import Ast
5−
6−class LetBoundVars a where
7− letBoundVars :: a -> [String]
8−
9−instance LetBoundVars a => LetBoundVars [a] where
10− letBoundVars = concatMap letBoundVars
11−
12−instance LetBoundVars Statement where
13− letBoundVars stmt =
14− case stmt of
15− Definition d -> letBoundVars d
16− Datatype _ _ tcs -> []
17− ImportEvent _ e _ _ -> letBoundVars e
18− ExportEvent _ _ _ -> []
19− TypeAnnotation _ _ -> []
20− TypeAlias _ _ _ -> []
21−
22−instance LetBoundVars Def where
23− letBoundVars (FnDef n _ e) = n : letBoundVars e
24− letBoundVars (OpDef _ _ _ e) = letBoundVars e
25− letBoundVars _ = []
26−
27−instance LetBoundVars e => LetBoundVars (Context e) where
28− letBoundVars (C _ _ e) = letBoundVars e
29−
30−instance LetBoundVars Expr where
31− letBoundVars expr =
32− let f = letBoundVars in
33− case expr of
34− IntNum _ -> []
35− FloatNum _ -> []
36− Chr _ -> []
37− Str _ -> []
38− Boolean _ -> []
39− Range e1 e2 -> f e1 ++ f e2
40− Access e _ -> []
41− Remove e _ -> []
42− Insert e1 _ e2 -> f e1 ++ f e2
43− Modify e ps -> f e ++ concatMap (f . snd) ps
44− Record trps -> concatMap (\(_,_,e) -> f e) trps
45− Binop op e1 e2 -> f e1 ++ f e2
46− Lambda x e -> f e
47− App e1 e2 -> f e1 ++ f e2
48− If e1 e2 e3 -> concatMap f [e1,e2,e3]
49− MultiIf ps -> concatMap (\(b,e) -> f b ++ f e) ps
50− Let defs e -> concatMap letBoundVars defs ++ f e
51− Var x -> []
52− Data name es -> concatMap f es
53− Case e cases -> f e ++ concatMap (f . snd) cases
54− Markdown _ -> []
compiler/Transform/Replace.hsdeleted−60
@@ -1,60 +0,0 @@
1−module Replace (replace, depth) where
2−
3−import Ast
4−import Control.Arrow ((***))
5−import Data.Set (singleton,empty,unions,member, Set)
6−
7−replace :: String -> Expr -> Expr -> Expr
8−replace y v expr =
9− let f = replace y v in
10− case expr of
11− Range e1 e2 -> Range (f e1) (f e2)
12− Access e x -> Access (f e) x
13− Binop op e1 e2 -> Binop op (f e1) (f e2)
14− App e1 e2 -> App (f e1) (f e2)
15− If e1 e2 e3 -> If (f e1) (f e2) (f e3)
16− Guard ps -> map (f *** f) ps
17− Lift e es -> Lift (f e) (map f es)
18− Fold e1 e2 e3 -> Fold (f e1) (f e2) (f e3)
19− Async e -> Async (f e)
20− Let defs e -> if y `elem` vs then Let defs e else Let (zip vs (map f es)) (f e)
21− where (vs,es) = unzip defs
22− Var x -> if x == y then v else Var x
23− ExplicitList es -> ExplicitList (map f es)
24− Data name es -> Data name (map f es)
25− Case e cases -> Case (f e) $ map (caseReplace y v) cases
26− _ -> expr
27−
28−caseReplace :: String -> Expr -> (Pattern, Expr) -> (Pattern, Expr)
29−caseReplace y v (p,e) =
30− if member y (patternVars p) then (p,e) else (p, replace y v e)
31−
32−patternVars :: Pattern -> Set String
33−patternVars pattern =
34− case pattern of
35− PData _ ps -> unions (map patternVars ps)
36− PVar x -> singleton x
37− PAsVar x p -> insert x (patternVars p)
38− PAnything -> empty
39− PLiteral _ -> empty
40−
41−depth :: Expr -> Integer
42−depth = depth' 0
43−depth' d expr =
44− let f = depth' (d+1) in
45− case expr of
46− Range e1 e2 -> max (f e1) (f e2)
47− Access e x -> f e
48− Binop op e1 e2 -> max (f e1) (f e2)
49− Lambda x e -> f e
50− App e1 e2 -> max (f e1) (f e2)
51− If e1 e2 e3 -> maximum [f e1, f e2, f e3]
52− Guard ps -> maximum (map (uncurry max . f *** f) ps)
53− Lift e es -> maximum $ f e : map f es
54− Fold e1 e2 e3 -> maximum [f e1, f e2, f e3]
55− Async e -> f e
56− Let defs e -> let (_,es) = unzip defs in maximum $ f e : map f es
57− Data "::" es -> maximum $ map (depth' d) es
58− Data name es -> maximum $ 1 : map f es
59− Case e cases -> maximum $ f e : map (f . snd) cases
60− _ -> d
compiler/Transform/SortDefinitions.hs+1−1
@@ -97,7 +97,7 @@ reorder lexpr@(L s expr) =
9797 Record fields ->
9898 Record `liftM` mapM reorderField fields
9999
100− Markdown _ -> return expr
100+ Markdown md es -> Markdown md <$> mapM reorder es
101101
102102 -- Actually do some reordering
103103 Let defs body ->
compiler/Transform/Substitute.hs+19−6
@@ -1,9 +1,11 @@
11{-# OPTIONS_GHC -Wall #-}
22module Transform.Substitute (subst) where
33
4+import Control.Arrow (second, (***))
45import SourceSyntax.Expression
56import SourceSyntax.Location
6−import Control.Arrow (second, (***))
7+import qualified Data.Set as Set
8+import qualified Transform.SortDefinitions as SD
79
810subst :: String -> Expr t v -> Expr t v -> Expr t v
911subst old new expr =
@@ -12,12 +14,23 @@ subst old new expr =
1214 Range e1 e2 -> Range (f e1) (f e2)
1315 ExplicitList es -> ExplicitList (map f es)
1416 Binop op e1 e2 -> Binop op (f e1) (f e2)
15− Lambda p e -> Lambda p (f e)
17+ Lambda p e
18+ | Set.member old (SD.boundVars p) -> expr
19+ | otherwise -> Lambda p (f e)
1620 App e1 e2 -> App (f e1) (f e2)
1721 MultiIf ps -> MultiIf (map (f *** f) ps)
18− Let defs body -> Let (map substDef defs) (f body)
19− where substDef (Def name e) = Def name (f e)
20− substDef anno@(TypeAnnotation _ _) = anno
22+
23+ Let defs body
24+ | anyShadow -> expr
25+ | otherwise -> Let (map substDef defs) (f body)
26+ where
27+ anyShadow =
28+ any (Set.member old . SD.boundVars) [ p | Def p _ <- defs ]
29+ substDef def =
30+ case def of
31+ TypeAnnotation _ _ -> def
32+ Def p e -> Def p (f e)
33+
2134 Var x -> if x == old then new else expr
2235 Case e cases -> Case (f e) $ map (second f) cases
2336 Data name es -> Data name (map f es)
@@ -27,4 +40,4 @@ subst old new expr =
2740 Modify r fs -> Modify (f r) (map (second f) fs)
2841 Record fs -> Record (map (second f) fs)
2942 Literal _ -> expr
30− Markdown _ -> expr
43+ Markdown md es -> Markdown md (map f es)
compiler/Type/Alias.hs+20−4
@@ -56,14 +56,16 @@ localizer metaModule = go
5656realias :: Rules -> Type -> Type
5757realias (aliases,localize) tipe = localize (canonicalRealias aliases tipe)
5858
59+-- Realias using canonical aliases, so results will have aliases
60+-- that are fully qualified and possible to compare.
5961canonicalRealias :: [(String,[String],Type)] -> Type -> Type
6062canonicalRealias aliases tipe =
6163 case concatMap tryRealias aliases of
62− [tipe''] -> f tipe''
63− _ -> if tipe == tipe' then tipe else f tipe'
64+ [] -> if tipe == tipe' then tipe else f tipe'
65+ tipes -> f (bestType tipes)
6466 where
65− tryRealias (name, args, t) =
66− case diff t tipe of
67+ tryRealias (name, args, aliasTipe) =
68+ case diff aliasTipe tipe of
6769 Nothing -> []
6870 Just kvs ->
6971 let holes = collectFields kvs
@@ -85,6 +87,20 @@ canonicalRealias aliases tipe =
8587allEqual [] = True
8688allEqual (x:xs) = all (==x) xs
8789
90+bestType tipes = fst $ List.minimumBy (\a b -> compare (snd a) (snd b)) pairs
91+ where
92+ pairs :: [(Type,Int)]
93+ pairs = zip tipes (map numFields tipes)
94+
95+ numFields :: Type -> Int
96+ numFields tipe =
97+ case tipe of
98+ Lambda t1 t2 -> numFields t1 + numFields t2
99+ Var _ -> 0
100+ Data _ ts -> sum (map numFields ts)
101+ EmptyRecord -> 0
102+ Record fields ext -> length fields + sum (map (numFields . snd) fields) + numFields ext
103+
88104diff :: Type -> Type -> Maybe [(String,Type)]
89105diff general specific =
90106 case (general, specific) of
compiler/Type/Constrain/Expression.hs+22−18
@@ -6,9 +6,10 @@ import qualified Data.Set as Set
66import Control.Arrow (second)
77import Control.Applicative ((<$>),(<*>))
88import qualified Control.Monad as Monad
9−import Control.Monad.Error (ErrorT, runErrorT)
9+import Control.Monad.Error
1010import Control.Monad.State
1111import Data.Traversable (traverse)
12+import qualified Text.PrettyPrint as PP
1213
1314import SourceSyntax.Location as Loc
1415import SourceSyntax.Pattern (Pattern(PVar))
@@ -22,7 +23,7 @@ import qualified Type.Constrain.Pattern as Pattern
2223import qualified Transform.SortDefinitions as SD
2324
2425
25−constrain :: Env.Environment -> LExpr a b -> Type -> IO TypeConstraint
26+constrain :: Env.Environment -> LExpr a b -> Type -> ErrorT [PP.Doc] IO TypeConstraint
2627constrain env (L span expr) tipe =
2728 let list t = Env.get env Env.types "_List" <| t
2829 and = L span . CAnd
@@ -32,7 +33,7 @@ constrain env (L span expr) tipe =
3233 clet schemes c = L span (CLet schemes c)
3334 in
3435 case expr of
35− Literal lit -> Literal.constrain env span lit tipe
36+ Literal lit -> liftIO $ Literal.constrain env span lit tipe
3637
3738 Var name | name == saveEnvName -> return (L span CSaveEnv)
3839 | otherwise -> return (name <? tipe)
@@ -87,7 +88,7 @@ constrain env (L span expr) tipe =
8788 and . (:) ce <$> mapM branch branches
8889
8990 Data name exprs ->
90− do vars <- forM exprs $ \_ -> var Flexible
91+ do vars <- forM exprs $ \_ -> liftIO (var Flexible)
9192 let pairs = zip exprs (map VarN vars)
9293 (ctipe, cs) <- Monad.foldM step (tipe,true) (reverse pairs)
9394 return $ ex vars (cs /\ name <? ctipe)
@@ -114,11 +115,11 @@ constrain env (L span expr) tipe =
114115
115116 Modify e fields ->
116117 exists $ \t -> do
117− oldVars <- forM fields $ \_ -> var Flexible
118+ oldVars <- forM fields $ \_ -> liftIO (var Flexible)
118119 let oldFields = SrcT.fieldMap (zip (map fst fields) (map VarN oldVars))
119120 cOld <- ex oldVars <$> constrain env e (record oldFields t)
120121
121− newVars <- forM fields $ \_ -> var Flexible
122+ newVars <- forM fields $ \_ -> liftIO (var Flexible)
122123 let newFields = SrcT.fieldMap (zip (map fst fields) (map VarN newVars))
123124 let cNew = tipe === record newFields t
124125
@@ -127,14 +128,17 @@ constrain env (L span expr) tipe =
127128 return $ cOld /\ ex newVars (and (cNew : cs))
128129
129130 Record fields ->
130− do vars <- forM fields $ \_ -> var Flexible
131+ do vars <- forM fields $ \_ -> liftIO (var Flexible)
131132 cs <- zipWithM (constrain env) (map snd fields) (map VarN vars)
132133 let fields' = SrcT.fieldMap (zip (map fst fields) (map VarN vars))
133134 recordType = record fields' (TermN EmptyRecord1)
134135 return . ex vars . and $ tipe === recordType : cs
135136
136− Markdown _ ->
137− return ("Graphics.Element.markdown" <? tipe)
137+ Markdown _ es ->
138+ do vars <- forM es $ \_ -> liftIO (var Flexible)
139+ let tvars = map VarN vars
140+ cs <- zipWithM (constrain env) es tvars
141+ return . ex vars $ and ("Text.markdown" <? tipe : cs)
138142
139143 Let defs body ->
140144 do c <- constrain env body tipe
@@ -146,15 +150,16 @@ constrain env (L span expr) tipe =
146150 (clet [Scheme rqs fqs (clet [monoscheme header] c2) header ]
147151 (c1 /\ c))
148152
153+
149154constrainDef env info (pattern, expr, maybeTipe) =
150155 let qs = [] -- should come from the def, but I'm not sure what would live there...
151156 (schemes, rigidQuantifiers, flexibleQuantifiers, headers, c2, c1) = info
152157 in
153− do rigidVars <- mapM (\_ -> var Rigid) qs -- Some mistake may be happening here.
154− -- Currently, qs is always the empty list.
158+ do rigidVars <- forM qs (\_ -> liftIO $ var Rigid) -- Some mistake may be happening here.
159+ -- Currently, qs is always [].
155160 case (pattern, maybeTipe) of
156161 (PVar name, Just tipe) -> do
157− flexiVars <- mapM (\_ -> var Flexible) qs
162+ flexiVars <- forM qs (\_ -> liftIO $ var Flexible)
158163 let inserts = zipWith (\arg typ -> Map.insert arg (VarN typ)) qs flexiVars
159164 env' = env { Env.value = List.foldl' (\x f -> f x) (Env.value env) inserts }
160165 (vars, typ) <- Env.instantiateType env tipe Map.empty
@@ -171,7 +176,7 @@ constrainDef env info (pattern, expr, maybeTipe) =
171176 , fl rigidVars c /\ c1 )
172177
173178 (PVar name, Nothing) -> do
174− v <- var Flexible
179+ v <- liftIO $ var Flexible
175180 let tipe = VarN v
176181 inserts = zipWith (\arg typ -> Map.insert arg (VarN typ)) qs rigidVars
177182 env' = env { Env.value = List.foldl' (\x f -> f x) (Env.value env) inserts }
@@ -183,7 +188,6 @@ constrainDef env info (pattern, expr, maybeTipe) =
183188 , c /\ c2
184189 , c1 )
185190
186−
187191expandPattern :: (Pattern, LExpr t v, Maybe SrcT.Type)
188192 -> [(Pattern, LExpr t v, Maybe SrcT.Type)]
189193expandPattern triple@(pattern, lexpr@(L s _), maybeType) =
@@ -212,9 +216,9 @@ collapseDefs = concatMap expandPattern . go [] Map.empty Map.empty
212216 TypeAnnotation name typ ->
213217 go output defs (Map.insert name typ typs) ds
214218
215−try :: SrcSpan -> ErrorT String IO a -> IO a
219+try :: SrcSpan -> ErrorT (SrcSpan -> PP.Doc) IO a -> ErrorT [PP.Doc] IO a
216220try span computation = do
217− result <- runErrorT computation
221+ result <- liftIO $ runErrorT computation
218222 case result of
219− Left msg -> error $ "\nType error " ++ show span ++ "\n" ++ msg
220− Right value -> return value
223+ Left err -> throwError [err span]
224+ Right value -> return value
compiler/Type/Constrain/Literal.hs+5−5
@@ -10,12 +10,12 @@ constrain env span literal tipe =
1010 do tipe' <- litType
1111 return . L span $ CEqual tipe tipe'
1212 where
13− prim name = Env.get env Env.types name
13+ prim name = return (Env.get env Env.types name)
1414
1515 litType =
1616 case literal of
1717 IntNum _ -> VarN `fmap` var (Is Number)
18− FloatNum _ -> return (prim "Float")
19− Chr _ -> return (prim "Char")
20− Str _ -> return (TermN (App1 (prim "_List") (prim "Char")))
21− Boolean _ -> return (prim "Bool")
18+ FloatNum _ -> prim "Float"
19+ Chr _ -> prim "Char"
20+ Str _ -> prim "String"
21+ Boolean _ -> prim "Bool"
compiler/Type/Constrain/Pattern.hs+16−3
@@ -1,3 +1,4 @@
1+{-# LANGUAGE FlexibleInstances #-}
12module Type.Constrain.Pattern where
23
34import Control.Arrow (second)
@@ -7,8 +8,10 @@ import Control.Monad.Error
78import qualified Data.List as List
89import qualified Data.Maybe as Maybe
910import qualified Data.Map as Map
11+import qualified Text.PrettyPrint as PP
1012
1113import SourceSyntax.Pattern
14+import SourceSyntax.Location
1215import SourceSyntax.PrettyPrint
1316import Text.PrettyPrint (render)
1417import qualified SourceSyntax.Location as Loc
@@ -18,7 +21,7 @@ import Type.Environment as Env
1821import qualified Type.Constrain.Literal as Literal
1922
2023
21−constrain :: Environment -> Pattern -> Type -> ErrorT String IO Fragment
24+constrain :: Environment -> Pattern -> Type -> ErrorT (SrcSpan -> PP.Doc) IO Fragment
2225constrain env pattern tipe =
2326 let span = Loc.NoSpan (render $ pretty pattern)
2427 t1 === t2 = Loc.L span (CEqual t1 t2)
@@ -51,7 +54,11 @@ constrain env pattern tipe =
5154 let msg = concat [ "Constructor '", name, "' expects ", show kind
5255 , " argument", if kind == 1 then "" else "s"
5356 , " but was given ", show (length patterns), "." ]
54− if length patterns /= kind then throwError msg else do
57+ err span = PP.vcat [ PP.text $ "Type error " ++ show span
58+ , PP.text msg ]
59+ case length patterns == kind of
60+ False -> throwError err
61+ True -> do
5562 fragment <- Monad.liftM joinFragments (Monad.zipWithM (constrain env) patterns args)
5663 return $ fragment {
5764 typeConstraint = typeConstraint fragment /\ tipe === result,
@@ -61,9 +68,15 @@ constrain env pattern tipe =
6168 PRecord fields -> do
6269 pairs <- liftIO $ mapM (\name -> (,) name <$> var Flexible) fields
6370 let tenv = Map.fromList (map (second VarN) pairs)
64− c <- liftIO . exists $ \t -> return (tipe === record (Map.map (:[]) tenv) t)
71+ c <- exists $ \t -> return (tipe === record (Map.map (:[]) tenv) t)
6572 return $ Fragment {
6673 typeEnv = tenv,
6774 vars = map snd pairs,
6875 typeConstraint = c
6976 }
77+
78+instance Error (SrcSpan -> PP.Doc) where
79+ noMsg _ = PP.empty
80+ strMsg str span =
81+ PP.vcat [ PP.text $ "Type error " ++ show span
82+ , PP.text str ]
compiler/Type/Environment.hs+13−8
@@ -1,12 +1,16 @@
11module Type.Environment where
22
33import Control.Applicative ((<$>), (<*>))
4+import Control.Exception (try, SomeException)
45import Control.Monad
6+import Control.Monad.Trans.Error (ErrorList(..))
7+import Control.Monad.Error (ErrorT, throwError, liftIO)
58import qualified Control.Monad.State as State
69import qualified Data.Traversable as Traverse
710import qualified Data.Map as Map
811import Data.List (isPrefixOf)
912import qualified Data.UnionFind.IO as UF
13+import qualified Text.PrettyPrint as PP
1014
1115import qualified SourceSyntax.Type as Src
1216import SourceSyntax.Module (ADT)
@@ -51,7 +55,7 @@ makeTypes datatypes =
5155 builtins :: [(String,Int)]
5256 builtins = concat [ map tuple [0..9]
5357 , kind 1 ["_List"]
54− , kind 0 ["Int","Float","Char","Bool"]
58+ , kind 0 ["Int","Float","Char","String","Bool"]
5559 ]
5660
5761
@@ -105,11 +109,15 @@ get env subDict key = Map.findWithDefault err key (subDict env)
105109freshDataScheme :: Environment -> String -> IO (Int, [Variable], [Type], Type)
106110freshDataScheme env name = get env constructor name
107111
108−instantiateType ::
109− Environment -> Src.Type -> VarDict -> IO ([Variable], Type)
112+instance ErrorList PP.Doc where
113+ listMsg str = [PP.text str]
114+
115+instantiateType :: Environment -> Src.Type -> VarDict -> ErrorT [PP.Doc] IO ([Variable], Type)
110116instantiateType env sourceType dict =
111− do (tipe, (dict',_)) <- State.runStateT (instantiator env sourceType) (dict, Map.empty)
112− return (Map.elems dict', tipe)
117+ do result <- liftIO $ try (State.runStateT (instantiator env sourceType) (dict, Map.empty))
118+ case result :: Either SomeException (Type, (VarDict, TypeDict)) of
119+ Left someError -> throwError [ PP.text $ show someError ]
120+ Right (tipe, (dict',_)) -> return (Map.elems dict', tipe)
113121
114122instantiator :: Environment -> Src.Type
115123 -> State.StateT (VarDict, TypeDict) IO Type
@@ -135,9 +143,6 @@ instantiator env sourceType = go sourceType
135143 | "appendable" `isPrefixOf` x = Is Appendable
136144 | otherwise = Flexible
137145
138− Src.Data "String" [] ->
139− return (get env types "_List" <| get env types "Char")
140−
141146 Src.Data name ts -> do
142147 ts' <- mapM go ts
143148 case (Map.lookup name (types env), Map.lookup name (aliases env)) of
compiler/Type/Inference.hs+24−18
@@ -16,7 +16,8 @@ import SourceSyntax.Type (Type)
1616import Text.PrettyPrint
1717import qualified Type.State as TS
1818import Type.ExtraChecks (extraChecks)
19−import Control.Monad.State
19+import Control.Monad.State (execStateT, forM)
20+import Control.Monad.Error (runErrorT, liftIO)
2021import Control.Arrow (second)
2122import qualified Type.Alias as Alias
2223
@@ -33,20 +34,25 @@ infer interfaces modul = unsafePerformIO $ do
3334 do (_, vars, args, result) <- Env.freshDataScheme env name
3435 return (name, (vars, foldr (T.==>) result args))
3536
36− importedVars <-
37− forM (concatMap (Map.toList . iTypes) $ Map.elems interfaces) $ \(name,tipe) ->
38− (,) name `fmap` Env.instantiateType env tipe Map.empty
39−
40− let allTypes = ctors ++ importedVars
41− vars = concatMap (fst . snd) allTypes
42− header = Map.map snd (Map.fromList allTypes)
43− environ = noneNoDocs . T.CLet [ T.Scheme vars [] (noneNoDocs T.CTrue) header ]
44−
45− fvar <- T.var T.Flexible
46− constraint <- environ `fmap` TcExpr.constrain env (program modul) (T.VarN fvar)
47−
48− state <- execStateT (Solve.solve constraint) TS.initialState
49− let rules = Alias.rules interfaces modul
50− case TS.sErrors state of
51− errors@(_:_) -> Left `fmap` sequence (map ($ rules) (reverse errors))
52− [] -> extraChecks rules (Map.difference (TS.sSavedEnv state) header)
37+ attemptConstraint <- runErrorT $ do
38+ importedVars <-
39+ forM (concatMap (Map.toList . iTypes) $ Map.elems interfaces) $ \(name,tipe) ->
40+ (,) name `fmap` Env.instantiateType env tipe Map.empty
41+
42+ let allTypes = ctors ++ importedVars
43+ vars = concatMap (fst . snd) allTypes
44+ header = Map.map snd (Map.fromList allTypes)
45+ environ = noneNoDocs . T.CLet [ T.Scheme vars [] (noneNoDocs T.CTrue) header ]
46+
47+ fvar <- liftIO $ T.var T.Flexible
48+ c <- TcExpr.constrain env (program modul) (T.VarN fvar)
49+ return (header, environ c)
50+
51+ case attemptConstraint of
52+ Left err -> return $ Left err
53+ Right (header, constraint) -> do
54+ state <- execStateT (Solve.solve constraint) TS.initialState
55+ let rules = Alias.rules interfaces modul
56+ case TS.sErrors state of
57+ errors@(_:_) -> Left `fmap` sequence (map ($ rules) (reverse errors))
58+ [] -> extraChecks rules (Map.difference (TS.sSavedEnv state) header)
compiler/Type/Type.hs+3−2
@@ -9,6 +9,7 @@ import Text.PrettyPrint as P
99import System.IO.Unsafe
1010import Control.Applicative ((<$>),(<*>))
1111import Control.Monad.State
12+import Control.Monad.Error
1213import Data.Traversable (traverse)
1314import SourceSyntax.Location
1415import SourceSyntax.Helpers (isTuple)
@@ -130,9 +131,9 @@ ex fqs constraint@(L s _) = L s $ CLet [Scheme [] fqs constraint Map.empty] (L s
130131fl :: [Variable] -> TypeConstraint -> TypeConstraint
131132fl rqs constraint@(L s _) = L s $ CLet [Scheme rqs [] constraint Map.empty] (L s CTrue)
132133
133−exists :: (Type -> IO TypeConstraint) -> IO TypeConstraint
134+exists :: Error e => (Type -> ErrorT e IO TypeConstraint) -> ErrorT e IO TypeConstraint
134135exists f = do
135− v <- var Flexible
136+ v <- liftIO $ var Flexible
136137 ex [v] <$> f (VarN v)
137138
138139
compiler/Type/Unify.hs+6−4
@@ -82,10 +82,10 @@ actuallyUnify span variable1 variable2 = do
8282
8383 comparableError str = TS.addError span (str ++ msg) variable1 variable2
8484 where msg = "Expecting something comparable such as an\n" ++
85− "Int, Float, Char, or a list or tuple of comparables."
85+ "Int, Float, Char, String, or a list or tuple of comparables."
8686
8787 unifyComparable var name
88− | name `elem` ["Int","Float","Char","comparable"] = flexAndUnify var
88+ | name `elem` ["Int","Float","Char","String","comparable"] = flexAndUnify var
8989 | otherwise = comparableError ""
9090
9191 unifyComparableStructure varSuper varFlex =
@@ -129,8 +129,10 @@ actuallyUnify span variable1 variable2 = do
129129 (Is Comparable, _, _, _) -> unifyComparableStructure variable1 variable2
130130 (_, Is Comparable, _, _) -> unifyComparableStructure variable2 variable1
131131
132− (Is Appendable, _, _, Just "Text.Text") -> flexAndUnify variable1
133− (_, Is Appendable, Just "Text.Text", _) -> flexAndUnify variable2
132+ (Is Appendable, _, _, Just ctor)
133+ | ctor `elem` ["Text.Text","String"] -> flexAndUnify variable1
134+ (_, Is Appendable, Just ctor, _)
135+ | ctor `elem` ["Text.Text","String"] -> flexAndUnify variable2
134136 (Is Appendable, _, _, _) -> unifyAppendable variable1 variable2
135137 (_, Is Appendable, _, _) -> unifyAppendable variable2 variable1
136138
compiler/Unique.hsdeleted−19
@@ -1,19 +0,0 @@
1−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
2−module Unique (guid, set, run, runAt, Unique) where
3−
4−import Control.Monad.State (evalState, State, get, put)
5−
6−-- Wrapper around State monad.
7−newtype Unique a = U { runU :: State Int a }
8− deriving (Monad)
9−
10−-- Get the next GUID, incrementing the counter.
11−guid :: Unique Int
12−guid = U $ do n <- get
13− put (n + 1)
14− return n
15−
16−set n = U (put n)
17−
18−run = runAt 0
19−runAt n x = evalState (runU x) n
libraries/Automaton.elm+49−27
@@ -1,8 +1,24 @@
1−-- This library is a way to package up dynamic behavior. It makes it easier to
2−-- dynamically create dynamic components. See the [original release
3−-- notes](/blog/announce/version-0.5.0.elm) on this library to get a feel for how
4−-- it can be used.
5−module Automaton where
1+module Automaton ( pure, state, hiddenState, run, step
2+ , (<<<), (>>>), combine, count, average
3+ ) where
4+
5+{-| This library is a way to package up dynamic behavior. It makes it easier to
6+dynamically create dynamic components. See the [original release
7+notes](/blog/announce/version-0.5.0.elm) on this library to get a feel for how
8+it can be used.
9+
10+# Create
11+@docs pure, state, hiddenState
12+
13+# Evaluate
14+@docs run, step
15+
16+# Combine
17+@docs (>>>), (<<<), combine
18+
19+# Common Automatons
20+@docs count, average
21+-}
622
723import open Basics
824import Signal (lift,foldp,Signal)
@@ -11,59 +27,66 @@ import Maybe (Just, Nothing)
1127
1228data Automaton a b = Step (a -> (Automaton a b, b))
1329
14−-- Run an automaton on a given signal. The automaton steps forward
15−-- whenever the input signal updates.
30+{-| Run an automaton on a given signal. The automaton steps forward whenever the
31+input signal updates.
32+-}
1633run : Automaton a b -> b -> Signal a -> Signal b
1734run auto base inputs =
1835 let step a (Step f, _) = f a
1936 in lift (\(x,y) -> y) (foldp step (auto,base) inputs)
2037
21−-- Step an automaton forward once with a given input.
38+{-| Step an automaton forward once with a given input. -}
2239step : a -> Automaton a b -> (Automaton a b, b)
2340step a (Step f) = f a
2441
25−-- Compose two automatons, chaining them together.
42+{-| Compose two automatons, chaining them together. -}
2643(>>>) : Automaton a b -> Automaton b c -> Automaton a c
2744f >>> g =
2845 Step (\a -> let (f', b) = step a f
2946 (g', c) = step b g
3047 in (f' >>> g', c))
3148
32−-- Compose two automatons, chaining them together.
49+{-| Compose two automatons, chaining them together. -}
3350(<<<) : Automaton b c -> Automaton a b -> Automaton a c
3451g <<< f = f >>> g
3552
36−-- Combine a list of automatons into a single automaton that produces a list.
53+{-| Combine a list of automatons into a single automaton that produces a
54+list.
55+-}
3756combine : [Automaton a b] -> Automaton a [b]
3857combine autos =
3958 Step (\a -> let (autos', bs) = unzip (map (step a) autos)
4059 in (combine autos', bs))
4160
42−-- Create an automaton with no memory. It just applies the given function to
43−-- every input.
61+{-| Create an automaton with no memory. It just applies the given function to
62+every input.
63+-}
4464pure : (a -> b) -> Automaton a b
4565pure f = Step (\x -> (pure f, f x))
4666
47−-- Create an automaton with state. Requires an initial state and a step
48−-- function to step the state forward. For example, an automaton that counted
49−-- how many steps it has taken would look like this:
50−--
51−-- count = Automaton a Int
52−-- count = state 0 (\\_ c -> c+1)
53−--
54−-- It is a stateful automaton. The initial state is zero, and the step function
55−-- increments the state on every step.
67+
68+{-| Create an automaton with state. Requires an initial state and a step
69+function to step the state forward. For example, an automaton that counted
70+how many steps it has taken would look like this:
71+
72+ count = Automaton a Int
73+ count = state 0 (\\_ c -> c+1)
74+
75+It is a stateful automaton. The initial state is zero, and the step function
76+increments the state on every step.
77+-}
5678state : b -> (a -> b -> b) -> Automaton a b
5779state s f = Step (\x -> let s' = f x s
5880 in (state s' f, s'))
5981
60−-- Create an automaton with hidden state. Requires an initial state and a
61−-- step function to step the state forward and produce an output.
82+{-| Create an automaton with hidden state. Requires an initial state and a
83+step function to step the state forward and produce an output.
84+-}
6285hiddenState : s -> (a -> s -> (s,b)) -> Automaton a b
6386hiddenState s f = Step (\x -> let (s',out) = f x s
6487 in (hiddenState s' f, out))
6588
66−-- Count the number of steps taken.
89+{-| Count the number of steps taken. -}
6790count : Automaton a Int
6891count = state 0 (\_ c -> c + 1)
6992
@@ -75,7 +98,7 @@ dequeue q = case q of
7598 (en,[]) -> dequeue ([], reverse en)
7699 (en,hd::tl) -> Just (hd, (en,tl))
77100
78−-- Computes the running average of the last `n` inputs.
101+{-| Computes the running average of the last `n` inputs. -}
79102average : Int -> Automaton Float Float
80103average k =
81104 let step n (ns,len,sum) =
@@ -98,4 +121,3 @@ library faster and better:
98121Speeding things up is a really low priority. Language features and
99122libraries with nice APIs and are way more important!
100123--}
101−
libraries/AutomatonV2.elmnew file+149
@@ -0,0 +1,149 @@
1+module AutomatonV2 where
2+{-| This library is a way to package up dynamic behavior. It makes it easier to
3+dynamically create dynamic components. See the [original release
4+notes](/blog/announce/version-0.5.0.elm) on this library to get a feel for how
5+it can be used.
6+-}
7+
8+import open Basics
9+import Signal (lift,foldp,Signal)
10+import open List
11+import Maybe (Just, Nothing)
12+
13+data Automaton input output = Pure (input -> output)
14+ | Stateful state (input -> state -> (output,state))
15+
16+-- The basics
17+
18+-- AFRP name: arr
19+pure: (i -> o) -> Automaton i o
20+pure = Pure
21+
22+-- AFRP name: >>>
23+andThen: Automaton i inter -> Automaton inter o -> Automaton i o
24+andThen first second =
25+ case first of
26+ Pure f -> case second of -- f is the function from first
27+ Pure s -> Pure (s . f) -- s is the function from second
28+ Stateful b s -> Stateful b (\i -> s (f i)) -- b is the base state from second
29+ Stateful fb f -> case second of -- fb is the base state from first
30+ Pure s -> Stateful fb (\i st -> -- sb is the base state from second
31+ let (inter, st') = f i st -- i is the input
32+ in (s inter, st')) -- st is the input state
33+ Stateful sb s -> Stateful (fb, sb) (\i (fst, sst) -> -- inter is the intermediate value
34+ let (inter, fst') = f i fst -- st' is the new state
35+ (o, sst') = s inter sst -- fst and sst are the state of first and second
36+ in (o, (fst', sst'))) -- ect...
37+
38+-- AFRP name: first
39+extendDown: Automaton i o -> Automaton (i,extra) (o,extra)
40+extendDown auto = case auto of
41+ Pure fun -> Pure (\(i,extra) -> (fun i, extra))
42+ Stateful base fun -> Stateful base (\(i,extra) s -> (fun i s, extra))
43+
44+-- AFRP name: loop
45+loop: s -> Automaton (i,s) (o,s) -> Automaton i o
46+loop base auto = case auto of
47+ Pure fun -> Stateful base (curry fun)
48+ Stateful base2 fun -> -- fun: (i, s) -> s2 -> ((o, s), s2)
49+ let newFun = (\i (s,s2) ->
50+ let ((o, s'), s2') = fun (i, s) s2
51+ in (o, (s', s2'))) -- newFun: i -> (s, s2) -> (o, (s, s2))
52+ in Stateful (base, base2) newFun
53+
54+-- Run an automaton on a given signal
55+run: Automaton i o -> o -> Signal i -> Signal o
56+run auto baseOut input = case auto of
57+ Pure fun -> lift fun input
58+ Stateful base fun -> lift fst
59+ (foldp (\i (o, s) -> fun i s)
60+ (baseOut, base) input)
61+
62+
63+-- Other frequently used functions/operators
64+
65+-- Create an automaton with state. Requires an initial state and a step
66+-- function to step the state forward. For example, an automaton that counted
67+-- how many steps it has taken would look like this:
68+--
69+-- count = Automaton a Int
70+-- count = state 0 (\\_ c -> c+1)
71+--
72+-- It is a stateful automaton. The initial state is zero, and the step function
73+-- increments the state on every step.
74+state : s -> (i -> s -> s) -> Automaton i s
75+state base fun = loop base (pure (\(i,s) ->
76+ let s' = fun i s
77+ in (s',s')))
78+
79+-- Create an automaton with hidden state. Requires an initial state and a
80+-- step function to step the state forward and produce an output.
81+hiddenState : s -> (i -> s -> (s,o)) -> Automaton i o
82+hiddenState base fun = loop base (pure (\(i,s) ->
83+ let (o,s') = fun i s
84+ in (s',o)))
85+
86+-- AFRP name: second
87+extendUp: Automaton i o -> Automaton (extra,i) (extra,o)
88+extendUp auto =
89+ let swap (a, b) = (b, a)
90+ in pure swap `andThen` extendDown auto `andThen` pure swap
91+
92+-- (parallel composition)
93+pair: Automaton i1 o1 -> Automaton i2 o2 -> Automaton (i1,i2) (o1,o2)
94+pair f g = extendDown f `andThen` extendUp g
95+
96+branch : Automaton i o1 -> Automaton i o2 -> Automaton i (o1,o2)
97+branch f g =
98+ let double = pure (\i -> (i,i))
99+ in double `andThen` pair f g
100+
101+combi: Automaton i o -> Automaton i [o] -> Automaton i [o]
102+combi a1 a2 = (a1 `branch` a2) `andThen` pure (uncurry (::))
103+
104+-- Combine a list of automatons into a single automaton that produces a list.
105+combine : [Automaton i o] -> Automaton i [o]
106+combine autos =
107+ let l = length autos
108+ in if l == 0
109+ then pure (\_ -> [])
110+ else foldr combi (last autos `andThen` pure (\a -> [a])) (take (l-1) autos)
111+
112+
113+-- Examples of automata
114+
115+-- Count the number of steps taken.
116+count : Automaton a Int
117+count = state 0 (\_ c -> c + 1)
118+
119+type Queue t = ([t],[t])
120+empty = ([],[])
121+enqueue x (en,de) = (x::en, de)
122+dequeue q = case q of
123+ ([],[]) -> Nothing
124+ (en,[]) -> dequeue ([], reverse en)
125+ (en,hd::tl) -> Just (hd, (en,tl))
126+
127+-- Computes the running average of the last `n` inputs.
128+average : Int -> Automaton Float Float
129+average k =
130+ let step n (ns,len,sum) =
131+ if len == k then stepFull n (ns,len,sum)
132+ else ((enqueue n ns, len+1, sum+n), (sum+n) / (toFloat len+1))
133+ stepFull n (ns,len,sum) =
134+ case dequeue ns of
135+ Nothing -> ((ns,len,sum), 0)
136+ Just (m,ns') -> let sum' = sum + n - m
137+ in ((enqueue n ns', len, sum'), sum' / toFloat len)
138+ in hiddenState (empty,0,0) step
139+
140+
141+{-- TODO(evancz): See the following papers for ideas on how to make this
142+library faster and better:
143+
144+- Functional Reactive Programming, Continued -- took some inspirations from this paper (Apanatshka)
145+- Causal commutative arrows and their optimization
146+
147+Speeding things up is a really low priority. Language features and
148+libraries with nice APIs and are way more important!
149+--}
libraries/Basics.elm+165−85
@@ -1,30 +1,77 @@
11
22module Basics where
33
4−import Native.Basics
4+{-| Tons of useful functions that get imported by default.
5+
6+The following libraries also get imported by default: List, Signal,
7+Text, Maybe, Time, Graphics.Element, Color, Graphics.Collage.
8+
9+# Equality
10+@docs (==), (/=)
11+
12+# Comparison
13+
14+These functions only work on `comparable` types. This includes numbers,
15+characters, strings, lists of comparable things, and tuples of comparable
16+things. Note that tuples with 7 or more elements are not comparable; why
17+are your tuples so big?
18+
19+@docs (<), (>), (<=), (>=), max, min, Order, compare
20+
21+# Booleans
22+@docs not, (&&), (||), xor, otherwise
23+
24+# Mathematics
25+@docs (+), (-), (*), (/), (^), div, rem, mod, abs, sqrt, clamp, logBase, e
26+
27+# Trigonometry
28+@docs pi, cos, sin, tan, acos, asin, atan, atan2
29+
30+# Number Conversions
31+@docs round, floor, ceiling, truncate, toFloat
532
6−type String = [Char]
33+# Angle Conversions
34+All angle conversions result in &ldquo;standard Elm angles&rdquo;
35+which happen to be radians.
736
8−-- Convert radians to standard Elm angles (radians).
37+@docs degrees, radians, turns
38+
39+# Polar Coordinates
40+@docs toPolar, fromPolar
41+
42+# Tuples
43+@docs fst, snd
44+
45+# Higher-Order Helpers
46+@docs id, (<|), (|>), (.), flip, curry, uncurry
47+
48+-}
49+
50+import Native.Basics
51+
52+{-| Convert radians to standard Elm angles (radians). -}
953radians : Float -> Float
1054radians t = t
1155
12−-- Convert degrees to standard Elm angles (radians).
56+{-| Convert degrees to standard Elm angles (radians). -}
1357degrees : Float -> Float
1458degrees d = d * Native.Basics.pi / 180
1559
16−-- Convert turns to standard Elm angles (radians).
17−-- One turn is equal to 360&deg;.
60+{-| Convert turns to standard Elm angles (radians).
61+One turn is equal to 360&deg;.
62+-}
1863turns : Float -> Float
1964turns r = 2 * Native.Basics.pi * r
2065
21−-- Start with polar coordinates (r,&theta;)
22−-- and get out cartesian coordinates (x,y).
66+{-| Start with polar coordinates (r,&theta;)
67+and get out cartesian coordinates (x,y).
68+-}
2369fromPolar : (Float,Float) -> (Float,Float)
2470fromPolar (r,t) = (r * Native.Basics.cos t, r * Native.Basics.sin t)
2571
26−-- Start with cartesian coordinates (x,y)
27−-- and get out polar coordinates (r,&theta;).
72+{-| Start with cartesian coordinates (x,y)
73+and get out polar coordinates (r,&theta;).
74+-}
2875toPolar : (Float,Float) -> (Float,Float)
2976toPolar (x,y) = (Native.Basics.sqrt (x^2 + y^2), Native.Basics.atan2 y x)
3077
@@ -37,23 +84,33 @@ toPolar (x,y) = (Native.Basics.sqrt (x^2 + y^2), Native.Basics.atan2 y x)
3784(*) : number -> number -> number
3885(*) = Native.Basics.mul
3986
40−-- Floating point division.
87+{-| Floating point division. -}
4188(/) : Float -> Float -> Float
4289(/) = Native.Basics.floatDiv
4390
44−-- Integer division, remainder is discarded.
91+infixl 6 +
92+infixl 6 -
93+infixl 7 *
94+infixl 7 /
95+infixl 8 ^
96+
97+infixl 7 `div`
98+infixl 7 `mod`
99+infixl 7 `rem`
100+
101+{-| Integer division, remainder is discarded. -}
45102div : Int -> Int -> Int
46103div = Native.Basics.div
47104
48−-- Finds the remainder after dividing one number by another: ``4 `rem` 3 == 1``
105+{-| Finds the remainder after dividing one number by another: ``4 `rem` 3 == 1`` -}
49106rem : Int -> Int -> Int
50107rem = Native.Basics.rem
51108
52−-- Perform modular arithmetic: ``7 `mod` 2 == 1``
109+{-| Perform modular arithmetic: ``7 `mod` 2 == 1`` -}
53110mod : Int -> Int -> Int
54111mod = Native.Basics.mod
55112
56−-- Exponentiation: `3^2 == 9`
113+{-| Exponentiation: `3^2 == 9` -}
57114(^) : number -> number -> number
58115(^) = Native.Basics.exp
59116
@@ -72,58 +129,53 @@ acos = Native.Basics.acos
72129asin : Float -> Float
73130asin = Native.Basics.asin
74131
75−-- You probably do not want to use this. Because it takes `(y/x)` as the argument
76−-- there is no way to know where the negative signs come from so the resulting
77−-- angle is always between &pi;/2 and -&pi;/2 (in quadrants I and IV).
132+{-| You probably do not want to use this. It takes `(y/x)` as the
133+argument, so there is no way to know whether the negative signs comes from
134+the `y` or `x`. Thus, the resulting angle is always between &pi;/2 and -&pi;/2
135+(in quadrants I and IV). You probably want to use `atan2` instead.
136+-}
78137atan : Float -> Float
79138atan = Native.Basics.atan
80139
81−-- This helps you find the angle of a cartesian coordinate.
82−-- You will almost certainly want to use this instead of `atan`.
83−-- So `atan2 y x` computes *atan(y/x)* but also keeps track of which
84−-- quadrant the angle should really be in. The result will be between
85−-- &pi; and -&pi;, giving you the full range of angles.
140+{-| This helps you find the angle of a cartesian coordinate.
141+You will almost certainly want to use this instead of `atan`.
142+So `atan2 y x` computes *atan(y/x)* but also keeps track of which
143+quadrant the angle should really be in. The result will be between
144+&pi; and -&pi;, giving you the full range of angles.
145+-}
86146atan2 : Float -> Float -> Float
87147atan2 = Native.Basics.atan2
88148
89−-- Take the square root of a number.
149+{-| Take the square root of a number. -}
90150sqrt : number -> number
91151sqrt = Native.Basics.sqrt
92152
93−-- Take the absolute value of a number.
153+{-| Take the absolute value of a number. -}
94154abs : number -> number
95155abs = Native.Basics.abs
96156
97−-- Calculate the logarithm of a number with a given base: `logBase 10 100 == 2`
157+{-| Calculate the logarithm of a number with a given base: `logBase 10 100 == 2` -}
98158logBase : number -> number -> number
99159logBase = Native.Basics.logBase
100160
101−-- Given two comparables, returns the smaller one.
102−min : comparable -> comparable -> comparable
103−min = Native.Basics.min
104−
105−-- Given two comparables, returns the larger one.
106−max : comparable -> comparable -> comparable
107−max = Native.Basics.max
161+{-| Clamps a number within a given range. With the expression
162+`clamp 100 200 x` the results are as follows:
108163
109−-- Clamps a number within a given range. With the expression `clamp 100 200 x`
110−-- the results are as follows:
111−--
112−-- * `100 if x < 100`
113−-- * ` x if 100 <= x < 200`
114−-- * `200 if 200 <= x`
164+ 100 if x < 100
165+ x if 100 <= x < 200
166+ 200 if 200 <= x
167+-}
115168clamp : number -> number -> number -> number
116169clamp = Native.Basics.clamp
117170
118−-- An approximation of pi.
171+{-| An approximation of pi. -}
119172pi : Float
120173pi = Native.Basics.pi
121174
122−-- An approximation of e.
175+{-| An approximation of e. -}
123176e : Float
124177e = Native.Basics.e
125178
126−-- Compare any two values for structural equality. Functions cannot be compared.
127179(==) : a -> a -> Bool
128180(==) = Native.Basics.eq
129181
@@ -142,113 +194,141 @@ e = Native.Basics.e
142194(>=) : comparable -> comparable -> Bool
143195(>=) = Native.Basics.ge
144196
145−-- Compare any two comparable values. Comparable values include `String`, `Char`,
146−-- `Int`, `Float`, `Time`, or a list or tuple containing comparable values.
147−-- These are also the only values that work as `Dict` keys or `Set` members.
197+infix 4 ==
198+infix 4 /=
199+infix 4 <
200+infix 4 >
201+infix 4 <=
202+infix 4 >=
203+
204+{-| Compare any two comparable values. Comparable values include `String`, `Char`,
205+`Int`, `Float`, `Time`, or a list or tuple containing comparable values.
206+These are also the only values that work as `Dict` keys or `Set` members.
207+-}
148208compare : comparable -> comparable -> Order
149209compare = Native.Basics.compare
150210
151−-- Represents the relative ordering of two things.
152−-- The relations are less than, equal to, and greater than.
211+{-| Represents the relative ordering of two things.
212+The relations are less than, equal to, and greater than.
213+-}
153214data Order = LT | EQ | GT
154215
155−-- The and operator. True if both inputs are True.
216+{-| Given two comparables, returns the smaller one. -}
217+min : comparable -> comparable -> comparable
218+min = Native.Basics.min
219+
220+{-| Given two comparables, returns the larger one. -}
221+max : comparable -> comparable -> comparable
222+max = Native.Basics.max
223+
224+{-| The and operator. True if both inputs are True. -}
156225(&&) : Bool -> Bool -> Bool
157226(&&) = Native.Basics.and
158227
159−-- The or operator. True if one or both inputs are True.
228+{-| The or operator. True if one or both inputs are True. -}
160229(||) : Bool -> Bool -> Bool
161230(||) = Native.Basics.or
162231
163−-- The exclusive-or operator. True if exactly one input is True.
232+infixr 3 &&
233+infixr 2 ||
234+
235+{-| The exclusive-or operator. True if exactly one input is True. -}
164236xor : Bool -> Bool -> Bool
165237xor = Native.Basics.xor
166238
167−-- Negate a boolean value: `(not True == False)` and `(not False == True)`
239+{-| Negate a boolean value: `(not True == False)` and `(not False == True)` -}
168240not : Bool -> Bool
169241not = Native.Basics.not
170242
171−-- Equal to true. Useful as the last case of a multi-way-if.
243+{-| Equal to true. Useful as the last case of a multi-way-if. -}
172244otherwise : Bool
173245otherwise = True
174246
175247
176248-- Conversions
177249
178−-- Round a number to the nearest integer.
250+{-| Round a number to the nearest integer. -}
179251round : Float -> Int
180252round = Native.Basics.round
181253
182−-- Truncate a decimal number, rounding towards zero.
254+{-| Truncate a decimal number, rounding towards zero. -}
183255truncate : Float -> Int
184256truncate = Native.Basics.truncate
185257
186−-- Floor function, rounding down.
258+{-| Floor function, rounding down. -}
187259floor : Float -> Int
188260floor = Native.Basics.floor
189261
190−-- Ceiling function, rounding up.
262+{-| Ceiling function, rounding up. -}
191263ceiling : Float -> Int
192264ceiling = Native.Basics.ceiling
193265
194−-- Convert an integer into a float.
266+{-| Convert an integer into a float. -}
195267toFloat : Int -> Float
196268toFloat = Native.Basics.toFloat
197269
198270
199271-- Function Helpers
200272
201−-- Function composition: `(f . g == (\\x -> f (g x)))`
273+{-| Function composition: `(f . g == (\\x -> f (g x)))` -}
202274(.) : (b -> c) -> (a -> b) -> (a -> c)
203275(.) f g x = f (g x)
204276
205−-- Forward function application `x |> f == f x`. This function is useful
206−-- for avoiding parenthesis and writing code in a more natural way.
207−-- Consider the following code to create a pentagon:
208−--
209−-- scale 2 (move (10,10) (filled blue (ngon 5 30)))
210−--
211−-- This can also be written as:
212−--
213−-- ngon 5 30 |> filled blue
214−-- |> move (10,10)
215−-- |> scale 2
277+{-| Forward function application `x |> f == f x`. This function is useful
278+for avoiding parenthesis and writing code in a more natural way.
279+Consider the following code to create a pentagon:
280+
281+ scale 2 (move (10,10) (filled blue (ngon 5 30)))
282+
283+This can also be written as:
284+
285+ ngon 5 30 |> filled blue
286+ |> move (10,10)
287+ |> scale 2
288+-}
216289(|>) : a -> (a -> b) -> b
217290x |> f = f x
218291
219−-- Function application `f <| x == f x`. This function is useful for avoiding
220−-- parenthesis. Consider the following code to create a text element:
221−--
222−-- text (monospace (toText "code"))
223−--
224−-- This can also be written as:
225−--
226−-- text . monospace <| toText "code"
292+{-| Function application `f <| x == f x`. This function is useful for avoiding
293+parenthesis. Consider the following code to create a text element:
294+
295+ text (monospace (toText "code"))
296+
297+This can also be written as:
298+
299+ text . monospace <| toText "code"
300+-}
227301(<|) : (a -> b) -> a -> b
228302f <| x = f x
229303
230−-- Given a value, returns exactly the same value.
304+infixr 9 .
305+infixr 0 <|
306+infixl 0 |>
307+
308+{-| Given a value, returns exactly the same value. -}
231309id : a -> a
232310id x = x
233311
234−-- Given a 2-tuple, returns the first value.
312+{-| Given a 2-tuple, returns the first value. -}
235313fst : (a,b) -> a
236314fst = Native.Basics.fst
237315
238−-- Given a 2-tuple, returns the second value.
316+{-| Given a 2-tuple, returns the second value. -}
239317snd : (a,b) -> b
240318snd = Native.Basics.snd
241319
242−-- Flips the order of the first two arguments to a function.
320+{-| Flips the order of the first two arguments to a function. -}
243321flip : (a -> b -> c) -> (b -> a -> c)
244322flip f b a = f a b
245323
246−-- Change how arguments are passed to a function. This splits paired arguments
247−-- into two separate arguments.
324+{-| Change how arguments are passed to a function.
325+This splits paired arguments into two separate arguments.
326+-}
248327curry : ((a,b) -> c) -> a -> b -> c
249328curry = Native.Basics.curry
250329
251−-- Change how arguments are passed to a function. This combines two arguments
252−-- into a sigle pair.
330+{-| Change how arguments are passed to a function.
331+This combines two arguments into a sigle pair.
332+-}
253333uncurry : (a -> b -> c) -> (a,b) -> c
254334uncurry = Native.Basics.uncurry
libraries/Char.elm+23−11
@@ -1,50 +1,62 @@
11
22module Char where
33
4+{-| Functions for working with characters. Character literals are enclosed in
5+`'a'` pair of single quotes.
6+
7+# Classification
8+@docs isUpper, isLower, isDigit, isOctDigit, isHexDigit
9+
10+# Conversion
11+@docs toUpper, toLower, toLocaleUpper, toLocaleLower, toCode, fromCode
12+
13+-}
14+
415import Native.Char
516
6−-- True for upper case letters.
17+{-| True for upper case letters. -}
718isUpper : Char -> Bool
819isUpper = Native.Char.isUpper
920
10−-- True for lower case letters.
21+{-| True for lower case letters. -}
1122isLower : Char -> Bool
1223isLower = Native.Char.isLower
1324
14−-- True for ASCII digits (`0..9`).
25+{-| True for ASCII digits `[0-9]`. -}
1526isDigit : Char -> Bool
1627isDigit = Native.Char.isDigit
1728
18−-- True for ASCII octal digits (`0..7`).
29+{-| True for ASCII octal digits `[0-7]`. -}
1930isOctDigit : Char -> Bool
2031isOctDigit = Native.Char.isOctDigit
2132
22−-- True for ASCII hexadecimal digits (`0..9a..fA..F`).
33+{-| True for ASCII hexadecimal digits `[0-9a-fA-F]`. -}
2334isHexDigit : Char -> Bool
2435isHexDigit = Native.Char.isHexDigit
2536
26−-- Convert to upper case.
37+{-| Convert to upper case. -}
2738toUpper : Char -> Char
2839toUpper = Native.Char.toUpper
2940
30−-- Convert to lower case.
41+{-| Convert to lower case. -}
3142toLower : Char -> Char
3243toLower = Native.Char.toLower
3344
34−-- Convert to upper case, according to any locale-specific case mappings.
45+{-| Convert to upper case, according to any locale-specific case mappings. -}
3546toLocaleUpper : Char -> Char
3647toLocaleUpper = Native.Char.toLocaleUpper
3748
38−-- Convert to lower case, according to any locale-specific case mappings.
49+{-| Convert to lower case, according to any locale-specific case mappings. -}
3950toLocaleLower : Char -> Char
4051toLocaleLower = Native.Char.toLocaleLower
4152
4253type KeyCode = Int
4354
44−-- Convert to unicode.
55+{-| Convert to unicode. Used with the [`Keyboard`](/docs/Keyboard.elm)
56+library, which expects the input to be uppercase. -}
4557toCode : Char -> KeyCode
4658toCode = Native.Char.toCode
4759
48−-- Convert from unicode.
60+{-| Convert from unicode. -}
4961fromCode : KeyCode -> Char
5062fromCode = Native.Char.fromCode
libraries/Color.elm+121−47
@@ -1,82 +1,156 @@
1−
21module Color where
32
3+{-| Library for working with colors. Includes
4+[RGB](https://en.wikipedia.org/wiki/RGB_color_model) and
5+[HSV](http://en.wikipedia.org/wiki/HSL_and_HSV) creation, gradients, and
6+built-in names.
7+
8+# Creation
9+@docs rgb, rgba, hsv, hsva, grayscale, greyscale
10+
11+# From Other Colors
12+@docs complement
13+
14+# Gradients
15+@docs linear, radial
16+
17+# Built-in Colors
18+These colors come from the [Tango
19+palette](http://tango.freedesktop.org/Tango_Icon_Theme_Guidelines)
20+which provides aesthetically reasonable defaults for colors. Each color also
21+comes with a light and dark version.
22+
23+### Standard
24+@docs red, orange, yellow, green, blue, purple, brown
25+
26+### Light
27+@docs lightRed, lightOrange, lightYellow, lightGreen, lightBlue, lightPurple,
28+ lightBrown
29+
30+### Dark
31+@docs darkRed, darkOrange, darkYellow, darkGreen, darkBlue, darkPurple,
32+ darkBrown
33+
34+### Eight Shades of Grey
35+These colors are a compatible series of shades of grey, fitting nicely
36+with the Tango palette.
37+@docs white, lightGrey, grey, darkGrey, lightCharcoal, charcoal, darkCharcoal, black
38+
39+These are identical to the *grey* versions. It seems the spelling is regional, but
40+that has never helped me remember which one I should be writing.
41+@docs lightGray, gray, darkGray
42+
43+-}
44+
445import Native.Color
546import Basics ((-))
647
748data Color = Color Int Int Int Float
849
9−-- Create RGB colors with an alpha component for transparency.
10−-- The alpha component is specified with numbers between 0 and 1.
50+{-| Create RGB colors with an alpha component for transparency.
51+The alpha component is specified with numbers between 0 and 1. -}
1152rgba : Int -> Int -> Int -> Float -> Color
1253rgba = Color
1354
14−-- Create RGB colors from numbers between 0 and 255 inclusive.
55+{-| Create RGB colors from numbers between 0 and 255 inclusive. -}
1556rgb : Int -> Int -> Int -> Color
1657rgb r g b = Color r g b 1
1758
18−lightYellow = Color 255 233 79 1
19−yellow = Color 237 212 0 1
20−darkYellow = Color 196 160 0 1
59+lightRed : Color
60+lightRed = Color 239 41 41 1
61+red : Color
62+red = Color 204 0 0 1
63+darkRed : Color
64+darkRed = Color 164 0 0 1
2165
66+lightOrange : Color
2267lightOrange = Color 252 175 62 1
23−orange = Color 245 121 0 1
24−darkOrange = Color 206 92 0 1
25−
26−lightBrown = Color 233 185 110 1
27−brown = Color 193 125 17 1
28−darkBrown = Color 143 89 2 1
68+orange : Color
69+orange = Color 245 121 0 1
70+darkOrange : Color
71+darkOrange = Color 206 92 0 1
2972
30−lightGreen = Color 138 226 52 1
31−green = Color 115 210 22 1
73+lightYellow : Color
74+lightYellow = Color 255 233 79 1
75+yellow : Color
76+yellow = Color 237 212 0 1
77+darkYellow : Color
78+darkYellow = Color 196 160 0 1
79+
80+lightGreen : Color
81+lightGreen = Color 138 226 52 1
82+green : Color
83+green = Color 115 210 22 1
84+darkGreen : Color
3285darkGreen = Color 78 154 6 1
3386
34−lightBlue = Color 114 159 207 1
35−blue = Color 52 101 164 1
36−darkBlue = Color 32 74 135 1
87+lightBlue : Color
88+lightBlue = Color 114 159 207 1
89+blue : Color
90+blue = Color 52 101 164 1
91+darkBlue : Color
92+darkBlue = Color 32 74 135 1
3793
94+lightPurple : Color
3895lightPurple = Color 173 127 168 1
39−purple = Color 117 80 123 1
40−darkPurple = Color 92 53 102 1
41−
42−lightRed = Color 239 41 41 1
43−red = Color 204 0 0 1
44−darkRed = Color 164 0 0 1
96+purple : Color
97+purple = Color 117 80 123 1
98+darkPurple : Color
99+darkPurple = Color 92 53 102 1
100+
101+lightBrown : Color
102+lightBrown = Color 233 185 110 1
103+brown : Color
104+brown = Color 193 125 17 1
105+darkBrown : Color
106+darkBrown = Color 143 89 2 1
45107
46−black = Color 0 0 0 1
47−white = Color 255 255 255 1
108+black : Color
109+black = Color 0 0 0 1
110+white : Color
111+white = Color 255 255 255 1
48112
49−lightGrey = Color 238 238 236 1
50−grey = Color 211 215 207 1
51−darkGrey = Color 186 189 182 1
113+lightGrey : Color
114+lightGrey = Color 238 238 236 1
115+grey : Color
116+grey = Color 211 215 207 1
117+darkGrey : Color
118+darkGrey = Color 186 189 182 1
52119
120+lightGray : Color
53121lightGray = Color 238 238 236 1
122+gray : Color
54123gray = Color 211 215 207 1
124+darkGray : Color
55125darkGray = Color 186 189 182 1
56126
127+lightCharcoal : Color
57128lightCharcoal = Color 136 138 133 1
129+charcoal : Color
58130charcoal = Color 85 87 83 1
131+darkCharcoal : Color
59132darkCharcoal = Color 46 52 54 1
60133
134+{-| Produce a gray based on the input. 0 is white, 1 is black. -}
61135grayscale : Float -> Color
62136grayscale p = hsv 0 0 (1-p)
137+
138+greyscale : Float -> Color
63139greyscale p = hsv 0 0 (1-p)
64140
65−-- Produce a &ldquo;complementary color&rdquo;.
66−-- The two colors will accent each other.
141+{-| Produce a &ldquo;complementary color&rdquo;.
142+The two colors will accent each other. -}
67143complement : Color -> Color
68144complement = Native.Color.complement
69145
70−-- Create [HSV colors](http://en.wikipedia.org/wiki/HSL_and_HSV)
71−-- with an alpha component for transparency.
146+{-| Create [HSV colors](http://en.wikipedia.org/wiki/HSL_and_HSV)
147+with an alpha component for transparency. -}
72148hsva : Float -> Float -> Float -> Float -> Color
73149hsva = Native.Color.hsva
74150
75−-- Create [HSV colors](http://en.wikipedia.org/wiki/HSL_and_HSV).
76−-- This is very convenient for creating colors that cycle and shift.
77−-- Hue is an angle and should be given in standard Elm angles (radians).
78−--
79−-- hsv (degrees 240) 1 1 == blue
151+{-| Create [HSV colors](http://en.wikipedia.org/wiki/HSL_and_HSV). This is very
152+convenient for creating colors that cycle and shift. Hue is an angle and should
153+be given in standard Elm angles (radians). -}
80154hsv : Float -> Float -> Float -> Color
81155hsv = Native.Color.hsv
82156
@@ -84,17 +158,17 @@ data Gradient
84158 = Linear (Float,Float) (Float,Float) [(Float,Color)]
85159 | Radial (Float,Float) Float (Float,Float) Float [(Float,Color)]
86160
87−-- Create a linear gradient. Takes a start and end point and then a series
88−-- of &ldquo;color stops&rdquo; that indicate how to interpolate between
89−-- the start and end points. See [this example](/edit/examples/Elements/LinearGradient.elm) for
90−-- a more visual explanation.
161+{-| Create a linear gradient. Takes a start and end point and then a series of
162+&ldquo;color stops&rdquo; that indicate how to interpolate between the start and
163+end points. See [this example](/edit/examples/Elements/LinearGradient.elm) for a
164+more visual explanation. -}
91165linear : (number, number) -> (number, number) -> [(Float,Color)] -> Gradient
92166linear = Linear
93167
94−-- Create a radial gradient. First takes a start point and inner radius.
95−-- Then takes an end point and outer radius. It then takes a series
96−-- of &ldquo;color stops&rdquo; that indicate how to interpolate between
97−-- the inner and outer circles. See [this example](/edit/examples/Elements/RadialGradient.elm) for
98−-- a more visual explanation.
168+{-| Create a radial gradient. First takes a start point and inner radius. Then
169+takes an end point and outer radius. It then takes a series of &ldquo;color
170+stops&rdquo; that indicate how to interpolate between the inner and outer
171+circles. See [this example](/edit/examples/Elements/RadialGradient.elm) for a
172+more visual explanation. -}
99173radial : (number,number) -> number -> (number,number) -> number -> [(Float,Color)] -> Gradient
100174radial = Radial
libraries/Date.elm+32−25
@@ -1,65 +1,72 @@
11
2−-- Library for working with dates. It is still a work in progress, so email
3−-- the mailing list if you are having issues with internationalization or
4−-- locale formatting or something.
52module Date where
63
7−import Basics (String)
4+{-| Library for working with dates. Email the mailing list if you encounter
5+issues with internationalization or locale formatting.
6+
7+# Conversions
8+@docs read, toTime
9+
10+# Extractions
11+@docs year, month, Month, day, dayOfWeek, Day, hour, minute, second
12+
13+-}
14+
815import Native.Date
916import Time (Time)
1017import Maybe (Maybe)
1118
1219data Date = Date
1320
14−-- Represents the days of the week.
21+{-| Represents the days of the week. -}
1522data Day = Mon | Tue | Wed | Thu | Fri | Sat | Sun
1623
17−-- Represents the month of the year.
24+{-| Represents the month of the year. -}
1825data Month = Jan | Feb | Mar | Apr
1926 | May | Jun | Jul | Aug
2027 | Sep | Oct | Nov | Dec
2128
22−-- Attempt to read a date from a string.
29+{-| Attempt to read a date from a string. -}
2330read : String -> Maybe Date
2431read = Native.Date.read
2532
26−-- Convert a date into a time since midnight (UTC) of 1 January 1990 (i.e.
27−-- [UNIX time](http://en.wikipedia.org/wiki/Unix_time)). Given the date 23 June
28−-- 1990 at 11:45AM this returns the corresponding time.
33+{-| Convert a date into a time since midnight (UTC) of 1 January 1990 (i.e.
34+[UNIX time](http://en.wikipedia.org/wiki/Unix_time)). Given the date 23 June
35+1990 at 11:45AM this returns the corresponding time. -}
2936toTime : Date -> Time
3037toTime = Native.Date.toTime
3138
32−-- Extract the year of a given date. Given the date 23 June 1990 at 11:45AM
33−-- this returns the integer `1990`.
39+{-| Extract the year of a given date. Given the date 23 June 1990 at 11:45AM
40+this returns the integer `1990`. -}
3441year : Date -> Int
3542year = Native.Date.year
3643
37−-- Extract the month of a given date. Given the date 23 June 1990 at 11:45AM
38−-- this returns the Month `Jun` as defined below.
44+{-| Extract the month of a given date. Given the date 23 June 1990 at 11:45AM
45+this returns the Month `Jun` as defined below. -}
3946month : Date -> Month
4047month = Native.Date.month
4148
42−-- Extract the day of a given date. Given the date 23 June 1990 at 11:45AM
43−-- this returns the integer `23`.
49+{-| Extract the day of a given date. Given the date 23 June 1990 at 11:45AM
50+this returns the integer `23`. -}
4451day : Date -> Int
4552day = Native.Date.day
4653
47−-- Extract the day of the week for a given date. Given the date 23 June
48−-- 1990 at 11:45AM this returns the Day `Thu` as defined below.
54+{-| Extract the day of the week for a given date. Given the date 23 June
55+1990 at 11:45AM this returns the Day `Thu` as defined below. -}
4956dayOfWeek : Date -> Day
5057dayOfWeek = Native.Date.dayOfWeek
5158
52−-- Extract the hour of a given date. Given the date 23 June 1990 at 11:45AM
53−-- this returns the integer `11`.
59+{-| Extract the hour of a given date. Given the date 23 June 1990 at 11:45AM
60+this returns the integer `11`. -}
5461hour : Date -> Int
5562hour = Native.Date.hour
5663
57−-- Extract the minute of a given date. Given the date 23 June 1990 at 11:45AM
58−-- this returns the integer `45`.
64+{-| Extract the minute of a given date. Given the date 23 June 1990 at 11:45AM
65+this returns the integer `45`. -}
5966minute : Date -> Int
6067minute = Native.Date.minute
6168
62−-- Extract the second of a given date. Given the date 23 June 1990 at 11:45AM
63−-- this returns the integer `0`.
69+{-| Extract the second of a given date. Given the date 23 June 1990 at 11:45AM
70+this returns the integer `0`. -}
6471second : Date -> Int
65−second = Native.Date.second
72+second = Native.Date.second
libraries/Dict.elm+198−253
@@ -1,4 +1,3 @@
1−
21module Dict (empty,singleton,insert
32 ,lookup,findWithDefault
43 ,remove,member
@@ -8,151 +7,88 @@ module Dict (empty,singleton,insert
87 ,toList,fromList
98 ) where
109
10+{-| A dictionary mapping unique keys to values. The keys can be any comparable
11+type. This includes `Int`, `Float`, `Time`, `Char`, `String`, and tuples or
12+lists of comparable types.
13+
14+Insert, remove, and query operations all take *O(log n)* time.
15+
16+# Build
17+@docs empty, singleton, insert, remove
18+
19+# Query
20+@docs member, lookup, findWithDefault
21+
22+# Combine
23+@docs union, intersect, diff
24+
25+# Lists
26+@docs keys, values, toList, fromList
27+
28+# Transform
29+@docs map, foldl, foldr
30+
31+-}
32+
33+
1134import open Basics
1235import open Maybe
1336import Native.Error
1437import List as List
1538import Native.Utils
1639
40+-- BBlack and NBlack should only be used during the deletion
41+-- algorithm. Any other occurrence is a bug and should fail an assert.
1742data NColor = Red | Black
43+ | BBlack | NBlack
1844
19−data Dict k v = RBNode NColor k v (Dict k v) (Dict k v) | RBEmpty
20−
21−-- Create an empty dictionary.
22−empty : Dict comparable v
23−empty = RBEmpty
24−
25−{-- Helpers for checking invariants
26−
27−-- Check that the tree has an equal number of black nodes on each path
28−equal_pathLen t =
29− let path_numBlacks t =
30− case t of
31− RBEmpty -> 1
32− RBNode col _ _ l r ->
33− let { bl = path_numBlacks l ; br = path_numBlacks r } in
34− if bl /= br || bl == 0-1 || br == 0-1
35− then 0-1
36− else bl + (if col == Red then 0 else 1)
37− in 0-1 /= path_numBlacks t
38−
39−rootBlack t =
40− case t of
41− RBEmpty -> True
42− RBNode Black _ _ _ _ -> True
43− _ -> False
44−
45−redBlack_children t =
46− case t of
47− { RBNode Red _ _ (RBNode Red _ _ _ _) _ -> False
48− ; RBNode Red _ _ _ (RBNode Red _ _ _ _) -> False
49− ; RBEmpty -> True
50− ; RBNode _ _ _ l r -> redBlack_children l && redBlack_children r
51− }
52−
53−findExtreme f t =
54− case t of
55− { RBEmpty -> Nothing
56− ; RBNode c k _ l r ->
57− case findExtreme f (f (l,r)) of
58− { Nothing -> Just k
59− ; Just k' -> Just k' }
60− }
61−
62−findminRbt t = findExtreme fst t
63−findmaxRbt t = findExtreme snd t
64−
65−-- "Option LT than"
66−-- Returns True if either xo or yo is Nothing
67−-- Otherwise returns the result of comparing the values using f
68−
69−optionRelation f u xo yo =
70− case (xo,yo) of
71− { (Nothing,_) -> u
72− ; (_,Nothing) -> u
73− ; (Just x, Just y) -> f x y }
74−
75−olt xo yo = optionRelation (< ) True xo yo
76−olte xo yo = optionRelation (<=) True xo yo
77−
78−ordered t =
79− case t of
80− { RBEmpty -> True
81− ; RBNode c k v l r ->
82− let (lmax,rmin) = (findmaxRbt l, findminRbt r) in
83− olte lmax (Just k) && olte (Just k) rmin && ordered l && ordered r
84− }
85−
86−-- Check that there aren't any right red nodes in the tree *)
87−leftLeaning t =
88− case t of
89− { RBEmpty -> True
90− ; RBNode _ _ _ (RBNode Black _ _ _ _) (RBNode Red _ _ _ _) -> False
91− ; RBNode _ _ _ RBEmpty (RBNode Red _ _ _ _) -> False
92− ; RBNode _ _ _ l r -> (leftLeaning l) && (leftLeaning r)
93− }
94−
95−invariants_hold t =
96− ordered t && rootBlack t && redBlack_children t &&
97− equal_pathLen t && leftLeaning t
45+data LeafColor = LBlack | LBBlack
9846
99−--** End invariant helpers *****
100−--}
47+data Dict k v = RBNode NColor k v (Dict k v) (Dict k v)
48+ | RBEmpty LeafColor
10149
50+{-| Create an empty dictionary. -}
51+empty : Dict comparable v
52+empty = RBEmpty LBlack
10253
10354min : Dict k v -> (k,v)
10455min t =
10556 case t of
106− RBNode _ k v RBEmpty _ -> (k,v)
57+ RBNode _ k v (RBEmpty LBlack) _ -> (k,v)
10758 RBNode _ _ _ l _ -> min l
108− RBEmpty -> Native.Error.raise "(min Empty) is not defined"
59+ RBEmpty LBlack -> Native.Error.raise "(min Empty) is not defined"
10960
110−{--
61+max : Dict k v -> (k, v)
11162max t =
11263 case t of
113− { RBNode _ k v _ RBEmpty -> (k,v)
114− ; RBNode _ _ _ _ r -> max r
115− ; RBEmpty -> Native.Error.raise "(max Empty) is not defined"
116− }
117−--}
64+ RBNode _ k v _ (RBEmpty _) -> (k,v)
65+ RBNode _ _ _ _ r -> max r
66+ RBEmpty _ -> Native.Error.raise "(max Empty) is not defined"
11867
119−-- Lookup the value associated with a key.
68+{-| Lookup the value associated with a key. -}
12069lookup : comparable -> Dict comparable v -> Maybe v
12170lookup k t =
12271 case t of
123− RBEmpty -> Nothing
72+ RBEmpty LBlack -> Nothing
12473 RBNode _ k' v l r ->
12574 case Native.Utils.compare k k' of
12675 LT -> lookup k l
12776 EQ -> Just v
12877 GT -> lookup k r
12978
130−-- Find the value associated with a key. If the key is not found,
131−-- return the default value.
79+{-| Find the value associated with a key. If the key is not found,
80+return the default value. -}
13281findWithDefault : v -> comparable -> Dict comparable v -> v
13382findWithDefault base k t =
13483 case t of
135− RBEmpty -> base
84+ RBEmpty LBlack -> base
13685 RBNode _ k' v l r ->
13786 case Native.Utils.compare k k' of
13887 LT -> findWithDefault base k l
13988 EQ -> v
14089 GT -> findWithDefault base k r
14190
142−{--
143−-- Find the value associated with a key. If the key is not found, there will be a runtime error.
144−find k t =
145− case t of
146− { RBEmpty -> Native.Error.raise "Key was not found in dictionary!"
147− ; RBNode _ k' v l r ->
148− case Native.Utils.compare k k' of
149− { LT -> find k l
150− ; EQ -> v
151− ; GT -> find k r }
152− }
153−--}
154−
155−-- Determine if a key is in a dictionary.
91+{-| Determine if a key is in a dictionary. -}
15692member : comparable -> Dict comparable v -> Bool
15793-- Does t contain k?
15894member k t = isJust <| lookup k t
@@ -206,15 +142,16 @@ ensureBlackRoot : Dict k v -> Dict k v
206142ensureBlackRoot t =
207143 case t of
208144 RBNode Red k v l r -> RBNode Black k v l r
209− _ -> t
145+ RBNode Black _ _ _ _ -> t
146+ RBEmpty LBlack -> t
210147
211−-- Insert a key-value pair into a dictionary. Replaces value when there is
212−-- a collision.
148+{-| Insert a key-value pair into a dictionary. Replaces value when there is
149+a collision. -}
213150insert : comparable -> v -> Dict comparable v -> Dict comparable v
214151insert k v t = -- Invariant: t is a valid left-leaning rb tree
215152 let ins t =
216153 case t of
217− RBEmpty -> RBNode Red k v RBEmpty RBEmpty
154+ RBEmpty LBlack -> RBNode Red k v (RBEmpty LBlack) (RBEmpty LBlack)
218155 RBNode c k' v' l r ->
219156 let h = case Native.Utils.compare k k' of
220157 LT -> RBNode c k' v' (ins l) r
@@ -222,182 +159,190 @@ insert k v t = -- Invariant: t is a valid left-leaning rb tree
222159 GT -> RBNode c k' v' l (ins r)
223160 in fixUp h
224161 in ensureBlackRoot (ins t)
225−{--
226− if not (invariants_hold t) then
227− Native.Error.raise "invariants broken before insert"
228− else (let new_t = ensureBlackRoot (ins t) in
229− if not (invariants_hold new_t) then
230− Native.Error.raise "invariants broken after insert"
231− else new_t)
232−--}
233−
234−-- Create a dictionary with one key-value pair.
235−singleton : comparable -> v -> Dict comparable v
236−singleton k v = insert k v RBEmpty
237−
238−isRed : Dict k v -> Bool
239−isRed t =
240− case t of
241− RBNode Red _ _ _ _ -> True
242− _ -> False
243162
244−isRedLeft : Dict k v -> Bool
245−isRedLeft t =
246− case t of
247− RBNode _ _ _ (RBNode Red _ _ _ _) _ -> True
248− _ -> False
249−
250−isRedLeftLeft : Dict k v -> Bool
251−isRedLeftLeft t =
252− case t of
253− RBNode _ _ _ (RBNode _ _ _ (RBNode Red _ _ _ _) _) _ -> True
254− _ -> False
255−
256−isRedRight : Dict k v -> Bool
257−isRedRight t =
258− case t of
259− RBNode _ _ _ _ (RBNode Red _ _ _ _) -> True
260− _ -> False
261−
262−isRedRightLeft : Dict k v -> Bool
263−isRedRightLeft t =
264− case t of
265− RBNode _ _ _ _ (RBNode _ _ _ (RBNode Red _ _ _ _) _) -> True
266− _ -> False
267−
268−moveRedLeft : Dict k v -> Dict k v
269−moveRedLeft t =
270− let t' = color_flip t in
271− case t' of
272− RBNode c k v l r ->
273− case r of
274− RBNode _ _ _ (RBNode Red _ _ _ _) _ ->
275− color_flip (rotateLeft (RBNode c k v l (rotateRight r)))
276− _ -> t'
277− _ -> t'
278−
279−moveRedRight : Dict k v -> Dict k v
280−moveRedRight t =
281− let t' = color_flip t in
282− if isRedLeftLeft t' then color_flip (rotateRight t') else t'
283−
284−moveRedLeftIfNeeded : Dict k v -> Dict k v
285−moveRedLeftIfNeeded t =
286− if isRedLeft t || isRedLeftLeft t then t else moveRedLeft t
287−
288−moveRedRightIfNeeded : Dict k v -> Dict k v
289−moveRedRightIfNeeded t =
290− if isRedRight t || isRedRightLeft t then t else moveRedRight t
291−
292−deleteMin : Dict k v -> Dict k v
293−deleteMin t =
294− let del t =
295− case t of
296− RBNode _ _ _ RBEmpty _ -> RBEmpty
297− _ -> case moveRedLeftIfNeeded t of
298− RBNode c k v l r -> fixUp (RBNode c k v (del l) r)
299− RBEmpty -> RBEmpty
300− in ensureBlackRoot (del t)
301−
302−{--
303−deleteMax t =
304− let del t =
305− let t' = if isRedLeft t then rotateRight t else t in
306− case t' of
307− { RBNode _ _ _ _ RBEmpty -> RBEmpty
308− ; _ -> let t'' = moveRedRightIfNeeded t' in
309− case t'' of
310− { RBNode c k v l r -> fixUp (RBNode c k v l (del r))
311− ; RBEmpty -> RBEmpty } }
312− in ensureBlackRoot (del t)
313−--}
314−
315−-- Remove a key-value pair from a dictionary. If the key is not found,
316−-- no changes are made.
163+{-| Create a dictionary with one key-value pair. -}
164+singleton : comparable -> v -> Dict comparable v
165+singleton k v = insert k v (RBEmpty LBlack)
166+
167+{- Remove helpers: everything from here to remove should only be used
168+ internally by remove as they would otherwise break rb-invariants -}
169+
170+isBBlack : Dict k v -> Bool
171+isBBlack t = case t of
172+ RBNode c _ _ _ _ -> case c of
173+ BBlack -> True
174+ _ -> False
175+ RBEmpty LBBlack -> True
176+ _ -> False
177+
178+moreBlack : NColor -> NColor
179+moreBlack c = case c of
180+ BBlack -> BBlack
181+ Black -> BBlack
182+ Red -> Black
183+ NBlack -> Red
184+lessBlack : NColor -> NColor
185+lessBlack c = case c of
186+ BBlack -> Black
187+ Black -> Red
188+ Red -> NBlack
189+ NBlack -> NBlack
190+
191+moreBlackTree : Dict k v -> Dict k v
192+moreBlackTree t = case t of
193+ RBNode c k v l r -> RBNode (moreBlack c) k v l r
194+ RBEmpty _ -> RBEmpty LBBlack
195+
196+lessBlackTree : Dict k v -> Dict k v
197+lessBlackTree t = case t of
198+ RBNode c k v l r -> RBNode (lessBlack c) k v l r
199+ RBEmpty _ -> RBEmpty LBlack
200+
201+-- Finds and deletes k in t
202+del : comparable -> Dict comparable v -> Dict comparable v
203+del k t = case t of
204+ RBEmpty _ -> t
205+ RBNode c k' v l r -> case Native.Utils.compare k k' of
206+ LT -> bubble c k' v (del k l) r
207+ EQ -> rem t
208+ GT -> bubble c k' v l (del k r)
209+
210+-- Remove the top node from the tree, may leave behind BBlacks
211+rem : Dict k v -> Dict k v
212+rem t = case t of
213+ RBNode c k v (RBEmpty _) (RBEmpty _) -> case c of
214+ Red -> RBEmpty LBlack
215+ Black -> RBEmpty LBBlack
216+ RBNode Black _ _ (RBEmpty _) (RBNode _ k v l r) ->
217+ RBNode Black k v l r
218+ RBNode Black _ _ (RBNode _ k v l r) (RBEmpty _) ->
219+ RBNode Black k v l r
220+ -- l and r are both RBNodes
221+ RBNode c _ _ l r ->
222+ let (k, v) = max l
223+ l' = remove_max l
224+ in bubble c k v l' r
225+
226+-- Kills a BBlack or moves it upward, may leave behind NBlack
227+bubble : NColor -> k -> v -> Dict k v -> Dict k v -> Dict k v
228+bubble c k v l r = if isBBlack l || isBBlack r
229+ then balance (moreBlack c) k v (lessBlackTree l) (lessBlackTree r)
230+ else RBNode c k v l r
231+
232+-- Removes rightmost node, may leave root as BBlack
233+remove_max : Dict k v -> Dict k v
234+remove_max t = case t of
235+ RBNode c k v l (RBEmpty _) -> rem t
236+ RBNode c k v l r -> bubble c k v l (remove_max r)
237+
238+-- generalized tree balancing act
239+balance : NColor -> k -> v -> Dict k v -> Dict k v -> Dict k v
240+balance c k v l r = balance_node (RBNode c k v l r)
241+
242+blackish : Dict k v -> Bool
243+blackish (RBNode c _ _ _ _) = c == Black || c == BBlack
244+
245+balance_node : Dict k v -> Dict k v
246+balance_node t =
247+ let assemble col xk xv yk yv zk zv a b c d =
248+ RBNode (lessBlack col) yk yv (RBNode Black xk xv a b) (RBNode Black zk zv c d)
249+ in
250+ if blackish t
251+ then case t of
252+ RBNode col zk zv (RBNode Red yk yv (RBNode Red xk xv a b) c) d ->
253+ assemble col xk xv yk yv zk zv a b c d
254+ RBNode col zk zv (RBNode Red xk xv a (RBNode Red yk yv b c)) d ->
255+ assemble col xk xv yk yv zk zv a b c d
256+ RBNode col xk xv a (RBNode Red zk zv (RBNode Red yk yv b c) d) ->
257+ assemble col xk xv yk yv zk zv a b c d
258+ RBNode col xk xv a (RBNode Red yk yv b (RBNode Red zk zv c d)) ->
259+ assemble col xk xv yk yv zk zv a b c d
260+
261+ RBNode BBlack xk xv a (RBNode NBlack zk zv (RBNode Black yk yv b c) d) ->
262+ case d of
263+ (RBNode Black _ _ _ _) ->
264+ RBNode Black yk yv (RBNode Black xk xv a b) (balance Black zk zv c (redden d))
265+ _ -> t
266+
267+ RBNode BBlack zk zv (RBNode NBlack xk xv a (RBNode Black yk yv b c)) d ->
268+ case a of
269+ (RBNode Black _ _ _ _) ->
270+ RBNode Black yk yv (balance Black xk xv (redden a) b) (RBNode Black zk zv c d)
271+ _ -> t
272+
273+ _ -> t
274+
275+ else t
276+
277+-- make the top node black
278+blacken : Dict k v -> Dict k v
279+blacken t = case t of
280+ RBEmpty _ -> RBEmpty LBlack
281+ RBNode _ k v l r -> RBNode Black k v l r
282+
283+-- make the top node red
284+redden : Dict k v -> Dict k v
285+redden t = case t of
286+ RBEmpty _ -> Native.Error.raise "can't make a Leaf red"
287+ RBNode _ k v l r -> RBNode Red k v l r
288+
289+{-| Remove a key-value pair from a dictionary. If the key is not found,
290+no changes are made. -}
317291remove : comparable -> Dict comparable v -> Dict comparable v
318−remove k t =
319− let eq_and_noRightNode t =
320− case t of { RBNode _ k' _ _ RBEmpty -> k == k' ; _ -> False }
321− eq t = case t of { RBNode _ k' _ _ _ -> k == k' ; _ -> False }
322− delLT t = case moveRedLeftIfNeeded t of
323− RBNode c k' v l r -> fixUp (RBNode c k' v (del l) r)
324− RBEmpty -> Native.Error.raise "delLT on Empty"
325− delEQ t = case t of -- Replace with successor
326− RBNode c _ _ l r -> let (k',v') = min r in
327− fixUp (RBNode c k' v' l (deleteMin r))
328− RBEmpty -> Native.Error.raise "delEQ called on a Empty"
329− delGT t = case t of
330− RBNode c k' v l r -> fixUp (RBNode c k' v l (del r))
331− RBEmpty -> Native.Error.raise "delGT called on a Empty"
332− del t = case t of
333− RBEmpty -> RBEmpty
334− RBNode _ k' _ _ _ ->
335− if k < k' then delLT t else
336− let u = if isRedLeft t then rotateRight t else t in
337− if eq_and_noRightNode u then RBEmpty else
338− let t' = moveRedRightIfNeeded t in
339− if eq t' then delEQ t' else delGT t'
340− in if member k t then ensureBlackRoot (del t) else t
341−{--
342− if not (invariants_hold t) then
343− Native.Error.raise "invariants broken before remove"
344− else (let t' = ensureBlackRoot (del t) in
345− if invariants_hold t' then t' else
346− Native.Error.raise "invariants broken after remove")
347−--}
348−
349−-- Apply a function to all values in a dictionary.
292+remove k t = blacken <| del k t
293+
294+{-| Apply a function to all values in a dictionary. -}
350295map : (a -> b) -> Dict comparable a -> Dict comparable b
351296map f t =
352297 case t of
353− RBEmpty -> RBEmpty
298+ RBEmpty LBlack -> RBEmpty LBlack
354299 RBNode c k v l r -> RBNode c k (f v) (map f l) (map f r)
355300
356−-- Fold over the key-value pairs in a dictionary, in order from lowest
357−-- key to highest key.
301+{-| Fold over the key-value pairs in a dictionary, in order from lowest
302+key to highest key. -}
358303foldl : (comparable -> v -> b -> b) -> b -> Dict comparable v -> b
359304foldl f acc t =
360305 case t of
361− RBEmpty -> acc
306+ RBEmpty LBlack -> acc
362307 RBNode _ k v l r -> foldl f (f k v (foldl f acc l)) r
363308
364−-- Fold over the key-value pairs in a dictionary, in order from highest
365−-- key to lowest key.
309+{-| Fold over the key-value pairs in a dictionary, in order from highest
310+key to lowest key. -}
366311foldr : (comparable -> v -> b -> b) -> b -> Dict comparable v -> b
367312foldr f acc t =
368313 case t of
369− RBEmpty -> acc
314+ RBEmpty LBlack -> acc
370315 RBNode _ k v l r -> foldr f (f k v (foldr f acc r)) l
371316
372−-- Combine two dictionaries. If there is a collision, preference is given
373−-- to the first dictionary.
317+{-| Combine two dictionaries. If there is a collision, preference is given
318+to the first dictionary. -}
374319union : Dict comparable v -> Dict comparable v -> Dict comparable v
375320union t1 t2 = foldl insert t2 t1
376321
377−-- Keep a key-value pair when its key appears in the second dictionary.
378−-- Preference is given to values in the first dictionary.
322+{-| Keep a key-value pair when its key appears in the second dictionary.
323+Preference is given to values in the first dictionary. -}
379324intersect : Dict comparable v -> Dict comparable v -> Dict comparable v
380325intersect t1 t2 =
381326 let combine k v t = if k `member` t2 then insert k v t else t
382327 in foldl combine empty t1
383328
384−-- Keep a key-value pair when its key does not appear in the second dictionary.
385−-- Preference is given to the first dictionary.
329+{-| Keep a key-value pair when its key does not appear in the second dictionary.
330+Preference is given to the first dictionary. -}
386331diff : Dict comparable v -> Dict comparable v -> Dict comparable v
387332diff t1 t2 = foldl (\k v t -> remove k t) t1 t2
388333
389−-- Get all of the keys in a dictionary.
334+{-| Get all of the keys in a dictionary. -}
390335keys : Dict comparable v -> [comparable]
391336keys t = foldr (\k v acc -> k :: acc) [] t
392337
393−-- Get all of the values in a dictionary.
338+{-| Get all of the values in a dictionary. -}
394339values : Dict comparable v -> [v]
395340values t = foldr (\k v acc -> v :: acc) [] t
396341
397−-- Convert a dictionary into an association list of key-value pairs.
342+{-| Convert a dictionary into an association list of key-value pairs. -}
398343toList : Dict comparable v -> [(comparable,v)]
399344toList t = foldr (\k v acc -> (k,v) :: acc) [] t
400345
401−-- Convert an association list into a dictionary.
346+{-| Convert an association list into a dictionary. -}
402347fromList : [(comparable,v)] -> Dict comparable v
403348fromList assocs = List.foldl (\(k,v) d -> insert k v d) empty assocs
libraries/Either.elm+42−14
@@ -1,51 +1,79 @@
1−
21module Either where
32
3+{-| Represents any data that can take two different types.
4+
5+# Type and Constructors
6+@docs Either
7+
8+# Taking Eithers apart
9+@docs either, isLeft, isRight
10+
11+# Eithers and Lists
12+@docs lefts, rights, partition
13+
14+-}
15+
416import List
517
6−-- Represents any data that can take two different types.
7−--
8−-- This can also be used for error handling `(Either String a)` where error
9−-- messages are stored on the left, and the correct values (&ldquo;right&rdquo;
10−-- values) are stored on the right.
18+{-| Represents any data may take two forms. For example, a user ID may be
19+either an `Int` or a `String`.
20+
21+This can also be used for error handling `(Either String a)` where
22+error messages are stored on the left, and the correct values
23+(&ldquo;right&rdquo; values) are stored on the right.
24+-}
1125data Either a b = Left a | Right b
1226
13−-- Apply the first function to a `Left` and the second function to a `Right`.
14−-- This allows the extraction of a value from an `Either`.
27+{-| Apply the first function to a `Left` and the second function to a `Right`.
28+This allows the extraction of a value from an `Either`.
29+-}
1530either : (a -> c) -> (b -> c) -> Either a b -> c
1631either f g e = case e of { Left x -> f x ; Right y -> g y }
1732
18−-- True if the value is a `Left`.
33+{-| True if the value is a `Left`. -}
1934isLeft : Either a b -> Bool
2035isLeft e = case e of { Left _ -> True ; _ -> False }
2136
22−-- True if the value is a `Right`.
37+{-| True if the value is a `Right`. -}
2338isRight : Either a b -> Bool
2439isRight e = case e of { Right _ -> True ; _ -> False }
2540
26−-- Keep only the values held in `Left` values.
41+{-| Keep only the values held in `Left` values. -}
2742lefts : [Either a b] -> [a]
2843lefts es = List.foldr consLeft [] es
2944
30−-- Keep only the values held in `Right` values.
45+{-| Keep only the values held in `Right` values. -}
3146rights : [Either a b] -> [b]
3247rights es = List.foldr consRight [] es
3348
34−-- Split into two lists, lefts on the left and rights on the right. So we
35−-- have the equivalence: `(partition es == (lefts es, rights es))`
49+{-| Split into two lists, lefts on the left and rights on the right. So we
50+have the equivalence: `(partition es == (lefts es, rights es))`
51+-}
3652partition : [Either a b] -> ([a],[b])
3753partition es = List.foldr consEither ([],[]) es
3854
55+{-| If `Left`, add the value to the front of the list.
56+If `Right`, return the list unchanged
57+-}
58+consLeft : Either a b -> [a] -> [a]
3959consLeft e vs =
4060 case e of
4161 Left v -> v::vs
4262 Right _ -> vs
4363
64+{-| If `Right`, add the value to the front of the list.
65+If `Left`, return the list unchanged.
66+-}
67+consRight : Either a b -> [b] -> [b]
4468consRight e vs =
4569 case e of
4670 Left _ -> vs
4771 Right v -> v::vs
4872
73+{-| If `Left`, add the value to the left list.
74+If `Right`, add the value to the right list.
75+-}
76+consEither : Either a b -> ([a], [b]) -> ([a], [b])
4977consEither e (ls,rs) =
5078 case e of
5179 Left l -> (l::ls,rs)
libraries/Graphics/Collage.elm+103−58
@@ -1,6 +1,35 @@
1−
21module Graphics.Collage where
32
3+{-| The collage API is for freeform graphics. You can move, rotate, scale, etc.
4+all sorts of forms including lines, shapes, images, and elements.
5+
6+# Unstructured Graphics
7+@docs collage
8+
9+# Creating Forms
10+@docs toForm, filled, textured, gradient, outlined, traced
11+
12+# Transforming Forms
13+@docs move, moveX, moveY, scale, rotate, alpha
14+
15+# Grouping Forms
16+Grouping forms makes it easier to write modular graphics code. You can create
17+a form that is a composite of many subforms. From there it is easy to transform
18+it as a single unit.
19+
20+@docs group, groupTransform
21+
22+# Shapes
23+@docs rect, oval, square, circle, ngon, polygon
24+
25+# Paths
26+@docs segment, path
27+
28+# Line Styles
29+@docs solid, dashed, dotted, LineStyle, LineCap, LineJoin, defaultLine
30+
31+-}
32+
433import open Basics
534import List
635import Either (Either, Left, Right)
@@ -25,16 +54,18 @@ data FillStyle
2554 | Texture String
2655 | Grad Gradient
2756
28−-- The shape of the ends of a line.
57+{-| The shape of the ends of a line. -}
2958data LineCap = Flat | Round | Padded
3059
31−-- The shape of the &ldquo;joints&rdquo; of a line, where each line segment
32−-- meets. `Sharp` takes an argument to limit the length of the joint. This
33−-- defaults to 10.
60+{-| The shape of the &ldquo;joints&rdquo; of a line, where each line segment
61+meets. `Sharp` takes an argument to limit the length of the joint. This
62+defaults to 10.
63+-}
3464data LineJoin = Smooth | Sharp Float | Clipped
3565
36−-- All of the attributes of a line style. This lets you build up a line style
37−-- however you want. You can also update existing line styles with record updates.
66+{-| All of the attributes of a line style. This lets you build up a line style
67+however you want. You can also update existing line styles with record updates.
68+-}
3869type LineStyle = {
3970 color : Color,
4071 width : Float,
@@ -44,11 +75,12 @@ type LineStyle = {
4475 dashOffset : Int
4576 }
4677
47−-- The default line style, which is solid black with flat caps and sharp joints.
48−-- You can use record updates to build the line style you
49−-- want. For example, to make a thicker line, you could say:
50−--
51−-- { defaultLine | width <- 10 }
78+{-| The default line style, which is solid black with flat caps and sharp joints.
79+You can use record updates to build the line style you
80+want. For example, to make a thicker line, you could say:
81+
82+ { defaultLine | width <- 10 }
83+-}
5284defaultLine : LineStyle
5385defaultLine = {
5486 color = black,
@@ -59,15 +91,15 @@ defaultLine = {
5991 dashOffset = 0
6092 }
6193
62−-- Create a solid line style with a given color.
94+{-| Create a solid line style with a given color. -}
6395solid : Color -> LineStyle
6496solid clr = { defaultLine | color <- clr }
6597
66−-- Create a dashed line style with a given color. Dashing equals `[8,4]`.
98+{-| Create a dashed line style with a given color. Dashing equals `[8,4]`. -}
6799dashed : Color -> LineStyle
68100dashed clr = { defaultLine | color <- clr, dashing <- [8,4] }
69101
70−-- Create a dotted line style with a given color. Dashing equals `[3,3]`.
102+{-| Create a dotted line style with a given color. Dashing equals `[3,3]`. -}
71103dotted : Color -> LineStyle
72104dotted clr = { defaultLine | color <- clr, dashing <- [3,3] }
73105
@@ -83,113 +115,125 @@ form f = { theta=0, scale=1, x=0, y=0, alpha=1, form=f }
83115
84116fill style shape = form (FShape (Right style) shape)
85117
86−-- Create a filled in shape.
118+{-| Create a filled in shape. -}
87119filled : Color -> Shape -> Form
88120filled color shape = fill (Solid color) shape
89121
90−-- Create a textured shape. The texture is described by some url and is
91−-- tiled to fill the entire shape.
122+{-| Create a textured shape. The texture is described by some url and is
123+tiled to fill the entire shape.
124+-}
92125textured : String -> Shape -> Form
93126textured src shape = fill (Texture src) shape
94127
95−-- Fill a shape with a [gradient](/docs/Color.elm#linear).
128+{-| Fill a shape with a [gradient](/docs/Color.elm#linear). -}
96129gradient : Gradient -> Shape -> Form
97130gradient grad shape = fill (Grad grad) shape
98131
99−-- Outline a shape with a given line style.
132+{-| Outline a shape with a given line style. -}
100133outlined : LineStyle -> Shape -> Form
101134outlined style shape = form (FShape (Left style) shape)
102135
103−-- Trace a path with a given line style.
136+{-| Trace a path with a given line style. -}
104137traced : LineStyle -> Path -> Form
105138traced style path = form (FPath style path)
106139
107−-- Create a sprite from a sprite sheet. It cuts out a rectangle
108−-- at a given position.
140+{-| Create a sprite from a sprite sheet. It cuts out a rectangle
141+at a given position.
142+-}
109143sprite : Int -> Int -> (Int,Int) -> String -> Form
110144sprite w h pos src = form (FImage w h pos src)
111145
112−-- Turn any `Element` into a `Form`. This lets you use text, gifs, and video
113−-- in your collage. This means you can move, rotate, and scale
114−-- an `Element` however you want.
146+{-| Turn any `Element` into a `Form`. This lets you use text, gifs, and video
147+in your collage. This means you can move, rotate, and scale
148+an `Element` however you want.
149+-}
115150toForm : Element -> Form
116151toForm e = form (FElement e)
117152
118−-- Flatten many forms into a single `Form`. This lets you move and rotate them
119−-- as a single unit, making it possible to build small, modular components.
153+{-| Flatten many forms into a single `Form`. This lets you move and rotate them
154+as a single unit, making it possible to build small, modular components.
155+-}
120156group : [Form] -> Form
121157group fs = form (FGroup identity fs)
122158
123−-- Flatten many forms into a single `Form` and then apply a matrix
124−-- transformation.
159+{-| Flatten many forms into a single `Form` and then apply a matrix
160+transformation.
161+-}
125162groupTransform : Transform2D -> [Form] -> Form
126163groupTransform matrix fs = form (FGroup matrix fs)
127164
128−-- Rotate a form by a given angle. Rotate takes standard Elm angles (radians)
129−-- and turns things counterclockwise. So to turn `form` 30&deg; to the left
130−-- you would say, `(rotate (degrees 30) form)`.
165+{-| Rotate a form by a given angle. Rotate takes standard Elm angles (radians)
166+and turns things counterclockwise. So to turn `form` 30&deg; to the left
167+you would say, `(rotate (degrees 30) form)`.
168+-}
131169rotate : number -> Form -> Form
132170rotate t f = { f | theta <- f.theta + t }
133171
134−-- Scale a form by a given factor. Scaling by 2 doubles the size.
172+{-| Scale a form by a given factor. Scaling by 2 doubles the size.
173+-}
135174scale : number -> Form -> Form
136175scale s f = { f | scale <- f.scale * s }
137176
138−-- Move a form by the given amount. This is a relative translation so
139−-- `(move (10,10) form)` would move `form` ten pixels up and ten pixels to the
140−-- right.
177+{-| Move a form by the given amount. This is a relative translation so
178+`(move (10,10) form)` would move `form` ten pixels up and ten pixels to the
179+right.
180+-}
141181move : (number,number) -> Form -> Form
142182move (x,y) f = { f | x <- f.x + x, y <- f.y + y }
143183
144−-- Move a shape in the x direction. This is relative so `(moveX 10 form)` moves
145−-- `form` 10 pixels to the right.
184+{-| Move a shape in the x direction. This is relative so `(moveX 10 form)` moves
185+`form` 10 pixels to the right.
186+-}
146187moveX : number -> Form -> Form
147188moveX x f = { f | x <- f.x + x }
148189
149−-- Move a shape in the y direction. This is relative so `(moveY 10 form)` moves
150−-- `form` upwards by 10 pixels.
190+{-| Move a shape in the y direction. This is relative so `(moveY 10 form)` moves
191+`form` upwards by 10 pixels.
192+-}
151193moveY : number -> Form -> Form
152194moveY y f = { f | y <- f.y + y }
153195
154−-- Set the alpha of a `Form`. The default is 1, and 0 is totally transparent.
196+{-| Set the alpha of a `Form`. The default is 1, and 0 is totally transparent. -}
155197alpha : Float -> Form -> Form
156198alpha a f = { f | alpha <- a }
157199
158−-- A collage is a collection of 2D forms. There are no strict positioning
159−-- relationships between forms, so you are free to do all kinds of 2D graphics.
200+{-| A collage is a collection of 2D forms. There are no strict positioning
201+relationships between forms, so you are free to do all kinds of 2D graphics.
202+-}
160203collage : Int -> Int -> [Form] -> Element
161204collage = Native.Graphics.Collage.collage
162205
163206
164207type Path = [(number,number)]
165208
166−-- Create a path that follows a sequence of points.
209+{-| Create a path that follows a sequence of points. -}
167210path : [(number,number)] -> Path
168211path ps = ps
169212
170−-- Create a path along a given line segment.
213+{-| Create a path along a given line segment. -}
171214segment : (number,number) -> (number,number) -> Path
172215segment p1 p2 = [p1,p2]
173216
174217type Shape = [(number,number)]
175218
176−-- Create an arbitrary polygon by specifying its corners in order.
177−-- `polygon` will automatically close all shapes, so the given list
178−-- of points does not need to start and end with the same position.
219+{-| Create an arbitrary polygon by specifying its corners in order.
220+`polygon` will automatically close all shapes, so the given list
221+of points does not need to start and end with the same position.
222+-}
179223polygon : [(number,number)] -> Shape
180224polygon points = points
181225
182−-- A rectangle with a given width and height.
226+{-| A rectangle with a given width and height. -}
183227rect : number -> number -> Shape
184228rect w h = let hw = w/2
185229 hh = h/2
186230 in [ (0-hw,0-hh), (0-hw,hh), (hw,hh), (hw,0-hh) ]
187231
188−-- A square with a given edge length.
232+{-| A square with a given edge length. -}
189233square : number -> Shape
190234square n = rect n n
191235
192−-- An oval with a given width and height.
236+{-| An oval with a given width and height. -}
193237oval : number -> number -> Shape
194238oval w h =
195239 let n = 50
@@ -199,15 +243,16 @@ oval w h =
199243 f i = (hw * cos (t*i), hh * sin (t*i))
200244 in List.map f [0..n-1]
201245
202−-- A circle with a given radius.
246+{-| A circle with a given radius. -}
203247circle : number -> Shape
204248circle r = oval (2*r) (2*r)
205249
206−-- A regular polygon with N sides. The first argument specifies the number
207−-- of sides and the second is the radius. So to create a pentagon with radius
208−-- 30 you would say:
209−--
210−-- ngon 5 30
250+{-| A regular polygon with N sides. The first argument specifies the number
251+of sides and the second is the radius. So to create a pentagon with radius
252+30 you would say:
253+
254+ ngon 5 30
255+-}
211256ngon : Int -> number -> Shape
212257ngon n r =
213258 let m = toFloat n
libraries/Graphics/Element.elm+95−51
@@ -1,5 +1,41 @@
1−
21module Graphics.Element where
2+{-| Graphical elements that snap together to build complex widgets and layouts.
3+Each Element is a rectangle with a known width and height, making them easy to
4+combine and position.
5+
6+# Images
7+@docs image, fittedImage, croppedImage, tiledImage
8+
9+# Styling
10+@docs width, height, size, color, opacity, link, tag
11+
12+# Inspection
13+@docs widthOf, heightOf, sizeOf
14+
15+# Layout
16+@docs flow, up, down, left, right, inward, outward
17+
18+## Layout Aliases
19+There are also some convenience functions for working
20+with `flow` in specific cases:
21+
22+@docs layers, above, below, beside
23+
24+# Positioning
25+@docs spacer, container
26+
27+## Specific Positions
28+
29+To create a `Position` you can use any of the built-in positions
30+which cover nine common positions.
31+@docs middle, midTop, midBottom, midLeft, midRight, topLeft, topRight,
32+ bottomLeft, bottomRight
33+
34+If you need more precision, you can create custom positions.
35+
36+@docs absolute, relative, middleAt, midTopAt, midBottomAt, midLeftAt,
37+ midRightAt, topLeftAt, topRightAt, bottomLeftAt, bottomRightAt
38+-}
339
440import open Basics
541import Native.Utils
@@ -22,19 +58,19 @@ type Properties = {
2258
2359type Element = { props : Properties, element : ElementPrim }
2460
25−-- Get the width of an Element
61+{-| Get the width of an Element -}
2662widthOf : Element -> Int
2763widthOf e = e.props.width
2864
29−-- Get the height of an Element
65+{-| Get the height of an Element -}
3066heightOf : Element -> Int
3167heightOf e = e.props.height
3268
33−-- Get the width and height of an Element
69+{-| Get the width and height of an Element -}
3470sizeOf : Element -> (Int,Int)
3571sizeOf e = (e.props.width, e.props.height)
3672
37−-- Create an `Element` with a given width.
73+{-| Create an `Element` with a given width. -}
3874width : Int -> Element -> Element
3975width nw e =
4076 let p = e.props
@@ -44,7 +80,7 @@ width nw e =
4480 _ -> p
4581 in { element=e.element, props={ props | width <- nw } }
4682
47−-- Create an `Element` with a given height.
83+{-| Create an `Element` with a given height. -}
4884height : Int -> Element -> Element
4985height nh e =
5086 let p = e.props
@@ -53,30 +89,32 @@ height nh e =
5389 _ -> p
5490 in { element=e.element, props={ p | height <- nh} }
5591
56−-- Create an `Element` with a new width and height.
92+{-| Create an `Element` with a new width and height. -}
5793size : Int -> Int -> Element -> Element
5894size w h e = height h (width w e)
5995
60−-- Create an `Element` with a given opacity. Opacity is a number between 0 and 1
61−-- where 0 means totally clear.
96+{-| Create an `Element` with a given opacity. Opacity is a number between 0 and 1
97+where 0 means totally clear.
98+-}
6299opacity : Float -> Element -> Element
63100opacity o e = let p = e.props in { element=e.element, props={p| opacity <- o} }
64101
65−-- Create an `Element` with a given background color.
102+{-| Create an `Element` with a given background color. -}
66103color : Color -> Element -> Element
67104color c e = let p = e.props in
68105 { element = e.element
69106 , props = { p | color <- Just c}
70107 }
71108
72−-- Create an `Element` with a tag. This lets you link directly to it.
73−-- The element `(tag "all-about-badgers" thirdParagraph)` can be reached
74−-- with a link lik this: `/facts-about-animals.elm#all-about-badgers`
109+{-| Create an `Element` with a tag. This lets you link directly to it.
110+The element `(tag "all-about-badgers" thirdParagraph)` can be reached
111+with a link lik this: `/facts-about-animals.elm#all-about-badgers`
112+-}
75113tag : String -> Element -> Element
76114tag name e = let p = e.props in
77115 { element=e.element, props={p | tag <- JS.fromString name} }
78116
79−-- Create an `Element` that is a hyper-link.
117+{-| Create an `Element` that is a hyper-link. -}
80118link : String -> Element -> Element
81119link href e = let p = e.props in
82120 { element=e.element, props={p | href <- JS.fromString href} }
@@ -95,20 +133,22 @@ data ElementPrim
95133
96134data ImageStyle = Plain | Fitted | Cropped (Int,Int) | Tiled
97135
98−-- Create an image given a width, height, and image source.
136+{-| Create an image given a width, height, and image source. -}
99137image : Int -> Int -> String -> Element
100138image w h src = newElement w h (Image Plain w h (JS.fromString src))
101139
102−-- Create a fitted image given a width, height, and image source.
103−-- This will crop the picture to best fill the given dimensions.
140+{-| Create a fitted image given a width, height, and image source.
141+This will crop the picture to best fill the given dimensions.
142+-}
104143fittedImage : Int -> Int -> String -> Element
105144fittedImage w h src = newElement w h (Image Fitted w h (JS.fromString src))
106145
107−-- Create a cropped image. Take a rectangle out of the picture starting
108−-- at the given top left coordinate. If you have a 140-by-140 image,
109−-- the following will cut a 100-by-100 square out of the middle of it.
110−--
111−-- croppedImage (20,20) 100 100 "yogi.jpg"
146+{-| Create a cropped image. Take a rectangle out of the picture starting
147+at the given top left coordinate. If you have a 140-by-140 image,
148+the following will cut a 100-by-100 square out of the middle of it.
149+
150+ croppedImage (20,20) 100 100 "yogi.jpg"
151+-}
112152croppedImage : (Int,Int) -> Int -> Int -> String -> Element
113153croppedImage pos w h src =
114154 newElement w h (Image (Cropped pos) w h (JS.fromString src))
@@ -117,38 +157,38 @@ tiledImage : Int -> Int -> String -> Element
117157tiledImage w h src =
118158 newElement w h (Image Tiled w h (JS.fromString src))
119159
120−markdown : Element
121−markdown = Native.Utils.undefined
122−
123160data Three = P | Z | N
124161data Pos = Absolute Int | Relative Float
125162type Position = { horizontal : Three, vertical : Three, x : Pos, y : Pos }
126163
127−-- Put an element in a container. This lets you position the element really
128−-- easily, and there are tons of ways to set the `Position`.
129−-- To center `element` exactly in a 300-by-300 square you would say:
130−--
131−-- container 300 300 middle element
132−--
133−-- By setting the color of the container, you can create borders.
164+{-| Put an element in a container. This lets you position the element really
165+easily, and there are tons of ways to set the `Position`.
166+To center `element` exactly in a 300-by-300 square you would say:
167+
168+ container 300 300 middle element
169+
170+By setting the color of the container, you can create borders.
171+-}
134172container : Int -> Int -> Position -> Element -> Element
135173container w h pos e = newElement w h (Container pos e)
136174
137−-- Create an empty box. This is useful for getting your spacing right and
138−-- for making borders.
175+{-| Create an empty box. This is useful for getting your spacing right and
176+for making borders.
177+-}
139178spacer : Int -> Int -> Element
140179spacer w h = newElement w h Spacer
141180
142181data Direction = DUp | DDown | DLeft | DRight | DIn | DOut
143182
144−-- Have a list of elements flow in a particular direction.
145−-- The `Direction` starts from the first element in the list.
146−--
147−-- flow right [a,b,c]
148−--
149−-- +---+---+---+
150−-- | a | b | c |
151−-- +---+---+---+
183+{-| Have a list of elements flow in a particular direction.
184+The `Direction` starts from the first element in the list.
185+
186+ flow right [a,b,c]
187+
188+ +---+---+---+
189+ | a | b | c |
190+ +---+---+---+
191+-}
152192flow : Direction -> [Element] -> Element
153193flow dir es =
154194 let ws = List.map widthOf es
@@ -164,33 +204,37 @@ flow dir es =
164204 DIn -> newFlow (List.maximum ws) (List.maximum hs)
165205 DOut -> newFlow (List.maximum ws) (List.maximum hs)
166206
167−-- Stack elements vertically. To put `a` above `b` you would say:
168−--
169−-- a `above` b
207+{-| Stack elements vertically. To put `a` above `b` you would say:
208+
209+ a `above` b
210+-}
170211above : Element -> Element -> Element
171212above hi lo =
172213 newElement (max (widthOf hi) (widthOf lo))
173214 (heightOf hi + heightOf lo)
174215 (Flow DDown [hi,lo])
175216
176−-- Stack elements vertically. To put `a` below `b` you would say:
177−--
178−-- a `below` b
217+{-| Stack elements vertically. To put `a` below `b` you would say:
218+
219+ a `below` b
220+-}
179221below : Element -> Element -> Element
180222below lo hi =
181223 newElement (max (widthOf hi) (widthOf lo))
182224 (heightOf hi + heightOf lo)
183225 (Flow DDown [hi,lo])
184226
185−-- Put elements beside each other horizontally.
227+{-| Put elements beside each other horizontally.
228+-}
186229beside : Element -> Element -> Element
187230beside lft rht =
188231 newElement (widthOf lft + widthOf rht)
189232 (max (heightOf lft) (heightOf rht))
190233 (Flow right [lft,rht])
191234
192−-- Layer elements on top of each other, starting from the bottom.
193−-- `(layers == flow outward)`
235+{-| Layer elements on top of each other, starting from the bottom.
236+`(layers == flow outward)`
237+-}
194238layers : [Element] -> Element
195239layers es =
196240 let ws = List.map widthOf es
libraries/Graphics/Input.elm+115−76
@@ -1,6 +1,31 @@
1−
21module Graphics.Input where
32
3+{-| This module is for creating standard input widgets such as buttons and
4+text boxes. In general, functions in this library return a signal representing
5+events from the user.
6+
7+The simplest inputs are *one-way inputs*, meaning the user can update
8+them, but the programmer cannot. If you need to update an input from
9+within the program you want the slightly more complex *two-way inputs*.
10+This document will always show the one-way inputs first, *then* the
11+two-way inputs.
12+
13+# Buttons
14+@docs button, customButton, buttons, customButtons
15+
16+# Fields
17+@docs field, password, email, fields, FieldState, emptyFieldState
18+
19+# Checkboxes
20+@docs checkbox, checkboxes
21+
22+# Drop Downs
23+@docs stringDropDown, dropDown
24+
25+# Mouse Hover
26+@docs hoverable, hoverables
27+-}
28+
429import Basics (String)
530import Signal (Signal,lift,dropRepeats)
631import Native.Graphics.Input
@@ -11,116 +36,127 @@ import JavaScript (JSString)
1136
1237id x = x
1338
14−-- Create a group of buttons.
15−--
16−-- * The first argument is the default value of the `events` signal.
17−-- * The `events` signal represents all of the activity in this group
18−-- of buttons.
19−-- * The `button` function creates a button
20−-- with the given name, like &ldquo;Submit&rdquo; or &ldquo;Cancel&rdquo;.
21−-- The `a` value is sent to `events` whenever the button is pressed.
39+{-| Create a group of buttons.
40+
41+ * The first argument is the default value of the `events` signal.
42+ * The `events` signal represents all of the activity in this group
43+ of buttons.
44+ * The `button` function creates a button
45+ with the given name, like &ldquo;Submit&rdquo; or &ldquo;Cancel&rdquo;.
46+ The `a` value is sent to `events` whenever the button is pressed.
47+-}
2248buttons : a -> { events : Signal a,
2349 button : a -> String -> Element }
2450buttons = Native.Graphics.Input.buttons
2551
26−-- Create a button with a given label. The result is an `Element` and
27−-- a signal of units. This signal triggers whenever the button is pressed.
52+{-| Create a button with a given label. The result is an `Element` and
53+a signal of units. This signal triggers whenever the button is pressed.
54+-}
2855button : String -> (Element, Signal ())
2956button txt =
3057 let pool = buttons ()
3158 in (pool.button () txt, pool.events)
3259
33−-- Create a group of custom buttons.
34−--
35−-- * The first argument is the default value of the `events` signal.
36−-- * The `events` signal represents all of the activity in this group
37−-- of custom buttons.
38−-- * The `customButton` function creates a button with three different visual
39−-- states, one for up, hovering, and down. The resulting button has dimensions
40−-- large enough to fit all three possible `Elements`.
41−-- The `a` value is sent to `events` whenever the button is pressed.
60+{-| Create a group of custom buttons.
61+
62+ * The first argument is the default value of the `events` signal.
63+ * The `events` signal represents all of the activity in this group
64+ of custom buttons.
65+ * The `customButton` function creates a button with three different visual
66+ states, one for up, hovering, and down. The resulting button has dimensions
67+ large enough to fit all three possible `Elements`.
68+ The `a` value is sent to `events` whenever the button is pressed.
69+-}
4270customButtons : a -> { events : Signal a,
4371 customButton : a -> Element -> Element -> Element -> Element }
4472customButtons = Native.Graphics.Input.customButtons
4573
46−-- Create a button with custom states for up, hovering, and down
47−-- (given in that order). The result is an `Element` and
48−-- a signal of units. This signal triggers whenever the button is pressed.
74+{-| Create a button with custom states for up, hovering, and down
75+(given in that order). The result is an `Element` and a signal of
76+units. This signal triggers whenever the button is pressed.
77+-}
4978customButton : Element -> Element -> Element -> (Element, Signal ())
5079customButton up hover down =
5180 let pool = customButtons ()
5281 in (pool.customButton () up hover down, pool.events)
5382
54−-- Create a group of checkboxes.
55−--
56−-- * The first argument is the default value of the `events` signal.
57−-- * The `events` signal represents all of the activity in this group
58−-- of checkboxes.
59−-- * The `checkbox` function creates a
60−-- checkbox with a given state. The `(Bool -> a)` function is used
61−-- when the checkbox is modified. It takes the new state and turns
62−-- it into a value that can be sent to `events`. For example, this
63−-- lets you add an ID to distinguish between checkboxes.
83+{-| Create a group of checkboxes.
84+
85+ * The first argument is the default value of the `events` signal.
86+ * The `events` signal represents all of the activity in this group
87+ of checkboxes.
88+ * The `checkbox` function creates a
89+ checkbox with a given state. The `(Bool -> a)` function is used
90+ when the checkbox is modified. It takes the new state and turns
91+ it into a value that can be sent to `events`. For example, this
92+ lets you add an ID to distinguish between checkboxes.
93+-}
6494checkboxes : a -> { events : Signal a,
6595 checkbox : (Bool -> a) -> Bool -> Element }
6696checkboxes = Native.Graphics.Input.checkboxes
6797
68−-- Create a checkbox with a given start state. Unlike `button`, this result
69−-- is a *signal* of elements. That is because a checkbox has state that
70−-- updates based on user input.
71−-- The boolean signal represents the current state of the checkbox.
98+{-| Create a checkbox with a given start state. Unlike `button`, this
99+result is a *signal* of elements. That is because a checkbox has state
100+that updates based on user input. The boolean signal represents the
101+current state of the checkbox.
102+-}
72103checkbox : Bool -> (Signal Element, Signal Bool)
73104checkbox b =
74105 let cbs = checkboxes b
75106 in (lift (cbs.checkbox id) cbs.events, cbs.events)
76107
77−-- Detect when the mouse is hovering over some elements. This
78−-- allows you to create and destroy elements dynamically and still
79−-- detect hover information.
108+{-| Detect when the mouse is hovering over some elements. This
109+allows you to create and destroy elements dynamically and still
110+detect hover information.
111+-}
80112hoverables : a -> { events : Signal a,
81113 hoverable : (Bool -> a) -> Element -> Element }
82114hoverables = Native.Graphics.Input.hoverables
83115
84−-- Detect when the mouse is hovering over a specifici `Element`.
116+{-| Detect when the mouse is hovering over a specifici `Element`. -}
85117hoverable : Element -> (Element, Signal Bool)
86118hoverable elem =
87119 let pool = hoverables False
88120 in (pool.hoverable id elem, pool.events)
89121
90−-- Represents the current state of a text field. The `string` represents the
91−-- characters filling the text field. The `selectionStart` and `selectionEnd`
92−-- values represent what the user has selected with their mouse or keyboard.
93−-- For example:
94−--
95−-- { string="She sells sea shells", selectionStart=3, selectionEnd=0 }
96−--
97−-- This means the user highlighted the substring `"She"` backwards.
122+{-| Represents the current state of a text field. The `string` represents the
123+characters filling the text field. The `selectionStart` and `selectionEnd`
124+values represent what the user has selected with their mouse or keyboard.
125+For example:
126+
127+ { string="She sells sea shells", selectionStart=3, selectionEnd=0 }
128+
129+This means the user highlighted the substring `"She"` backwards.
130+-}
98131type FieldState = { string:String, selectionStart:Int, selectionEnd:Int }
99132
100−-- Create a group of text input fields.
101−--
102−-- * The first argument is the default value of the `events` signal.
103−-- * The `events` signal represents all of the activity in this group
104−-- of text fields.
105−-- * The `field` function creates a
106−-- field with the given ghost text and initial field state.
107−-- When the field is modified, the `(FieldState -> a)` function
108−-- takes the new state and turns
109−-- it into a value that can be sent to `events`. For example, this
110−-- lets you add an ID to distinguish between input fields.
133+{-| Create a group of text input fields.
134+
135+ * The first argument is the default value of the `events` signal.
136+ * The `events` signal represents all of the activity in this group
137+ of text fields.
138+ * The `field` function creates a
139+ field with the given ghost text and initial field state.
140+ When the field is modified, the `(FieldState -> a)` function
141+ takes the new state and turns
142+ it into a value that can be sent to `events`. For example, this
143+ lets you add an ID to distinguish between input fields.
144+-}
111145fields : a -> { events : Signal a,
112146 field : (FieldState -> a) -> String -> FieldState -> Element }
113147fields = Native.Graphics.Input.fields
114148
115−-- The empty field state:
116−--
117−-- { string="", selectionStart=0, selectionEnd=0 }
149+{-| The empty field state:
150+
151+ { string="", selectionStart=0, selectionEnd=0 }
152+-}
118153emptyFieldState : FieldState
119154emptyFieldState = { string="", selectionStart=0, selectionEnd=0 }
120155
121−-- Create a field with the given default text. The output is an element that
122−-- updates to match the user input and a signal of strings representing the
123−-- content of the field.
156+{-| Create a field with the given default text. The output is an element
157+that updates to match the user input and a signal of strings representing
158+the content of the field.
159+-}
124160field : String -> (Signal Element, Signal String)
125161field placeHolder =
126162 let tfs = fields emptyFieldState
@@ -128,7 +164,7 @@ field placeHolder =
128164 in (lift (tfs.field id placeHolder) changes,
129165 dropRepeats (lift .string changes))
130166
131−-- Same as `field` but the UI element blocks out each characters.
167+{-| Same as `field` but the UI element blocks out each characters. -}
132168password : String -> (Signal Element, Signal String)
133169password placeHolder =
134170 let tfs = Native.Graphics.Input.passwords emptyFieldState
@@ -136,9 +172,10 @@ password placeHolder =
136172 in (lift (tfs.field id placeHolder) changes,
137173 dropRepeats (lift .string changes))
138174
139−-- Same as `field` but it adds an annotation that this field is for email
140−-- addresses. This is helpful for auto-complete and for mobile users who may
141−-- get a custom keyboard with an `@` and `.com` button.
175+{-| Same as `field` but it adds an annotation that this field is for email
176+addresses. This is helpful for auto-complete and for mobile users who may
177+get a custom keyboard with an `@` and `.com` button.
178+-}
142179email : String -> (Signal Element, Signal String)
143180email placeHolder =
144181 let tfs = Native.Graphics.Input.emails emptyFieldState
@@ -146,15 +183,17 @@ email placeHolder =
146183 in (lift (tfs.field id placeHolder) changes,
147184 dropRepeats (lift .string changes))
148185
149−-- Create a drop-down menu. When the user selects a string,
150−-- the current state of the drop-down is set to the associated
151−-- value. This lets you avoid manually mapping the string onto
152−-- functions and values.
186+{-| Create a drop-down menu. When the user selects a string,
187+the current state of the drop-down is set to the associated
188+value. This lets you avoid manually mapping the string onto
189+functions and values.
190+-}
153191dropDown : [(String,a)] -> (Signal Element, Signal a)
154192dropDown = Native.Graphics.Input.dropDown
155193
156−-- Create a drop-down menu for selecting strings. The resulting
157−-- signal of strings represents the string that is currently selected.
194+{-| Create a drop-down menu for selecting strings. The resulting
195+signal of strings represents the string that is currently selected.
196+-}
158197stringDropDown : [String] -> (Signal Element, Signal String)
159198stringDropDown strs =
160199 dropDown (List.map (\s -> (s,s)) strs)
libraries/Http.elm+28−17
@@ -1,15 +1,25 @@
1−-- A library for asynchronous HTTP requests (AJAX). See the
2−-- [WebSocket](http://elm-lang.org/docs/WebSocket.elm) library if
3−-- you have very strict latency requirements.
4−
51module Http where
62
7−import open Basics
3+{-| A library for asynchronous HTTP requests. See the
4+[WebSocket](http://elm-lang.org/docs/WebSocket.elm) library if
5+you have very strict latency requirements.
6+
7+# Sending Requests
8+@docs send, sendGet
9+
10+# Creating Requests
11+@docs get, post, request
12+
13+# Responses
14+@docs Response
15+-}
16+
817import open Signal
918import Native.Http
1019
11−-- The datatype for responses. Success contains only the returned message.
12−-- Failures contain both an error code and an error message.
20+{-| The datatype for responses. Success contains only the returned message.
21+Failures contain both an error code and an error message.
22+-}
1323data Response a = Success a | Waiting | Failure Int String
1424
1525type Request a = {
@@ -19,27 +29,28 @@ type Request a = {
1929 headers : [(String,String)]
2030 }
2131
22−-- Create a customized request. Arguments are request type (get, post, put,
23−-- delete, etc.), target url, data, and a list of additional headers.
32+{-| Create a customized request. Arguments are request type (get, post, put,
33+delete, etc.), target url, data, and a list of additional headers.
34+-}
2435request : String -> String -> String -> [(String,String)] -> Request String
2536request = Request
2637
27−-- Create a GET request to the given url.
38+{-| Create a GET request to the given url. -}
2839get : String -> Request String
2940get url = Request "GET" url "" []
3041
31−-- Create a POST request to the given url, carrying the given data.
42+{-| Create a POST request to the given url, carrying the given data. -}
3243post : String -> String -> Request String
3344post url body = Request "POST" url body []
3445
35−
36−-- Performs an HTTP request with the given requests. Produces a signal
37−-- that carries the responses.
46+{-| Performs an HTTP request with the given requests. Produces a signal
47+that carries the responses.
48+-}
3849send : Signal (Request a) -> Signal (Response String)
3950send = Native.Http.send
4051
41−-- Performs an HTTP GET request with the given urls. Produces a signal
42−-- that carries the responses.
52+{-| Performs an HTTP GET request with the given urls. Produces a signal
53+that carries the responses.
54+-}
4355sendGet : Signal String -> Signal (Response String)
4456sendGet reqs = send (lift get reqs)
45−
libraries/JavaScript.elm+22−8
@@ -1,8 +1,22 @@
11
22module JavaScript where
33
4+{-|This library does basic conversions between Elm and JS values. This allows
5+the internal data structures of Elm to change and improve with no impact on JS
6+integration.
7+
8+# Javascript to Elm
9+@docs toString, toInt, toFloat, toBool, toList
10+
11+# JavaScript from Elm
12+@docs fromString, fromInt, fromFloat, fromBool fromList
13+-}
14+{-
15+# DOM Nodes and Elements
16+@docs toElement, fromElement
17+-}
18+
419import Native.JavaScript
5−import open Basics
620
721data JSNumber = JSNumber
822data JSBool = JSBool
@@ -11,7 +25,7 @@ data JSArray a = JSArray a
1125data JSDomNode = JSDomNode
1226data JSObject = JSObject
1327
14−-- Requires that the input array be uniform (all members have the same type)
28+{-| Requires that the input array be uniform (all members have the same type) -}
1529toList : JSArray a -> [a]
1630toList = Native.JavaScript.toList
1731
@@ -28,7 +42,7 @@ toString : JSString -> String
2842toString = Native.JavaScript.toString
2943
3044
31−-- Produces a uniform JavaScript array with all members of the same type.
45+{-| Produces a uniform JavaScript array with all members of the same type. -}
3246fromList : [a] -> JSArray a
3347fromList = Native.JavaScript.fromList
3448
@@ -44,13 +58,13 @@ fromBool = Native.JavaScript.fromBool
4458fromString : String -> JSString
4559fromString = Native.JavaScript.fromString
4660
47−{--
48−-- Turn an `Element` into a plain old DOM node.
61+{-
62+{-| Turn an `Element` into a DOM node. -}
4963fromElement : Element -> JSDomNode
5064fromElement = Native.JavaScript.fromElement
5165
52−-- Turn a DOM node into an `Element`. You can resize the node
53−-- using the normal `width` and `height` functions.
66+{-| Turn a DOM node into an `Element`. You can resize the node
67+using the normal `width` and `height` functions. -}
5468toElement : Int -> Int -> JSDomNode -> Element
5569toElement = Native.JavaScript.toElement
56−--}
70+-}
libraries/JavaScript/Experimental.elm+31−22
@@ -1,32 +1,41 @@
1−
21module JavaScript.Experimental where
2+{-| A pair of very experimental functions for converting between
3+Elm records and JavaScript objects. It currently uses a best effort
4+conversion that can cause runtime errors. This API should change and
5+improve as we find its key failings.
6+
7+# Converting between Elm records and JS Objects
8+@docs toRecord, fromRecord
9+-}
310
411import JavaScript (JSObject)
512import Native.JavaScript
613
7−-- Turn arbitrary JavaScript objects into Elm records.
8−-- Arrays are converted into lists, nested objects are allowed.
9−-- No `null` values or non-homogeneous arrays.
10−--
11−-- -- OK objects
12−-- { student:"Steve", scores:[83,94,99,72] }
13−-- { errorLevel:10, critical:true }
14−--
15−-- -- BAD objects
16−-- { answer:null }
17−-- { info:[true,42,'what'] }
14+{-| Turn arbitrary JavaScript objects into Elm records.
15+Arrays are converted into lists, nested objects are allowed.
16+No `null` values or non-homogeneous arrays.
17+
18+ -- OK objects
19+ { student:"Steve", scores:[83,94,99,72] }
20+ { errorLevel:10, critical:true }
21+
22+ -- BAD objects
23+ { answer:null }
24+ { info:[true,42,'what'] }
25+-}
1826toRecord : JSObject -> a
1927toRecord = Native.JavaScript.toRecord
2028
21−-- Turn arbitrary Elm records into JavaScript objects.
22−-- Lists become arrays, nested records are allowed. No ADTs.
23−--
24−-- -- OK records
25−-- { student="Steve", scores=[83,94,99,72] }
26−-- { errorLevel=10, critical=True }
27−--
28−-- -- BAD records
29−-- { answer = Nothing }
30−-- { result = Left "An error occurred" }
29+{-| Turn arbitrary Elm records into JavaScript objects.
30+Lists become arrays, nested records are allowed. No ADTs.
31+
32+ -- OK records
33+ { student="Steve", scores=[83,94,99,72] }
34+ { errorLevel=10, critical=True }
35+
36+ -- BAD records
37+ { answer = Nothing }
38+ { result = Left "An error occurred" }
39+-}
3140fromRecord : a -> JSObject
3241fromRecord = Native.JavaScript.fromRecord
libraries/Json.elm+51−39
@@ -1,8 +1,19 @@
11
2−-- TOOD: Evan please review texts
3−
42module Json where
53
4+{-| Library for working with [JSON](https://en.wikipedia.org/wiki/JSON) values.
5+
6+# Strings
7+@docs fromString, toString
8+
9+# JS Strings
10+@docs fromJSString, toJSString
11+
12+# JS Objects
13+@docs fromJSObject, toJSObject
14+
15+-}
16+
617import open Basics
718import Dict
819import Maybe (Maybe)
@@ -10,9 +21,9 @@ import JavaScript as JS
1021import Native.Json
1122import JavaScript (JSObject, JSString)
1223
13−-- This datatype can represent all valid values that can be held in a JSON
14−-- object. In Elm, a proper JSON object is represented as a (Dict String JsonValue)
15−-- which is a mapping from strings to Json Values.
24+{-| This datatype can represent all valid values that can be held in a JSON
25+object. In Elm, a proper JSON object is represented as a (Dict String JsonValue)
26+which is a mapping from strings to Json Values. -}
1627data JsonValue
1728 = String String
1829 | Number Float
@@ -24,42 +35,43 @@ data JsonValue
2435
2536-- String Converters
2637
27−-- Convert a `JsonValue` into a prettified string.
28−-- The first argument is a separator token (e.g. \" \", \"\\n\", etc.) that will
29−-- be used for indentation in the prettified string version of the JSON.
38+{-| Convert a `JsonValue` into a prettified string.
39+The first argument is a separator token (e.g. \" \", \"\\n\", etc.) that will
40+be used for indentation in the prettified string version of the JSON. -}
3041toString : String -> JsonValue -> String
3142toString sep v = JS.toString (Native.Json.toJSString sep v)
3243
33−-- Convert a proper JSON object into a JavaScript string.
34−-- Note that the type JSString seen here is not the same as the type constructor
35−-- JsonString used elsewhere in this module.
44+{-| Convert a proper JSON object into a JavaScript string.
45+Note that the type JSString seen here is not the same as the type constructor
46+JsonString used elsewhere in this module. -}
3647toJSString : String -> JsonValue -> JSString
3748toJSString = Native.Json.toJSString
3849
39−-- Parse a string representation of a proper JSON object into
40−-- its Elm representation.
50+{-| Parse a string representation of a proper JSON object into
51+its Elm representation. -}
4152fromString : String -> Maybe JsonValue
4253fromString s = Native.Json.fromJSString (JS.fromString s)
4354
44−-- Parse a JavaScript string representation of a proper JSON object into
45−-- its Elm representation.
55+{-| Parse a JavaScript string representation of a proper JSON object into
56+its Elm representation. -}
4657fromJSString : JSString -> Maybe JsonValue
4758fromJSString = Native.Json.fromJSString
4859
49−-- Convert a JS object into a `JsonValue`.
60+{-| Convert a JS object into a `JsonValue`. -}
5061fromJSObject : JSObject -> JsonValue
5162fromJSObject = Native.Json.fromJSObject
5263
53−-- Convert a `JsonValue` into a `JSObject`. Paired with the
54−-- [`JavaScript.Experimental` library](/docs/JavaScript/Experimental.elm),
55−-- This lets you convert strings into Elm records:
56−--
57−-- import JavaScript.Experimental as JS
58−--
59−-- stringToRecord str =
60−-- case fromString str of
61−-- Just jsonValue -> Just (JS.toRecord (toJSObject jsonValue))
62−-- Nothing -> Nothing
64+{-| Convert a `JsonValue` into a `JSObject`. Paired with the
65+[`JavaScript.Experimental` library](/docs/JavaScript/Experimental.elm),
66+This lets you convert strings into Elm records:
67+
68+ import JavaScript.Experimental as JS
69+
70+ stringToRecord str =
71+ case fromString str of
72+ Just jsonValue -> Just (JS.toRecord (toJSObject jsonValue))
73+ Nothing -> Nothing
74+-}
6375toJSObject : JsonValue -> JSObject
6476toJSObject = Native.Json.toJSObject
6577
@@ -83,8 +95,8 @@ toJSObject = Native.Json.toJSObject
8395
8496 -- Extract Elm values from dictionaries of Json values
8597
86− -- Find a value in a Json Object using the passed get function. If the key is
87− -- not found, this returns the given default/base value.
98+ {-| Find a value in a Json Object using the passed get function. If the key is
99+ not found, this returns the given default/base value. -}
88100 find get base =
89101 let f key dict =
90102 case Dict.lookup key dict of
@@ -92,28 +104,28 @@ toJSObject = Native.Json.toJSObject
92104 Just v -> get v
93105 in f
94106
95− -- Find a string value in an Elm Json object. If the key is not found or the
96− -- value found is not a string, this returns the empty string.
107+ {-| Find a string value in an Elm Json object. If the key is not found or the
108+ value found is not a string, this returns the empty string. -}
97109 findString : String -> Object -> String
98110 findString = find string ""
99111
100− -- Find a number value in an Elm Json object. If the key is not found or the
101− -- value found is not a number, this returns 0
112+ {-| Find a number value in an Elm Json object. If the key is not found or the
113+ value found is not a number, this returns 0 -}
102114 findNumber : String -> Object -> Float
103115 findNumber = find number 0
104116
105− -- Find a boolean value in an Elm Json object. If the key is not found or the
106− -- value found is not a boolean, this returns the False.
117+ {-| Find a boolean value in an Elm Json object. If the key is not found or the
118+ value found is not a boolean, this returns the False. -}
107119 findBoolean : String -> Object -> Bool
108120 findBoolean = find boolean False
109121
110− -- Find an array value in an Elm Json object. If the key is not found or the
111− -- value found is not an array, this returns an empty list.
122+ {-| Find an array value in an Elm Json object. If the key is not found or the
123+ value found is not an array, this returns an empty list. -}
112124 findArray : String -> Object -> [JsonValue]
113125 findArray = find array []
114126
115− -- Find an object value in an Elm Json object. If the key is not found or the
116− -- value found is not an object, this returns an empty object.
127+ {-| Find an object value in an Elm Json object. If the key is not found or the
128+ value found is not an object, this returns an empty object. -}
117129 findObject : String -> Object -> Object
118130 findObject = find object Dict.empty
119− --}
131+ --}
libraries/Keyboard.elm+42−22
@@ -1,57 +1,77 @@
11module Keyboard where
22
3+{-| Library for working with keyboard input.
4+
5+# Representing Keys
6+@docs KeyCode
7+
8+# Directions
9+@docs arrows, wasd, directions
10+
11+# Specific Keys
12+@docs shift, enter, space, ctrl
13+
14+# General Keypresses
15+@docs isDown, keysDown, lastPressed
16+
17+-}
18+
319import Signal (Signal)
420import Native.Keyboard
521
6−-- Type alias to make it clearer what integers are supposed to represent
7−-- in this library. Use [`Char.toCode`](docs/Char.elm#toCode) and
8−-- [`Char.fromCode`](/docs/Char.elm#fromCode) to convert key codes to characters.
22+{-| Type alias to make it clearer what integers are supposed to represent
23+in this library. Use [`Char.toCode`](docs/Char.elm#toCode) and
24+[`Char.fromCode`](/docs/Char.elm#fromCode) to convert key codes to characters.
25+Use the uppercase character with `toCode`.
26+-}
927type KeyCode = Int
1028
11−-- Custom key directions so that you can support different locales.
12−-- The plan is to have a locale independent version of this function
13−-- that uses the physical location of keys, but I don't know how to do it.
29+{-| Custom key directions to support different locales. The order is up, down,
30+left, right.
31+-}
1432directions : KeyCode -> KeyCode -> KeyCode -> KeyCode -> Signal { x:Int, y:Int }
1533directions = Native.Keyboard.directions
1634
17−-- A signal of records indicating which arrow keys are pressed.
18−--
19−-- `{ x = 0, y = 0 }` when pressing no arrows.<br>
20−-- `{ x =-1, y = 0 }` when pressing the left arrow.<br>
21−-- `{ x = 1, y = 1 }` when pressing the up and right arrows.<br>
22−-- `{ x = 0, y =-1 }` when pressing the down, left, and right arrows.
35+{-| A signal of records indicating which arrow keys are pressed.
36+
37+`{ x = 0, y = 0 }` when pressing no arrows.<br>
38+`{ x =-1, y = 0 }` when pressing the left arrow.<br>
39+`{ x = 1, y = 1 }` when pressing the up and right arrows.<br>
40+`{ x = 0, y =-1 }` when pressing the down, left, and right arrows.
41+-}
2342arrows : Signal { x:Int, y:Int }
2443arrows = directions 38 40 37 39
2544
26−-- Just like the arrows signal, but this uses keys w, a, s, and d,
27−-- which are common controls for many computer games.
45+{-| Just like the arrows signal, but this uses keys w, a, s, and d,
46+which are common controls for many computer games.
47+-}
2848wasd : Signal { x:Int, y:Int }
2949wasd = directions 87 83 65 68
3050
31−-- Whether an arbitrary key is pressed.
51+{-| Whether an arbitrary key is pressed. -}
3252isDown : KeyCode -> Signal Bool
3353isDown = Native.Keyboard.isDown
3454
35−-- Whether the shift key is pressed.
55+{-| Whether the shift key is pressed. -}
3656shift : Signal Bool
3757shift = isDown 16
3858
39−-- Whether the control key is pressed.
59+{-| Whether the control key is pressed. -}
4060ctrl : Signal Bool
4161ctrl = isDown 17
4262
43−-- Whether the space key is pressed.
63+{-| Whether the space key is pressed. -}
4464space : Signal Bool
4565space = isDown 32
4666
47−-- Whether the enter key is pressed.
67+{-| Whether the enter key is pressed. -}
4868enter : Signal Bool
4969enter = isDown 13
5070
51−-- List of keys that are currently down.
71+{-| List of keys that are currently down. -}
5272keysDown : Signal [KeyCode]
5373keysDown = Native.Keyboard.keysDown
5474
55−-- The latest key that has been pressed.
75+{-| The latest key that has been pressed. -}
5676lastPressed : Signal KeyCode
57−lastPressed = Native.Keyboard.lastPressed
77+lastPressed = Native.Keyboard.lastPressed
libraries/List.elm+105−66
@@ -1,131 +1,166 @@
1−
21module List where
32
3+{-| A library for manipulating lists of values. Every value in a
4+list must have the same type.
5+
6+# Basics
7+@docs (::), (++), isEmpty, length, reverse, map
8+
9+# Sub-lists
10+@docs head, tail, last, filter, take, drop
11+
12+# Putting Lists Together
13+@docs concat, concatMap, join, intersperse, zip, zipWith
14+
15+# Taking Lists Apart
16+@docs partition, unzip
17+
18+# Folds
19+@docs foldr, foldl, foldr1, foldl1, scanl, scanl1
20+
21+# Special Folds
22+@docs sum, product, maximum, minimum, all, any, and, or
23+-}
24+
425import open Basics
526import Native.List
627
7−-- Add an element to the front of a list `(1 :: [2,3] == [1,2,3])`
28+{-| Add an element to the front of a list `(1 :: [2,3] == [1,2,3])` -}
829(::) : a -> [a] -> [a]
930(::) = Native.List.cons
1031
11−-- Puts two appendable things together:
12−--
13−-- [1,1] ++ [2,3] == [1,1,2,3]
14−-- "abc" ++ "123" == "abc123"
32+{-| Puts two appendable things together:
33+
34+ [1,1] ++ [2,3] == [1,1,2,3]
35+ "abc" ++ "123" == "abc123"
36+-}
1537(++) : appendable -> appendable -> appendable
1638(++) = Native.List.append
1739
18−-- Extract the first element of a list. List must be non-empty.
19−-- `(head [1,2,3] == 1)`
40+infixr 5 ::
41+infixr 5 ++
42+
43+{-| Extract the first element of a list. List must be non-empty.
44+`(head [1,2,3] == 1)`
45+-}
2046head : [a] -> a
2147head = Native.List.head
2248
23−-- Extract the elements after the head of the list. List must be non-empty.
24−-- `(tail [1,2,3] == [2,3])`
49+{-| Extract the elements after the head of the list. List must be non-empty.
50+`(tail [1,2,3] == [2,3])`
51+-}
2552tail : [a] -> [a]
2653tail = Native.List.tail
2754
28−-- Extract the last element of a list. List must be non-empty.
29−-- `(last [1,2,3] == 3)`
55+{-| Extract the last element of a list. List must be non-empty.
56+`(last [1,2,3] == 3)`
57+-}
3058last : [a] -> a
3159last = Native.List.last
3260
33−-- Check if a list is empty `(isEmpty [] == True)`
61+{-| Check if a list is empty `(isEmpty [] == True)` -}
3462isEmpty : [a] -> Bool
3563isEmpty xs =
3664 case xs of
3765 [] -> True
3866 _ -> False
3967
40−-- Apply a function to every element of a list: `(map sqrt [1,4,9] == [1,2,3])`
68+{-| Apply a function to every element of a list: `(map sqrt [1,4,9] == [1,2,3])` -}
4169map : (a -> b) -> [a] -> [b]
4270map = Native.List.map
4371
44−-- Reduce a list from the left: `(foldl (::) [] "gateman" == "nametag")`
72+{-| Reduce a list from the left: `(foldl (::) [] [1,2,3] == [3,2,1])` -}
4573foldl : (a -> b -> b) -> b -> [a] -> b
4674foldl = Native.List.foldl
4775
48−-- Reduce a list from the right: `(foldr (+) 0 [1,2,3] == 6)`
76+{-| Reduce a list from the right: `(foldr (+) 0 [1,2,3] == 6)` -}
4977foldr : (a -> b -> b) -> b -> [a] -> b
5078foldr = Native.List.foldr
5179
52−-- Reduce a list from the left without a base case. List must be non-empty.
80+{-| Reduce a list from the left without a base case. List must be non-empty. -}
5381foldl1 : (a -> a -> a) -> [a] -> a
5482foldl1 = Native.List.foldl1
5583
56−-- Reduce a list from the right without a base case. List must be non-empty.
84+{-| Reduce a list from the right without a base case. List must be non-empty. -}
5785foldr1 : (a -> a -> a) -> [a] -> a
5886foldr1 = Native.List.foldr1
5987
60−-- Reduce a list from the left, building up all of the intermediate results into a list.
61−--
62−-- scanl (+) 0 [1,2,3,4] == [0,1,3,6,10]
88+{-| Reduce a list from the left, building up all of the intermediate results into a list.
89+
90+ scanl (+) 0 [1,2,3,4] == [0,1,3,6,10]
91+-}
6392scanl : (a -> b -> b) -> b -> [a] -> [b]
6493scanl = Native.List.scanl
6594
66−-- Same as scanl but it doesn't require a base case. List must be non-empty.
67−--
68−-- scanl1 (+) [1,2,3,4] == [1,3,6,10]
95+{-| Same as scanl but it doesn't require a base case. List must be non-empty.
96+
97+ scanl1 (+) [1,2,3,4] == [1,3,6,10]
98+-}
6999scanl1 : (a -> a -> a) -> [a] -> [a]
70100scanl1 = Native.List.scanl1
71101
72−-- Filter out elements which do not satisfy the predicate: `(filter isLower "AaBbCc" == "abc")`
102+{-| Keep only elements that satisfy the predicate:
103+`(filter isEven [1..6] == [2,4,6])`
104+-}
73105filter : (a -> Bool) -> [a] -> [a]
74106filter = Native.List.filter
75107
76−-- Determine the length of a list: `(length "innumerable" == 11)`
108+{-| Determine the length of a list: `(length [1,2,3] == 3)` -}
77109length : [a] -> Int
78110length = Native.List.length
79111
80−-- Reverse a list. `(reverse [1..4] == [4,3,2,1])`
112+{-| Reverse a list. `(reverse [1..4] == [4,3,2,1])` -}
81113reverse : [a] -> [a]
82114reverse = Native.List.reverse
83115
84−-- Check to see if all elements satisfy the predicate.
116+{-| Check to see if all elements satisfy the predicate. -}
85117all : (a -> Bool) -> [a] -> Bool
86118all = Native.List.all
87119
88−-- Check to see if any elements satisfy the predicate.
120+{-| Check to see if any elements satisfy the predicate. -}
89121any : (a -> Bool) -> [a] -> Bool
90122any = Native.List.any
91123
92−-- Check to see if all elements are True.
124+{-| Check to see if all elements are True. -}
93125and : [Bool] -> Bool
94126and = foldl (&&) True
95127
96−-- Check to see if any elements are True.
128+{-| Check to see if any elements are True. -}
97129or : [Bool] -> Bool
98130or = foldl (||) False
99131
100−-- Concatenate a list of appendable things:
101−--
102−-- concat ["tree","house"] == "treehouse"
132+{-| Concatenate a list of appendable things:
133+
134+ concat [[1,2],[3],[4,5]] == [1,2,3,4,5]
135+ concat ["tree","house"] == "treehouse"
136+-}
103137concat : [appendable] -> appendable
104138concat = Native.List.concat
105139
106−-- Map a given function onto a list and flatten the resulting lists.
107−--
108−-- concatMap f xs == concat (map f xs)
140+{-| Map a given function onto a list and flatten the resulting lists.
141+
142+ concatMap f xs == concat (map f xs)
143+-}
109144concatMap : (a -> appendable) -> [a] -> appendable
110145concatMap f list = concat (map f list)
111146
112−-- Get the sum of the list elements. `(sum [1..4] == 10)`
147+{-| Get the sum of the list elements. `(sum [1..4] == 10)` -}
113148sum : [number] -> number
114149sum = foldl (+) 0
115150
116−-- Get the product of the list elements. `(product [1..4] == 24)`
151+{-| Get the product of the list elements. `(product [1..4] == 24)` -}
117152product : [number] -> number
118153product = foldl (*) 1
119154
120−-- Find the maximum element in a non-empty list: `maximum [1,4,2] == 4`
155+{-| Find the maximum element in a non-empty list: `maximum [1,4,2] == 4` -}
121156maximum : [comparable] -> comparable
122157maximum = foldl1 max
123158
124−-- Find the minimum element in a non-empty list: `minimum [3,2,1] == 1`
159+{-| Find the minimum element in a non-empty list: `minimum [3,2,1] == 1` -}
125160minimum : [comparable] -> comparable
126161minimum = foldl1 min
127162
128−-- Split a list based on the predicate.
163+{-| Split a list based on the predicate. -}
129164partition : (a -> Bool) -> [a] -> ([a],[a])
130165partition pred lst =
131166 case lst of
@@ -133,44 +168,42 @@ partition pred lst =
133168 x::xs -> let (bs,cs) = partition pred xs in
134169 if pred x then (x::bs,cs) else (bs,x::cs)
135170
136−-- Combine two lists, combining them into tuples pairwise.
137−-- If one list is longer, the extra elements are dropped.
138−--
139−-- zip [1,2,3] [6,7] == [(1,6),(2,7)]
140−-- zip == zipWith (,)
171+{-| Combine two lists, combining them into tuples pairwise.
172+If one list is longer, the extra elements are dropped.
173+
174+ zip [1,2,3] [6,7] == [(1,6),(2,7)]
175+ zip == zipWith (,)
176+-}
141177zip : [a] -> [b] -> [(a,b)]
142178zip = Native.List.zip
143179
144−-- Combine two lists, combining them with the given function.
145−-- If one list is longer, the extra elements are dropped.
146−--
147−-- zipWith (+) [1,2,3] [1,2,3,4] == [2,4,6]
180+{-| Combine two lists, combining them with the given function.
181+If one list is longer, the extra elements are dropped.
182+
183+ zipWith (+) [1,2,3] [1,2,3,4] == [2,4,6]
184+-}
148185zipWith : (a -> b -> c) -> [a] -> [b] -> [c]
149186zipWith = Native.List.zipWith
150187
151−-- Decompose a list of tuples.
188+{-| Decompose a list of tuples. -}
152189unzip : [(a,b)] -> ([a],[b])
153190unzip pairs =
154191 case pairs of
155192 [] -> ([],[])
156193 (x,y)::ps -> let (xs,ys) = (unzip ps) in (x::xs,y::ys)
157194
158−-- Split a list with a given seperator.
159−--
160−-- split "," "hello,there,friend" == ["hello", "there", "friend"]
161−split : [a] -> [a] -> [[a]]
162−split = Native.List.split
195+{-| Places the given value between all of the lists in the second
196+argument and concatenates the result.
163197
164−-- Places the given value between all of the lists in the second argument
165−-- and concatenates the result.
166−--
167−-- join "a" ["H","w","ii","n"] == "Hawaiian"
198+ join "a" ["H","w","ii","n"] == "Hawaiian"
199+-}
168200join : appendable -> [appendable] -> appendable
169201join = Native.List.join
170202
171−-- Places the given value between all members of the given list.
172−--
173−-- intersperse ' ' "INCEPTION" == "I N C E P T I O N"
203+{-| Places the given value between all members of the given list.
204+
205+ intersperse "on" ["turtles","turtles","turtles"] == ["turtles","on","turtles","on","turtles"]
206+-}
174207intersperse : a -> [a] -> [a]
175208intersperse sep xs =
176209 case xs of
@@ -178,10 +211,16 @@ intersperse sep xs =
178211 [a] -> [a]
179212 [] -> []
180213
181−-- Take the first n members of a list: `(take 2 [1,2,3,4] == [1,2])`
214+{-| Take the first n members of a list: `(take 2 [1,2,3,4] == [1,2])` -}
182215take : Int -> [a] -> [a]
183216take = Native.List.take
184217
185−-- Drop the first n members of a list: `(drop 2 [1,2,3,4] == [3,4])`
218+{-| Drop the first n members of a list: `(drop 2 [1,2,3,4] == [3,4])` -}
186219drop : Int -> [a] -> [a]
187220drop = Native.List.drop
221+
222+{-| Creates a list with *n* copies of a value:
223+`(repeat 3 (0,0) == [(0,0),(0,0),(0,0)]`
224+-}
225+repeat : Int -> a -> [a]
226+repeat = Native.List.repeat
libraries/Maybe.elm+28−10
@@ -1,34 +1,52 @@
1−
21module Maybe where
32
3+{-| Represents an optional value. Maybe it is there, maybe it is not.
4+
5+# Type and Constructors
6+@docs Maybe
7+
8+# Taking Maybes apart
9+@docs maybe, isJust, isNothing
10+
11+# Maybes and Lists
12+@docs justs
13+-}
14+
415import Basics (not, (.))
516import List (foldr)
617
7−-- The Maybe datatype. Useful when a computation may or may not
8−-- result in a value (e.g. logarithm is defined only for positive numbers).
18+{-| The Maybe datatype. Useful when a computation may or may not
19+result in a value (e.g. logarithm is defined only for positive
20+numbers).
21+-}
922data Maybe a = Just a | Nothing
1023
11−-- Apply a function to the contents of a `Maybe`.
12−-- Return default when given `Nothing`.
24+{-| Apply a function to the contents of a `Maybe`.
25+Return default when given `Nothing`.
26+-}
1327maybe : b -> (a -> b) -> Maybe a -> b
1428maybe b f m = case m of
1529 Just v -> f v
1630 Nothing -> b
1731
18−-- Check if constructed with `Just`.
32+{-| Check if constructed with `Just`.
33+-}
1934isJust : Maybe a -> Bool
2035isJust = maybe False (\_ -> True)
2136
22−-- Check if constructed with `Nothing`.
37+{-| Check if constructed with `Nothing`.
38+-}
2339isNothing : Maybe a -> Bool
2440isNothing = not . isJust
2541
2642
27−-- If `Just`, adds the value to the front of the list.
28−-- If `Nothing`, list is unchanged.
43+{-| If `Just`, adds the value to the front of the list.
44+If `Nothing`, list is unchanged.
45+-}
2946cons : Maybe a -> [a] -> [a]
3047cons mx xs = maybe xs (\x -> x :: xs) mx
3148
32−-- Filters out Nothings and extracts the remaining values.
49+{-| Filters out Nothings and extracts the remaining values.
50+-}
3351justs : [Maybe a] -> [a]
3452justs = foldr cons []
libraries/Mouse.elm+19−9
@@ -1,31 +1,41 @@
11
22module Mouse where
33
4+{-| Library for working with mouse input.
5+
6+# Position
7+@docs position, x, y
8+
9+# Button Status
10+@docs isDown, clicks, isClicked
11+
12+-}
13+
414import Signal (Signal)
515import Native.Mouse
616
7−-- The current mouse position.
17+{-| The current mouse position. -}
818position : Signal (Int,Int)
919position = Native.Mouse.position
1020
11−-- The current x-coordinate of the mouse.
21+{-| The current x-coordinate of the mouse. -}
1222x : Signal Int
1323x = Native.Mouse.x
1424
15−-- The current y-coordinate of the mouse.
25+{-| The current y-coordinate of the mouse. -}
1626y : Signal Int
1727y = Native.Mouse.y
1828
19−-- The current state of the left mouse-button.
20−-- True when the button is down, and false otherwise.
29+{-| The current state of the left mouse-button.
30+True when the button is down, and false otherwise. -}
2131isDown : Signal Bool
2232isDown = Native.Mouse.isDown
2333
24−-- True immediately after the left mouse-button has been clicked,
25−-- and false otherwise.
34+{-| True immediately after the left mouse-button has been clicked,
35+and false otherwise. -}
2636isClicked : Signal Bool
2737isClicked = Native.Mouse.isClicked
2838
29−-- Always equal to unit. Event triggers on every mouse click.
39+{-| Always equal to unit. Event triggers on every mouse click. -}
3040clicks : Signal ()
31−clicks = Native.Mouse.clicks
41+clicks = Native.Mouse.clicks
libraries/Native/Basics.js+8−47
@@ -1,12 +1,12 @@
11
2−Elm.Native.Basics = function(elm) {
3− 'use strict';
4− if (elm.Native.Basics) return elm.Native.Basics;
2+Elm.Native.Basics = {};
3+Elm.Native.Basics.make = function(elm) {
4+ elm.Native = elm.Native || {};
5+ elm.Native.Basics = elm.Native.Basics || {};
6+ if (elm.Native.Basics.values) return elm.Native.Basics.values;
57
6− var JS = Elm.Native.JavaScript(elm);
7− // var Maybe = Elm.Maybe(elm);
8− var Utils = Elm.Native.Utils(elm);
9− //var Char = Elm.Char(elm);
8+ var JS = Elm.Native.JavaScript.make(elm);
9+ var Utils = Elm.Native.Utils.make(elm);
1010
1111 function div(a,b) { return (a/b)|0; }
1212 function rem(a,b) { return a % b; }
@@ -26,43 +26,7 @@ Elm.Native.Basics = function(elm) {
2626 function uncurry(f,v) { return A2(f,v._0,v._1); }
2727 function fst(t) { return t._0; }
2828 function snd(t) { return t._1; }
29−/*
30− function readInt(str) {
31− var s = JS.fromString(str);
32− var len = s.length;
33− if (len === 0) { return Maybe.Nothing; }
34− var start = 0;
35− if (s[0] == '-') {
36− if (len === 1) { return Maybe.Nothing; }
37− start = 1;
38− }
39− for (var i = start; i < len; ++i) {
40− if (!Char.isDigit(s[i])) { return Maybe.Nothing; }
41− }
42− return Maybe.Just(parseInt(s, 10));
43− }
4429
45− function readFloat(str) {
46− var s = JS.fromString(str);
47− var len = s.length;
48− if (len === 0) { return Maybe.Nothing; }
49− var start = 0;
50− if (s[0] == '-') {
51− if (len === 1) { return Maybe.Nothing; }
52− start = 1;
53− }
54− var dotCount = 0;
55− for (var i = start; i < len; ++i) {
56− if (Char.isDigit(s[i])) { continue; }
57− if (s[i] === '.') {
58− dotCount += 1;
59− if (dotCount <= 1) { continue; }
60− }
61− return Maybe.Nothing;
62− }
63− return Maybe.Just(parseFloat(s));
64− }
65−*/
6630 var basics = {
6731 div:F2(div),
6832 rem:F2(rem),
@@ -95,14 +59,11 @@ Elm.Native.Basics = function(elm) {
9559 round:Math.round,
9660 toFloat:function(x) { return x; },
9761
98− //readInt:readInt,
99− //readFloat:readFloat,
100−
10162 curry:F3(curry),
10263 uncurry:F2(uncurry),
10364 fst:fst,
10465 snd:snd
10566 };
10667
107− return elm.Native.Basics = basics;
68+ return elm.Native.Basics.values = basics;
10869};
libraries/Native/Char.js+26−28
@@ -1,31 +1,29 @@
1+Elm.Native.Char = {};
2+Elm.Native.Char.make = function(elm) {
3+ elm.Native = elm.Native || {};
4+ elm.Native.Char = elm.Native.Char || {};
5+ if (elm.Native.Char.values) return elm.Native.Char.values;
16
2−Elm.Native.Char = function(elm) {
3− 'use strict';
4−
5− elm.Native = elm.Native || {};
6− if (elm.Native.Char) return elm.Native.Char;
7−
8− function isBetween(lo,hi) { return function(chr) {
9− var c = chr.charCodeAt(0);
10− return lo <= c && c <= hi;
11− };
12− }
13− var isDigit = isBetween('0'.charCodeAt(0),'9'.charCodeAt(0));
14− var chk1 = isBetween('a'.charCodeAt(0),'f'.charCodeAt(0));
15− var chk2 = isBetween('A'.charCodeAt(0),'F'.charCodeAt(0));
16−
17− return elm.Native.Char = {
18− fromCode : function(c) { return String.fromCharCode(c); },
19− toCode : function(c) { return c.toUpperCase().charCodeAt(0); },
20− toUpper : function(c) { return c.toUpperCase(); },
21− toLower : function(c) { return c.toLowerCase(); },
22− toLocaleUpper : function(c) { return c.toLocaleUpperCase(); },
23− toLocaleLower : function(c) { return c.toLocaleLowerCase(); },
24− isLower : isBetween('a'.charCodeAt(0),'z'.charCodeAt(0)),
25− isUpper : isBetween('A'.charCodeAt(0),'Z'.charCodeAt(0)),
26− isDigit : isDigit,
27− isOctDigit : isBetween('0'.charCodeAt(0),'7'.charCodeAt(0)),
28− isHexDigit : function(c) { return isDigit(c) || chk1(c) || chk2(c); }
29− };
7+ function isBetween(lo,hi) { return function(chr) {
8+ var c = chr.charCodeAt(0);
9+ return lo <= c && c <= hi;
10+ };
11+ }
12+ var isDigit = isBetween('0'.charCodeAt(0),'9'.charCodeAt(0));
13+ var chk1 = isBetween('a'.charCodeAt(0),'f'.charCodeAt(0));
14+ var chk2 = isBetween('A'.charCodeAt(0),'F'.charCodeAt(0));
3015
16+ return elm.Native.Char.values = {
17+ fromCode : function(c) { return String.fromCharCode(c); },
18+ toCode : function(c) { return c.toUpperCase().charCodeAt(0); },
19+ toUpper : function(c) { return c.toUpperCase(); },
20+ toLower : function(c) { return c.toLowerCase(); },
21+ toLocaleUpper : function(c) { return c.toLocaleUpperCase(); },
22+ toLocaleLower : function(c) { return c.toLocaleLowerCase(); },
23+ isLower : isBetween('a'.charCodeAt(0),'z'.charCodeAt(0)),
24+ isUpper : isBetween('A'.charCodeAt(0),'Z'.charCodeAt(0)),
25+ isDigit : isDigit,
26+ isOctDigit : isBetween('0'.charCodeAt(0),'7'.charCodeAt(0)),
27+ isHexDigit : function(c) { return isDigit(c) || chk1(c) || chk2(c); }
28+ };
3129};
libraries/Native/Color.js+56−58
@@ -1,71 +1,69 @@
1+Elm.Native.Color = {};
2+Elm.Native.Color.make = function(elm) {
3+ elm.Native = elm.Native || {};
4+ elm.Native.Color = elm.Native.Color || {};
5+ if (elm.Native.Color.values) return elm.Native.Color.values;
16
7+ var Utils = Elm.Native.Utils.make(elm);
28
3−Elm.Native.Color = function(elm) {
4− "use strict";
9+ function complement(rgb) {
10+ var hsv = toHSV(rgb);
11+ hsv.hue = (hsv.hue + 180) % 360;
12+ return toRGB(hsv);
13+ }
514
6− elm.Native = elm.Native || {};
7− if (elm.Native.Color) return elm.Native.Color;
15+ function hsva(h,s,v,a) {
16+ var degree = A2(Utils.mod, h * 180 / Math.PI, 360);
17+ var clr = toRGB({hue:degree, saturation:s, value:v});
18+ clr._3 = a;
19+ return clr;
20+ }
821
9− var Utils = Elm.Native.Utils(elm);
22+ function hsv(h,s,v) {
23+ var degree = A2(Utils.mod, h * 180 / Math.PI, 360);
24+ return toRGB({hue:degree, saturation:s, value:v});
25+ }
1026
11− function complement(rgb) {
12− var hsv = toHSV(rgb);
13− hsv.hue = (hsv.hue + 180) % 360;
14− return toRGB(hsv);
15− }
27+ function toHSV(rgb) {
28+ var hsv = {};
29+ var r = rgb._0 / 255.0, g = rgb._1 / 255.0, b = rgb._2 / 255.0;
30+ var M = Math.max(r,g,b);
31+ var m = Math.min(r,g,b);
32+ var c = M - m;
1633
17− function hsva(h,s,v,a) {
18− var degree = A2(Utils.mod, h * 180 / Math.PI, 360);
19− var clr = toRGB({hue:degree, saturation:s, value:v});
20− clr._3 = a;
21− return clr;
22− }
34+ var h = 0;
35+ if (c === 0) { h = 0; }
36+ else if (M === r) { h = ((g - b) / c) % 6; }
37+ else if (M === g) { h = ((b - r) / c) + 2; }
38+ else if (M === b) { h = ((r - g) / c) + 4; }
39+ h *= 60;
2340
24− function hsv(h,s,v) {
25− var degree = A2(Utils.mod, h * 180 / Math.PI, 360);
26− return toRGB({hue:degree, saturation:s, value:v});
27− }
41+ return { value : M, hue : h, saturation : (M === 0 ? 0 : c / M) };
42+ }
2843
29− function toHSV(rgb) {
30− var hsv = {};
31− var r = rgb._0 / 255.0, g = rgb._1 / 255.0, b = rgb._2 / 255.0;
32− var M = Math.max(r,g,b);
33− var m = Math.min(r,g,b);
34− var c = M - m;
44+ function between(lo,hi,x) { return lo <= x && x < hi; }
45+ function norm(n) { return Math.round(n*255); }
3546
36− var h = 0;
37− if (c === 0) { h = 0; }
38− else if (M === r) { h = ((g - b) / c) % 6; }
39− else if (M === g) { h = ((b - r) / c) + 2; }
40− else if (M === b) { h = ((r - g) / c) + 4; }
41− h *= 60;
47+ function toRGB(hsv) {
48+ var c = hsv.value * hsv.saturation;
49+ var hue = hsv.hue / 60;
50+ var x = c * (1 - Math.abs((hue % 2) - 1));
51+ var r = 0, g = 0, b = 0;
52+ if (between(0,1,hue)) { r = c; g = x; b = 0; }
53+ else if (between(1,2,hue)) { r = x; g = c; b = 0; }
54+ else if (between(2,3,hue)) { r = 0; g = c; b = x; }
55+ else if (between(3,4,hue)) { r = 0; g = x; b = c; }
56+ else if (between(4,5,hue)) { r = x; g = 0; b = c; }
57+ else if (between(5,6,hue)) { r = c; g = 0; b = x; }
4258
43− return { value : M, hue : h, saturation : (M === 0 ? 0 : c / M) };
44− }
59+ var m = hsv.value - c;
60+ return { ctor:"Color", _0:norm(r+m), _1:norm(g+m), _2:norm(b+m), _3:1 };
61+ }
4562
46− function between(lo,hi,x) { return lo <= x && x < hi; }
47− function norm(n) { return Math.round(n*255); }
48−
49− function toRGB(hsv) {
50− var c = hsv.value * hsv.saturation;
51− var hue = hsv.hue / 60;
52− var x = c * (1 - Math.abs((hue % 2) - 1));
53− var r = 0, g = 0, b = 0;
54− if (between(0,1,hue)) { r = c; g = x; b = 0; }
55− else if (between(1,2,hue)) { r = x; g = c; b = 0; }
56− else if (between(2,3,hue)) { r = 0; g = c; b = x; }
57− else if (between(3,4,hue)) { r = 0; g = x; b = c; }
58− else if (between(4,5,hue)) { r = x; g = 0; b = c; }
59− else if (between(5,6,hue)) { r = c; g = 0; b = x; }
60−
61− var m = hsv.value - c;
62− return { ctor:"Color", _0:norm(r+m), _1:norm(g+m), _2:norm(b+m), _3:1 };
63− }
64−
65− return elm.Native.Color = {
66− hsva:F4(hsva),
67− hsv:F3(hsv),
68− complement:complement
69− };
63+ return elm.Native.Color.values = {
64+ hsva:F4(hsva),
65+ hsv:F3(hsv),
66+ complement:complement
67+ };
7068
7169};
libraries/Native/Date.js+7−8
@@ -1,12 +1,11 @@
1−
2−Elm.Native.Date = function(elm) {
3− 'use strict';
4−
1+Elm.Native.Date = {};
2+Elm.Native.Date.make = function(elm) {
53 elm.Native = elm.Native || {};
6− if (elm.Native.Date) return elm.Native.Date;
4+ elm.Native.Date = elm.Native.Date || {};
5+ if (elm.Native.Date.values) return elm.Native.Date.values;
76
8− var JS = Elm.JavaScript(elm);
9− var Maybe = Elm.Maybe(elm);
7+ var JS = Elm.JavaScript.make(elm);
8+ var Maybe = Elm.Maybe.make(elm);
109
1110 function dateNow() { return new window.Date; }
1211 function readDate(str) {
@@ -19,7 +18,7 @@ Elm.Native.Date = function(elm) {
1918 var monthTable = ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
2019 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
2120
22− return elm.Native.Date = {
21+ return elm.Native.Date.values = {
2322 read : readDate,
2423 year : function(d) { return d.getFullYear(); },
2524 month : function(d) { return { ctor:monthTable[d.getMonth()] }; },
libraries/Native/Error.js+6−6
@@ -1,10 +1,10 @@
1−
2−Elm.Native.Error = function(elm) {
3− 'use strict';
1+Elm.Native.Error = {};
2+Elm.Native.Error.make = function(elm) {
43 elm.Native = elm.Native || {};
5− if (elm.Native.Error) return elm.Native.Error;
4+ elm.Native.Error = elm.Native.Error || {};
5+ if (elm.Native.Error.values) return elm.Native.Error.values;
66
7− var fromString = Elm.Native.JavaScript(elm).fromString;
7+ var fromString = Elm.Native.JavaScript.make(elm).fromString;
88
99 function indent(lines) {
1010 var msg = '';
@@ -28,5 +28,5 @@ Elm.Native.Error = function(elm) {
2828
2929 function raise(str) { throw new Error(fromString(str)); }
3030
31− return elm.Native.Error = { Case: Case, If: If, raise: raise };
31+ return elm.Native.Error.values = { Case: Case, If: If, raise: raise };
3232};
libraries/Native/Graphics/Collage.js+6−6
@@ -1,12 +1,12 @@
1−
2−Elm.Native.Graphics.Collage = function(elm) {
3− "use strict";
1+Elm.Native.Graphics.Collage = {};
2+Elm.Native.Graphics.Collage.make = function(elm) {
43
54 elm.Native = elm.Native || {};
65 elm.Native.Graphics = elm.Native.Graphics || {};
7− if (elm.Native.Graphics.Collage) return elm.Native.Graphics.Collage;
6+ elm.Native.Graphics.Collage = elm.Native.Graphics.Collage || {};
7+ if (elm.Native.Graphics.Collage.values) return elm.Native.Graphics.Collage.values;
88
9− var newElement = Elm.Graphics.Element(elm).newElement;
9+ var newElement = Elm.Graphics.Element.make(elm).newElement;
1010 var C = ElmRuntime.use(ElmRuntime.Render.Collage);
1111
1212 function collage(w,h,forms) {
@@ -18,6 +18,6 @@ Elm.Native.Graphics.Collage = function(elm) {
1818 model: {w:w, h:h, forms:forms}
1919 });
2020 }
21− return elm.Native.Graphics.Collage = { collage:F3(collage) };
21+ return elm.Native.Graphics.Collage.values = { collage:F3(collage) };
2222
2323};
libraries/Native/Graphics/Input.js+9−9
@@ -1,18 +1,18 @@
1−
2−Elm.Native.Graphics.Input = function(elm) {
3− "use strict";
1+Elm.Native.Graphics.Input = {};
2+Elm.Native.Graphics.Input.make = function(elm) {
43
54 elm.Native = elm.Native || {};
65 elm.Native.Graphics = elm.Native.Graphics || {};
7− if (elm.Native.Graphics.Input) return elm.Native.Graphics.Input;
6+ elm.Native.Graphics.Input = elm.Native.Graphics.Input || {};
7+ if (elm.Native.Graphics.Input.values) return elm.Native.Graphics.Input.values;
88
99 var Render = ElmRuntime.use(ElmRuntime.Render.Element);
1010 var newNode = ElmRuntime.use(ElmRuntime.Render.Utils).newElement;
1111
12− var Signal = Elm.Signal(elm);
13− var newElement = Elm.Graphics.Element(elm).newElement;
14− var JS = Elm.Native.JavaScript(elm);
15− var Utils = Elm.Native.Utils(elm);
12+ var Signal = Elm.Signal.make(elm);
13+ var newElement = Elm.Graphics.Element.make(elm).newElement;
14+ var JS = Elm.Native.JavaScript.make(elm);
15+ var Utils = Elm.Native.Utils.make(elm);
1616 var Tuple2 = Utils.Tuple2;
1717
1818 function dropDown(values) {
@@ -290,7 +290,7 @@ Elm.Native.Graphics.Input = function(elm) {
290290 }
291291 }
292292
293− return elm.Native.Graphics.Input = {
293+ return elm.Native.Graphics.Input.values = {
294294 buttons:buttons,
295295 customButtons:customButtons,
296296 hoverables:hoverables,
libraries/Native/JavaScript.js+13−18
@@ -1,18 +1,17 @@
1−
2−Elm.Native.JavaScript = function(elm) {
3− 'use strict';
4−
1+Elm.Native.JavaScript = {};
2+Elm.Native.JavaScript.make = function(elm) {
53 elm.Native = elm.Native || {};
6− if (elm.Native.JavaScript) return elm.Native.JavaScript;
4+ elm.Native.JavaScript = elm.Native.JavaScript || {};
5+ if (elm.Native.JavaScript.values) return elm.Native.JavaScript.values;
76
8− var List = Elm.Native.List(elm);
7+ var List = Elm.Native.List.make(elm);
98 var Render = ElmRuntime.use(ElmRuntime.Render.Element);
109
1110 function fromJS(v) {
1211 var type = typeof v;
1312 if (type === 'number' ) return v;
1413 if (type === 'boolean') return v;
15− if (type === 'string' ) return List.fromArray(v);
14+ if (type === 'string' ) return v;
1615 if (v instanceof Array) {
1716 var arr = [];
1817 var len = v.length;
@@ -46,12 +45,8 @@ Elm.Native.JavaScript = function(elm) {
4645 }
4746 if (type === 'object' && (v.ctor === '::' || v.ctor === '[]')) {
4847 var array = List.toArray(v);
49− if (typeof array[0] === 'string') {
50− array = array.join('');
51− } else {
52− for (var i = array.length; i--; ) {
53− array[i] = toJS(array[i]);
54− }
48+ for (var i = array.length; i--; ) {
49+ array[i] = toJS(array[i]);
5550 }
5651 return array;
5752 }
@@ -84,13 +79,13 @@ Elm.Native.JavaScript = function(elm) {
8479 return Render.render(element);
8580 }
8681
87− return elm.Native.JavaScript = {
88− toFloat : id,
89− toBool : id,
82+ return elm.Native.JavaScript.values = {
9083 toInt : function(n) { return n|0; },
91− toString : List.fromArray,
84+ toFloat : function(n) { return +n; },
85+ toBool : id,
86+ toString : id,
9287 toList : List.fromArray,
93− fromString : function(s) { return List.toArray(s).join(''); },
88+ fromString : id,
9489 fromList : List.toArray,
9590 fromInt : id,
9691 fromFloat : id,
libraries/Native/Json.js+11−8
@@ -1,12 +1,15 @@
1+Elm.Native.Json = {};
2+Elm.Native.Json.make = function(elm) {
13
2−Elm.Native.Json = function(elm) {
3− 'use strict';
4+ elm.Native = elm.Native || {};
5+ elm.Native.Json = elm.Native.Json || {};
6+ if (elm.Native.Json.values) return elm.Native.Json.values;
47
5− var Maybe = Elm.Maybe(elm);
6− var Dict = Elm.Dict(elm);
7− var List = Elm.List(elm);
8− var JS = Elm.JavaScript(elm);
9− var Utils = Elm.Native.Utils(elm);
8+ var Maybe = Elm.Maybe.make(elm);
9+ var Dict = Elm.Dict.make(elm);
10+ var List = Elm.List.make(elm);
11+ var JS = Elm.JavaScript.make(elm);
12+ var Utils = Elm.Native.Utils.make(elm);
1013
1114 function fromValue(v) {
1215 switch (v.ctor) {
@@ -59,7 +62,7 @@ Elm.Native.Json = function(elm) {
5962 }
6063 }
6164
62− return elm.Native.Json = {
65+ return elm.Native.Json.values = {
6366 toJSString : F2(toPrettyJSString),
6467 fromJSString : fromJSString,
6568 toJSObject : fromValue,
libraries/Native/List.js+272−315
@@ -1,353 +1,310 @@
1−Elm.Native.List = function(elm) {
2− "use strict";
3−
4− elm.Native = elm.Native || {};
5− if (elm.Native.List) return elm.Native.List;
6− if ('values' in Elm.Native.List)
7− return elm.Native.List = Elm.Native.List.values;
8−
9− var Utils = Elm.Native.Utils(elm);
10−
11− // TODO: Improve Nil handling
12− // We can change places like: if (xs.ctor === '[]') ... to if (xs === Nil) ...
13− // but only if we're confident Nil can only be defined once.
14− // Currently (27Mar2013) each module can have different instantiations, so multiple Nil objects can exist
15− // (and if they're used interchangeably then direct object comparison fails where ctor doesn't).
16− // So, this can only be fixed when modules initialisation is also fixed.
17− // The performance overhead of the .ctor calls is 5-10% according to jsperf (depending on fn + list size)
18− // (on firefox 19)
19−
20− var Nil = { ctor:'[]' };
21−
22− // using freeze for every cons would be nice but is a huge (9x on firefox 19)
23− // performance penalty
24− function Cons(hd,tl) { return { ctor:"::", _0:hd, _1:tl }; }
25−
26− function throwError(f) {
27− throw new Error("Function '" + f + "' expects a non-empty list!");
28− }
29−
30− function toArray(xs) {
31− var out = [];
32− while (xs.ctor !== '[]') {
33− out.push(xs._0);
34− xs = xs._1;
1+Elm.Native.List = {};
2+Elm.Native.List.make = function(elm) {
3+ elm.Native = elm.Native || {};
4+ elm.Native.List = elm.Native.List || {};
5+ if (elm.Native.List.values) return elm.Native.List.values;
6+ if ('values' in Elm.Native.List)
7+ return elm.Native.List.values = Elm.Native.List.values;
8+
9+ var Utils = Elm.Native.Utils.make(elm);
10+
11+ // TODO: Improve Nil handling
12+ // We can change places like: if (xs.ctor === '[]') ... to if (xs === Nil) ...
13+ // but only if we're confident Nil can only be defined once.
14+ // Currently (27Mar2013) each module can have different instantiations, so multiple Nil objects can exist
15+ // (and if they're used interchangeably then direct object comparison fails where ctor doesn't).
16+ // So, this can only be fixed when modules initialisation is also fixed.
17+ // The performance overhead of the .ctor calls is 5-10% according to jsperf (depending on fn + list size)
18+ // (on firefox 19)
19+
20+ var Nil = { ctor:'[]' };
21+
22+ // using freeze for every cons would be nice but is a huge (9x on firefox 19)
23+ // performance penalty
24+ function Cons(hd,tl) { return { ctor:"::", _0:hd, _1:tl }; }
25+
26+ function throwError(f) {
27+ throw new Error("Function '" + f + "' expects a non-empty list!");
3528 }
36− return out;
37− }
3829
39− function fromArray(arr) {
40− var out = Nil;
41− for (var i = arr.length; i--; ) {
42− out = Cons(arr[i], out);
30+ function toArray(xs) {
31+ var out = [];
32+ while (xs.ctor !== '[]') {
33+ out.push(xs._0);
34+ xs = xs._1;
35+ }
36+ return out;
4337 }
44− return out;
45− }
4638
47− function range(lo,hi) {
48− var lst = Nil;
49− if (lo <= hi) {
50− do { lst = Cons(hi,lst) } while (hi-->lo);
39+ function fromArray(arr) {
40+ var out = Nil;
41+ for (var i = arr.length; i--; ) {
42+ out = Cons(arr[i], out);
43+ }
44+ return out;
5145 }
52− return lst
53− }
54−
55− function append(xs,ys) {
56− if (typeof xs === "string") { return xs.concat(ys); }
57− if (xs.ctor === '[]') { return ys; }
58− var root = Cons(xs._0, Nil);
59− var curr = root;
60− xs = xs._1;
61− while (xs.ctor !== '[]') {
62− curr._1 = Cons(xs._0, Nil);
63− xs = xs._1;
64− curr = curr._1;
46+
47+ function range(lo,hi) {
48+ var lst = Nil;
49+ if (lo <= hi) {
50+ do { lst = Cons(hi,lst) } while (hi-->lo);
51+ }
52+ return lst
6553 }
66− curr._1 = ys;
67− return root;
68− }
69−
70− function head(v) { return v.ctor === '[]' ? throwError('head') : v._0; }
71− function tail(v) { return v.ctor === '[]' ? throwError('tail') : v._1; }
72−
73− function last(xs) {
74− if (xs.ctor === '[]') { throwError('last'); }
75− var out = xs._0;
76− while (xs.ctor !== '[]') {
77− out = xs._0;
78− xs = xs._1;
54+
55+ function append(xs,ys) {
56+ if (xs.isText) return Utils.txt(xs.concat(ys));
57+ if (typeof xs === "string") return xs.concat(ys);
58+ if (xs.ctor === '[]') { return ys; }
59+ var root = Cons(xs._0, Nil);
60+ var curr = root;
61+ xs = xs._1;
62+ while (xs.ctor !== '[]') {
63+ curr._1 = Cons(xs._0, Nil);
64+ xs = xs._1;
65+ curr = curr._1;
66+ }
67+ curr._1 = ys;
68+ return root;
7969 }
80− return out;
81− }
82−
83− function map(f, xs) {
84− var arr = [];
85− while (xs.ctor !== '[]') {
86− arr.push(f(xs._0));
87− xs = xs._1;
70+
71+ function head(v) { return v.ctor === '[]' ? throwError('head') : v._0; }
72+ function tail(v) { return v.ctor === '[]' ? throwError('tail') : v._1; }
73+
74+ function last(xs) {
75+ if (xs.ctor === '[]') { throwError('last'); }
76+ var out = xs._0;
77+ while (xs.ctor !== '[]') {
78+ out = xs._0;
79+ xs = xs._1;
80+ }
81+ return out;
8882 }
89− return fromArray(arr);
90− }
91−
92− // f defined similarly for both foldl and foldr (NB: different from Haskell)
93− // ie, foldl : (a -> b -> b) -> b -> [a] -> b
94− function foldl(f, b, xs) {
95− var acc = b;
96− while (xs.ctor !== '[]') {
97− acc = A2(f, xs._0, acc);
98− xs = xs._1;
83+
84+ function map(f, xs) {
85+ var arr = [];
86+ while (xs.ctor !== '[]') {
87+ arr.push(f(xs._0));
88+ xs = xs._1;
89+ }
90+ return fromArray(arr);
9991 }
100− return acc;
101− }
102−
103− function foldr(f, b, xs) {
104− var arr = toArray(xs);
105− var acc = b;
106− for (var i = arr.length; i--; ) {
107− acc = A2(f, arr[i], acc);
92+
93+ // f defined similarly for both foldl and foldr (NB: different from Haskell)
94+ // ie, foldl : (a -> b -> b) -> b -> [a] -> b
95+ function foldl(f, b, xs) {
96+ var acc = b;
97+ while (xs.ctor !== '[]') {
98+ acc = A2(f, xs._0, acc);
99+ xs = xs._1;
100+ }
101+ return acc;
108102 }
109− return acc;
110− }
111−
112− function foldl1(f, xs) {
113− return xs.ctor === '[]' ? throwError('foldl1') : foldl(f, xs._0, xs._1);
114− }
115−
116− function foldr1(f, xs) {
117− if (xs.ctor === '[]') { throwError('foldr1'); }
118− var arr = toArray(xs);
119− var acc = arr.pop();
120− for (var i = arr.length; i--; ) {
121− acc = A2(f, arr[i], acc);
103+
104+ function foldr(f, b, xs) {
105+ var arr = toArray(xs);
106+ var acc = b;
107+ for (var i = arr.length; i--; ) {
108+ acc = A2(f, arr[i], acc);
109+ }
110+ return acc;
122111 }
123− return acc;
124− }
125−
126− function scanl(f, b, xs) {
127− var arr = toArray(xs);
128− arr.unshift(b);
129− var len = arr.length;
130− for (var i = 1; i < len; ++i) {
131− arr[i] = A2(f, arr[i], arr[i-1]);
112+
113+ function foldl1(f, xs) {
114+ return xs.ctor === '[]' ? throwError('foldl1') : foldl(f, xs._0, xs._1);
132115 }
133− return fromArray(arr);
134− }
135−
136− function scanl1(f, xs) {
137− return xs.ctor === '[]' ? throwError('scanl1') : scanl(f, xs._0, xs._1);
138− }
139−
140− function filter(pred, xs) {
141− var arr = [];
142− while (xs.ctor !== '[]') {
143− if (pred(xs._0)) { arr.push(xs._0); }
144− xs = xs._1;
116+
117+ function foldr1(f, xs) {
118+ if (xs.ctor === '[]') { throwError('foldr1'); }
119+ var arr = toArray(xs);
120+ var acc = arr.pop();
121+ for (var i = arr.length; i--; ) {
122+ acc = A2(f, arr[i], acc);
123+ }
124+ return acc;
145125 }
146− return fromArray(arr);
147− }
148−
149− function length(xs) {
150− var out = 0;
151− while (xs.ctor !== '[]') {
152− out += 1;
153− xs = xs._1;
126+
127+ function scanl(f, b, xs) {
128+ var arr = toArray(xs);
129+ arr.unshift(b);
130+ var len = arr.length;
131+ for (var i = 1; i < len; ++i) {
132+ arr[i] = A2(f, arr[i], arr[i-1]);
133+ }
134+ return fromArray(arr);
154135 }
155− return out;
156− }
157136
158− function member(x, xs) {
159− while (xs.ctor !== '[]') {
160− if (Utils.eq(x,xs._0)) return true;
161− xs = xs._1;
137+ function scanl1(f, xs) {
138+ return xs.ctor === '[]' ? throwError('scanl1') : scanl(f, xs._0, xs._1);
162139 }
163− return false;
164− }
165−
166− function reverse(xs) { return fromArray(toArray(xs).reverse()); }
167−
168− function concat(xss) {
169− if (xss.ctor === '[]') return xss;
170− var arr = toArray(xss);
171− var xs = arr[arr.length-1];
172− for (var i = arr.length-1; i--; ) {
173− xs = append(arr[i], xs);
174− }
175− return xs;
176− }
177−
178− function all(pred, xs) {
179− while (xs.ctor !== '[]') {
180− if (!pred(xs._0)) return false;
181− xs = xs._1;
140+
141+ function filter(pred, xs) {
142+ var arr = [];
143+ while (xs.ctor !== '[]') {
144+ if (pred(xs._0)) { arr.push(xs._0); }
145+ xs = xs._1;
146+ }
147+ return fromArray(arr);
182148 }
183− return true;
184− }
185149
186− function any(pred, xs) {
187− while (xs.ctor !== '[]') {
188− if (pred(xs._0)) return true;
189− xs = xs._1;
150+ function length(xs) {
151+ var out = 0;
152+ while (xs.ctor !== '[]') {
153+ out += 1;
154+ xs = xs._1;
155+ }
156+ return out;
190157 }
191− return false;
192− }
193−
194− function zipWith(f, xs, ys) {
195− var arr = [];
196− while (xs.ctor !== '[]' && ys.ctor !== '[]') {
197− arr.push(A2(f, xs._0, ys._0));
198− xs = xs._1;
199− ys = ys._1;
158+
159+ function member(x, xs) {
160+ while (xs.ctor !== '[]') {
161+ if (Utils.eq(x,xs._0)) return true;
162+ xs = xs._1;
163+ }
164+ return false;
200165 }
201− return fromArray(arr);
202− }
203−
204− function zip(xs, ys) {
205− var arr = [];
206− while (xs.ctor !== '[]' && ys.ctor !== '[]') {
207− arr.push(Utils.Tuple2(xs._0, ys._0));
208− xs = xs._1;
209− ys = ys._1;
166+
167+ function reverse(xs) { return fromArray(toArray(xs).reverse()); }
168+
169+ function concat(xss) {
170+ if (xss.ctor === '[]') return xss;
171+ var arr = toArray(xss);
172+ var xs = arr[arr.length-1];
173+ for (var i = arr.length-1; i--; ) {
174+ xs = append(arr[i], xs);
175+ }
176+ return xs;
210177 }
211− return fromArray(arr);
212− }
213178
214− function sort(xs) {
215− function cmp(a,b) {
216− var ord = Utils.compare(a,b).ctor;
217− return ord=== 'EQ' ? 0 : ord === 'LT' ? -1 : 1;
179+ function all(pred, xs) {
180+ while (xs.ctor !== '[]') {
181+ if (!pred(xs._0)) return false;
182+ xs = xs._1;
183+ }
184+ return true;
218185 }
219− return fromArray(toArray(xs).sort(cmp));
220− }
221−
222− function nth(xs, n) {
223− return toArray(xs)[n];
224− }
225−
226− function take(n, xs) {
227− var arr = [];
228− while (xs.ctor !== '[]' && n > 0) {
229− arr.push(xs._0);
230− xs = xs._1;
231− --n;
186+
187+ function any(pred, xs) {
188+ while (xs.ctor !== '[]') {
189+ if (pred(xs._0)) return true;
190+ xs = xs._1;
191+ }
192+ return false;
232193 }
233− return fromArray(arr);
234− }
235194
236− function drop(n, xs) {
237− while (xs.ctor !== '[]' && n > 0) {
238− xs = xs._1;
239− --n;
195+ function zipWith(f, xs, ys) {
196+ var arr = [];
197+ while (xs.ctor !== '[]' && ys.ctor !== '[]') {
198+ arr.push(A2(f, xs._0, ys._0));
199+ xs = xs._1;
200+ ys = ys._1;
201+ }
202+ return fromArray(arr);
240203 }
241− return xs;
242− }
243−
244− function join(sep, xss) {
245− if (typeof sep === 'string') return toArray(xss).join(sep);
246− if (xss.ctor === '[]') return Nil;
247− var s = toArray(sep);
248− var out = toArray(xss._0);
249− xss = xss._1;
250− while (xss.ctor !== '[]') {
251− out = out.concat(s, toArray(xss._0));
252− xss = xss._1;
204+
205+ function zip(xs, ys) {
206+ var arr = [];
207+ while (xs.ctor !== '[]' && ys.ctor !== '[]') {
208+ arr.push(Utils.Tuple2(xs._0, ys._0));
209+ xs = xs._1;
210+ ys = ys._1;
211+ }
212+ return fromArray(arr);
253213 }
254− return fromArray(out);
255− }
256−
257− function split(seperator, list) {
258− var array = toArray(list);
259− var alen = array.length;
260− if (alen === 0) {
261− // splitting an empty list is a list of lists: [[]]
262− return Cons(Nil,Nil);
214+
215+ function sort(xs) {
216+ function cmp(a,b) {
217+ var ord = Utils.compare(a,b).ctor;
218+ return ord=== 'EQ' ? 0 : ord === 'LT' ? -1 : 1;
219+ }
220+ return fromArray(toArray(xs).sort(cmp));
263221 }
264222
265− var sep = toArray(seperator);
266− var seplen = sep.length;
267− if (seplen === 0) {
268− // splitting with an empty sep is a list of all elements
269− // Same as (map (\x -> [x]) list)
270− var out = Nil;
271− for (var i = alen; i--; ) {
272− out = Cons(Cons(array[i],Nil), out);
273− }
274− return out;
223+ function nth(xs, n) {
224+ return toArray(xs)[n];
275225 }
276226
277− var matches = [-seplen];
278− var sepStart = sep[0];
279− var len = alen - seplen + 1;
280− for (var i = 0; i < len; ++i) {
281− if (Utils.eq(array[i], sepStart)) {
282− var match = true;
283− for (var j = seplen; --j; ) {
284− if (!Utils.eq(array[i+j], sep[j])) { match = false; break; }
227+ function take(n, xs) {
228+ var arr = [];
229+ while (xs.ctor !== '[]' && n > 0) {
230+ arr.push(xs._0);
231+ xs = xs._1;
232+ --n;
285233 }
286− if (match) {
287− matches.push(i);
288− i += seplen - 1;
234+ return fromArray(arr);
235+ }
236+
237+ function drop(n, xs) {
238+ while (xs.ctor !== '[]' && n > 0) {
239+ xs = xs._1;
240+ --n;
289241 }
290− }
242+ return xs;
291243 }
292244
293− // shortcut in case of no matches
294− if (matches.length === 0) {
295− return Cons(list,Nil);
245+ function repeat(n, x) {
246+ var arr = [];
247+ var pattern = [x];
248+ while (n > 0) {
249+ if (n & 1) arr = arr.concat(pattern);
250+ n >>= 1, pattern = pattern.concat(pattern);
251+ }
252+ return fromArray(arr);
296253 }
297254
298− var out = Nil;
299− var index = alen - 1;
300− for (var i = matches.length; i--; ) {
301− var temp = Nil;
302− var stop = matches[i] + seplen - 1;
303− for ( ; index > stop; --index ) {
304− temp = Cons(array[index], temp);
305− }
306− out = Cons(temp,out);
307− index -= seplen;
255+ function join(sep, xss) {
256+ if (sep.isText) return Utils.txt(toArray(xss).join(sep));
257+ if (typeof sep === 'string') return toArray(xss).join(sep);
258+ if (xss.ctor === '[]') return Nil;
259+ var s = toArray(sep);
260+ var out = toArray(xss._0);
261+ xss = xss._1;
262+ while (xss.ctor !== '[]') {
263+ out = out.concat(s, toArray(xss._0));
264+ xss = xss._1;
265+ }
266+ return fromArray(out);
308267 }
309− return out;
310− }
311−
312− Elm.Native.List.values = {
313− Nil:Nil,
314− Cons:Cons,
315− cons:F2(Cons),
316− toArray:toArray,
317− fromArray:fromArray,
318− range:range,
319− append:append,
320−
321− head:head,
322− tail:tail,
323− last:last,
324−
325− map:F2(map),
326− foldl:F3(foldl),
327− foldr:F3(foldr),
328−
329− foldl1:F2(foldl1),
330− foldr1:F2(foldr1),
331− scanl:F3(scanl),
332− scanl1:F2(scanl1),
333− filter:F2(filter),
334− length:length,
335− member:F2(member),
336− reverse:reverse,
337− concat:concat,
338−
339− all:F2(all),
340− any:F2(any),
341− zipWith:F3(zipWith),
342− zip:F2(zip),
343− sort:sort,
344− nth:F2(nth),
345− take:F2(take),
346− drop:F2(drop),
347−
348− join:F2(join),
349− split:F2(split)
350− };
351− return elm.Native.List = Elm.Native.List.values;
352−
353−};
268+
269+ Elm.Native.List.values = {
270+ Nil:Nil,
271+ Cons:Cons,
272+ cons:F2(Cons),
273+ toArray:toArray,
274+ fromArray:fromArray,
275+ range:range,
276+ append:append,
277+
278+ head:head,
279+ tail:tail,
280+ last:last,
281+
282+ map:F2(map),
283+ foldl:F3(foldl),
284+ foldr:F3(foldr),
285+
286+ foldl1:F2(foldl1),
287+ foldr1:F2(foldr1),
288+ scanl:F3(scanl),
289+ scanl1:F2(scanl1),
290+ filter:F2(filter),
291+ length:length,
292+ member:F2(member),
293+ reverse:reverse,
294+ concat:concat,
295+
296+ all:F2(all),
297+ any:F2(any),
298+ zipWith:F3(zipWith),
299+ zip:F2(zip),
300+ sort:sort,
301+ nth:F2(nth),
302+ take:F2(take),
303+ drop:F2(drop),
304+ repeat:F2(repeat),
305+
306+ join:F2(join)
307+ };
308+ return elm.Native.List.values = Elm.Native.List.values;
309+
310+};
libraries/Native/Prelude.js+10−9
@@ -1,11 +1,12 @@
1+Elm.Native.Prelude = {};
2+Elm.Native.Prelude.make = function(elm) {
3+ elm.Native = elm.Native || {};
4+ elm.Native.Prelude = elm.Native.Prelude || {};
5+ if (elm.Native.Prelude.values) return elm.Native.Prelude.values;
16
2−Elm.Native.Prelude = function(elm) {
3− 'use strict';
4− if (elm.Native.Prelude) return elm.Native.Prelude;
5−
6− var JS = Elm.Native.JavaScript(elm);
7− var Maybe = Elm.Maybe(elm);
8− var Char = Elm.Char(elm);
7+ var JS = Elm.Native.JavaScript.make(elm);
8+ var Maybe = Elm.Maybe.make(elm);
9+ var Char = Elm.Char.make(elm);
910
1011 function readInt(str) {
1112 var s = JS.fromString(str);
@@ -43,9 +44,9 @@ Elm.Native.Prelude = function(elm) {
4344 return Maybe.Just(parseFloat(s));
4445 }
4546
46− return elm.Native.Prelude = {
47+ return elm.Native.Prelude.values = {
4748 readInt:readInt,
48− readFloat:readFloat,
49+ readFloat:readFloat
4950 };
5051
5152};
libraries/Native/Show.js+35−40
@@ -1,29 +1,31 @@
1−
2−Elm.Native.Show = function(elm) {
3− 'use strict';
4−
1+Elm.Native.Show = {};
2+Elm.Native.Show.make = function(elm) {
53 elm.Native = elm.Native || {};
6− if (elm.Native.Show) return elm.Native.Show;
4+ elm.Native.Show = elm.Native.Show || {};
5+ if (elm.Native.Show.values) return elm.Native.Show.values;
76
8− var NList = Elm.Native.List(elm);
9− var List = Elm.List(elm);
10− var Maybe = Elm.Maybe(elm);
11− var JS = Elm.JavaScript(elm);
12− var Dict = Elm.Dict(elm);
13− var Json = Elm.Json(elm);
14− var Tuple2 = Elm.Native.Utils(elm).Tuple2;
7+ var NList = Elm.Native.List.make(elm);
8+ var List = Elm.List.make(elm);
9+ var Maybe = Elm.Maybe.make(elm);
10+ var JS = Elm.JavaScript.make(elm);
11+ var Dict = Elm.Dict.make(elm);
12+ var Json = Elm.Json.make(elm);
13+ var Tuple2 = Elm.Native.Utils.make(elm).Tuple2;
1514
1615 var toString = function(v) {
17− if (typeof v === "function") {
16+ var type = typeof v;
17+ if (type === "function") {
1818 var name = v.func ? v.func.name : v.name;
1919 return '<function' + (name === '' ? '' : ': ') + name + '>';
20− } else if (typeof v === "boolean") {
20+ } else if (type === "boolean") {
2121 return v ? "True" : "False";
22− } else if (typeof v === "number") {
22+ } else if (type === "number") {
2323 return v+"";
24− } else if (typeof v === "string" && v.length < 2) {
25− return "'" + showChar(v) + "'";
26− } else if (typeof v === "object" && '_' in v) {
24+ } else if (v.isChar && v instanceof String) {
25+ return "'" + addSlashes(v) + "'";
26+ } else if (type === "string") {
27+ return '"' + addSlashes(v) + '"';
28+ } else if (type === "object" && '_' in v) {
2729 var output = [];
2830 for (var k in v._) {
2931 for (var i = v._[k].length; i--; ) {
@@ -36,7 +38,7 @@ Elm.Native.Show = function(elm) {
3638 }
3739 if (output.length === 0) return "{}";
3840 return "{ " + output.join(", ") + " }";
39− } else if (typeof v === "object" && 'ctor' in v) {
41+ } else if (type === "object" && 'ctor' in v) {
4042 if (v.ctor.substring(0,6) === "_Tuple") {
4143 var output = [];
4244 for (var k in v) {
@@ -45,18 +47,13 @@ Elm.Native.Show = function(elm) {
4547 }
4648 return "(" + output.join(",") + ")";
4749 } else if (v.ctor === "::") {
48− var isStr = typeof v._0 === "string",
49− start = isStr ? '"' : "[",
50− end = isStr ? '"' : "]",
51− sep = isStr ? "" : ",",
52− f = !isStr ? toString : showChar;
53− var output = start + f(v._0);
50+ var output = '[' + toString(v._0);
5451 v = v._1;
5552 while (v.ctor === "::") {
56− output += sep + f(v._0);
53+ output += "," + toString(v._0);
5754 v = v._1;
5855 }
59− return output + end;
56+ return output + ']';
6057 } else if (v.ctor === "[]") {
6158 return "[]";
6259 } else if (v.ctor === "RBNode" || v.ctor === "RBEmpty") {
@@ -79,22 +76,20 @@ Elm.Native.Show = function(elm) {
7976 return v.ctor + output;
8077 }
8178 }
82− if (typeof v === 'object' && 'recv' in v) return '<signal>';
79+ if (type === 'object' && 'recv' in v) return '<signal>';
8380 return "<internal structure>";
8481 };
85− function show(v) { return NList.fromArray(toString(v)); }
8682
87− function showChar (c) {
88− return c === '\n' ? '\\n' :
89− c === '\t' ? '\\t' :
90− c === '\b' ? '\\b' :
91− c === '\r' ? '\\r' :
92− c === '\v' ? '\\v' :
93− c === '\0' ? '\\0' :
94− c === '\'' ? "\\'" :
95− c === '\"' ? '\\"' :
96− c === '\\' ? '\\\\' : c;
83+ function addSlashes(str) {
84+ return str.replace(/\\/g, '\\\\')
85+ .replace(/\n/g, '\\n')
86+ .replace(/\t/g, '\\t')
87+ .replace(/\r/g, '\\r')
88+ .replace(/\v/g, '\\v')
89+ .replace(/\0/g, '\\0')
90+ .replace(/\'/g, "\\'")
91+ .replace(/\"/g, '\\"');
9792 }
9893
99− return elm.Native.Show = { show:show };
94+ return elm.Native.Show.values = { show:toString };
10095};
libraries/Native/Signal/Http.js+9−8
@@ -1,13 +1,14 @@
1+Elm.Native.Http = {};
2+Elm.Native.Http.make = function(elm) {
13
2−Elm.Native.Http = function(elm) {
3− 'use strict';
44 elm.Native = elm.Native || {};
5− if (elm.Native.Http) return elm.Native.Http;
5+ elm.Native.Http = elm.Native.Http || {};
6+ if (elm.Native.Http.values) return elm.Native.Http.values;
67
78
8− var JS = Elm.JavaScript(elm);
9− var List = Elm.List(elm);
10− var Signal = Elm.Signal(elm);
9+ var JS = Elm.JavaScript.make(elm);
10+ var List = Elm.List.make(elm);
11+ var Signal = Elm.Signal.make(elm);
1112
1213
1314 function registerReq(queue,responses) { return function(req) {
@@ -50,12 +51,12 @@ Elm.Native.Http = function(elm) {
5051 }
5152
5253 function send(requests) {
53− var responses = Signal.constant(elm.Http.Waiting);
54+ var responses = Signal.constant(elm.Http.values.Waiting);
5455 var sender = A2( Signal.lift, registerReq([],responses), requests );
5556 function f(x) { return function(y) { return x; } }
5657 return A3( Signal.lift2, f, responses, sender );
5758 }
5859
59− return elm.Native.Http = {send:send};
60+ return elm.Native.Http.values = {send:send};
6061
6162};
libraries/Native/Signal/Keyboard.js+14−10
@@ -1,8 +1,9 @@
1+Elm.Native.Keyboard = {};
2+Elm.Native.Keyboard.make = function(elm) {
13
2−Elm.Native.Keyboard = function(elm) {
3− 'use strict';
44 elm.Native = elm.Native || {};
5− if (elm.Native.Keyboard) return elm.Native.Keyboard;
5+ elm.Native.Keyboard = elm.Native.Keyboard || {};
6+ if (elm.Native.Keyboard.values) return elm.Native.Keyboard.values;
67
78 // Duplicated from Native.Signal
89 function send(node, timestep, changed) {
@@ -12,9 +13,9 @@ Elm.Native.Keyboard = function(elm) {
1213 }
1314 }
1415
15− var Signal = Elm.Signal(elm);
16− var NList = Elm.Native.List(elm);
17− var Utils = Elm.Native.Utils(elm);
16+ var Signal = Elm.Signal.make(elm);
17+ var NList = Elm.Native.List.make(elm);
18+ var Utils = Elm.Native.Utils.make(elm);
1819
1920 var downEvents = Signal.constant(0);
2021 var upEvents = Signal.constant(0);
@@ -76,10 +77,13 @@ Elm.Native.Keyboard = function(elm) {
7677
7778 function keySignal(f) {
7879 var signal = A2(Signal.lift, f, keysDown);
79− // what's the significance of these two following lines? -jpm
80+ // must set the default number of kids to make it possible to filter
81+ // these signals if they are not actually used.
8082 keysDown.defaultNumberOfKids += 1;
81− signal.defaultNumberOfKids = 0;
82− return signal;
83+ signal.defaultNumberOfKids = 1;
84+ var filtered = Signal.dropRepeats(signal)
85+ filtered.defaultNumberOfKids = 0;
86+ return filtered;
8387 }
8488
8589 function dir(up, down, left, right) {
@@ -103,7 +107,7 @@ Elm.Native.Keyboard = function(elm) {
103107
104108 var lastPressed = Signal.dropRepeats(downEvents);
105109
106− return elm.Native.Keyboard = {
110+ return elm.Native.Keyboard.values = {
107111 isDown:is,
108112 directions:F4(dir),
109113 keysDown:keysDown,
libraries/Native/Signal/Mouse.js+50−65
@@ -1,66 +1,51 @@
1−
2−Elm.Native.Mouse = function(elm) {
3− 'use strict';
4− elm.Native = elm.Native || {};
5− if (elm.Native.Mouse) return elm.Native.Mouse;
6−
7− var Signal = Elm.Signal(elm);
8− var Utils = Elm.Native.Utils(elm);
9−
10− var position = Signal.constant(Utils.Tuple2(0,0));
11− position.defaultNumberOfKids = 2;
12−
13− // do not move x and y into Elm. By setting their default number
14− // of kids, it is possible to detatch the mouse listeners if
15− // they are not needed.
16− var x = A2( Signal.lift, function(p){return p._0}, position);
17− x.defaultNumberOfKids = 0;
18− var y = A2( Signal.lift, function(p){return p._1}, position);
19− y.defaultNumberOfKids = 0;
20−
21− var isDown = Signal.constant(false);
22− var isClicked = Signal.constant(false);
23− var clicks = Signal.constant(Utils.Tuple0);
24−
25− function getXY(e) {
26− var posx = 0;
27− var posy = 0;
28− if (!e) e = window.event;
29− if (e.pageX || e.pageY) {
30− posx = e.pageX;
31− posy = e.pageY;
32− } else if (e.clientX || e.clientY) {
33− posx = e.clientX + document.body.scrollLeft +
34− document.documentElement.scrollLeft;
35− posy = e.clientY + document.body.scrollTop +
36− document.documentElement.scrollTop;
37− }
38− return Utils.Tuple2(posx-elm.node.offsetX, posy-elm.node.offsetY);
39− }
40−
41− var node = elm.display === ElmRuntime.Display.FULLSCREEN ? document : elm.node;
42−
43− elm.addListener([isClicked.id, clicks.id], node, 'click', function click() {
44− elm.notify(isClicked.id, true);
45− elm.notify(clicks.id, Utils.Tuple0);
46− elm.notify(isClicked.id, false);
47− });
48− elm.addListener([isDown.id], node, 'mousedown', function down() {
49− elm.notify(isDown.id, true);
50− });
51− elm.addListener([isDown.id], node, 'mouseup', function up() {
52− elm.notify(isDown.id, false);
53− });
54− elm.addListener([position.id], node, 'mousemove', function move(e) {
55− elm.notify(position.id, getXY(e));
56− });
57−
58− return elm.Native.Mouse = {
59− position: position,
60− x:x,
61− y:y,
62− isClicked: isClicked,
63− isDown: isDown,
64− clicks: clicks
65− };
1+Elm.Native.Mouse = {};
2+Elm.Native.Mouse.make = function(elm) {
3+
4+ elm.Native = elm.Native || {};
5+ elm.Native.Mouse = elm.Native.Mouse || {};
6+ if (elm.Native.Mouse.values) return elm.Native.Mouse.values;
7+
8+ var Signal = Elm.Signal.make(elm);
9+ var Utils = Elm.Native.Utils.make(elm);
10+
11+ var position = Signal.constant(Utils.Tuple2(0,0));
12+ position.defaultNumberOfKids = 2;
13+
14+ // do not move x and y into Elm. By setting their default number
15+ // of kids, it is possible to detatch the mouse listeners if
16+ // they are not needed.
17+ var x = A2( Signal.lift, function(p){return p._0}, position);
18+ x.defaultNumberOfKids = 0;
19+ var y = A2( Signal.lift, function(p){return p._1}, position);
20+ y.defaultNumberOfKids = 0;
21+
22+ var isDown = Signal.constant(false);
23+ var isClicked = Signal.constant(false);
24+ var clicks = Signal.constant(Utils.Tuple0);
25+
26+ var node = elm.display === ElmRuntime.Display.FULLSCREEN ? document : elm.node;
27+
28+ elm.addListener([isClicked.id, clicks.id], node, 'click', function click() {
29+ elm.notify(isClicked.id, true);
30+ elm.notify(clicks.id, Utils.Tuple0);
31+ elm.notify(isClicked.id, false);
32+ });
33+ elm.addListener([isDown.id], node, 'mousedown', function down() {
34+ elm.notify(isDown.id, true);
35+ });
36+ elm.addListener([isDown.id], node, 'mouseup', function up() {
37+ elm.notify(isDown.id, false);
38+ });
39+ elm.addListener([position.id], node, 'mousemove', function move(e) {
40+ elm.notify(position.id, Utils.getXY(e));
41+ });
42+
43+ return elm.Native.Mouse.values = {
44+ position: position,
45+ x:x,
46+ y:y,
47+ isClicked: isClicked,
48+ isDown: isDown,
49+ clicks: clicks
50+ };
6651};
libraries/Native/Signal/Random.js+32−16
@@ -1,23 +1,39 @@
1+Elm.Native.Random = {};
2+Elm.Native.Random.make = function(elm) {
13
2−Elm.Native.Random = function(elm) {
3− 'use strict';
4− elm.Native = elm.Native || {};
5− if (elm.Native.Random) return elm.Native.Random;
4+ elm.Native = elm.Native || {};
5+ elm.Native.Random = elm.Native.Random || {};
6+ if (elm.Native.Random.values) return elm.Native.Random.values;
67
7− var Signal = Elm.Signal(elm);
8+ var Signal = Elm.Signal.make(elm);
9+ var List = Elm.Native.List.make(elm);
810
9− function range(min, max, signal) {
10− function f(x) { return Math.floor(Math.random() * (max-min+1)) + min; }
11− return A2( Signal.lift, f, signal );
12− }
11+ function range(min, max, signal) {
12+ function f(x) { return Math.floor(Math.random() * (max-min+1)) + min; }
13+ return A2( Signal.lift, f, signal );
14+ }
1315
14− function flt(signal) {
15− function f(x) { return Math.random(); }
16− return A2( Signal.lift, f, signal );
17− }
16+ function float_(signal) {
17+ function f(x) { return Math.random(); }
18+ return A2( Signal.lift, f, signal );
19+ }
1820
19− elm.Native.Random = { range: F3(range) };
20− elm.Native.Random['float'] = flt;
21− return elm.Native.Random;
21+ function floatList(signal) {
22+ function f(n) {
23+ if (n < 0) return List.Nil;
24+ var arr = new Array(n);
25+ for (var i = n; i--; ) {
26+ arr[i] = Math.random();
27+ }
28+ return List.fromArray(arr);
29+ }
30+ return A2( Signal.lift, f, signal );
31+ }
32+
33+ return elm.Native.Random.values = {
34+ range: F3(range),
35+ float_: float_,
36+ floatList: floatList
37+ };
2238
2339};
libraries/Native/Signal/Signal.js+8−7
@@ -1,12 +1,13 @@
11
2−Elm.Native.Signal = function(elm) {
3− 'use strict';
2+Elm.Native.Signal = {};
3+Elm.Native.Signal.make = function(elm) {
44
55 elm.Native = elm.Native || {};
6− if (elm.Native.Signal) return elm.Native.Signal;
6+ elm.Native.Signal = elm.Native.Signal || {};
7+ if (elm.Native.Signal.values) return elm.Native.Signal.values;
78
8− var Utils = Elm.Native.Utils(elm);
9− var foldl1 = Elm.List(elm).foldl1;
9+ var Utils = Elm.Native.Utils.make(elm);
10+ var foldr1 = Elm.List.make(elm).foldr1;
1011
1112 function send(node, timestep, changed) {
1213 var kids = node.kids;
@@ -201,9 +202,9 @@ Elm.Native.Signal = function(elm) {
201202 }
202203
203204 function merge(s1,s2) { return new Merge(s1,s2); }
204− function merges(ss) { return A2(foldl1, F2(merge), ss); }
205+ function merges(ss) { return A2(foldr1, F2(merge), ss); }
205206
206− return elm.Native.Signal = {
207+ return elm.Native.Signal.values = {
207208 constant : function(v) { return new Input(v); },
208209 lift : F2(lift ),
209210 lift2 : F3(lift2),
libraries/Native/Signal/Time.js+10−7
@@ -1,11 +1,14 @@
1+Elm.Native.Time = {};
2+Elm.Native.Time.make = function(elm) {
13
2−Elm.Native.Time = function(elm) {
3− 'use strict';
4+ elm.Native = elm.Native || {};
5+ elm.Native.Time = elm.Native.Time || {};
6+ if (elm.Native.Time.values) return elm.Native.Time.values;
47
5− var Signal = Elm.Signal(elm);
6− var NS = Elm.Native.Signal(elm);
7− var Maybe = Elm.Maybe(elm);
8− var Utils = Elm.Native.Utils(elm);
8+ var Signal = Elm.Signal.make(elm);
9+ var NS = Elm.Native.Signal.make(elm);
10+ var Maybe = Elm.Maybe.make(elm);
11+ var Utils = Elm.Native.Utils.make(elm);
912
1013 function fpsWhen(desiredFPS, isOn) {
1114 var msPerFrame = 1000 / desiredFPS;
@@ -50,7 +53,7 @@ Elm.Native.Time = function(elm) {
5053 var t = Date.parse(s);
5154 return isNaN(t) ? Maybe.Nothing : Maybe.Just(t);
5255 }
53− return elm.Native.Time = {
56+ return elm.Native.Time.values = {
5457 fpsWhen : F2(fpsWhen),
5558 fps : function(t) { return fpsWhen(t, Signal.constant(true)); },
5659 every : function(t) { return everyWhen(t, Signal.constant(true)) },
libraries/Native/Signal/Touch.js+135−132
@@ -1,149 +1,152 @@
1+Elm.Native.Touch = {};
2+Elm.Native.Touch.make = function(elm) {
13
2−Elm.Native.Touch = function(elm) {
3− 'use strict';
4+ elm.Native = elm.Native || {};
5+ elm.Native.Touch = elm.Native.Touch || {};
6+ if (elm.Native.Touch.values) return elm.Native.Touch.values;
47
5− elm.Native = elm.Native || {};
6− if (elm.Native.Touch) return elm.Native.Touch;
8+ var Signal = Elm.Signal.make(elm);
9+ var JS = Elm.JavaScript.make(elm);
10+ var Utils = Elm.Native.Utils.make(elm);
711
8− var Signal = Elm.Signal(elm);
9− var JS = Elm.JavaScript(elm);
10− var _ = Elm.Native.Utils(elm);
11−
12− function Dict() {
13− this.keys = [];
14− this.values = [];
15−
16− this.insert = function(key,value) {
17− this.keys.push(key);
18− this.values.push(value);
19− };
20− this.lookup = function(key) {
21− var i = this.keys.indexOf(key)
22− return i >= 0 ? this.values[i] : {x:0,y:0,t:0};
23− };
24− this.remove = function(key) {
25− var i = this.keys.indexOf(key);
26− if (i < 0) return;
27− var t = this.values[i];
28− this.keys.splice(i,1);
29− this.values.splice(i,1);
30− return t;
31− };
32− this.clear = function() {
12+ function Dict() {
3313 this.keys = [];
3414 this.values = [];
35− };
36− }
37−
38− var root = Signal.constant([]),
39− tapTime = 500,
40− hasTap = false,
41− tap = {_:{},x:0,y:0},
42− dict = new Dict();
4315
44− function touch(t) {
45− var r = dict.lookup(t.identifier);
46− return {_ : {},
47− id: t.identifier,
48− x : t.pageX - elm.node.offsetX,
49− y : t.pageY - elm.node.offsetY,
50− x0: r.x,
51− y0: r.y,
52− t0: r.t
53− };
54− }
16+ this.insert = function(key,value) {
17+ this.keys.push(key);
18+ this.values.push(value);
19+ };
20+ this.lookup = function(key) {
21+ var i = this.keys.indexOf(key)
22+ return i >= 0 ? this.values[i] : {x:0,y:0,t:0};
23+ };
24+ this.remove = function(key) {
25+ var i = this.keys.indexOf(key);
26+ if (i < 0) return;
27+ var t = this.values[i];
28+ this.keys.splice(i,1);
29+ this.values.splice(i,1);
30+ return t;
31+ };
32+ this.clear = function() {
33+ this.keys = [];
34+ this.values = [];
35+ };
36+ }
37+
38+ var root = Signal.constant([]),
39+ tapTime = 500,
40+ hasTap = false,
41+ tap = {_:{},x:0,y:0},
42+ dict = new Dict();
43+
44+ function touch(t) {
45+ var r = dict.lookup(t.identifier);
46+ var point = Utils.getXY(t);
47+ return {_ : {},
48+ id: t.identifier,
49+ x : point._0,
50+ y : point._1,
51+ x0: r.x,
52+ y0: r.y,
53+ t0: r.t
54+ };
55+ }
5556
56− var node = elm.display === ElmRuntime.Display.FULLSCREEN ? document : elm.node;
57+ var node = elm.display === ElmRuntime.Display.FULLSCREEN ? document : elm.node;
5758
58− function start(e) {
59− dict.insert(e.identifier,
60− {x: e.pageX - elm.node.offsetX,
61− y: e.pageY - elm.node.offsetY,
62− t: Date.now()});
63− }
64− function end(e) {
65− var t = dict.remove(e.identifier);
66− if (Date.now() - t.t < tapTime) {
67− hasTap = true;
68− tap = {_:{}, x:t.x, y:t.y};
59+ function start(e) {
60+ var point = Utils.getXY(e);
61+ dict.insert(e.identifier,
62+ {x: point._0,
63+ y: point._1,
64+ t: Date.now()});
6965 }
70− }
71−
72− function listen(name, f) {
73− function update(e) {
74− for (var i = e.changedTouches.length; i--; ) { f(e.changedTouches[i]); }
75− var ts = new Array(e.touches.length);
76− for (var i = e.touches.length; i--; ) { ts[i] = touch(e.touches[i]); }
77− elm.notify(root.id, ts);
78− e.preventDefault();
66+ function end(e) {
67+ var t = dict.remove(e.identifier);
68+ if (Date.now() - t.t < tapTime) {
69+ hasTap = true;
70+ tap = {_:{}, x:t.x, y:t.y};
71+ }
7972 }
80− elm.addListener([root.id], node, name, update);
81− }
8273
83− listen("touchstart", start);
84− listen("touchmove", function(_){});
85− listen("touchend", end);
86− listen("touchcancel", end);
87− listen("touchleave", end);
88−
89− var mouseID = -1;
90− function move(e) {
91− for (var i = root.value.length; i--; ) {
92− if (root.value[i].id === mouseID) {
93− root.value[i].x = e.pageX - elm.node.offsetX;
94− root.value[i].y = e.pageY - elm.node.offsetY;
95− elm.notify(root.id, root.value);
96− break;
97− }
98− }
99− }
100− elm.addListener([root.id], node, "mousedown", function down(e) {
101− node.addEventListener("mousemove", move);
102− e.identifier = mouseID;
103− start(e);
104− root.value.push(touch(e));
105− elm.notify(root.id, root.value);
106− });
107− elm.addListener([root.id], node, "mouseup", function up(e) {
108− node.removeEventListener("mousemove", move);
109− e.identifier = mouseID;
110− end(e);
111− for (var i = root.value.length; i--; ) {
112− if (root.value[i].id === mouseID) {
113− root.value.splice(i, 1);
114− --mouseID;
115− break;
116− }
117− }
118− elm.notify(root.id, root.value);
119− });
120− elm.addListener([root.id], node, "blur", function blur(e) {
121− node.removeEventListener("mousemove", move);
122− if (root.value.length > 0) {
123− elm.notify(root.id, []);
124− --mouseID;
125− }
126− dict.clear();
127− });
74+ function listen(name, f) {
75+ function update(e) {
76+ for (var i = e.changedTouches.length; i--; ) { f(e.changedTouches[i]); }
77+ var ts = new Array(e.touches.length);
78+ for (var i = e.touches.length; i--; ) { ts[i] = touch(e.touches[i]); }
79+ elm.notify(root.id, ts);
80+ e.preventDefault();
81+ }
82+ elm.addListener([root.id], node, name, update);
83+ }
12884
129− function dependency(f) {
130− var sig = A2( Signal.lift, f, root );
131− root.defaultNumberOfKids += 1;
132− sig.defaultNumberOfKids = 0;
133− return sig;
134− }
85+ listen("touchstart", start);
86+ listen("touchmove", function(_){});
87+ listen("touchend", end);
88+ listen("touchcancel", end);
89+ listen("touchleave", end);
90+
91+ var mouseID = -1;
92+ function move(e) {
93+ var point = Utils.getXY(e);
94+ for (var i = root.value.length; i--; ) {
95+ if (root.value[i].id === mouseID) {
96+ root.value[i].x = point._0;
97+ root.value[i].y = point._1;
98+ elm.notify(root.id, root.value);
99+ break;
100+ }
101+ }
102+ }
103+ elm.addListener([root.id], node, "mousedown", function down(e) {
104+ node.addEventListener("mousemove", move);
105+ e.identifier = mouseID;
106+ start(e);
107+ root.value.push(touch(e));
108+ elm.notify(root.id, root.value);
109+ });
110+ elm.addListener([root.id], node, "mouseup", function up(e) {
111+ node.removeEventListener("mousemove", move);
112+ e.identifier = mouseID;
113+ end(e);
114+ for (var i = root.value.length; i--; ) {
115+ if (root.value[i].id === mouseID) {
116+ root.value.splice(i, 1);
117+ --mouseID;
118+ break;
119+ }
120+ }
121+ elm.notify(root.id, root.value);
122+ });
123+ elm.addListener([root.id], node, "blur", function blur(e) {
124+ node.removeEventListener("mousemove", move);
125+ if (root.value.length > 0) {
126+ elm.notify(root.id, []);
127+ --mouseID;
128+ }
129+ dict.clear();
130+ });
131+
132+ function dependency(f) {
133+ var sig = A2( Signal.lift, f, root );
134+ root.defaultNumberOfKids += 1;
135+ sig.defaultNumberOfKids = 0;
136+ return sig;
137+ }
135138
136− var touches = dependency(JS.toList);
139+ var touches = dependency(JS.toList);
137140
138− var taps = function() {
139− var sig = dependency(function(_) { return tap; });
140− sig.defaultNumberOfKids = 1;
141− function pred(_) { var b = hasTap; hasTap = false; return b; }
142− var sig2 = A3( Signal.keepIf, pred, {_:{},x:0,y:0}, sig);
143− sig2.defaultNumberOfKids = 0;
144− return sig2;
145− }();
141+ var taps = function() {
142+ var sig = dependency(function(_) { return tap; });
143+ sig.defaultNumberOfKids = 1;
144+ function pred(_) { var b = hasTap; hasTap = false; return b; }
145+ var sig2 = A3( Signal.keepIf, pred, {_:{},x:0,y:0}, sig);
146+ sig2.defaultNumberOfKids = 0;
147+ return sig2;
148+ }();
146149
147− return elm.Native.Touch = { touches: touches, taps: taps };
150+ return elm.Native.Touch.values = { touches: touches, taps: taps };
148151
149152};
libraries/Native/Signal/WebSocket.js+8−8
@@ -1,13 +1,13 @@
1−
2−Elm.Native.WebSocket = function(elm) {
3− 'use strict';
1+Elm.Native.WebSocket = {};
2+Elm.Native.WebSocket.make = function(elm) {
43
54 elm.Native = elm.Native || {};
6− if (elm.Native.WebSocket) return elm.Native.WebSocket;
5+ elm.Native.WebSocket = elm.Native.WebSocket || {};
6+ if (elm.Native.WebSocket.values) return elm.Native.WebSocket.values;
77
8− var Signal = Elm.Signal(elm);
9− var JS = Elm.JavaScript(elm);
10− var List = Elm.Native.List(elm);
8+ var Signal = Elm.Signal.make(elm);
9+ var JS = Elm.JavaScript.make(elm);
10+ var List = Elm.Native.List.make(elm);
1111
1212 function open(url, outgoing) {
1313 var incoming = Signal.constant(List.Nil);
@@ -34,5 +34,5 @@ Elm.Native.WebSocket = function(elm) {
3434 return A3(Signal.lift2, F2(take1), incoming, A2(Signal.lift, send, outgoing));
3535 }
3636
37− return elm.Native.WebSocket = { connect: F2(open) };
37+ return elm.Native.WebSocket.values = { connect: F2(open) };
3838};
libraries/Native/Signal/Window.js+7−7
@@ -1,12 +1,12 @@
1−
2−Elm.Native.Window = function(elm) {
3− 'use strict';
1+Elm.Native.Window = {};
2+Elm.Native.Window.make = function(elm) {
43
54 elm.Native = elm.Native || {};
6− if (elm.Native.Window) return elm.Native.Window;
5+ elm.Native.Window = elm.Native.Window || {};
6+ if (elm.Native.Window.values) return elm.Native.Window.values;
77
8− var Signal = Elm.Signal(elm);
9− var Tuple2 = Elm.Native.Utils(elm).Tuple2;
8+ var Signal = Elm.Signal.make(elm);
9+ var Tuple2 = Elm.Native.Utils.make(elm).Tuple2;
1010
1111 function getWidth() { return elm.node.clientWidth; }
1212 function getHeight() {
@@ -35,7 +35,7 @@ Elm.Native.Window = function(elm) {
3535 }
3636 elm.addListener([dimensions.id], window, 'resize', resizeIfNeeded);
3737
38− return elm.Native.Window = {
38+ return elm.Native.Window.values = {
3939 dimensions:dimensions,
4040 width:width,
4141 height:height,
libraries/Native/String.jsnew file+232
@@ -0,0 +1,232 @@
1+Elm.Native.String = {};
2+Elm.Native.String.make = function(elm) {
3+ elm.Native = elm.Native || {};
4+ elm.Native.String = elm.Native.String || {};
5+ if (elm.Native.String.values) return elm.Native.String.values;
6+ if ('values' in Elm.Native.String)
7+ return elm.Native.String.values = Elm.Native.String.values;
8+
9+ var Char = Elm.Char.make(elm);
10+ var Maybe = Elm.Maybe.make(elm);
11+ var JS = Elm.JavaScript.make(elm);
12+ var Utils = Elm.Native.Utils.make(elm);
13+
14+ function isEmpty(str) {
15+ return str.length === 0;
16+ }
17+ function cons(chr,str) {
18+ return chr + str;
19+ }
20+ function uncons(str) {
21+ var hd;
22+ return (hd = str[0]) ? Maybe.Just(Utils.Tuple2(Utils.chr(hd), str.slice(1)))
23+ : Maybe.Nothing;
24+ }
25+ function length(str) {
26+ return str.length;
27+ }
28+ function map(f,str) {
29+ return str.split('').map(f).join('');
30+ }
31+ function filter(pred,str) {
32+ return str.split('').filter(pred).join('');
33+ }
34+ function reverse(str) {
35+ return str.split('').reverse().join('');
36+ }
37+ function foldl(f,b,str) {
38+ var len = str.length;
39+ for (var i = 0; i < len; ++i) {
40+ b = A2(f, str[i], b);
41+ }
42+ return b;
43+ }
44+ function foldr(f,b,str) {
45+ for (var i = str.length; i--; ) {
46+ b = A2(f, str[i], b);
47+ }
48+ return b;
49+ }
50+
51+ function split(sep, str) {
52+ return JS.toList(str.split(sep));
53+ }
54+ function join(sep, strs) {
55+ return JS.fromList(strs).join(sep);
56+ }
57+ function repeat(n, str) {
58+ var result = '';
59+ while (n > 0) {
60+ if (n & 1) result += str;
61+ n >>= 1, str += str;
62+ }
63+ return result;
64+ }
65+
66+ function sub(start, end, str) {
67+ return str.slice(start,end);
68+ }
69+ function left(n, str) {
70+ return n < 1 ? "" : str.slice(0,n);
71+ }
72+ function right(n, str) {
73+ return n < 1 ? "" : str.slice(-n);
74+ }
75+ function dropLeft(n, str) {
76+ return n < 1 ? str : str.slice(n);
77+ }
78+ function dropRight(n, str) {
79+ return n < 1 ? str : str.slice(0,-n);
80+ }
81+
82+ function pad(n,chr,str) {
83+ var half = (n - str.length) / 2;
84+ return repeat(Math.ceil(half),chr) + str + repeat(half|0,chr);
85+ }
86+ function padRight(n,chr,str) {
87+ return str + repeat(n - str.length, chr);
88+ }
89+ function padLeft(n,chr,str) {
90+ return repeat(n - str.length, chr) + str;
91+ }
92+
93+ function trim(str) {
94+ return str.trim();
95+ }
96+ function trimLeft(str) {
97+ return str.trimLeft();
98+ }
99+ function trimRight(str) {
100+ return str.trimRight();
101+ }
102+
103+ function words(str) {
104+ return JS.toList(str.split(/\s+/g));
105+ }
106+ function lines(str) {
107+ return JS.toList(str.split(/\r\n|\r|\n/g));
108+ }
109+
110+ function toUpper(str) {
111+ return str.toUpperCase();
112+ }
113+ function toLower(str) {
114+ return str.toLowerCase();
115+ }
116+
117+ function any(pred, str) {
118+ for (var i = str.length; i--; ) {
119+ if (pred(str[i])) return true;
120+ }
121+ return false;
122+ }
123+ function all(pred, str) {
124+ for (var i = str.length; i--; ) {
125+ if (!pred(str[i])) return false;
126+ }
127+ return true;
128+ }
129+
130+ function contains(sub, str) {
131+ return str.indexOf(sub) > -1;
132+ }
133+ function startsWith(sub, str) {
134+ return str.indexOf(sub) === 0;
135+ }
136+ function endsWith(sub, str) {
137+ return str.lastIndexOf(sub) === str.length - sub.length;
138+ }
139+ function indexes(sub, str) {
140+ var subLen = sub.length;
141+ var i = 0;
142+ var is = [];
143+ while ((i = str.indexOf(sub, i)) > -1) {
144+ is.push(i);
145+ i = i + subLen;
146+ }
147+ return JS.toList(is);
148+ }
149+
150+ function toInt(str) {
151+ var s = JS.fromString(str);
152+ var len = s.length;
153+ if (len === 0) { return Maybe.Nothing; }
154+ var start = 0;
155+ if (s[0] == '-') {
156+ if (len === 1) { return Maybe.Nothing; }
157+ start = 1;
158+ }
159+ for (var i = start; i < len; ++i) {
160+ if (!Char.isDigit(s[i])) { return Maybe.Nothing; }
161+ }
162+ return Maybe.Just(parseInt(s, 10));
163+ }
164+
165+ function toFloat(str) {
166+ var s = JS.fromString(str);
167+ var len = s.length;
168+ if (len === 0) { return Maybe.Nothing; }
169+ var start = 0;
170+ if (s[0] == '-') {
171+ if (len === 1) { return Maybe.Nothing; }
172+ start = 1;
173+ }
174+ var dotCount = 0;
175+ for (var i = start; i < len; ++i) {
176+ if (Char.isDigit(s[i])) { continue; }
177+ if (s[i] === '.') {
178+ dotCount += 1;
179+ if (dotCount <= 1) { continue; }
180+ }
181+ return Maybe.Nothing;
182+ }
183+ return Maybe.Just(parseFloat(s));
184+ }
185+
186+ return Elm.Native.String.values = {
187+ isEmpty: isEmpty,
188+ cons: F2(cons),
189+ uncons: uncons,
190+ length: length,
191+ map: F2(map),
192+ filter: F2(filter),
193+ reverse: reverse,
194+ foldl: F3(foldl),
195+ foldr: F3(foldr),
196+
197+ split: F2(split),
198+ join: F2(join),
199+ repeat: F2(repeat),
200+
201+ sub: F3(sub),
202+ left: F2(left),
203+ right: F2(right),
204+ dropLeft: F2(dropLeft),
205+ dropRight: F2(dropRight),
206+
207+ pad: F3(pad),
208+ padLeft: F3(padLeft),
209+ padRight: F3(padRight),
210+
211+ trim: trim,
212+ trimLeft: trimLeft,
213+ trimRight: trimRight,
214+
215+ words: words,
216+ lines: lines,
217+
218+ toUpper: toUpper,
219+ toLower: toLower,
220+
221+ any: F2(any),
222+ all: F2(all),
223+
224+ contains: F2(contains),
225+ startsWith: F2(startsWith),
226+ endsWith: F2(endsWith),
227+ indexes: F2(indexes),
228+
229+ toInt: toInt,
230+ toFloat: toFloat,
231+ };
232+};
libraries/Native/Text.js+122−122
@@ -1,136 +1,136 @@
1+Elm.Native.Text = {};
2+Elm.Native.Text.make = function(elm) {
3+ elm.Native = elm.Native || {};
4+ elm.Native.Text = elm.Native.Text || {};
5+ if (elm.Native.Text.values) return elm.Native.Text.values;
6+
7+ var JS = Elm.JavaScript.make(elm);
8+ var Utils = Elm.Native.Utils.make(elm);
9+ var Color = Elm.Native.Color.make(elm);
10+ var Element = Elm.Graphics.Element.make(elm);
11+ var show = Elm.Native.Show.make(elm).show;
12+
13+ function makeSpaces(s) {
14+ if (s.length == 0) { return s; }
15+ var arr = s.split('');
16+ if (arr[0] == ' ') { arr[0] = "&nbsp;" }
17+ for (var i = arr.length; --i; ) {
18+ if (arr[i][0] == ' ' && arr[i-1] == ' ') {
19+ arr[i-1] = arr[i-1] + arr[i];
20+ arr[i] = '';
21+ }
22+ }
23+ for (var i = arr.length; i--; ) {
24+ if (arr[i].length > 1 && arr[i][0] == ' ') {
25+ var spaces = arr[i].split('');
26+ for (var j = spaces.length - 2; j >= 0; j -= 2) {
27+ spaces[j] = '&nbsp;';
28+ }
29+ arr[i] = spaces.join('');
30+ }
31+ }
32+ arr = arr.join('');
33+ if (arr[arr.length-1] === " ") {
34+ return arr.slice(0,-1) + '&nbsp;';
35+ }
36+ return arr;
37+ }
138
2−Elm.Native.Text = function(elm) {
3− 'use strict';
4−
5− elm.Native = elm.Native || {};
6− if (elm.Native.Text) return elm.Native.Text;
39+ function properEscape(str) {
40+ if (str.length == 0) return str;
41+ str = str //.replace(/&/g, "&#38;")
42+ .replace(/"/g, '&#34;')
43+ .replace(/'/g, "&#39;")
44+ .replace(/</g, "&#60;")
45+ .replace(/>/g, "&#62;")
46+ .replace(/\n/g, "<br/>");
47+ var arr = str.split('<br/>');
48+ for (var i = arr.length; i--; ) {
49+ arr[i] = makeSpaces(arr[i]);
50+ }
51+ return arr.join('<br/>');
52+ }
753
8− var JS = Elm.JavaScript(elm);
9− var htmlHeight = Elm.Native.Utils(elm).htmlHeight;
10− var Color = Elm.Native.Color(elm);
11− var Element = Elm.Graphics.Element(elm);
12− var show = Elm.Native.Show(elm).show;
54+ function toText(str) { return Utils.txt(properEscape(JS.fromString(str))); }
1355
14− function makeSpaces(s) {
15− if (s.length == 0) { return s; }
16− var arr = s.split('');
17− if (arr[0] == ' ') { arr[0] = "&nbsp;" }
18− for (var i = arr.length; --i; ) {
19− if (arr[i][0] == ' ' && arr[i-1] == ' ') {
20− arr[i-1] = arr[i-1] + arr[i];
21− arr[i] = '';
22− }
23− }
24− for (var i = arr.length; i--; ) {
25− if (arr[i].length > 1 && arr[i][0] == ' ') {
26− var spaces = arr[i].split('');
27− for (var j = spaces.length - 2; j >= 0; j -= 2) {
28− spaces[j] = '&nbsp;';
56+ function addTag(tag) {
57+ return function(text) {
58+ return Utils.txt('<' + tag + '>' + text + '</' + tag + '>');
2959 }
30− arr[i] = spaces.join('');
31− }
3260 }
33− arr = arr.join('');
34− if (arr[arr.length-1] === " ") {
35− return arr.slice(0,-1) + '&nbsp;';
61+
62+ function addStyle(style, value, text) {
63+ return Utils.txt("<span style='" + style + ":" + value + "'>" + text + "</span>");
3664 }
37− return arr;
38− }
3965
40− function properEscape(str) {
41− if (str.length == 0) return str;
42− str = str //.replace(/&/g, "&#38;")
43− .replace(/"/g, /*"*/ '&#34;')
44− .replace(/'/g, /*'*/ "&#39;")
45− .replace(/</g, "&#60;")
46− .replace(/>/g, "&#62;")
47− .replace(/\n/g, "<br/>");
48− var arr = str.split('<br/>');
49− for (var i = arr.length; i--; ) {
50− arr[i] = makeSpaces(arr[i]);
66+ function typeface(name, text) {
67+ return addStyle('font-family', JS.fromString(name), text);
5168 }
52− return arr.join('<br/>');
53− }
54−
55− function toText(str) { return properEscape(JS.fromString(str)); }
56−
57− function addTag(tag) { return function(text) {
58− return '<' + tag + ' style="padding:0;margin:0">' + text + '</' + tag + '>';
69+ function monospace(text) {
70+ return addStyle('font-family', 'monospace', text);
71+ }
72+ function size(px, text) { return addStyle('font-size', px + 'px', text) }
73+ var header = addTag('h1');
74+ function height(h, text) { return addStyle('font-size', h+'px', text) }
75+ function italic(text) { return addStyle('font-style', 'italic', text) }
76+ var bold = addTag('b');
77+
78+ function extract(c) {
79+ if (c._3 === 1) { return 'rgb(' + c._0 + ', ' + c._1 + ', ' + c._2 + ')'; }
80+ return 'rgba(' + c._0 + ', ' + c._1 + ', ' + c._2 + ', ' + c._3 + ')';
81+ }
82+ function color(c, text) {
83+ return addStyle('color', extract(c), text);
84+ }
85+ function underline(text) { return addStyle('text-decoration', 'underline', text) }
86+ function overline(text) { return addStyle('text-decoration', 'overline', text) }
87+ function strikeThrough(text) {
88+ return addStyle('text-decoration', 'line-through', text);
89+ }
90+ function link(href, text) {
91+ return Utils.txt("<a href='" + toText(href) + "'>" + text + "</a>");
5992 }
60− }
61−
62− function addStyle(style, value, text) {
63− return "<span style='" + style + ":" + value + "'>" + text + "</span>";
64− }
65−
66− function typeface(name, text) {
67− return addStyle('font-family', JS.fromString(name), text);
68− }
69− function monospace(text) {
70− return addStyle('font-family', 'monospace', text);
71− }
72− function size(px, text) { return addStyle('font-size', px + 'px', text) }
73− var header = addTag('h1');
74− function height(h, text) { return addStyle('font-size', h+'px', text) }
75− function italic(text) { return addStyle('font-style', 'italic', text) }
76− var bold = addTag('b');
77−
78− function extract(c) {
79− if (c._3 === 1) { return 'rgb(' + c._0 + ',' + c._1 + ',' + c._2 + ')'; }
80− return 'rgba(' + c._0 + ',' + c._1 + ',' + c._2 + ',' + c._3 + ')';
81− }
82− function color(c, text) {
83− return addStyle('color', extract(c), text);
84− }
85− function underline(text) { return addStyle('text-decoration', 'underline', text) }
86− function overline(text) { return addStyle('text-decoration', 'overline', text) }
87− function strikeThrough(text) {
88− return addStyle('text-decoration', 'line-through', text);
89− }
90− function link(href, text) {
91− return "<a href='" + toText(href) + "'>" + text + "</a>";
92− }
93−
94− function position(pos) { return function(text) {
95− var e = {ctor:'RawHtml',
96− _0: '<div style="padding:0;margin:0;text-align:' +
97− pos + '">' + text + '</div>'
98− };
99− var p = A2(htmlHeight, 0, text);
100− return A3(Element.newElement, p._0, p._1, e);
101− }
102− }
103−
104− function asText(v) {
105− return position('left')(monospace(toText(show(v))));
106− }
107−
108− function plainText(v) {
109− return position('left')(toText(v));
110− }
111−
112− return elm.Native.Text = {
113− toText: toText,
11493
115− header : header,
116− height : F2(height),
117− italic : italic,
118− bold : bold,
119− underline : underline,
120− overline : overline,
121− strikeThrough : strikeThrough,
122− monospace : monospace,
123− typeface : F2(typeface),
124− color : F2(color),
125− link : F2(link),
94+ function position(pos) {
95+ return function(text) {
96+ var e = {ctor:'RawHtml',
97+ _0: '<div style="padding:0;margin:0;text-align:' +
98+ pos + '">' + text + '</div>'
99+ };
100+ var p = A2(Utils.htmlHeight, 0, text);
101+ return A3(Element.newElement, p._0, p._1, e);
102+ }
103+ }
126104
127− justified : position('justify'),
128− centered : position('center'),
129− righted : position('right'),
130− text : position('left'),
131− plainText : plainText,
105+ function asText(v) {
106+ return position('left')(monospace(toText(show(v))));
107+ }
132108
133− asText : asText
134− };
109+ function plainText(v) {
110+ return position('left')(toText(v));
111+ }
135112
113+ return elm.Native.Text.values = {
114+ toText: toText,
115+
116+ header : header,
117+ height : F2(height),
118+ italic : italic,
119+ bold : bold,
120+ underline : underline,
121+ overline : overline,
122+ strikeThrough : strikeThrough,
123+ monospace : monospace,
124+ typeface : F2(typeface),
125+ color : F2(color),
126+ link : F2(link),
127+
128+ justified : position('justify'),
129+ centered : position('center'),
130+ righted : position('right'),
131+ text : position('left'),
132+ plainText : plainText,
133+
134+ asText : asText
135+ };
136136};
libraries/Native/Transform2D.js+5−5
@@ -1,9 +1,9 @@
1−
2−Elm.Native.Transform2D = function(elm) {
3− "use strict";
1+Elm.Native.Transform2D = {};
2+Elm.Native.Transform2D.make = function(elm) {
43
54 elm.Native = elm.Native || {};
6− if (elm.Native.Transform2D) return elm.Native.Transform2D;
5+ elm.Native.Transform2D = elm.Native.Transform2D || {};
6+ if (elm.Native.Transform2D.values) return elm.Native.Transform2D.values;
77
88 var A;
99 if (typeof Float32Array === 'undefined') {
@@ -80,7 +80,7 @@ Elm.Native.Transform2D = function(elm) {
8080 m21*ndx + m22*ndy + mdy]);
8181 }
8282
83− return elm.Native.Transform2D = {
83+ return elm.Native.Transform2D.values = {
8484 identity:identity,
8585 matrix:F6(matrix),
8686 rotation:rotation,
libraries/Native/Utils.js+172−149
@@ -1,160 +1,183 @@
1+Elm.Native.Utils = {};
2+Elm.Native.Utils.make = function(elm) {
3+
4+ elm.Native = elm.Native || {};
5+ elm.Native.Utils = elm.Native.Utils || {};
6+ if (elm.Native.Utils.values) return elm.Native.Utils.values;
7+
8+ function eq(x,y) {
9+ if (x === y) return true;
10+ if (typeof x === "object") {
11+ var c = 0;
12+ for (var i in x) { ++c; if (!eq(x[i],y[i])) return false; }
13+ return c === Object.keys(y).length;
14+ }
15+ if (typeof x === 'function') {
16+ throw new Error('Equality error: general function equality is ' +
17+ 'undecidable, and therefore, unsupported');
18+ }
19+ return x === y;
20+ }
21+
22+ // code in Generate/JavaScript.hs depends on the particular
23+ // integer values assigned to LT, EQ, and GT
24+ var LT = -1, EQ = 0, GT = 1, ord = ['LT','EQ','GT'];
25+ function compare(x,y) { return { ctor: ord[cmp(x,y)+1] } }
26+ function cmp(x,y) {
27+ var ord;
28+ if (typeof x !== 'object') return x === y ? EQ : x < y ? LT : GT;
29+
30+ if (x.ctor === "::" || x.ctor === "[]") {
31+ while (true) {
32+ if (x.ctor === "[]" && y.ctor === "[]") return EQ;
33+ if (x.ctor !== y.ctor) return x.ctor === '[]' ? LT : GT;
34+ ord = cmp(x._0, y._0);
35+ if (ord !== EQ) return ord;
36+ x = x._1;
37+ y = y._1;
38+ }
39+ }
40+
41+ if (x.ctor.slice(0,6) === '_Tuple') {
42+ var n = x.ctor.slice(6) - 0;
43+ var err = 'cannot compare tuples with more than 6 elements.';
44+ if (n === 0) return EQ;
45+ if (n >= 1) { ord = cmp(x._0, y._0); if (ord !== EQ) return ord;
46+ if (n >= 2) { ord = cmp(x._1, y._1); if (ord !== EQ) return ord;
47+ if (n >= 3) { ord = cmp(x._2, y._2); if (ord !== EQ) return ord;
48+ if (n >= 4) { ord = cmp(x._3, y._3); if (ord !== EQ) return ord;
49+ if (n >= 5) { ord = cmp(x._4, y._4); if (ord !== EQ) return ord;
50+ if (n >= 6) { ord = cmp(x._5, y._5); if (ord !== EQ) return ord;
51+ if (n >= 7) throw new Error('Comparison error: ' + err); } } } } } }
52+ return EQ;
53+ }
54+ throw new Error('Comparison error: comparison is only defined on ints, ' +
55+ 'floats, times, chars, strings, lists of comparable values, ' +
56+ 'and tuples of comparable values.')
57+ }
158
2−Elm.Native.Utils = function(elm) {
3− 'use strict';
459
5− elm.Native = elm.Native || {};
6− if (elm.Native.Utils) return elm.Native.Utils;
60+ var Tuple0 = { ctor: "_Tuple0" };
61+ function Tuple2(x,y) { return { ctor:"_Tuple2", _0:x, _1:y } }
762
8− function eq(x,y) {
9− if (x === y) return true;
10− if (typeof x === "object") {
11− var c = 0;
12− for (var i in x) { ++c; if (!eq(x[i],y[i])) return false; }
13− return c === Object.keys(y).length;
63+ function chr(c) {
64+ var x = new String(c);
65+ x.isChar = true;
66+ return x;
1467 }
15− if (typeof x === 'function') {
16− throw new Error('Equality error: general function equality is ' +
17− 'undecidable, and therefore, unsupported');
68+
69+ function txt(str) {
70+ var t = new String(str);
71+ t.isText = true;
72+ return t;
1873 }
19− return x === y;
20− }
21−
22− // code in Generate/JavaScript.hs depends on the particular
23− // integer values assigned to LT, EQ, and GT
24− var LT = -1, EQ = 0, GT = 1, ord = ['LT','EQ','GT'];
25− function compare(x,y) { return { ctor: ord[cmp(x,y)+1] } }
26− function cmp(x,y) {
27− var ord;
28− if (typeof x !== 'object') return x === y ? EQ : x < y ? LT : GT;
29−
30− if (x.ctor === "::" || x.ctor === "[]") {
31− while (true) {
32− if (x.ctor === "[]" && y.ctor === "[]") return EQ;
33− if (x.ctor !== y.ctor) return x.ctor === '[]' ? LT : GT;
34− ord = cmp(x._0, y._0);
35− if (ord !== EQ) return ord;
36− x = x._1;
37− y = y._1;
38− }
74+
75+ var count = 0;
76+ function guid(_) { return count++ }
77+
78+ function copy(r) {
79+ var o = {};
80+ for (var i in r) { o[i] = r[i]; }
81+ return o;
3982 }
4083
41− if (x.ctor.slice(0,6) === '_Tuple') {
42− var n = x.ctor.slice(6) - 0;
43− var err = 'cannot compare tuples with more than 6 elements.';
44− if (n === 0) return EQ;
45− if (n >= 1) { ord = cmp(x._0, y._0); if (ord !== EQ) return ord;
46− if (n >= 2) { ord = cmp(x._1, y._1); if (ord !== EQ) return ord;
47− if (n >= 3) { ord = cmp(x._2, y._2); if (ord !== EQ) return ord;
48− if (n >= 4) { ord = cmp(x._3, y._3); if (ord !== EQ) return ord;
49− if (n >= 5) { ord = cmp(x._4, y._4); if (ord !== EQ) return ord;
50− if (n >= 6) { ord = cmp(x._5, y._5); if (ord !== EQ) return ord;
51− if (n >= 7) throw new Error('Comparison error: ' + err); } } } } } }
52− return EQ;
84+ function remove(x,r) {
85+ var o = copy(r);
86+ if (x in o._) {
87+ o[x] = o._[x][0];
88+ o._[x] = o._[x].slice(1);
89+ if (o._[x].length === 0) { delete o._[x]; }
90+ } else {
91+ delete o[x];
92+ }
93+ return o;
5394 }
54− throw new Error('Comparison error: comparison is only defined on ints, ' +
55− 'floats, times, chars, strings, lists of comparable values, ' +
56− 'and tuples of comparable values.')
57− }
58−
59−
60− var Tuple0 = { ctor: "_Tuple0" };
61− function Tuple2(x,y) { return { ctor:"_Tuple2", _0:x, _1:y } }
62−
63− var count = 0;
64− function guid(_) { return count++ }
65−
66− function copy(r) {
67− var o = {};
68− for (var i in r) { o[i] = r[i]; }
69− return o;
70− }
71−
72− function remove(x,r) {
73− var o = copy(r);
74− if (x in o._) {
75− o[x] = o._[x][0];
76− o._[x] = o._[x].slice(1);
77− if (o._[x].length === 0) { delete o._[x]; }
78− } else {
79− delete o[x];
95+
96+ function replace(kvs,r) {
97+ var o = copy(r);
98+ for (var i = kvs.length; i--; ) {
99+ var kvsi = kvs[i];
100+ o[kvsi[0]] = kvsi[1];
101+ }
102+ return o;
80103 }
81− return o;
82− }
83−
84− function replace(kvs,r) {
85− var o = copy(r);
86− for (var i = kvs.length; i--; ) {
87− var kvsi = kvs[i];
88− o[kvsi[0]] = kvsi[1];
104+
105+ function insert(x,v,r) {
106+ var o = copy(r);
107+ if (x in o) o._[x] = [o[x]].concat(x in o._ ? o._[x].slice(0) : []);
108+ o[x] = v;
109+ return o;
89110 }
90− return o;
91− }
92−
93− function insert(x,v,r) {
94− var o = copy(r);
95− if (x in o) o._[x] = [o[x]].concat(x in o._ ? o._[x].slice(0) : []);
96− o[x] = v;
97− return o;
98− }
99−
100− function max(a,b) { return a > b ? a : b }
101− function min(a,b) { return a < b ? a : b }
102−
103− function mod(a,b) {
104− var r = a % b;
105− var m = a === 0 ? 0 : (b > 0 ? (a >= 0 ? r : r+b) : -mod(-a,-b));
106−
107− return m === b ? 0 : m;
108− }
109−
110− function htmlHeight(width, html) {
111− var t = document.createElement('div');
112− t.innerHTML = html;
113− if (width > 0) { t.style.width = width + "px"; }
114− t.style.visibility = "hidden";
115− t.style.styleFloat = "left";
116− t.style.cssFloat = "left";
117−
118− elm.node.appendChild(t);
119− var style = window.getComputedStyle(t, null);
120− var w = Math.ceil(style.getPropertyValue("width").slice(0,-2) - 0);
121− var h = Math.ceil(style.getPropertyValue("height").slice(0,-2) - 0);
122− elm.node.removeChild(t);
123− return Tuple2(w,h);
124− }
125−
126− function adjustOffset() {
127− var node = elm.node;
128− var offsetX = 0, offsetY = 0;
129− if (node.offsetParent) {
130− do {
131− offsetX += node.offsetLeft;
132− offsetY += node.offsetTop;
133− } while (node = node.offsetParent);
134− }
135− elm.node.offsetX = offsetX;
136− elm.node.offsetY = offsetY;
137− }
138−
139− if (elm.display === ElmRuntime.Display.COMPONENT) {
140− elm.addListener(elm.inputs, elm.node, 'mouseover', adjustOffset);
141− }
142−
143− return elm.Native.Utils = {
144− eq:eq,
145− cmp:cmp,
146− compare:F2(compare),
147− Tuple0:Tuple0,
148− Tuple2:Tuple2,
149− copy: copy,
150− remove: remove,
151− replace: replace,
152− insert: insert,
153− guid: guid,
154− max : F2(max),
155− min : F2(min),
156− mod : F2(mod),
157− htmlHeight: F2(htmlHeight),
158− toFloat: function(x){return x}
159− };
111+
112+ function max(a,b) { return a > b ? a : b }
113+ function min(a,b) { return a < b ? a : b }
114+
115+ function mod(a,b) {
116+ if (b === 0) {
117+ throw new Error("Cannot perform mod 0. Division by zero error.");
118+ }
119+ var r = a % b;
120+ var m = a === 0 ? 0 : (b > 0 ? (a >= 0 ? r : r+b) : -mod(-a,-b));
121+
122+ return m === b ? 0 : m;
123+ }
124+
125+ function htmlHeight(width, html) {
126+ var t = document.createElement('div');
127+ t.innerHTML = html;
128+ if (width > 0) { t.style.width = width + "px"; }
129+ t.style.visibility = "hidden";
130+ t.style.styleFloat = "left";
131+ t.style.cssFloat = "left";
132+
133+ document.body.appendChild(t);
134+ var style = window.getComputedStyle(t, null);
135+ var w = Math.ceil(style.getPropertyValue("width").slice(0,-2) - 0);
136+ var h = Math.ceil(style.getPropertyValue("height").slice(0,-2) - 0);
137+ document.body.removeChild(t);
138+ return Tuple2(w,h);
139+ }
140+
141+ function getXY(e) {
142+ var posx = 0;
143+ var posy = 0;
144+ if (e.pageX || e.pageY) {
145+ posx = e.pageX;
146+ posy = e.pageY;
147+ } else if (e.clientX || e.clientY) {
148+ posx = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
149+ posy = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
150+ }
151+
152+ if (elm.display === ElmRuntime.Display.COMPONENT) {
153+ var rect = elm.node.getBoundingClientRect();
154+ var relx = rect.left + document.body.scrollLeft + document.documentElement.scrollLeft;
155+ var rely = rect.top + document.body.scrollTop + document.documentElement.scrollTop;
156+ // TODO: figure out if there is a way to avoid rounding here
157+ posx = posx - Math.round(relx) - elm.node.clientLeft;
158+ posy = posy - Math.round(rely) - elm.node.clientTop;
159+ }
160+ return Tuple2(posx, posy);
161+ }
162+
163+ return elm.Native.Utils.values = {
164+ eq:eq,
165+ cmp:cmp,
166+ compare:F2(compare),
167+ Tuple0:Tuple0,
168+ Tuple2:Tuple2,
169+ chr:chr,
170+ txt:txt,
171+ copy: copy,
172+ remove: remove,
173+ replace: replace,
174+ insert: insert,
175+ guid: guid,
176+ max : F2(max),
177+ min : F2(min),
178+ mod : F2(mod),
179+ htmlHeight: F2(htmlHeight),
180+ getXY: getXY,
181+ toFloat: function(x) { return +x; }
182+ };
160183};
libraries/Prelude.elm+1
@@ -1,4 +1,5 @@
11module Prelude where
2+{-| Everything that is automatically imported -}
23
34import Basics (String)
45import Maybe (Maybe)
libraries/Random.elm+21−7
@@ -1,16 +1,30 @@
1−
21module Random where
32
3+{-| Since the core of Elm is pure, randomness must be handled via signals.
4+
5+# Random Numbers
6+@docs range, float
7+-}
8+
49import Signal (Signal)
510import Native.Random
611
7−-- Given a range from low to high and a signal of values, this produces
8−-- a new signal that changes whenever the input signal changes. The new
9−-- values are random number between 'low' and 'high' inclusive.
12+{-| Given a range from low to high and a signal of values, this produces
13+a new signal that changes whenever the input signal changes. The new
14+values are random number between 'low' and 'high' inclusive.
15+-}
1016range : Int -> Int -> Signal a -> Signal Int
1117range = Native.Random.range
1218
13−-- Produces a new signal that changes whenever the input signal changes.
14−-- The new values are random numbers in [0..1).
19+{-| Produces a new signal that changes whenever the input signal changes.
20+The new values are random numbers in [0..1).
21+-}
1522float : Signal a -> Signal Float
16−float = Native.Random.float
23+float = Native.Random.float_
24+
25+{-| Produces a new signal of lists that changes whenever the input signal
26+changes. The input signal specifies the length of the random list. Each value is
27+a random number in [0..1).
28+-}
29+floatList : Signal Int -> Signal [Float]
30+floatList = Native.Random.floatList
libraries/Set.elm+38−14
@@ -6,61 +6,85 @@ module Set (empty,singleton,insert,remove
66 ,toList,fromList
77 ) where
88
9+{-| A set of unique values. The values can be any comparable type. This
10+includes `Int`, `Float`, `Time`, `Char`, `String`, and tuples or lists
11+of comparable types.
12+
13+Insert, remove, and query operations all take *O(log n)* time.
14+
15+# Build
16+@docs empty, singleton, insert, remove
17+
18+# Query
19+@docs member
20+
21+# Combine
22+@docs union, intersect, diff
23+
24+# Lists
25+@docs toList, fromList
26+
27+# Transform
28+@docs map, foldl, foldr
29+
30+-}
31+
932import Maybe (Maybe)
1033import Dict as Dict
1134import List as List
1235
1336type Set t = Dict.Dict t ()
1437
15−-- Create an empty set.
38+{-| Create an empty set. -}
1639empty : Set comparable
1740empty = Dict.empty
1841
19−-- Create a set with one value.
42+{-| Create a set with one value. -}
2043singleton : comparable -> Set comparable
2144singleton k = Dict.singleton k ()
2245
23−-- Insert a value into a set.
46+{-| Insert a value into a set. -}
2447insert : comparable -> Set comparable -> Set comparable
2548insert k = Dict.insert k ()
2649
27−-- Remove a value from a set. If the value is not found, no changes are made.
50+{-| Remove a value from a set. If the value is not found, no changes are made.
51+-}
2852remove : comparable -> Set comparable -> Set comparable
2953remove = Dict.remove
3054
31−-- Determine if a value is in a set.
55+{-| Determine if a value is in a set. -}
3256member : comparable -> Set comparable -> Bool
3357member = Dict.member
3458
35−-- Get the union of two sets. Keep all values.
59+{-| Get the union of two sets. Keep all values. -}
3660union : Set comparable -> Set comparable -> Set comparable
3761union = Dict.union
3862
39−-- Get the intersection of two sets. Keeps values that appear in both sets.
63+{-| Get the intersection of two sets. Keeps values that appear in both sets. -}
4064intersect : Set comparable -> Set comparable -> Set comparable
4165intersect = Dict.intersect
4266
43−-- Get the difference between the first set and the second. Keeps values
44−-- that do not appear in the second set.
67+{-| Get the difference between the first set and the second. Keeps values
68+that do not appear in the second set. -}
4569diff : Set comparable -> Set comparable -> Set comparable
4670diff = Dict.diff
4771
48−-- Convert a set into a list.
72+{-| Convert a set into a list. -}
4973toList : Set comparable -> [comparable]
5074toList = Dict.keys
5175
52−-- Convert a list into a set, removing any duplicates.
76+{-| Convert a list into a set, removing any duplicates. -}
5377fromList : [comparable] -> Set comparable
5478fromList xs = List.foldl insert empty xs
5579
56−-- Fold over the values in a set, in order from lowest to highest.
80+{-| Fold over the values in a set, in order from lowest to highest. -}
5781foldl : (comparable -> b -> b) -> b -> Set comparable -> b
5882foldl f b s = Dict.foldl (\k _ b -> f k b) b s
5983
60−-- Fold over the values in a set, in order from highest to lowest.
84+{-| Fold over the values in a set, in order from highest to lowest. -}
6185foldr : (comparable -> b -> b) -> b -> Set comparable -> b
6286foldr f b s = Dict.foldr (\k _ b -> f k b) b s
6387
64−-- Map a function onto a set, creating a new set with no duplicates.
88+{-| Map a function onto a set, creating a new set with no duplicates. -}
6589map : (comparable -> comparable') -> Set comparable -> Set comparable'
6690map f s = fromList (List.map f (toList s))
libraries/Signal.elm+84−59
@@ -1,32 +1,51 @@
1−
2−-- The library for general signal manipulation. Some useful functions for
3−-- working with time (e.g. setting FPS) and combining signals and time (e.g.
4−-- delaying updates, getting timestamps) can be found in the
5−-- [`Time`](/docs/Signal/Time.elm) library.
6−--
7−-- Note: There are lift functions up to `lift8`.
81module Signal where
2+{-| The library for general signal manipulation. Includes lift functions up to
3+`lift8` and infix lift operators `<~` and `~`, combinations, filters, and
4+past-dependence.
5+
6+Signals are time-varying values. Lifted functions are reevaluated whenver any of
7+their input signals has an event. Signal events may be of the same value as the
8+previous value of the signal. Such signals are useful for timing and
9+past-dependence.
10+
11+Some useful functions for working with time (e.g. setting FPS) and combining
12+signals and time (e.g. delaying updates, getting timestamps) can be found in
13+the [`Time`](/docs/Signal/Time.elm) library.
14+
15+# Combine
16+@docs constant, lift, lift2, merge, merges, combine
17+
18+# Pretty Lift
19+@docs (<~), (~)
20+
21+# Past-Dependence
22+@docs foldp, count, countIf
23+
24+#Filters
25+@docs keepIf, dropIf, keepWhen, dropWhen, dropRepeats, sampleOn
26+
27+# Do you even lift?
28+@docs lift3, lift4, lift5, lift6, lift7, lift8
29+
30+-}
931
1032import Native.Signal
1133import List (foldr)
1234
1335data Signal a = Signal
14−-- = Constant a
15−-- | Lift (a -> a) (Signal a)
1636
17−-- Create a constant signal that never changes.
37+{-| Create a constant signal that never changes. -}
1838constant : a -> Signal a
1939constant = Native.Signal.constant
2040
21−-- Transform a signal with a given function.
41+{-| Transform a signal with a given function. -}
2242lift : (a -> b) -> Signal a -> Signal b
2343lift = Native.Signal.lift
2444
25−-- Combine two signals with a given function.
45+{-| Combine two signals with a given function. -}
2646lift2 : (a -> b -> c) -> Signal a -> Signal b -> Signal c
2747lift2 = Native.Signal.lift2
2848
29−-- Combine three signals with a given function.
3049lift3 : (a -> b -> c -> d) -> Signal a -> Signal b -> Signal c -> Signal d
3150lift3 = Native.Signal.lift3
3251
@@ -49,25 +68,25 @@ lift8 : (a -> b -> c -> d -> e -> f -> g -> h -> i)
4968lift8 = Native.Signal.lift8
5069
5170
52−-- Create a past-dependent signal. Each value given on the input signal will
53−-- be accumulated, producing a new output value.
54−--
55−-- For instance, `(foldp (\\arrows number -> number + arrows.y) 0 Keyboard.arrows)`
56−-- increments or decrements the accumulated value (which starts at zero) when the up or down arrow keys are pressed.
71+{-| Create a past-dependent signal. Each value given on the input signal will
72+be accumulated, producing a new output value.
73+
74+For instance, `foldp (+) 0 (fps 40)` is the time the program has been running,
75+updated 40 times a second. -}
5776foldp : (a -> b -> b) -> b -> Signal a -> Signal b
5877foldp = Native.Signal.foldp
5978
60−-- Merge two signals into one, biased towards the first signal if both signals
61−-- update at the same time.
79+{-| Merge two signals into one, biased towards the first signal if both signals
80+update at the same time. -}
6281merge : Signal a -> Signal a -> Signal a
6382merge = Native.Signal.merge
6483
65−-- Merge many signals into one, biased towards the left-most signal if multiple
66−-- signals update simultaneously.
84+{-| Merge many signals into one, biased towards the left-most signal if multiple
85+signals update simultaneously. -}
6786merges : [Signal a] -> Signal a
6887merges = Native.Signal.merges
6988
70−-- Combine a list of signals into a signal of lists.
89+{-| Combine a list of signals into a signal of lists. -}
7190combine : [Signal a] -> Signal [a]
7291combine = foldr (Native.Signal.lift2 (::)) (Native.Signal.constant [])
7392
@@ -76,67 +95,73 @@ combine = foldr (Native.Signal.lift2 (::)) (Native.Signal.constant [])
7695 -- fold over non-homogeneous inputs.
7796 -- mergeEither : Signal a -> Signal b -> Signal (Either a b)
7897
79−-- Count the number of events that have occured.
98+{-| Count the number of events that have occured. -}
8099count : Signal a -> Signal Int
81100count = Native.Signal.count
82101
83−-- Count the number of events that have occured that satisfy a given predicate.
102+{-| Count the number of events that have occured that satisfy a given predicate.
103+-}
84104countIf : (a -> Bool) -> Signal a -> Signal Int
85105countIf = Native.Signal.countIf
86106
87−-- Keep only events that satisfy the given predicate. Elm does not allow
88−-- undefined signals, so a base case must be provided in case the predicate is
89−-- never satisfied.
107+{-| Keep only events that satisfy the given predicate. Elm does not allow
108+undefined signals, so a base case must be provided in case the predicate is
109+never satisfied. -}
90110keepIf : (a -> Bool) -> a -> Signal a -> Signal a
91111keepIf = Native.Signal.keepIf
92112
93−-- Drop events that satisfy the given predicate. Elm does not allow undefined
94−-- signals, so a base case must be provided in case the predicate is never
95−-- satisfied.
113+{-| Drop events that satisfy the given predicate. Elm does not allow undefined
114+signals, so a base case must be provided in case the predicate is never
115+satisfied. -}
96116dropIf : (a -> Bool) -> a -> Signal a -> Signal a
97117dropIf = Native.Signal.dropIf
98118
99−-- Keep events only when the first signal is true. When the first signal becomes
100−-- true, the most recent value of the second signal will be propagated. Until
101−-- the first signal becomes false again, all events will be propagated. Elm does
102−-- not allow undefined signals, so a base case must be provided in case the first
103−-- signal is never true.
119+{-| Keep events only when the first signal is true. When the first signal
120+becomes true, the most recent value of the second signal will be propagated.
121+Until the first signal becomes false again, all events will be propagated. Elm
122+does not allow undefined signals, so a base case must be provided in case the
123+first signal is never true. -}
104124keepWhen : Signal Bool -> a -> Signal a -> Signal a
105125keepWhen = Native.Signal.keepWhen
106126
107−-- Drop events when the first signal is true. When the first signal becomes false,
108−-- the most recent value of the second signal will be propagated. Until the first
109−-- signal becomes true again, all events will be propagated. Elm does not allow
110−-- undefined signals, so a base case must be provided in case the first signal is
111−-- always true.
127+{-| Drop events when the first signal is true. When the first signal becomes
128+false, the most recent value of the second signal will be propagated. Until the
129+first signal becomes true again, all events will be propagated. Elm does not
130+allow undefined signals, so a base case must be provided in case the first
131+signal is always true. -}
112132dropWhen : Signal Bool -> a -> Signal a -> Signal a
113133dropWhen = Native.Signal.dropWhen
114134
115−-- Drop sequential repeated values. For example, if a signal produces the
116−-- sequence `[1,1,2,2,1]`, it becomes `[1,2,1]` by dropping the values that
117−-- are the same as the previous value.
135+{-| Drop sequential repeated values. For example, if a signal produces the
136+sequence `[1,1,2,2,1]`, it becomes `[1,2,1]` by dropping the values that are the
137+same as the previous value. -}
118138dropRepeats : Signal a -> Signal a
119139dropRepeats = Native.Signal.dropRepeats
120140
121−-- Sample from the second input every time an event occurs on the first input.
122−-- For example, `(sampleOn clicks (every second))` will give the approximate
123−-- time of the latest click.
141+{-| Sample from the second input every time an event occurs on the first input.
142+For example, `(sampleOn clicks (every second))` will give the approximate time
143+of the latest click. -}
124144sampleOn : Signal a -> Signal b -> Signal b
125145sampleOn = Native.Signal.sampleOn
126146
127−-- An alias for `lift`. A prettier way to apply a
128−-- function to the current value of a signal.
129−--
130−-- lift f signal == f <~ signal
147+{-| An alias for `lift`. A prettier way to apply a function to the current value
148+of a signal. -}
131149(<~) : (a -> b) -> Signal a -> Signal b
132150f <~ s = Native.Signal.lift f s
133151
134−-- Signal application. This takes two signals, holding a function and
135−-- a value. It applies the current function to the current value.
136−--
137−-- So the following expressions are equivalent:
138−--
139−-- scene <~ Window.dimensions ~ Mouse.position
140−-- lift2 scene Window.dimensions Mouse.position
152+{-| Informally, an alias for `liftN`. Intersperse it between additional signal
153+arguments of the lifted function.
154+
155+Formally, signal application. This takes two signals, holding a function and
156+a value. It applies the current function to the current value.
157+
158+The following expressions are equivalent:
159+
160+ scene <~ Window.dimensions ~ Mouse.position
161+ lift2 scene Window.dimensions Mouse.position
162+-}
141163(~) : Signal (a -> b) -> Signal a -> Signal b
142−sf ~ s = Native.Signal.lift2 (\f x -> f x) sf s
164+sf ~ s = Native.Signal.lift2 (\f x -> f x) sf s
165+
166+infixl 4 <~
167+infixl 4 ~
libraries/String.elmnew file+274
@@ -0,0 +1,274 @@
1+module String where
2+{-| A built-in representation for efficient string manipulation. String literals
3+are enclosed in `"double quotes"`. Strings are *not* lists of characters.
4+
5+# Basics
6+@docs isEmpty, length, cons, uncons, reverse,
7+ map, filter, foldl, foldr, any, all, repeat
8+
9+# Split and Join
10+@docs split, join, words, lines
11+
12+# Get Substrings
13+@docs sub, left, right, dropLeft, dropRight
14+
15+# Check for Substrings
16+@docs contains, startsWith, endsWith, indexes, indices
17+
18+# Conversion To Numbers
19+@docs toInt, toFloat
20+
21+# Formatting
22+Cosmetic operations such as padding with extra characters or trimming whitespace.
23+
24+@docs toUpper, toLower,
25+ pad, padLeft, padRight,
26+ trim, trimLeft, trimRight
27+-}
28+
29+import Native.String
30+import Maybe (Maybe)
31+
32+{-| Check if a string is empty `(isEmpty "" == True)` -}
33+isEmpty : String
34+isEmpty = Native.String.isEmpty
35+
36+{-| Add a character to the beginning of a string -}
37+cons : Char -> String -> String
38+cons = Native.String.cons
39+
40+{-| Split a non-empty string into its head and tail. This lets you
41+pattern match on strings exactly as you would with lists.
42+
43+ uncons "abc" == Just ('a',"bc")
44+ uncons "" == Nothing
45+-}
46+uncons : String -> Maybe (Char, String)
47+uncons = Native.String.uncons
48+
49+{-| Get the length of a string `(length "innumerable" == 11)` -}
50+length : String -> Int
51+length = Native.String.length
52+
53+{-| Transform every character in a string
54+
55+ map (\c -> if c == '/' then '.' else c) "a/b/c" == "a.b.c"
56+-}
57+map : (Char -> Char) -> String -> String
58+map = Native.String.map
59+
60+{-| Keep only the characters that satisfy the predicate:
61+
62+ filter isDigit "R2-D2" == "22"
63+-}
64+filter : (Char -> Bool) -> String -> String
65+filter = Native.String.filter
66+
67+{-| Reverse a string. `(reverse "stressed" == "desserts")` -}
68+reverse : String -> String
69+reverse = Native.String.reverse
70+
71+{-|
72+-}
73+foldl : (Char -> b -> b) -> b -> String -> b
74+foldl = Native.String.foldl
75+
76+{-|
77+-}
78+foldr : (Char -> b -> b) -> b -> String -> b
79+foldr = Native.String.foldr
80+
81+{-| Split a string using a given separator.
82+
83+ split "," "cat,dog,cow" == ["cat","dog","cow"]
84+ split "/" "home/evan/Desktop/" == ["home","evan","Desktop"]
85+-}
86+split : String -> String -> [String]
87+split = Native.String.split
88+
89+{-| Put many strings together with a given separator.
90+
91+ join " " ["cat","dog","cow"] == "cat dog cow"
92+ join "/" ["home","evan","Desktop"] == "home/evan/Desktop"
93+-}
94+join : String -> [String] -> String
95+join = Native.String.join
96+
97+{-| Repeat a string N times `(repeat 3 "ha" == "hahaha")` -}
98+repeat : Int -> String -> String
99+repeat = Native.String.repeat
100+
101+{-| Take a substring given a start and end index. Negative indexes
102+are taken starting from the *end* of the list.
103+
104+ sub 7 9 "snakes on a plane!" == "on"
105+ sub 0 6 "snakes on a plane!" == "snakes"
106+ sub 0 -7 "snakes on a plane!" == "snakes on a"
107+ sub -6 -1 "snakes on a plane!" == "plane"
108+-}
109+sub : Int -> Int -> String -> String
110+sub = Native.String.sub
111+
112+{-| Take N characters from the left side of a string. -}
113+left : Int -> String -> String
114+left = Native.String.left
115+
116+{-| Take N characters from the right side of a string. -}
117+right : Int -> String -> String
118+right = Native.String.right
119+
120+{-| Drop N characters from the left side of a string. -}
121+dropLeft : Int -> String -> String
122+dropLeft = Native.String.dropLeft
123+
124+{-| Drop N characters from the right side of a string. -}
125+dropRight : Int -> String -> String
126+dropRight = Native.String.dropRight
127+
128+{-| Pad a string on both sides until it has a given length.
129+
130+ pad 5 ' ' "1" == " 1 "
131+ pad 5 ' ' "11" == " 11 "
132+ pad 5 ' ' "121" == " 121 "
133+-}
134+pad : Int -> Char -> String -> String
135+pad = Native.String.pad
136+
137+{-| Pad a string on the left until it has a given length.
138+
139+ pad 5 '.' "1" == "....1"
140+ pad 5 '.' "11" == "...11"
141+ pad 5 '.' "121" == "..121"
142+-}
143+padLeft : Int -> Char -> String -> String
144+padLeft = Native.String.padLeft
145+
146+{-| Pad a string on the right until it has a given length.
147+
148+ pad 5 '.' "1" == "1...."
149+ pad 5 '.' "11" == "11..."
150+ pad 5 '.' "121" == "121.."
151+-}
152+padRight : Int -> Char -> String -> String
153+padRight = Native.String.padRight
154+
155+{-| Get rid of whitespace on both sides of a string.
156+
157+ trim " hats \n" == "hats"
158+-}
159+trim : String -> String
160+trim = Native.String.trim
161+
162+{-| Get rid of whitespace on the left of a string.
163+
164+ trimLeft " hats \n" == "hats \n"
165+-}
166+trimLeft : String -> String
167+trimLeft = Native.String.trimLeft
168+
169+{-| Get rid of whitespace on the left of a string.
170+
171+ trimRight " hats \n" == " hats"
172+-}
173+trimRight : String -> String
174+trimRight = Native.String.trimRight
175+
176+{-| Break a string into words, splitting on chunks of whitespace.
177+
178+ words "How are \t you? \n Good?" == ["How","are","you?","Good?"]
179+-}
180+words : String -> [String]
181+words = Native.String.words
182+
183+{-| Break a string into lines, splitting on newlines.
184+
185+ lines "How are you?\nGood? == ["How are you?", "Good?"]
186+-}
187+lines : String -> [String]
188+lines = Native.String.lines
189+
190+{-| Convert a string to all upper case. Useful for case insensitive comparisons
191+and VIRTUAL YELLING.
192+-}
193+toUpper : String -> String
194+toUpper = Native.String.toUpper
195+
196+{-| Convert a string to all lower case. Useful for case insensitive comparisons. -}
197+toLower : String -> String
198+toLower = Native.String.toLower
199+
200+{-| Check to see if *any* characters satisfy a predicate.
201+
202+ any isDigit "90210" == True
203+ any isDigit "R2-D2" == True
204+ any isDigit "heart" == False
205+-}
206+any : (Char -> Bool) -> String -> Bool
207+any = Native.String.any
208+
209+{-| Check to see if *all* characters satisfy a predicate.
210+
211+ all isDigit "90210" == True
212+ all isDigit "R2-D2" == False
213+ any isDigit "heart" == False
214+-}
215+all : (Char -> Bool) -> String -> Bool
216+all = Native.String.all
217+
218+{-| See if a string contains another one.
219+
220+ contains "the" "theory" == True
221+ contains "hat" "theory" == False
222+ contains "THE" "theory" == False
223+-}
224+contains : String -> String -> Bool
225+contains = Native.String.contains
226+
227+{-| See if a string starts with another one.
228+
229+ startsWith "the" "theory" == True
230+ startsWith "ory" "theory" == False
231+-}
232+startsWith : String -> String -> Bool
233+startsWith = Native.String.startsWith
234+
235+{-| See if a string ends with another one.
236+
237+ endsWith "the" "theory" == False
238+ endsWith "ory" "theory" == True
239+-}
240+endsWith : String -> String -> Bool
241+endsWith = Native.String.endsWith
242+
243+{-| Get all of the indexes for a substring.
244+
245+ indexes "i" "Mississippi" == [1,4,7,10]
246+ indexes "ss" "Mississippi" == [2,5]
247+ indexes "needle" "haystack" == []
248+-}
249+indexes : String -> String -> [Int]
250+indexes = Native.String.indexes
251+
252+{-| Alias for `indexes` -}
253+indices : String -> String -> [Int]
254+indices = Native.String.indexes
255+
256+{-| Try to convert a string into an int, failing on improperly formatted strings.
257+
258+ toInt "123" == Just 123
259+ toInt "-42" == Just -42
260+ toInt "3.1" == Nothing
261+ toInt "31a" == Nothing
262+-}
263+toInt : String -> Maybe Int
264+toInt = Native.String.toInt
265+
266+{-| Try to convert a string into a float, failing on improperly formatted strings.
267+
268+ toFloat "123" == Just 123.0
269+ toFloat "-42" == Just -42.0
270+ toFloat "3.1" == Just 3.1
271+ toFloat "31a" == Nothing
272+-}
273+toFloat : String -> Maybe Float
274+toFloat = Native.String.toFloat
libraries/Text.elm+50−24
@@ -1,6 +1,22 @@
11
22module Text where
33
4+{-| Functions for displaying text
5+
6+# Creating Text
7+@docs toText
8+
9+# Creating Elements
10+@docs plainText, asText, text, centered, justified, righted
11+
12+# Formatting
13+@docs color, typeface, height, link
14+
15+# Simple Formatting
16+@docs monospace, header, bold, italic, underline, overline, strikeThrough
17+
18+-}
19+
420import open Basics
521import Color (Color)
622import Graphics.Element (Element, Three, Pos, ElementPrim, Properties)
@@ -10,80 +26,90 @@ import Native.Text
1026
1127data Text = Text
1228
13−-- Convert a string into text which can be styled and displayed.
29+{-| Convert a string into text which can be styled and displayed. -}
1430toText : String -> Text
1531toText = Native.Text.toText
1632
17−-- Set the typeface of some text. The first argument should be a comma separated listing of the desired typefaces
18−-- "helvetica, arial, sans-serif"
19−-- Works the same as the CSS font-family property.
33+{-| Set the typeface of some text. The first argument should be a comma
34+separated listing of the desired typefaces
35+
36+ "helvetica, arial, sans-serif"
37+
38+Works the same as the CSS font-family property.
39+-}
2040typeface : String -> Text -> Text
2141typeface = Native.Text.typeface
2242
23−-- Switch to a monospace typeface. Good for code snippets.
43+{-| Switch to a monospace typeface. Good for code snippets. -}
2444monospace : Text -> Text
2545monospace = Native.Text.monospace
2646
27−-- Make text big and noticable.
47+{-| Make text big and noticable. -}
2848header : Text -> Text
2949header = Native.Text.header
3050
31−-- Create a link.
51+{-| Create a link. -}
3252link : String -> Text -> Text
3353link = Native.Text.link
3454
35−-- Set the height of text in pixels.
55+{-| Set the height of text in pixels. -}
3656height : Float -> Text -> Text
3757height = Native.Text.height
3858
39−-- Set the color of a string.
59+{-| Set the color of a string. -}
4060color : Color -> Text -> Text
4161color = Native.Text.color
4262
43−-- Make a string bold.
63+{-| Make a string bold. -}
4464bold : Text -> Text
4565bold = Native.Text.bold
4666
47−-- Italicize a string.
67+{-| Italicize a string. -}
4868italic : Text -> Text
4969italic = Native.Text.italic
5070
51−-- Draw a line above a string.
71+{-| Draw a line above a string. -}
5272overline : Text -> Text
5373overline = Native.Text.overline
5474
55−-- Underline a string.
75+{-| Underline a string. -}
5676underline : Text -> Text
5777underline = Native.Text.underline
5878
59−-- Draw a line through a string.
79+{-| Draw a line through a string. -}
6080strikeThrough : Text -> Text
6181strikeThrough = Native.Text.strikeThrough
6282
63−-- Display justified, styled text.
83+{-| Display justified, styled text. -}
6484justified : Text -> Element
6585justified = Native.Text.justified
6686
67−-- Display centered, styled text.
87+{-| Display centered, styled text. -}
6888centered : Text -> Element
6989centered = Native.Text.centered
7090
71−-- Display right justified, styled text.
91+{-| Display right justified, styled text. -}
7292righted : Text -> Element
7393righted = Native.Text.righted
7494
75−-- Display styled text.
95+{-| Display styled text. -}
7696text : Text -> Element
7797text = Native.Text.text
7898
79−-- Display a plain string.
99+{-| Display a plain string. -}
80100plainText : String -> Element
81101plainText = Native.Text.plainText
82102
83−-- Convert anything to it's textual representation and make it displayable in browser
84−--
85−-- asText == text . monospace . show
86−--
87−-- Excellent for debugging.
103+{-| for internal use only -}
104+markdown : Element
105+markdown = Native.Text.markdown
106+
107+{-| Convert anything to it's textual representation and make it displayable in
108+browser
109+
110+ asText == text . monospace . show
111+
112+Excellent for debugging.
113+-}
88114asText : a -> Element
89115asText = Native.Text.asText
libraries/Time.elm+46−28
@@ -1,17 +1,31 @@
1−-- Library for working with time. Type `Time` represents some number of milliseconds.
21module Time where
32
3+{-| Library for working with time.
4+
5+# Units
6+@docs Time, millisecond, second, minute, hour,
7+ inMilliseconds, inSeconds, inMinutes, inHours
8+
9+# Tickers
10+@docs fps, fpsWhen, every
11+
12+# Timing
13+@docs timestamp, delay, since
14+
15+-}
16+
417import open Basics
518import Native.Time
619import Signal (Signal)
720
8−-- Type alias to make it clearer when you are working with time values.
9−-- Using the `Time` constants instead of raw numbers is very highly recommended.
21+{-| Type alias to make it clearer when you are working with time values.
22+Using the `Time` constants instead of raw numbers is very highly recommended.
23+-}
1024type Time = Float
1125
12−-- Units of time, making it easier to specify things like a
13−-- half-second `(500 * milliseconds)` without remembering Elm&rsquo;s
14−-- underlying units of time.
26+{-| Units of time, making it easier to specify things like a half-second
27+`(500 * milliseconds)` without remembering Elm&rsquo;s underlying units of time.
28+-}
1529millisecond : Time
1630millisecond = 1
1731
@@ -36,42 +50,46 @@ inMinutes t = t / minute
3650inHours : Time -> Float
3751inHours t = t / hour
3852
39−-- Takes desired number of frames per second (fps). The resulting signal
40−-- gives a sequence of time deltas as quickly as possible until it reaches
41−-- the desired FPS. A time delta is the time between the last frame and the
42−-- current frame.
53+{-| Takes desired number of frames per second (fps). The resulting signal
54+gives a sequence of time deltas as quickly as possible until it reaches
55+the desired FPS. A time delta is the time between the last frame and the
56+current frame.
57+-}
4358fps : number -> Signal Time
4459fps = Native.Time.fps
4560
46−-- Same as the fps function, but you can turn it on and off. Allows you
47−-- to do brief animations based on user input without major inefficiencies.
48−-- The first time delta after a pause is always zero, no matter how long
49−-- the pause was. This way summing the deltas will actually give the amount
50−-- of time that the output signal has been running.
61+{-| Same as the fps function, but you can turn it on and off. Allows you
62+to do brief animations based on user input without major inefficiencies.
63+The first time delta after a pause is always zero, no matter how long
64+the pause was. This way summing the deltas will actually give the amount
65+of time that the output signal has been running.
66+-}
5167fpsWhen : number -> Signal Bool -> Signal Time
5268fpsWhen = Native.Time.fpsWhen
5369
54−-- Takes a time interval t. The resulting signal is the current time,
55−-- updated every t.
70+{-| Takes a time interval t. The resulting signal is the current time, updated
71+every t.
72+-}
5673every : Time -> Signal Time
5774every = Native.Time.every
5875
59−-- Takes a time `t` and any signal. The resulting boolean signal
60−-- is true for time `t` after every event on the input signal.
61−-- So ``(second `since` Mouse.clicks)`` would result in a signal
62−-- that is true for one second after each mouse click and false
63−-- otherwise.
76+{-| Takes a time `t` and any signal. The resulting boolean signal is true for
77+time `t` after every event on the input signal. So ``(second `since`
78+Mouse.clicks)`` would result in a signal that is true for one second after
79+each mouse click and false otherwise.
80+-}
6481since : Time -> Signal a -> Signal Bool
6582since = Native.Time.since
6683
67−-- Add a timestamp to any signal. Timestamps increase monotonically. Each
68−-- timestamp is related to a specfic event, so `Mouse.x` and `Mouse.y` will
69−-- always have the same timestamp because they both rely on the same
70−-- underlying event.
84+{-| Add a timestamp to any signal. Timestamps increase monotonically. Each
85+timestamp is related to a specfic event, so `Mouse.x` and `Mouse.y` will always
86+have the same timestamp because they both rely on the same underlying event.
87+-}
7188timestamp : Signal a -> Signal (Time, a)
7289timestamp = Native.Time.timestamp
7390
74−-- Delay a signal by a certain amount of time. So `(delay second Mouse.clicks)`
75−-- will update one second later than any mouse click.
91+{-| Delay a signal by a certain amount of time. So `(delay second Mouse.clicks)`
92+will update one second later than any mouse click.
93+-}
7694delay : Time -> Signal a -> Signal a
7795delay = Native.Time.delay
libraries/Touch.elm+22−12
@@ -1,24 +1,34 @@
1−-- This is an early version of the touch library. It will likely grow to
2−-- include gestures that would be useful for both games and web-pages.
31module Touch where
42
3+{-| This is an early version of the touch library. It will likely grow to
4+include gestures that would be useful for both games and web-pages.
5+
6+# Touches
7+@docs Touch, touches
8+
9+# Gestures
10+@docs taps
11+-}
12+
513import Signal (Signal)
614import Native.Touch
715import Time (Time)
816
9−-- Every `Touch` has `xy` coordinates. It also has an identifier `id` to
10−-- distinguish one touch from another.
11−--
12−-- A touch also keeps info about the intial point and time of contact:
13−-- `x0`, `y0`, and `t0`. This helps compute more complicated gestures
14−-- like taps, drags, and swipes which need to know about timing or direction.
17+{-| Every `Touch` has `xy` coordinates. It also has an identifier
18+`id` to distinguish one touch from another.
19+
20+A touch also keeps info about the initial point and time of contact:
21+`x0`, `y0`, and `t0`. This helps compute more complicated gestures
22+like taps, drags, and swipes which need to know about timing or direction.
23+-}
1524type Touch = { x:Int, y:Int, id:Int, x0:Int, y0:Int, t0:Time }
1625
17−-- A list of ongoing touches.
26+{-| A list of ongoing touches. -}
1827touches : Signal [Touch]
1928touches = Native.Touch.touches
2029
21−-- The last position that was tapped. Default value is `{x=0,y=0}`.
22−-- Updates whenever the user taps the screen.
30+{-| The last position that was tapped. Default value is `{x=0,y=0}`.
31+Updates whenever the user taps the screen.
32+-}
2333taps : Signal { x:Int, y:Int }
24−taps = Native.Touch.taps
34+taps = Native.Touch.taps
libraries/Transform2D.elm+40−27
@@ -1,44 +1,57 @@
1−
21module Transform2D where
2+{-| A library for performing [2D matrix transformations](http://en.wikipedia.org/wiki/Transformation_matrix#Affine_transformations).
3+It is used primarily with the `groupTransform` function from `Graphics.Collage` and
4+allows you to do things like rotation, scaling, translation, shearing, and reflection.
5+
6+# Basic Transforms
7+@docs identity, matrix, rotation
8+
9+# Multiplication
10+@docs multiply
11+-}
312
413import Native.Transform2D
514
615data Transform2D = Transform2D
716
8−-- Create an identity transform. Transforming by the identity does
9−-- not change anything, but it can come in handy as a default or
10−-- base case.
11−--
12−-- / 1 0 \\
13−-- \\ 0 1 /
17+{-| Create an identity transform. Transforming by the identity does
18+not change anything, but it can come in handy as a default or
19+base case.
20+
21+ / 1 0 \
22+ \ 0 1 /
23+-}
1424identity : Transform2D
1525identity = Native.Transform2D.identity
1626
17−-- Creates an arbitrary transformation matrix. This lets you create scales,
18−-- shears, reflections, translations, or any other 2D transform.
19−--
20−-- matrix a b c d dx dy
21−--
22−-- / a b \\
23−-- \\ c d /
24−--
25−-- And `dx` and `dy` are the translation values.
27+{-| Creates a transformation matrix. This lets you create transforms
28+such as scales, shears, reflections, and translations.
29+
30+ matrix a b c d dx dy
31+
32+ / a b \
33+ \ c d /
34+
35+And `dx` and `dy` are the translation values.
36+-}
2637matrix : Float -> Float -> Float -> Float -> Float -> Float -> Transform2D
2738matrix = Native.Transform2D.matrix
2839
29−-- Creates a [rotation matrix](http://en.wikipedia.org/wiki/Rotation_matrix).
30−-- Given an angle t, it creates a counterclockwise rotation matrix:
31−--
32−-- / cos t -sin t \\
33−-- \\ sin t cos t /
40+{-| Creates a [rotation matrix](http://en.wikipedia.org/wiki/Rotation_matrix).
41+Given an angle t, it creates a counterclockwise rotation matrix:
42+
43+ / cos t -sin t \
44+ \ sin t cos t /
45+-}
3446rotation : Float -> Transform2D
3547rotation = Native.Transform2D.rotation
3648
37−-- Multiplies two transforms together:
38−--
39−-- multiply a b
40−--
41−-- / a11 a12 \\ . / b11 b12 \\
42−-- \\ a21 a22 / \\ b21 b22 /
49+{-| Multiplies two transforms together:
50+
51+ multiply a b
52+
53+ / a11 a12 \ . / b11 b12 \
54+ \ a21 a22 / \ b21 b22 /
55+-}
4356multiply : Transform2D -> Transform2D -> Transform2D
4457multiply = Native.Transform2D.multiply
libraries/WebSocket.elm+11−5
@@ -1,14 +1,20 @@
1−-- A library for low latency HTTP communication. See the HTTP library for
2−-- standard requests like GET, POST, etc.
31module WebSocket where
2+{-| A library for low latency HTTP communication. See the HTTP library for
3+standard requests like GET, POST, etc. The API of this library is likely to
4+change to make it more flexible.
5+
6+# Open a Connection
7+@docs connect
8+-}
49
510import Signal (Signal)
611import Basics (String)
712import Native.WebSocket
813
9−-- Create a web-socket. The first argument is the URL of the desired
10−-- web-socket server. The input signal holds the outgoing messages,
11−-- and the resulting signal contains the incoming ones.
14+{-| Create a web-socket. The first argument is the URL of the desired
15+web-socket server. The input signal holds the outgoing messages,
16+and the resulting signal contains the incoming ones.
17+-}
1218connect : String -> Signal String -> Signal String
1319connect = Native.WebSocket.connect
1420
libraries/Window.elm+13−4
@@ -1,18 +1,27 @@
11
22module Window where
33
4+{-| Provides information about the container that your Elm program lives in.
5+When you embed Elm in a `<div>` it gives the dimensions of the container, not
6+the whole window.
7+
8+# Dimensions
9+@docs dimensions, width, height
10+
11+-}
12+
413import Signal (Signal)
514import Native.Window
615
7−-- The current dimensions of the window (i.e. the area viewable to the
8−-- user, not including scroll bars).
16+{-| The current width and height of the window (i.e. the area viewable to the
17+user, not including scroll bars). -}
918dimensions : Signal (Int,Int)
1019dimensions = Native.Window.dimensions
1120
12−-- The current width of the window.
21+{-| The current width of the window. -}
1322width : Signal Int
1423width = Native.Window.width
1524
16−-- The current height of the window.
25+{-| The current height of the window. -}
1726height : Signal Int
1827height = Native.Window.height
runtime/Init.js+6−9
@@ -13,7 +13,7 @@ Elm.fullscreen = function(module) {
1313 return init(ElmRuntime.Display.FULLSCREEN, container, module);
1414};
1515
16−Elm.domNode = function(container, module) {
16+Elm.embed = function(module, container) {
1717 var tag = container.tagName;
1818 if (tag !== 'DIV') {
1919 throw new Error('Elm.node must be given a DIV, not a ' + tag + '.');
@@ -41,9 +41,6 @@ function init(display, container, module, moduleToReplace) {
4141 return changed;
4242 }
4343
44− container.offsetX = 0;
45− container.offsetY = 0;
46−
4744 var listeners = [];
4845 function addListener(relevantInputs, domNode, eventName, func) {
4946 domNode.addEventListener(eventName, func);
@@ -99,10 +96,10 @@ function init(display, container, module, moduleToReplace) {
9996 var Module = {};
10097 var reportAnyErrors = function() {};
10198 try {
102− Module = module(elm);
99+ Module = module.make(elm);
103100 } catch(e) {
104101 var directions = "<br/>&nbsp; &nbsp; Open the developer console for more details."
105− Module.main = Elm.Text(elm).text('<code>' + e.message + directions + '</code>');
102+ Module.main = Elm.Text.make(elm).text('<code>' + e.message + directions + '</code>');
106103 reportAnyErrors = function() { throw e; }
107104 }
108105 inputs = ElmRuntime.filterDeadInputs(inputs);
@@ -150,7 +147,7 @@ function initGraphics(elm, Module) {
150147 var signalGraph = Module.main;
151148
152149 // make sure the signal graph is actually a signal & extract the visual model
153− var Signal = Elm.Signal(elm);
150+ var Signal = Elm.Signal.make(elm);
154151 if (!('recv' in signalGraph)) {
155152 signalGraph = Signal.constant(signalGraph);
156153 }
@@ -164,7 +161,7 @@ function initGraphics(elm, Module) {
164161 function domUpdate(newScene, currentScene) {
165162 ElmRuntime.draw(function(_) {
166163 Render.update(elm.node.firstChild, currentScene, newScene);
167− if (elm.Native.Window) elm.Native.Window.resizeIfNeeded();
164+ if (elm.Native.Window) elm.Native.Window.values.resizeIfNeeded();
168165 });
169166 return newScene;
170167 }
@@ -172,7 +169,7 @@ function initGraphics(elm, Module) {
172169
173170 // must check for resize after 'renderer' is created so
174171 // that changes show up.
175− if (elm.Native.Window) elm.Native.Window.resizeIfNeeded();
172+ if (elm.Native.Window) elm.Native.Window.values.resizeIfNeeded();
176173
177174 return renderer;
178175}
runtime/Render/Collage.js+9−5
@@ -1,9 +1,8 @@
11
22ElmRuntime.Render.Collage = function() {
3−'use strict';
43
54var Render = ElmRuntime.use(ElmRuntime.Render.Element);
6−var Transform = Elm.Transform2D({});
5+var Transform = Elm.Transform2D.make({});
76var Utils = ElmRuntime.use(ElmRuntime.Render.Utils);
87var newElement = Utils.newElement,
98 extract = Utils.extract, fromList = Utils.fromList,
@@ -167,6 +166,11 @@ function formToMatrix(form) {
167166 return matrix;
168167}
169168
169+function str(n) {
170+ if (n < 0.00001 && n > -0.00001) return 0;
171+ return n;
172+}
173+
170174function makeTransform(w, h, form, matrices) {
171175 var props = form.form._0.props;
172176 var m = A6( Transform.matrix, 1, 0, 0, 1,
@@ -176,9 +180,9 @@ function makeTransform(w, h, form, matrices) {
176180 for (var i = 0; i < len; ++i) { m = A2( Transform.multiply, m, matrices[i] ); }
177181 m = A2( Transform.multiply, m, formToMatrix(form) );
178182
179− return 'matrix(' + m[0] + ',' + m[3] + ',' +
180− (-m[1]) + ',' + (-m[4]) + ',' +
181− m[2] + ',' + m[5] + ')';
183+ return 'matrix(' + str( m[0]) + ',' + str( m[3]) + ',' +
184+ str(-m[1]) + ',' + str(-m[4]) + ',' +
185+ str( m[2]) + ',' + str( m[5]) + ')';
182186}
183187
184188function stepperHelp(list) {
runtime/Render/Element.js+8−16
@@ -124,19 +124,21 @@ function toPos(pos) {
124124 }
125125}
126126
127+// must clear right, left, top, bottom, and transform
128+// before calling this function
127129function setPos(pos,w,h,e) {
128130 e.style.position = 'absolute';
129131 e.style.margin = 'auto';
130132 var transform = '';
131133 switch(pos.horizontal.ctor) {
132− case 'P': e.style.right = toPos(pos.x); break;
134+ case 'P': e.style.right = toPos(pos.x); e.style.removeProperty('left'); break;
133135 case 'Z': transform = 'translateX(' + ((-w/2)|0) + 'px) ';
134− case 'N': e.style.left = toPos(pos.x); break;
136+ case 'N': e.style.left = toPos(pos.x); e.style.removeProperty('right'); break;
135137 }
136138 switch(pos.vertical.ctor) {
137− case 'N': e.style.bottom = toPos(pos.y); break;
139+ case 'N': e.style.bottom = toPos(pos.y); e.style.removeProperty('top'); break;
138140 case 'Z': transform += 'translateY(' + ((-h/2)|0) + 'px)';
139− case 'P': e.style.top = toPos(pos.y); break;
141+ case 'P': e.style.top = toPos(pos.y); e.style.removeProperty('bottom'); break;
140142 }
141143 if (transform !== '') addTransform(e.style, transform);
142144 return e;
@@ -220,18 +222,8 @@ function update(node, curr, next) {
220222 }
221223 break;
222224 case "Container":
223− var inner = node.firstChild;
224− if (!update(inner, currE._1, nextE._1)) {
225− if (nextE._0.horizontal.ctor !== currE._0.horizontal.ctor) {
226− inner.style.left = inner.style.right = 'none';
227− removeTransform(inner.style);
228− }
229− if (nextE._0.vertical.ctor !== currE._0.vertical.ctor) {
230− inner.style.top = inner.style.bottom = 'none';
231− removeTransform(inner.style);
232− }
233− }
234− setPos(nextE._0, nextE._1.props.width, nextE._1.props.height, inner);
225+ update(node.firstChild, currE._1, nextE._1)
226+ setPos(nextE._0, nextE._1.props.width, nextE._1.props.height, node.firstChild);
235227 break;
236228 case "Custom":
237229 if (currE.type === nextE.type) {
runtime/Render/Utils.js+2−3
@@ -1,6 +1,5 @@
11
22ElmRuntime.Render.Utils = function() {
3−'use strict';
43
54function newElement(elementType) {
65 var e = document.createElement(elementType);
@@ -34,7 +33,7 @@ function removeTransform(style) {
3433 style.OTransform = 'none';
3534}
3635
37−var List = Elm.Native.List({});
36+var List = Elm.Native.List.make({});
3837
3938return {addTo:addTo,
4039 newElement:newElement,
@@ -42,7 +41,7 @@ return {addTo:addTo,
4241 fromList: List.toArray,
4342 fromString: function(s) { return List.toArray(s).join(''); },
4443 toString: List.fromArray,
45− eq: Elm.Native.Utils({}).eq,
44+ eq: Elm.Native.Utils.make({}).eq,
4645 addTransform: addTransform,
4746 removeTransform: removeTransform
4847 };
server/LICENSE+1−1
@@ -1,4 +1,4 @@
1−Copyright (c)2012, Evan Czaplicki
1+Copyright (c)2012-2013, Evan Czaplicki
22
33All rights reserved.
44
server/Server.hs+30−13
@@ -1,7 +1,6 @@
1−
21module Main where
32
4−import Control.Monad (msum,guard)
3+import Control.Monad (msum,guard,when)
54import Control.Monad.Trans (MonadIO(liftIO))
65import Data.List (isPrefixOf, isSuffixOf, (\\))
76import Data.Version (showVersion)
@@ -34,24 +33,37 @@ serve portNumber libLoc = do
3433pageTitle :: String -> String
3534pageTitle = dropExtension . takeBaseName
3635
36+defaultCacheDirectory = "elm-server-cache"
37+
3738serveElm :: FilePath -> ServerPartT IO Response
3839serveElm fp = do
39− guard (takeExtension fp == ".elm")
40− let file = tail fp
41− args = [ "--make" ,"--runtime=" ++ runtime, "--cache-dir=elm-server-cache", file ]
42− (_, stdout, _, handle) <- liftIO $ createProcess $ (proc "elm" args) { std_out = CreatePipe }
40+ fileExists <- liftIO $ doesFileExist file
41+ guard $ fileExists && takeExtension fp == ".elm"
42+
43+ (_, stdout, _, handle) <- liftIO $ createProcess $
44+ (proc "elm" args) { std_out = CreatePipe }
4345 exitCode <- liftIO $ waitForProcess handle
44− liftIO $ removeDirectoryRecursive "elm-server-cache"
46+
47+ dirExists <- liftIO $ doesDirectoryExist defaultCacheDirectory
48+ when dirExists $ liftIO $ removeDirectoryRecursive defaultCacheDirectory
49+
4550 case (exitCode, stdout) of
51+ (ExitFailure 127, _) ->
52+ badRequest $ toResponse "Error: elm binary not found in your path."
4653 (ExitFailure _, Just out) ->
4754 do str <- liftIO $ hGetContents out
4855 badRequest $ toResponse str
4956 (ExitFailure _, Nothing) ->
5057 badRequest $ toResponse "See command line for error message."
5158 (ExitSuccess, _) ->
52− serveFile (asContentType "text/html") ("build" </> replaceExtension file "html")
59+ serveFile
60+ (asContentType "text/html") ("build" </> replaceExtension file "html")
61+
62+ where file = tail fp
63+ args = [ "--make" ,"--runtime=" ++ runtime,
64+ "--cache-dir=" ++ defaultCacheDirectory, file ]
5365
54−serveLib :: FilePath -> [Char] -> ServerPartT IO Response
66+serveLib :: FilePath -> String -> ServerPartT IO Response
5567serveLib libLoc fp = do
5668 guard (fp == runtime)
5769 serveFile (asContentType "application/javascript") libLoc
@@ -63,9 +75,11 @@ parse :: [String] -> IO ()
6375parse ("--help":_) = putStrLn usage
6476parse ("--version":_) = putStrLn ("The Elm Server " ++ showVersion version)
6577parse args =
66− case null remainingArgs of
67− True -> serve portNumber =<< elmRuntime
68− False -> putStrLn usageMini
78+ if null remainingArgs then
79+ serve portNumber =<< elmRuntime
80+ else
81+ putStrLn usageMini
82+
6983 where
7084 runtimeArg = filter (isPrefixOf "--runtime-location=") args
7185 portArg = filter (isPrefixOf "--port=") args
@@ -73,7 +87,10 @@ parse args =
7387
7488 argValue arg = tail $ dropWhile (/= '=') (head arg)
7589 portNumber = if null portArg then 8000 else read (argValue portArg) :: Int
76− elmRuntime = if null runtimeArg then Elm.runtime else return $ argValue runtimeArg
90+ elmRuntime = if null runtimeArg then
91+ Elm.runtime
92+ else
93+ return $ argValue runtimeArg
7794
7895usageMini :: String
7996usageMini =
server/elm-server.cabal+1−1
@@ -10,7 +10,7 @@ License-file: LICENSE
1010
1111Author: Evan Czaplicki
1212Maintainer: info@elm-lang.org
13−Copyright: Copyright: (c) 2011-2012 Evan Czaplicki
13+Copyright: Copyright: (c) 2011-2013 Evan Czaplicki
1414
1515Category: Compiler, Language
1616