packages feed

hs-bindgen-1.0.0.0: src-internal/HsBindgen/Frontend/Pass/ReparseMacroExpansions/Zip/Error.hs

-- | Errors arising while zipping C ASTs before and after reparsing
--
-- Defined in its own module to avoid cyclic module dependencies.
module HsBindgen.Frontend.Pass.ReparseMacroExpansions.Zip.Error (
    ZipError(..)
  , zipErrorNotZipped
  , zipErrorNotEqual
  ) where

import Data.Text (Text)
import Data.Text qualified as Text
import Text.SimplePrettyPrint qualified as PP

import HsBindgen.Util.Tracer

{-------------------------------------------------------------------------------
  Type
-------------------------------------------------------------------------------}

-- | Errors arising while zipping C ASTs before and after reparsing
data ZipError =
    -- | Expected two sub-trees to be zipped, but they were not
    ZipSubTreesNotZipped
    -- | Expected two sub-trees to be equal, but they were not
  | ZipSubTreesNotEqual
    -- | Printed LHS sub-tree
  | ZipSubTreeLHS Text
    -- | Printed RHS sub-tree
  | ZipSubTreeRHS Text
  deriving stock (Show, Eq)

-- | Smart constructor for 'ZipSubTreesNotZipped'
zipErrorNotZipped :: (Show a, Show b) => a -> b -> [ZipError]
zipErrorNotZipped lhs rhs = withDebugTraces lhs rhs ZipSubTreesNotZipped

-- | Smart constructor for 'ZipSubTreesNotEqual'
zipErrorNotEqual :: (Show a, Show b) => a -> b -> [ZipError]
zipErrorNotEqual lhs rhs = withDebugTraces lhs rhs ZipSubTreesNotEqual

-- | Add debug trace messages that print the LHS and RHS sub-trees at the point
-- where zipping failed
withDebugTraces :: (Show a, Show b) => a -> b -> ZipError -> [ZipError]
withDebugTraces lhs rhs err = concat [
      [ err ]
    , [ ZipSubTreeLHS $ Text.pack $ show lhs
      , ZipSubTreeRHS $ Text.pack $ show rhs
      ]
    ]

{-------------------------------------------------------------------------------
  Tracing
-------------------------------------------------------------------------------}

instance PrettyForTrace ZipError where
  prettyForTrace = \case
    ZipSubTreesNotZipped -> PP.hsep [
          "Expected two sub-trees in the C ASTs before and after reparsing to be"
        , "zipped, but they were not."
        ]
    ZipSubTreesNotEqual -> PP.hsep [
          "Expected two sub-trees in the C ASTs before and after reparsing to be"
        , "equal, but they were not."
        ]
    ZipSubTreeLHS lhs -> "Sub-tree before reparsing:" PP.<+> PP.text lhs
    ZipSubTreeRHS rhs -> "Sub-tree after reparsing:" PP.<+> PP.text rhs

instance IsTrace Level ZipError where
  getDefaultLogLevel = \case
      -- If zipping fails, then there might be a bug in the reparser
      --
      -- TODO <https://github.com/well-typed/hs-bindgen/issues/2122>
      -- However, 'ZipSubTreesNotZipped' is emitted by the test suite. The
      -- reason is that some Clang builtins arrive with erased @typedef@ nodes.
      -- For example:
      --
      --     fread(void *restrict, size_t, size_t, FILE *restrict)
      --
      -- arrives as
      --
      --     * cursor type: "unsigned long (void *, unsigned long, unsigned long, FILE *)"
      ZipSubTreesNotZipped{} -> Info
      -- 'ZipSubTreesNotEqual' is not emitted by the test suite and already a
      -- 'Bug' message.
      ZipSubTreesNotEqual{}  -> Bug
      -- Sub-trees are useful for debugging
      ZipSubTreeLHS{}        -> Debug
      ZipSubTreeRHS{}        -> Debug
  getSource = const HsBindgen
  getTraceId = const "zip"