1module Reporting.Render.Type
11import Control.Arrow ((***), first)
12import qualified Data.Map as Map
13import qualified Data.Set as Set
14import Text.PrettyPrint.ANSI.Leijen
15 ( Doc, (<+>), cat, colon, comma, dullyellow, equals, hang, hsep
16 , lbrace, lparen, parens, rbrace, rparen, sep, text, vcat
19import qualified AST.Helpers as Help
20import qualified AST.Type as Type
21import qualified AST.Variable as Var
22import qualified Reporting.Error.Helpers as Help
26-- PUBLIC API FOR CREATING DOCS
29toDoc :: Localizer -> Type.Canonical -> Doc
31 docType localizer None tipe
34diffToDocs :: Localizer -> Type.Canonical -> Type.Canonical -> (Doc,Doc)
35diffToDocs localizer leftType rightType =
36 case diff localizer None leftType rightType of
40 Diff leftDoc rightDoc ->
44decl :: Localizer -> String -> [String] -> [(String, [Type.Canonical])] -> Doc
45decl localizer name vars tags =
48 hang 2 (sep (text tag : map (docType localizer App) args))
51 (hsep (map text ("type" : name : vars)))
54 (equals : repeat (text "|"))
58annotation :: Localizer -> String -> Type.Canonical -> Doc
59annotation localizer name tipe =
62 if Help.isOp name then parens (text name) else text name
64 case Type.collectLambdas tipe of
69 (colon : repeat (text "->"))
70 (map (docType localizer Func) parts)
75 , docType localizer None tipe
87varToDoc :: Localizer -> Var.Canonical -> Doc
88varToDoc localizer var =
93 if name == "_Tuple0" then
97 text (maybe name id (Map.lookup name localizer))
109instance Functor Diff where
113 Diff (func left) (func right)
119instance Applicative Diff where
125 (Diff leftFunc rightFunc, Diff leftArg rightArg) ->
126 Diff (leftFunc leftArg) (rightFunc rightArg)
128 (Diff leftFunc rightFunc, Same arg) ->
129 Diff (leftFunc arg) (rightFunc arg)
131 (Same func, Diff leftArg rightArg) ->
132 Diff (func leftArg) (func rightArg)
134 (Same func, Same arg) ->
138partitionDiffs :: Map.Map k (Diff a) -> ( [(k, (a,a))], [(k, a)] )
141 collect key value (diffKeys, sameKeys) =
144 ( (key, (left, right)) : diffKeys
150 , (key, both) : sameKeys
153 Map.foldrWithKey collect ([],[]) dict
166diff :: Localizer -> Context -> Type.Canonical -> Type.Canonical -> Diff Doc
167diff localizer context leftType rightType =
171 case (leftType, rightType) of
172 (Type.Lambda _ _, Type.Lambda _ _) ->
174 leftParts = Type.collectLambdas leftType
175 rightParts = Type.collectLambdas rightType
178 if length leftParts /= length rightParts then
180 (docLambda context (map (docType localizer Func) leftParts))
181 (docLambda context (map (docType localizer Func) rightParts))
184 docLambda context <$> sequenceA (zipWith (go Func) leftParts rightParts)
186 (Type.Var x, Type.Var y) | x == y ->
189 (Type.Type leftName, Type.Type rightName) | leftName == rightName ->
190 pure (varToDoc localizer leftName)
192 (Type.App (Type.Type leftName) leftArgs, Type.App (Type.Type rightName) rightArgs) ->
193 if leftName /= rightName || length leftArgs /= length rightArgs then
195 (docApp localizer context leftName leftArgs)
196 (docApp localizer context rightName rightArgs)
201 if Var.isTuple leftName then None else App
203 docAppHelp localizer context leftName
204 <$> sequenceA (zipWith (go subContext) leftArgs rightArgs)
206 (Type.App _ _, Type.App _ _) ->
207 error "Type applications without concrete names should not get here."
209 (Type.Record outerLeftFields outerLeftExt, Type.Record outerRightFields outerRightExt) ->
211 (leftFields, leftExt) =
212 flattenRecord outerLeftFields outerLeftExt
214 (rightFields, rightExt) =
215 flattenRecord outerRightFields outerRightExt
217 diffRecord localizer leftFields leftExt rightFields rightExt
219 (Type.Aliased leftName leftArgs _, Type.Aliased rightName rightArgs _) | leftName == rightName ->
220 docAppHelp localizer context leftName
221 <$> sequenceA (zipWith (go App) (map snd leftArgs) (map snd rightArgs))
223 (Type.Aliased _ args real, _) ->
224 go context (Type.dealias args real) rightType
226 (_, Type.Aliased _ args real) ->
227 go context leftType (Type.dealias args real)
231 (docType localizer context leftType)
232 (docType localizer context rightType)
235difference :: Doc -> Doc -> Diff Doc
236difference leftDoc rightDoc =
237 Diff (dullyellow leftDoc) (dullyellow rightDoc)
244diffRecord :: Localizer -> Fields -> Maybe String -> Fields -> Maybe String -> Diff Doc
245diffRecord localizer leftFields leftExt rightFields rightExt =
247 (leftOnly, both, rightOnly) =
248 vennDiagram leftFields rightFields
250 if Map.null leftOnly && Map.null rightOnly then
253 Map.map (uncurry (diff localizer None)) both
255 case partitionDiffs fieldDiffs of
259 docRecord Full (map (first text) sames)
261 if leftExt == rightExt then
262 Same (mkRecord (fmap text leftExt))
266 (mkRecord (fmap (dullyellow . text) leftExt))
267 (mkRecord (fmap (dullyellow . text) rightExt))
271 (lefts, rights) = unzipDiffs diffs
272 style = if null sames then Full else Elide
275 (docRecord style lefts (fmap text leftExt))
276 (docRecord style rights (fmap text rightExt))
281 analyzeFields (Map.keys leftOnly) (Map.keys rightOnly)
284 if Map.null both then Full else Elide
287 (docRecord style lefts (fmap text leftExt))
288 (docRecord style rights (fmap text rightExt))
291unzipDiffs :: [(String, (Doc, Doc))] -> ( [(Doc, Doc)], [(Doc, Doc)] )
292unzipDiffs diffPairs =
294 unzipHelp (name, (left, right)) =
295 (,) (text name, left) (text name, right)
297 unzip (map unzipHelp diffPairs)
301-- RECORD DIFFS HELPERS
304analyzeFields :: [String] -> [String] -> ( [(Doc, Doc)], [(Doc, Doc)] )
305analyzeFields leftOnly rightOnly =
308 Help.findPotentialTypos leftOnly rightOnly
311 ( func (text name), text "..." )
313 mkFieldWith counts name =
314 mkField (if Set.member name counts then dullyellow else id) name
316 case Help.vetTypos potentialTypos of
317 Just (leftTypos, rightTypos) ->
318 ( map (mkFieldWith leftTypos) leftOnly
319 , map (mkFieldWith rightTypos) rightOnly
323 ( map (mkField dullyellow) leftOnly
324 , map (mkField dullyellow) rightOnly
329 Map.Map String Type.Canonical
333 Map.Map String (Type.Canonical,Type.Canonical)
336vennDiagram :: Fields -> Fields -> (Fields, DoubleFields, Fields)
337vennDiagram leftFields rightFields =
338 ( Map.difference leftFields rightFields
339 , Map.intersectionWith (,) leftFields rightFields
340 , Map.difference rightFields leftFields
345 :: [(String, Type.Canonical)]
346 -> Maybe Type.Canonical
347 -> (Fields, Maybe String)
348flattenRecord fields ext =
349 first Map.fromList (flattenRecordHelp fields ext)
353 :: [(String, Type.Canonical)]
354 -> Maybe Type.Canonical
355 -> ([(String, Type.Canonical)], Maybe String)
356flattenRecordHelp fields ext =
364 Just (Type.Record subFields subExt) ->
365 flattenRecordHelp (fields ++ subFields) subExt
367 Just (Type.Aliased _ args tipe) ->
368 flattenRecordHelp fields (Just (Type.dealias args tipe))
371 error "Trying to flatten ill-formed record."
378docType :: Localizer -> Context -> Type.Canonical -> Doc
379docType localizer context tipe =
382 docLambda context (map (docType localizer Func) (Type.collectLambdas tipe))
388 varToDoc localizer name
390 Type.App (Type.Type name) args ->
391 docApp localizer context name args
394 error "type applications should start with a type atom"
396 Type.Record outerFields outerExt ->
399 flattenRecordHelp outerFields outerExt
402 (map (text *** docType localizer None) fields)
405 Type.Aliased name args _ ->
406 docApp localizer context name (map snd args)
410docLambda :: Context -> [Doc] -> Doc
411docLambda context docs =
414 error "cannot call docLambda with an empty list"
419 sep (arg : map (text "->" <+>) rest)
424 , sep (arg : map (text "->" <+>) rest)
430docApp :: Localizer -> Context -> Var.Canonical -> [Type.Canonical] -> Doc
431docApp localizer context name args =
434 if Var.isTuple name then None else App
436 docAppHelp localizer context name (map (docType localizer argContext) args)
439docAppHelp :: Localizer -> Context -> Var.Canonical -> [Doc] -> Doc
440docAppHelp localizer context name args =
441 if Var.isTuple name then
443 [ cat (zipWith (<+>) (lparen : repeat comma) args)
447 else if null args then
448 varToDoc localizer name
455 , hang 4 (sep (varToDoc localizer name : args))
460 hang 4 (sep (varToDoc localizer name : args))
469docRecord :: Style -> [(Doc,Doc)] -> Maybe Doc -> Doc
470docRecord style fields maybeExt =
472 docField (name, tipe) =
473 hang 4 (sep [ name <+> colon, tipe ])
484 elision ++ map docField fields
486 case (fieldDocs, maybeExt) of
492 [ cat (zipWith (<+>) (lbrace : repeat comma) fieldDocs)
500 , cat (zipWith (<+>) (text "|" : repeat comma) fieldDocs)
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