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.Aliased leftName leftArgs _, Type.Aliased rightName rightArgs _) | leftName == rightName ->
173 docAppHelp localizer context leftName
174 <$> sequenceA (zipWith (go App) (map snd leftArgs) (map snd rightArgs))
176 (Type.Lambda _ _, _) ->
177 diffLambda localizer context leftType rightType
179 (_, Type.Lambda _ _) ->
180 diffLambda localizer context leftType rightType
182 (Type.Var x, Type.Var y) | x == y ->
185 (Type.Type leftName, Type.Type rightName) | leftName == rightName ->
186 pure (varToDoc localizer leftName)
188 (Type.App (Type.Type leftName) leftArgs, Type.App (Type.Type rightName) rightArgs) ->
189 if leftName /= rightName || length leftArgs /= length rightArgs then
191 (docApp localizer context leftName leftArgs)
192 (docApp localizer context rightName rightArgs)
197 if Var.isTuple leftName then None else App
199 docAppHelp localizer context leftName
200 <$> sequenceA (zipWith (go subContext) leftArgs rightArgs)
202 (Type.App _ _, Type.App _ _) ->
203 error "Type applications without concrete names should not get here."
205 (Type.Record outerLeftFields outerLeftExt, Type.Record outerRightFields outerRightExt) ->
207 (leftFields, leftExt) =
208 flattenRecord outerLeftFields outerLeftExt
210 (rightFields, rightExt) =
211 flattenRecord outerRightFields outerRightExt
213 diffRecord localizer leftFields leftExt rightFields rightExt
217 (docType localizer context leftType)
218 (docType localizer context rightType)
221difference :: Doc -> Doc -> Diff Doc
222difference leftDoc rightDoc =
223 Diff (dullyellow leftDoc) (dullyellow rightDoc)
230diffLambda :: Localizer -> Context -> Type.Canonical -> Type.Canonical -> Diff Doc
231diffLambda localizer context leftType rightType =
233 leftArgs = reverse $ Type.collectLambdas leftType
234 rightArgs = reverse $ Type.collectLambdas rightType
237 map (dullyellow . docType localizer Func) types
239 extraLefts = reverse $ extraToDoc $ drop (length rightArgs) leftArgs
240 extraRights = reverse $ extraToDoc $ drop (length leftArgs) rightArgs
243 reverse <$> sequenceA (zipWith (diff localizer Func) leftArgs rightArgs)
245 docLambda context <$>
246 case (extraLefts, extraRights, alignedArgDiff) of
251 Diff (extraLefts ++ docs) (extraRights ++ docs)
253 (_, _, Diff lefts rights) ->
254 Diff (extraLefts ++ lefts) (extraRights ++ rights)
261diffRecord :: Localizer -> Fields -> Maybe String -> Fields -> Maybe String -> Diff Doc
262diffRecord localizer leftFields leftExt rightFields rightExt =
264 (leftOnly, both, rightOnly) =
265 vennDiagram leftFields rightFields
267 if Map.null leftOnly && Map.null rightOnly then
270 Map.map (uncurry (diff localizer None)) both
272 case partitionDiffs fieldDiffs of
276 docRecord Full (map (first text) sames)
278 if leftExt == rightExt then
279 Same (mkRecord (fmap text leftExt))
283 (mkRecord (fmap (dullyellow . text) leftExt))
284 (mkRecord (fmap (dullyellow . text) rightExt))
288 (lefts, rights) = unzipDiffs diffs
289 style = if null sames then Full else Elide
292 (docRecord style lefts (fmap text leftExt))
293 (docRecord style rights (fmap text rightExt))
298 analyzeFields (Map.keys leftOnly) (Map.keys rightOnly)
301 if Map.null both then Full else Elide
304 (docRecord style lefts (fmap text leftExt))
305 (docRecord style rights (fmap text rightExt))
308unzipDiffs :: [(String, (Doc, Doc))] -> ( [(Doc, Doc)], [(Doc, Doc)] )
309unzipDiffs diffPairs =
311 unzipHelp (name, (left, right)) =
312 (,) (text name, left) (text name, right)
314 unzip (map unzipHelp diffPairs)
318-- RECORD DIFFS HELPERS
321analyzeFields :: [String] -> [String] -> ( [(Doc, Doc)], [(Doc, Doc)] )
322analyzeFields leftOnly rightOnly =
325 Help.findTypoPairs leftOnly rightOnly
328 ( func (text name), text "..." )
330 mkFieldWith counts name =
331 mkField (if Set.member name counts then dullyellow else id) name
333 case Help.vetTypos typoPairs of
334 Just (leftTypos, rightTypos) ->
335 ( map (mkFieldWith leftTypos) leftOnly
336 , map (mkFieldWith rightTypos) rightOnly
340 ( map (mkField dullyellow) leftOnly
341 , map (mkField dullyellow) rightOnly
346 Map.Map String Type.Canonical
350 Map.Map String (Type.Canonical,Type.Canonical)
353vennDiagram :: Fields -> Fields -> (Fields, DoubleFields, Fields)
354vennDiagram leftFields rightFields =
355 ( Map.difference leftFields rightFields
356 , Map.intersectionWith (,) leftFields rightFields
357 , Map.difference rightFields leftFields
362 :: [(String, Type.Canonical)]
363 -> Maybe Type.Canonical
364 -> (Fields, Maybe String)
365flattenRecord fields ext =
366 first Map.fromList (flattenRecordHelp fields ext)
370 :: [(String, Type.Canonical)]
371 -> Maybe Type.Canonical
372 -> ([(String, Type.Canonical)], Maybe String)
373flattenRecordHelp fields ext =
381 Just (Type.Record subFields subExt) ->
382 flattenRecordHelp (fields ++ subFields) subExt
384 Just (Type.Aliased _ args tipe) ->
385 flattenRecordHelp fields (Just (Type.dealias args tipe))
388 error "Trying to flatten ill-formed record."
395docType :: Localizer -> Context -> Type.Canonical -> Doc
396docType localizer context tipe =
399 docLambda context (map (docType localizer Func) (Type.collectLambdas tipe))
405 varToDoc localizer name
407 Type.App (Type.Type name) args ->
408 docApp localizer context name args
411 error "type applications should start with a type atom"
413 Type.Record outerFields outerExt ->
416 flattenRecordHelp outerFields outerExt
419 (map (text *** docType localizer None) fields)
422 Type.Aliased name args _ ->
423 docApp localizer context name (map snd args)
427docLambda :: Context -> [Doc] -> Doc
428docLambda context docs =
431 error "cannot call docLambda with an empty list"
436 sep (arg : map (text "->" <+>) rest)
441 , sep (arg : map (text "->" <+>) rest)
447docApp :: Localizer -> Context -> Var.Canonical -> [Type.Canonical] -> Doc
448docApp localizer context name args =
451 if Var.isTuple name then None else App
453 docAppHelp localizer context name (map (docType localizer argContext) args)
456docAppHelp :: Localizer -> Context -> Var.Canonical -> [Doc] -> Doc
457docAppHelp localizer context name args =
458 if Var.isTuple name then
460 [ cat (zipWith (<+>) (lparen : repeat comma) args)
464 else if null args then
465 varToDoc localizer name
472 , hang 4 (sep (varToDoc localizer name : args))
477 hang 4 (sep (varToDoc localizer name : args))
486docRecord :: Style -> [(Doc,Doc)] -> Maybe Doc -> Doc
487docRecord style fields maybeExt =
489 docField (name, tipe) =
490 hang 4 (sep [ name <+> colon, tipe ])
501 elision ++ map docField fields
503 case (fieldDocs, maybeExt) of
509 [ cat (zipWith (<+>) (lbrace : repeat comma) fieldDocs)
517 , 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