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.Aliased _ args real, _) ->
177 go context (Type.dealias args real) rightType
179 (_, Type.Aliased _ args real) ->
180 go context leftType (Type.dealias args real)
182 (Type.Lambda _ _, _) ->
183 diffLambda localizer context leftType rightType
185 (_, Type.Lambda _ _) ->
186 diffLambda localizer context leftType rightType
188 (Type.Var x, Type.Var y) | x == y ->
191 (Type.Type leftName, Type.Type rightName) | leftName == rightName ->
192 pure (varToDoc localizer leftName)
194 (Type.App (Type.Type leftName) leftArgs, Type.App (Type.Type rightName) rightArgs) ->
195 if leftName /= rightName || length leftArgs /= length rightArgs then
197 (docApp localizer context leftName leftArgs)
198 (docApp localizer context rightName rightArgs)
203 if Var.isTuple leftName then None else App
205 docAppHelp localizer context leftName
206 <$> sequenceA (zipWith (go subContext) leftArgs rightArgs)
208 (Type.App _ _, Type.App _ _) ->
209 error "Type applications without concrete names should not get here."
211 (Type.Record outerLeftFields outerLeftExt, Type.Record outerRightFields outerRightExt) ->
213 (leftFields, leftExt) =
214 flattenRecord outerLeftFields outerLeftExt
216 (rightFields, rightExt) =
217 flattenRecord outerRightFields outerRightExt
219 diffRecord localizer leftFields leftExt rightFields rightExt
223 (docType localizer context leftType)
224 (docType localizer context rightType)
227difference :: Doc -> Doc -> Diff Doc
228difference leftDoc rightDoc =
229 Diff (dullyellow leftDoc) (dullyellow rightDoc)
236diffLambda :: Localizer -> Context -> Type.Canonical -> Type.Canonical -> Diff Doc
237diffLambda localizer context leftType rightType =
239 leftArgs = reverse $ Type.collectLambdas leftType
240 rightArgs = reverse $ Type.collectLambdas rightType
243 map (dullyellow . docType localizer Func) types
245 extraLefts = reverse $ extraToDoc $ drop (length rightArgs) leftArgs
246 extraRights = reverse $ extraToDoc $ drop (length leftArgs) rightArgs
249 reverse <$> sequenceA (zipWith (diff localizer Func) leftArgs rightArgs)
251 docLambda context <$>
252 case (extraLefts, extraRights, alignedArgDiff) of
257 Diff (extraLefts ++ docs) (extraRights ++ docs)
259 (_, _, Diff lefts rights) ->
260 Diff (extraLefts ++ lefts) (extraRights ++ rights)
267diffRecord :: Localizer -> Fields -> Maybe String -> Fields -> Maybe String -> Diff Doc
268diffRecord localizer leftFields leftExt rightFields rightExt =
270 (leftOnly, both, rightOnly) =
271 vennDiagram leftFields rightFields
273 if Map.null leftOnly && Map.null rightOnly then
276 Map.map (uncurry (diff localizer None)) both
278 case partitionDiffs fieldDiffs of
282 docRecord Full (map (first text) sames)
284 if leftExt == rightExt then
285 Same (mkRecord (fmap text leftExt))
289 (mkRecord (fmap (dullyellow . text) leftExt))
290 (mkRecord (fmap (dullyellow . text) rightExt))
294 (lefts, rights) = unzipDiffs diffs
295 style = if null sames then Full else Elide
298 (docRecord style lefts (fmap text leftExt))
299 (docRecord style rights (fmap text rightExt))
304 analyzeFields (Map.keys leftOnly) (Map.keys rightOnly)
307 if Map.null both then Full else Elide
310 (docRecord style lefts (fmap text leftExt))
311 (docRecord style rights (fmap text rightExt))
314unzipDiffs :: [(String, (Doc, Doc))] -> ( [(Doc, Doc)], [(Doc, Doc)] )
315unzipDiffs diffPairs =
317 unzipHelp (name, (left, right)) =
318 (,) (text name, left) (text name, right)
320 unzip (map unzipHelp diffPairs)
324-- RECORD DIFFS HELPERS
327analyzeFields :: [String] -> [String] -> ( [(Doc, Doc)], [(Doc, Doc)] )
328analyzeFields leftOnly rightOnly =
331 Help.findPotentialTypos leftOnly rightOnly
334 ( func (text name), text "..." )
336 mkFieldWith counts name =
337 mkField (if Set.member name counts then dullyellow else id) name
339 case Help.vetTypos potentialTypos of
340 Just (leftTypos, rightTypos) ->
341 ( map (mkFieldWith leftTypos) leftOnly
342 , map (mkFieldWith rightTypos) rightOnly
346 ( map (mkField dullyellow) leftOnly
347 , map (mkField dullyellow) rightOnly
352 Map.Map String Type.Canonical
356 Map.Map String (Type.Canonical,Type.Canonical)
359vennDiagram :: Fields -> Fields -> (Fields, DoubleFields, Fields)
360vennDiagram leftFields rightFields =
361 ( Map.difference leftFields rightFields
362 , Map.intersectionWith (,) leftFields rightFields
363 , Map.difference rightFields leftFields
368 :: [(String, Type.Canonical)]
369 -> Maybe Type.Canonical
370 -> (Fields, Maybe String)
371flattenRecord fields ext =
372 first Map.fromList (flattenRecordHelp fields ext)
376 :: [(String, Type.Canonical)]
377 -> Maybe Type.Canonical
378 -> ([(String, Type.Canonical)], Maybe String)
379flattenRecordHelp fields ext =
387 Just (Type.Record subFields subExt) ->
388 flattenRecordHelp (fields ++ subFields) subExt
390 Just (Type.Aliased _ args tipe) ->
391 flattenRecordHelp fields (Just (Type.dealias args tipe))
394 error "Trying to flatten ill-formed record."
401docType :: Localizer -> Context -> Type.Canonical -> Doc
402docType localizer context tipe =
405 docLambda context (map (docType localizer Func) (Type.collectLambdas tipe))
411 varToDoc localizer name
413 Type.App (Type.Type name) args ->
414 docApp localizer context name args
417 error "type applications should start with a type atom"
419 Type.Record outerFields outerExt ->
422 flattenRecordHelp outerFields outerExt
425 (map (text *** docType localizer None) fields)
428 Type.Aliased name args _ ->
429 docApp localizer context name (map snd args)
433docLambda :: Context -> [Doc] -> Doc
434docLambda context docs =
437 error "cannot call docLambda with an empty list"
442 sep (arg : map (text "->" <+>) rest)
447 , sep (arg : map (text "->" <+>) rest)
453docApp :: Localizer -> Context -> Var.Canonical -> [Type.Canonical] -> Doc
454docApp localizer context name args =
457 if Var.isTuple name then None else App
459 docAppHelp localizer context name (map (docType localizer argContext) args)
462docAppHelp :: Localizer -> Context -> Var.Canonical -> [Doc] -> Doc
463docAppHelp localizer context name args =
464 if Var.isTuple name then
466 [ cat (zipWith (<+>) (lparen : repeat comma) args)
470 else if null args then
471 varToDoc localizer name
478 , hang 4 (sep (varToDoc localizer name : args))
483 hang 4 (sep (varToDoc localizer name : args))
492docRecord :: Style -> [(Doc,Doc)] -> Maybe Doc -> Doc
493docRecord style fields maybeExt =
495 docField (name, tipe) =
496 hang 4 (sep [ name <+> colon, tipe ])
507 elision ++ map docField fields
509 case (fieldDocs, maybeExt) of
515 [ cat (zipWith (<+>) (lbrace : repeat comma) fieldDocs)
523 , 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