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 =
90 name = Var.toString var
92 if name == "_Tuple0" then
96 text (maybe name id (Map.lookup name localizer))
108instance Functor Diff where
112 Diff (func left) (func right)
118instance Applicative Diff where
124 (Diff leftFunc rightFunc, Diff leftArg rightArg) ->
125 Diff (leftFunc leftArg) (rightFunc rightArg)
127 (Diff leftFunc rightFunc, Same arg) ->
128 Diff (leftFunc arg) (rightFunc arg)
130 (Same func, Diff leftArg rightArg) ->
131 Diff (func leftArg) (func rightArg)
133 (Same func, Same arg) ->
137partitionDiffs :: Map.Map k (Diff a) -> ( [(k, (a,a))], [(k, a)] )
140 collect key value (diffKeys, sameKeys) =
143 ( (key, (left, right)) : diffKeys
149 , (key, both) : sameKeys
152 Map.foldrWithKey collect ([],[]) dict
165diff :: Localizer -> Context -> Type.Canonical -> Type.Canonical -> Diff Doc
166diff localizer context leftType rightType =
170 case (leftType, rightType) of
171 (Type.Lambda _ _, Type.Lambda _ _) ->
173 leftParts = Type.collectLambdas leftType
174 rightParts = Type.collectLambdas rightType
177 if length leftParts /= length rightParts then
179 (docLambda context (map (docType localizer Func) leftParts))
180 (docLambda context (map (docType localizer Func) rightParts))
183 docLambda context <$> sequenceA (zipWith (go Func) leftParts rightParts)
185 (Type.Var x, Type.Var y) | x == y ->
188 (Type.Type leftName, Type.Type rightName) | leftName == rightName ->
189 pure (varToDoc localizer leftName)
191 (Type.App (Type.Type leftName) leftArgs, Type.App (Type.Type rightName) rightArgs) ->
192 if leftName /= rightName || length leftArgs /= length rightArgs then
194 (docApp localizer context leftName (map (docType localizer App) leftArgs))
195 (docApp localizer context rightName (map (docType localizer App) rightArgs))
198 docApp localizer context leftName
199 <$> sequenceA (zipWith (go App) leftArgs rightArgs)
201 (Type.App _ _, Type.App _ _) ->
202 error "Type applications without concrete names should not get here."
204 (Type.Record outerLeftFields outerLeftExt, Type.Record outerRightFields outerRightExt) ->
206 (leftFields, leftExt) =
207 flattenRecord outerLeftFields outerLeftExt
209 (rightFields, rightExt) =
210 flattenRecord outerRightFields outerRightExt
212 diffRecord localizer leftFields leftExt rightFields rightExt
214 (Type.Aliased leftName leftArgs _, Type.Aliased rightName rightArgs _) | leftName == rightName ->
215 docApp localizer context leftName
216 <$> sequenceA (zipWith (go App) (map snd leftArgs) (map snd rightArgs))
218 (Type.Aliased _ args real, _) ->
219 go context (Type.dealias args real) rightType
221 (_, Type.Aliased _ args real) ->
222 go context leftType (Type.dealias args real)
226 (docType localizer context leftType)
227 (docType localizer context rightType)
230difference :: Doc -> Doc -> Diff Doc
231difference leftDoc rightDoc =
232 Diff (dullyellow leftDoc) (dullyellow rightDoc)
239diffRecord :: Localizer -> Fields -> Maybe String -> Fields -> Maybe String -> Diff Doc
240diffRecord localizer leftFields leftExt rightFields rightExt =
242 (leftOnly, both, rightOnly) =
243 vennDiagram leftFields rightFields
245 if Map.null leftOnly && Map.null rightOnly then
248 Map.map (uncurry (diff localizer None)) both
250 case partitionDiffs fieldDiffs of
254 docRecord Full (map (first text) sames)
256 if leftExt == rightExt then
257 Same (mkRecord (fmap text leftExt))
261 (mkRecord (fmap (dullyellow . text) leftExt))
262 (mkRecord (fmap (dullyellow . text) rightExt))
266 (lefts, rights) = unzipDiffs diffs
267 style = if null sames then Full else Elide
270 (docRecord style lefts (fmap text leftExt))
271 (docRecord style rights (fmap text rightExt))
276 analyzeFields (Map.keys leftOnly) (Map.keys rightOnly)
279 if Map.null both then Full else Elide
282 (docRecord style lefts (fmap text leftExt))
283 (docRecord style rights (fmap text rightExt))
286unzipDiffs :: [(String, (Doc, Doc))] -> ( [(Doc, Doc)], [(Doc, Doc)] )
287unzipDiffs diffPairs =
289 unzipHelp (name, (left, right)) =
290 (,) (text name, left) (text name, right)
292 unzip (map unzipHelp diffPairs)
296-- RECORD DIFFS HELPERS
299analyzeFields :: [String] -> [String] -> ( [(Doc, Doc)], [(Doc, Doc)] )
300analyzeFields leftOnly rightOnly =
303 Help.findPotentialTypos leftOnly rightOnly
306 ( func (text name), text "…" )
308 mkFieldWith counts name =
309 mkField (if Set.member name counts then dullyellow else id) name
311 case Help.vetTypos potentialTypos of
312 Just (leftTypos, rightTypos) ->
313 ( map (mkFieldWith leftTypos) leftOnly
314 , map (mkFieldWith rightTypos) rightOnly
318 ( map (mkField dullyellow) leftOnly
319 , map (mkField dullyellow) rightOnly
324 Map.Map String Type.Canonical
328 Map.Map String (Type.Canonical,Type.Canonical)
331vennDiagram :: Fields -> Fields -> (Fields, DoubleFields, Fields)
332vennDiagram leftFields rightFields =
333 ( Map.difference leftFields rightFields
334 , Map.intersectionWith (,) leftFields rightFields
335 , Map.difference rightFields leftFields
340 :: [(String, Type.Canonical)]
341 -> Maybe Type.Canonical
342 -> (Fields, Maybe String)
343flattenRecord fields ext =
344 first Map.fromList (flattenRecordHelp fields ext)
348 :: [(String, Type.Canonical)]
349 -> Maybe Type.Canonical
350 -> ([(String, Type.Canonical)], Maybe String)
351flattenRecordHelp fields ext =
359 Just (Type.Record subFields subExt) ->
360 flattenRecordHelp (fields ++ subFields) subExt
362 Just (Type.Aliased _ args tipe) ->
363 flattenRecordHelp fields (Just (Type.dealias args tipe))
366 error "Trying to flatten ill-formed record."
373docType :: Localizer -> Context -> Type.Canonical -> Doc
374docType localizer context tipe =
377 docLambda context (map (docType localizer Func) (Type.collectLambdas tipe))
383 varToDoc localizer name
385 Type.App (Type.Type name) args ->
386 docApp localizer context name (map (docType localizer App) args)
389 error "type applications should start with a type atom"
391 Type.Record outerFields outerExt ->
394 flattenRecordHelp outerFields outerExt
397 (map (text *** docType localizer None) fields)
400 Type.Aliased name args _ ->
401 docApp localizer context name (map (docType localizer App . snd) args)
405docLambda :: Context -> [Doc] -> Doc
406docLambda context docs =
409 error "cannot call docLambda with an empty list"
414 sep (arg : map (text "->" <+>) rest)
419 , sep (arg : map (text "->" <+>) rest)
425docApp :: Localizer -> Context -> Var.Canonical -> [Doc] -> Doc
426docApp localizer context name args =
427 if Var.isTuple name then
429 [ cat (zipWith (<+>) (lparen : repeat comma) args)
433 else if null args then
434 varToDoc localizer name
441 , hang 4 (sep (varToDoc localizer name : args))
446 hang 4 (sep (varToDoc localizer name : args))
455docRecord :: Style -> [(Doc,Doc)] -> Maybe Doc -> Doc
456docRecord style fields maybeExt =
458 docField (name, tipe) =
459 hang 4 (sep [ name <+> colon, tipe ])
470 elision ++ map docField fields
472 case (fieldDocs, maybeExt) of
478 [ cat (zipWith (<+>) (lbrace : repeat comma) fieldDocs)
486 , 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