1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
3module Reporting.Render.Type
13import Control.Arrow ((***), first)
14import qualified Data.Map as Map
15import qualified Data.Set as Set
16import Data.Text (Text)
18import qualified AST.Helpers as Help
19import qualified AST.Type as Type
20import qualified AST.Variable as Var
21import qualified Reporting.Helpers as Help
22import Reporting.Helpers ( Doc, (<+>), cat, dullyellow, hang, hsep, parens, sep, text, vcat )
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 -> Text -> [Text] -> [(Text, [Type.Canonical])] -> Doc
45decl localizer name vars tags =
48 hang 2 (sep (text tag : map (docType localizer App) args))
51 (hsep ("type" : map text (name : vars)))
53 zipWith (<+>) ("=" : repeat "|") (map docTag tags)
56annotation :: Localizer -> Text -> Type.Canonical -> Doc
57annotation localizer name tipe =
60 if Help.isOp name then parens (text name) else text name
62 case Type.collectLambdas tipe of
68 (map (docType localizer Func) parts)
73 , docType localizer None tipe
82 Map.Map Var.Canonical Text
85varToDoc :: Localizer -> Var.Canonical -> Doc
86varToDoc localizer var =
91 if name == Help.zeroTuple then
95 text (maybe name id (Map.lookup var localizer))
107instance Functor Diff where
111 Diff (func left) (func right)
117instance Applicative Diff where
121 (<*>) function argument =
122 case (function, argument) of
123 (Diff leftFunc rightFunc, Diff leftArg rightArg) ->
124 Diff (leftFunc leftArg) (rightFunc rightArg)
126 (Diff leftFunc rightFunc, Same arg) ->
127 Diff (leftFunc arg) (rightFunc arg)
129 (Same func, Diff leftArg rightArg) ->
130 Diff (func leftArg) (func rightArg)
132 (Same func, Same arg) ->
136partitionDiffs :: Map.Map k (Diff a) -> ( [(k, (a,a))], [(k, a)] )
139 collect key value (diffKeys, sameKeys) =
142 ( (key, (left, right)) : diffKeys
148 , (key, both) : sameKeys
151 Map.foldrWithKey collect ([],[]) dict
164diff :: Localizer -> Context -> Type.Canonical -> Type.Canonical -> Diff Doc
165diff localizer context leftType rightType =
169 case (leftType, rightType) of
170 (Type.Aliased leftName leftArgs _, Type.Aliased rightName rightArgs _) | leftName == rightName ->
171 docAppHelp localizer context leftName
172 <$> sequenceA (zipWith (go App) (map snd leftArgs) (map snd rightArgs))
174 (Type.Lambda _ _, _) ->
175 diffLambda localizer context leftType rightType
177 (_, Type.Lambda _ _) ->
178 diffLambda localizer context leftType rightType
180 (Type.Var x, Type.Var y) | x == y ->
183 (Type.Type leftName leftArgs, Type.Type rightName rightArgs) ->
184 if leftName /= rightName || length leftArgs /= length rightArgs then
186 (docApp localizer context leftName leftArgs)
187 (docApp localizer context rightName rightArgs)
192 if Var.isTuple leftName then None else App
194 docAppHelp localizer context leftName
195 <$> sequenceA (zipWith (go subContext) leftArgs rightArgs)
197 (Type.Record outerLeftFields outerLeftExt, Type.Record outerRightFields outerRightExt) ->
199 (leftFields, leftExt) =
200 flattenRecord outerLeftFields outerLeftExt
202 (rightFields, rightExt) =
203 flattenRecord outerRightFields outerRightExt
205 diffRecord localizer leftFields leftExt rightFields rightExt
209 (docType localizer context leftType)
210 (docType localizer context rightType)
213difference :: Doc -> Doc -> Diff Doc
214difference leftDoc rightDoc =
215 Diff (dullyellow leftDoc) (dullyellow rightDoc)
222diffLambda :: Localizer -> Context -> Type.Canonical -> Type.Canonical -> Diff Doc
223diffLambda localizer context leftType rightType =
225 leftArgs = reverse $ Type.collectLambdas leftType
226 rightArgs = reverse $ Type.collectLambdas rightType
229 map (dullyellow . docType localizer Func) types
231 extraLefts = reverse $ extraToDoc $ drop (length rightArgs) leftArgs
232 extraRights = reverse $ extraToDoc $ drop (length leftArgs) rightArgs
235 reverse <$> sequenceA (zipWith (diff localizer Func) leftArgs rightArgs)
237 docLambda context <$>
238 case (extraLefts, extraRights, alignedArgDiff) of
243 Diff (extraLefts ++ docs) (extraRights ++ docs)
245 (_, _, Diff lefts rights) ->
246 Diff (extraLefts ++ lefts) (extraRights ++ rights)
253diffRecord :: Localizer -> Fields -> Maybe Text -> Fields -> Maybe Text -> Diff Doc
254diffRecord localizer leftFields leftExt rightFields rightExt =
256 (leftOnly, both, rightOnly) =
257 vennDiagram leftFields rightFields
259 if Map.null leftOnly && Map.null rightOnly then
262 Map.map (uncurry (diff localizer None)) both
264 case partitionDiffs fieldDiffs of
268 docRecord Full (map (first text) sames)
270 if leftExt == rightExt then
271 Same (mkRecord (fmap text leftExt))
275 (mkRecord (fmap (dullyellow . text) leftExt))
276 (mkRecord (fmap (dullyellow . text) rightExt))
280 (lefts, rights) = unzipDiffs diffs
281 style = if null sames then Full else Elide
284 (docRecord style lefts (fmap text leftExt))
285 (docRecord style rights (fmap text rightExt))
290 analyzeFields (Map.keys leftOnly) (Map.keys rightOnly)
293 if Map.null both then Full else Elide
296 (docRecord style lefts (fmap text leftExt))
297 (docRecord style rights (fmap text rightExt))
300unzipDiffs :: [(Text, (Doc, Doc))] -> ( [(Doc, Doc)], [(Doc, Doc)] )
301unzipDiffs diffPairs =
303 unzipHelp (name, (left, right)) =
304 (,) (text name, left) (text name, right)
306 unzip (map unzipHelp diffPairs)
310-- RECORD DIFFS HELPERS
313analyzeFields :: [Text] -> [Text] -> ( [(Doc, Doc)], [(Doc, Doc)] )
314analyzeFields leftOnly rightOnly =
317 Help.findTypoPairs leftOnly rightOnly
320 ( func (text name), text "..." )
322 mkFieldWith counts name =
323 mkField (if Set.member name counts then dullyellow else id) name
325 case Help.vetTypos typoPairs of
326 Just (leftTypos, rightTypos) ->
327 ( map (mkFieldWith leftTypos) leftOnly
328 , map (mkFieldWith rightTypos) rightOnly
332 ( map (mkField dullyellow) leftOnly
333 , map (mkField dullyellow) rightOnly
338 Map.Map Text Type.Canonical
342 Map.Map Text (Type.Canonical,Type.Canonical)
345vennDiagram :: Fields -> Fields -> (Fields, DoubleFields, Fields)
346vennDiagram leftFields rightFields =
347 ( Map.difference leftFields rightFields
348 , Map.intersectionWith (,) leftFields rightFields
349 , Map.difference rightFields leftFields
354 :: [(Text, Type.Canonical)]
355 -> Maybe Type.Canonical
356 -> (Fields, Maybe Text)
357flattenRecord fields ext =
358 first Map.fromList (flattenRecordHelp fields ext)
362 :: [(Text, Type.Canonical)]
363 -> Maybe Type.Canonical
364 -> ([(Text, Type.Canonical)], Maybe Text)
365flattenRecordHelp fields ext =
373 Just (Type.Record subFields subExt) ->
374 flattenRecordHelp (fields ++ subFields) subExt
376 Just (Type.Aliased _ args tipe) ->
377 flattenRecordHelp fields (Just (Type.dealias args tipe))
380 error "Trying to flatten ill-formed record."
387docType :: Localizer -> Context -> Type.Canonical -> Doc
388docType localizer context tipe =
391 docLambda context (map (docType localizer Func) (Type.collectLambdas tipe))
396 Type.Type name args ->
397 docApp localizer context name args
399 Type.Record outerFields outerExt ->
402 flattenRecordHelp outerFields outerExt
405 (map (text *** docType localizer None) fields)
408 Type.Aliased name args _ ->
409 docApp localizer context name (map snd args)
413docLambda :: Context -> [Doc] -> Doc
414docLambda context docs =
417 error "cannot call docLambda with an empty list"
422 sep (arg : map ("->" <+>) rest)
427 , sep (arg : map ("->" <+>) rest)
433docApp :: Localizer -> Context -> Var.Canonical -> [Type.Canonical] -> Doc
434docApp localizer context name args =
437 if Var.isTuple name then None else App
439 docAppHelp localizer context name (map (docType localizer argContext) args)
442docAppHelp :: Localizer -> Context -> Var.Canonical -> [Doc] -> Doc
443docAppHelp localizer context name arguments =
446 if Var.isTuple name then "()" else varToDoc localizer name
449 if Var.isTuple name then
451 [ cat ("(" <+> arg : map ("," <+>) args)
458 cat [ "(", hang 4 (sep (varToDoc localizer name : arg : args)), ")" ]
461 hang 4 (sep (varToDoc localizer name : arg : args))
470docRecord :: Style -> [(Doc,Doc)] -> Maybe Doc -> Doc
471docRecord style fields maybeExt =
473 docField (name, tipe) =
474 hang 4 (sep [ name <+> ":", tipe ])
485 elision ++ map docField fields
487 case (fieldDocs, maybeExt) of
493 [ cat (zipWith (<+>) ("{" : repeat ",") fieldDocs)
501 , cat (zipWith (<+>) (text "|" : repeat ",") 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