tilia-0.0.1.0: src/Tilia/Fixity/ByHand.hs
{-# LANGUAGE OverloadedStrings #-}
-- | Fixities for the few modules whose source defeats us.
module Tilia.Fixity.ByHand
( byHandFixities,
hscFixities,
)
where
import Data.Map.Strict (Map)
import Data.Map.Strict qualified as Map
import Data.Text (Text)
import Tilia.Fixity
-- | The modules, and the operators they declare.
byHandFixities :: Map Text (Map OpName Fixity)
byHandFixities =
Map.fromList
[ -- @Test.QuickCheck.Property@ invokes a macro it defines:
-- @WITNESSES(:: [Witness])@ stands in the middle of a record, and
-- only @cpp@ can expand it. No configuration of the module is
-- Haskell, so there is nothing to parse in any of them.
entry
"Test.QuickCheck.Property"
[ ("==>", RightAssoc, 0),
(".&.", RightAssoc, 1),
(".&&.", RightAssoc, 1),
(".||.", RightAssoc, 1),
("===", NoAssoc, 4),
("=/=", NoAssoc, 4)
],
-- @network@ writes its system calls as @foreign import CALLCONV@,
-- and @CALLCONV@ is a macro out of @HsNetDef.h@ standing where the
-- calling convention goes. It has to be expanded for the line to be
-- Haskell at all, so no configuration of these five parses.
--
-- Not one of them declares a fixity, defines an operator, or gives a
-- constructor an operator name, in any version; every entry below is
-- therefore empty. What that buys is not their own operators but
-- everything downstream: @Network.Socket@ is perfectly readable and
-- was only ever refused because these are what it passes on, and
-- refusing it refused @wai@, @http-client@, @warp@ and in the end
-- every @servant@ module that reaches one of them.
entry "Network.Socket.If" [],
entry "Network.Socket.Internal" [],
entry "Network.Socket.Name" [],
entry "Network.Socket.Shutdown" [],
entry "Network.Socket.Syscall" [],
-- @Data.HashMap.Internal.Array@ defines @CHECK_BOUNDS@ and calls it
-- where an expression goes, with the guarded @case@ on the line
-- below. Unexpanded it reads as a function applied to that @case@,
-- and both branches of the @#if@ that defines it leave the call
-- standing, so there is no configuration to fall back on.
--
-- It exports no operator and declares no fixity. What it costs to
-- refuse is @Data.HashMap.Strict@, and after that @Data.Aeson.KeyMap@
-- and everything that reads a JSON object.
entry "Data.HashMap.Internal.Array" [],
-- @monad-logger@ writes one method body once and hands it to sixteen
-- instances: @#define DEF monadLoggerLog a b c d = …@, and then
-- @instance … where DEF@ for each of them. A @where@ with a bare name
-- after it is not Haskell, and the @#define@ sits outside every
-- conditional, so there is no configuration in which it is.
--
-- It declares no fixity, and its export list is explicit throughout:
-- no module is handed on whole, and none of the types it exports with
-- @(..)@ keeps an operator. What refusing it costs is @Yesod.Core@,
-- and after that every module of @yesod@ that reaches one.
entry "Control.Monad.Logger" [],
-- @cereal@ writes its generic sum instances through three macros, and
-- the one that matters expands into a guard and its right-hand side
-- at once: @gPut | PUTSUM(Word8) | …@. Unexpanded that is a guard
-- with nothing after it.
--
-- It declares no fixity. It does hand @Data.Serialize.Get@, @.Put@
-- and @.IEEE754@ on whole, so this claim is about those as well, and
-- not one of the three declares a fixity or exports an operator
-- either: what they supply has the Report's @infixl 9@, which is what
-- an absence here already says.
entry "Data.Serialize" [],
-- @th-lift-instances@ has @LIFT_TYPED_DEFAULT@, defined three ways
-- against the @template-haskell@ version and to nothing at all in the
-- oldest of them, and written bare in five instance bodies.
--
-- Its export list is empty—the module exists for its orphan
-- instances—so it supplies no operator whatever it declares. It is
-- reached through eight modules of @persistent@, which is a long way
-- to be refused from.
entry "Instances.TH.Lift" []
]
where
entry name ops =
(name, Map.fromList [(OpName o, Fixity d p) | (o, d, p) <- ops])
-- | What the modules written for @hsc2hs@ declare.
--
-- A different question from 'byHandFixities', and asked at a different
-- moment. That table is a last resort for a module nothing could be made
-- of; this one is the whole answer for an @.hsc@, given instead of reading
-- it, and a module absent from here declares nothing rather than being
-- unreadable.
--
-- The claim behind the absence is that @hsc2hs@ modules hardly ever declare
-- a fixity. Of three hundred @.hsc@ files across the packages this project
-- builds against, exactly one module declares one, and it is below. One
-- other defines operators at all — @regex-posix@'s @Text.Regex.Posix.Wrap@,
-- which gives @=~@ and @=~~@ and no fixity for either, so the Report's
-- @infixl 9@ is what they have and is what an absence here already says.
-- Neither module can be parsed even with the @hsc2hs@ constructs blanked
-- out, so there was never a reading that would have found them.
--
-- Being wrong here costs indentation and nothing else: a fixity decides
-- how a chain of operators is grouped when it is broken across lines, and
-- nothing in the renderer adds or removes a parenthesis. A module missing
-- from this table is laid out as though its operators were @infixl 9@.
hscFixities :: Map Text (Map OpName Fixity)
hscFixities =
Map.fromList
[ -- @addSignal@ and @deleteSignal@ take a signal on the left and a set
-- on the right, so a chain of them only typechecks to the right, and
-- the module says so with a bare @infixr@—precedence 9, as the
-- Report has it when none is written.
entry
"System.Posix.Signals"
[ ("addSignal", RightAssoc, 9),
("deleteSignal", RightAssoc, 9)
]
]
where
entry name ops =
(name, Map.fromList [(OpName o, Fixity d p) | (o, d, p) <- ops])