2{-# LANGUAGE OverloadedStrings, DeriveDataTypeable #-}
5import System.Console.CmdArgs
11import Control.Applicative ((<$>))
12import Control.Arrow (second)
14import Data.Aeson.Encode.Pretty
15import qualified Data.List as List
16import qualified Data.Map as Map
17import qualified Data.ByteString.Lazy as BS
18import qualified Data.Text as Text
20import qualified AST.Helpers as Help
21import qualified AST.Type as T
22import qualified AST.Declaration as D
23import qualified AST.Expression.Source as Src
24import qualified AST.Variable as Var
26import Text.Parsec hiding (newline,spaces)
27import Parse.Declaration (alias,datatype,infixDecl)
28import Parse.Expression (typeAnnotation)
30import Parse.Module (moduleDef)
33 { files :: [FilePath] }
34 deriving (Data,Typeable,Show,Eq)
38 { files = def &= args &= typ "FILES"
39 } &= help "Generate documentation for Elm"
40 &= summary ("Generate documentation for Elm, (c) Evan Czaplicki")
44 flags <- cmdArgs defaultFlags
45 mapM_ parseFile (files flags)
48config = Config { confIndent = 2, confCompare = keyOrder keys }
50 keys = ["tag","name","document","comment","raw","aliases","datatypes"
51 ,"values","typeVariables","type","constructors"]
53parseFile :: FilePath -> IO ()
55 source <- readFile path
56 case iParse docs source of
58 putStrLn $ "Documenting " ++ path
59 let docPath = "docs" </> replaceExtension path ".json"
60 createDirectoryIfMissing True (dropFileName docPath)
61 BS.writeFile docPath (encodePretty' config json)
63 hPutStrLn stderr $ "Parse error in " ++ path ++ " at " ++ show err
68 (name, exports, structure) <- moduleDocs
70 return $ documentToJson name exports structure things
72docComment :: IParser String
75 contents <- closeComment
76 let reversed = dropWhile (`elem` " \n\r") . drop 2 $ reverse contents
77 return $ dropWhile (==' ') (reverse reversed)
79--moduleDocs :: IParser (String, [String], String)
82 (names,exports) <- moduleDef
83 manyTill (string " " <|> newline <?> "more whitespace")
84 (lookAhead (string "{-|") <?> "module documentation comment")
85 structure <- docComment
86 return (List.intercalate "." names, exports, structure)
88--document :: IParser [(String, D.SourceDecl, String)]
89document = onFreshLines (\t ts -> ts ++ [t]) [] docThing
91--docThing :: IParser (String, D.SourceDecl, String)
92docThing = uncommentable <|> commented <|> uncommented ""
103 uncommented comment = do
104 (src,def) <- withSource $ choice [ alias, datatype, D.Definition <$> typeAnnotation ]
105 return (comment, def, src)
108documentToJson name exports structure things =
109 object $ [ "name" .= name
110 , "document" .= structure
111-- , "values" .= toList values
112-- , "aliases" .= toList aliases
113-- , "datatypes" .= toList adts
117 (values, aliases, adts) = collect Map.empty Map.empty Map.empty Map.empty things
119 toList dict = map object . Map.elems $ filterPublics dict
121 exportMap = Map.fromList (zip exports exports)
123 case Map.null exportMap of
125 False -> Map.filterWithKey (\k _ -> Map.member k exportMap) dict
128collect infixes types aliases adts things =
130 [] -> (Map.union customOps nonCustomOps, aliases, adts)
132 nonCustomOps = Map.mapWithKey addDefaultInfix $ Map.difference types infixes
133 addDefaultInfix name pairs
134 | all Help.isSymbol name = addInfix (D.L, 9 :: Int) pairs
137 customOps = Map.intersectionWith addInfix infixes types
138 addInfix (assoc,prec) pairs =
139 [ "associativity" .= show assoc, "precedence" .= prec ] ++ pairs
141 (comment, decl, source) : rest ->
143 D.Fixity assoc prec name ->
144 collect (Map.insert name (assoc,prec) infixes) types aliases adts rest
145 D.Definition (Src.TypeAnnotation name tipe) ->
146 collect infixes (insert name [ "type" .= tipe ] types) aliases adts rest
147 D.TypeAlias name vars tipe ->
148 let fields = ["typeVariables" .= vars, "type" .= tipe ]
149 in collect infixes types (insert name fields aliases) adts rest
150 D.Datatype name vars ctors ->
151 let tipe = T.App (T.Type name) (map T.Var vars)
152 fields = ["typeVariables" .= vars
153 , "constructors" .= map (ctorToJson tipe) ctors ]
154 in collect infixes types aliases (insert name fields adts) rest
156 insert name fields dict = Map.insert name (obj name fields) dict
158 [ "name" .= name, "raw" .= source, "comment" .= comment ] ++ fields
160instance Var.ToString var => ToJSON (T.Type var) where
165 let tipes = T.collectLambdas tipe in
166 [ "tag" .= ("function" :: Text.Text)
167 , "args" .= toJSON (init tipes)
168 , "result" .= toJSON (last tipes)
172 [ "tag" .= ("var" :: Text.Text)
177 [ "tag" .= ("adt" :: Text.Text)
178 , "name" .= toJSON (Var.toString name)
179 , "args" .= ([] :: [()])
182 T.App (T.Type name) ts ->
183 [ "tag" .= ("adt" :: Text.Text)
184 , "name" .= toJSON (Var.toString name)
185 , "args" .= map toJSON ts
188 T.Record fields ext ->
189 [ "tag" .= ("record" :: Text.Text)
190 , "fields" .= toJSON (map (toJSON . second toJSON) fields)
191 , "extension" .= toJSON ext
194ctorToJson :: Var.ToString var => T.Type var -> (String, [T.Type var]) -> Value
195ctorToJson tipe (ctor, tipes) =
196 object [ "name" .= ctor
197 , "type" .= foldr T.Lambda tipe tipes ]
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list