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 leftArgs)
195 (docApp localizer context rightName rightArgs)
200 if Var.isTuple leftName then None else App
202 docAppHelp localizer context leftName
203 <$> sequenceA (zipWith (go subContext) leftArgs rightArgs)
205 (Type.App _ _, Type.App _ _) ->
206 error "Type applications without concrete names should not get here."
208 (Type.Record outerLeftFields outerLeftExt, Type.Record outerRightFields outerRightExt) ->
210 (leftFields, leftExt) =
211 flattenRecord outerLeftFields outerLeftExt
213 (rightFields, rightExt) =
214 flattenRecord outerRightFields outerRightExt
216 diffRecord localizer leftFields leftExt rightFields rightExt
218 (Type.Aliased leftName leftArgs _, Type.Aliased rightName rightArgs _) | leftName == rightName ->
219 docAppHelp localizer context leftName
220 <$> sequenceA (zipWith (go App) (map snd leftArgs) (map snd rightArgs))
222 (Type.Aliased _ args real, _) ->
223 go context (Type.dealias args real) rightType
225 (_, Type.Aliased _ args real) ->
226 go context leftType (Type.dealias args real)
230 (docType localizer context leftType)
231 (docType localizer context rightType)
234difference :: Doc -> Doc -> Diff Doc
235difference leftDoc rightDoc =
236 Diff (dullyellow leftDoc) (dullyellow rightDoc)
243diffRecord :: Localizer -> Fields -> Maybe String -> Fields -> Maybe String -> Diff Doc
244diffRecord localizer leftFields leftExt rightFields rightExt =
246 (leftOnly, both, rightOnly) =
247 vennDiagram leftFields rightFields
249 if Map.null leftOnly && Map.null rightOnly then
252 Map.map (uncurry (diff localizer None)) both
254 case partitionDiffs fieldDiffs of
258 docRecord Full (map (first text) sames)
260 if leftExt == rightExt then
261 Same (mkRecord (fmap text leftExt))
265 (mkRecord (fmap (dullyellow . text) leftExt))
266 (mkRecord (fmap (dullyellow . text) rightExt))
270 (lefts, rights) = unzipDiffs diffs
271 style = if null sames then Full else Elide
274 (docRecord style lefts (fmap text leftExt))
275 (docRecord style rights (fmap text rightExt))
280 analyzeFields (Map.keys leftOnly) (Map.keys rightOnly)
283 if Map.null both then Full else Elide
286 (docRecord style lefts (fmap text leftExt))
287 (docRecord style rights (fmap text rightExt))
290unzipDiffs :: [(String, (Doc, Doc))] -> ( [(Doc, Doc)], [(Doc, Doc)] )
291unzipDiffs diffPairs =
293 unzipHelp (name, (left, right)) =
294 (,) (text name, left) (text name, right)
296 unzip (map unzipHelp diffPairs)
300-- RECORD DIFFS HELPERS
303analyzeFields :: [String] -> [String] -> ( [(Doc, Doc)], [(Doc, Doc)] )
304analyzeFields leftOnly rightOnly =
307 Help.findPotentialTypos leftOnly rightOnly
310 ( func (text name), text "..." )
312 mkFieldWith counts name =
313 mkField (if Set.member name counts then dullyellow else id) name
315 case Help.vetTypos potentialTypos of
316 Just (leftTypos, rightTypos) ->
317 ( map (mkFieldWith leftTypos) leftOnly
318 , map (mkFieldWith rightTypos) rightOnly
322 ( map (mkField dullyellow) leftOnly
323 , map (mkField dullyellow) rightOnly
328 Map.Map String Type.Canonical
332 Map.Map String (Type.Canonical,Type.Canonical)
335vennDiagram :: Fields -> Fields -> (Fields, DoubleFields, Fields)
336vennDiagram leftFields rightFields =
337 ( Map.difference leftFields rightFields
338 , Map.intersectionWith (,) leftFields rightFields
339 , Map.difference rightFields leftFields
344 :: [(String, Type.Canonical)]
345 -> Maybe Type.Canonical
346 -> (Fields, Maybe String)
347flattenRecord fields ext =
348 first Map.fromList (flattenRecordHelp fields ext)
352 :: [(String, Type.Canonical)]
353 -> Maybe Type.Canonical
354 -> ([(String, Type.Canonical)], Maybe String)
355flattenRecordHelp fields ext =
363 Just (Type.Record subFields subExt) ->
364 flattenRecordHelp (fields ++ subFields) subExt
366 Just (Type.Aliased _ args tipe) ->
367 flattenRecordHelp fields (Just (Type.dealias args tipe))
370 error "Trying to flatten ill-formed record."
377docType :: Localizer -> Context -> Type.Canonical -> Doc
378docType localizer context tipe =
381 docLambda context (map (docType localizer Func) (Type.collectLambdas tipe))
387 varToDoc localizer name
389 Type.App (Type.Type name) args ->
390 docApp localizer context name args
393 error "type applications should start with a type atom"
395 Type.Record outerFields outerExt ->
398 flattenRecordHelp outerFields outerExt
401 (map (text *** docType localizer None) fields)
404 Type.Aliased name args _ ->
405 docApp localizer context name (map snd args)
409docLambda :: Context -> [Doc] -> Doc
410docLambda context docs =
413 error "cannot call docLambda with an empty list"
418 sep (arg : map (text "->" <+>) rest)
423 , sep (arg : map (text "->" <+>) rest)
429docApp :: Localizer -> Context -> Var.Canonical -> [Type.Canonical] -> Doc
430docApp localizer context name args =
433 if Var.isTuple name then None else App
435 docAppHelp localizer context name (map (docType localizer argContext) args)
438docAppHelp :: Localizer -> Context -> Var.Canonical -> [Doc] -> Doc
439docAppHelp localizer context name args =
440 if Var.isTuple name then
442 [ cat (zipWith (<+>) (lparen : repeat comma) args)
446 else if null args then
447 varToDoc localizer name
454 , hang 4 (sep (varToDoc localizer name : args))
459 hang 4 (sep (varToDoc localizer name : args))
468docRecord :: Style -> [(Doc,Doc)] -> Maybe Doc -> Doc
469docRecord style fields maybeExt =
471 docField (name, tipe) =
472 hang 4 (sep [ name <+> colon, tipe ])
483 elision ++ map docField fields
485 case (fieldDocs, maybeExt) of
491 [ cat (zipWith (<+>) (lbrace : repeat comma) fieldDocs)
499 , 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