packages feed

moonlight-pale-0.1.0.0: src-ghc-surface/Moonlight/Pale/Ghc/Expr/Convert/Metrics.hs

module Moonlight.Pale.Ghc.Expr.Convert.Metrics
  ( ConvertedModuleMetrics (..),
    convertedModuleMetrics,
  )
where

import Data.Kind (Type)
import Moonlight.Pale.Ghc.Expr.Convert.Coalgebra
  ( ConvertedBindingMetrics,
    ConvertedInstanceDeclaration (..),
    ConvertedModule (..),
    InstanceMethodSection (..),
    ModuleDeclaration (..),
    convertedBindingGlobalVarRefCount,
    convertedBindingLocalVarRefCount,
    convertedBindingMaxFreeScopeCount,
    convertedBindingScopedExprCount,
    convertedValueBindingMetrics,
  )
import Moonlight.Pale.Ghc.Expr.Scope
  ( scopeObservedCount,
  )

type ConvertedModuleMetrics :: Type
data ConvertedModuleMetrics = ConvertedModuleMetrics
  { cmmBindingCount :: !Int,
    cmmInstanceDeclarationCount :: !Int,
    cmmTraversableInstanceMethodCount :: !Int,
    cmmObstructedInstanceMethodCount :: !Int,
    cmmObservedContextCount :: !Int,
    cmmLambdaSiteCount :: !Int,
    cmmLetSiteCount :: !Int,
    cmmScopedExprCount :: !Int,
    cmmGlobalVarRefCount :: !Int,
    cmmLocalVarRefCount :: !Int,
    cmmMaxFreeScopeCount :: !Int
  }
  deriving stock (Eq, Ord, Show)

type ModuleMetricSection :: Type
data ModuleMetricSection = ModuleMetricSection
  { moduleMetricBindingCount :: !Int,
    moduleMetricInstanceDeclarationCount :: !Int,
    moduleMetricTraversableInstanceMethodCount :: !Int,
    moduleMetricObstructedInstanceMethodCount :: !Int,
    moduleMetricExpressionSection :: !ConvertedBindingMetrics
  }

instance Semigroup ModuleMetricSection where
  leftSection <> rightSection =
    ModuleMetricSection
      { moduleMetricBindingCount =
          moduleMetricBindingCount leftSection
            + moduleMetricBindingCount rightSection,
        moduleMetricInstanceDeclarationCount =
          moduleMetricInstanceDeclarationCount leftSection
            + moduleMetricInstanceDeclarationCount rightSection,
        moduleMetricTraversableInstanceMethodCount =
          moduleMetricTraversableInstanceMethodCount leftSection
            + moduleMetricTraversableInstanceMethodCount rightSection,
        moduleMetricObstructedInstanceMethodCount =
          moduleMetricObstructedInstanceMethodCount leftSection
            + moduleMetricObstructedInstanceMethodCount rightSection,
        moduleMetricExpressionSection =
          moduleMetricExpressionSection leftSection
            <> moduleMetricExpressionSection rightSection
      }

instance Monoid ModuleMetricSection where
  mempty =
    ModuleMetricSection
      { moduleMetricBindingCount = 0,
        moduleMetricInstanceDeclarationCount = 0,
        moduleMetricTraversableInstanceMethodCount = 0,
        moduleMetricObstructedInstanceMethodCount = 0,
        moduleMetricExpressionSection = mempty
      }

convertedModuleMetrics ::
  ConvertedModule ->
  ConvertedModuleMetrics
convertedModuleMetrics convertedModule =
  let scopeIndex = cmScopeIndex convertedModule
      metricSection =
        foldMap declarationMetricSection (cmDeclarations convertedModule)
      expressionMetrics =
        moduleMetricExpressionSection metricSection
   in
    ConvertedModuleMetrics
      { cmmBindingCount = moduleMetricBindingCount metricSection,
        cmmInstanceDeclarationCount =
          moduleMetricInstanceDeclarationCount metricSection,
        cmmTraversableInstanceMethodCount =
          moduleMetricTraversableInstanceMethodCount metricSection,
        cmmObstructedInstanceMethodCount =
          moduleMetricObstructedInstanceMethodCount metricSection,
        cmmObservedContextCount = scopeObservedCount scopeIndex,
        cmmLambdaSiteCount = length (cmLambdaSites convertedModule),
        cmmLetSiteCount = length (cmLetSites convertedModule),
        cmmScopedExprCount =
          convertedBindingScopedExprCount expressionMetrics,
        cmmGlobalVarRefCount =
          convertedBindingGlobalVarRefCount expressionMetrics,
        cmmLocalVarRefCount =
          convertedBindingLocalVarRefCount expressionMetrics,
        cmmMaxFreeScopeCount =
          convertedBindingMaxFreeScopeCount expressionMetrics
      }

declarationMetricSection ::
  ModuleDeclaration ->
  ModuleMetricSection
declarationMetricSection = \case
  ValueDeclaration bindingValue ->
    mempty
      { moduleMetricBindingCount = 1,
        moduleMetricExpressionSection =
          convertedValueBindingMetrics bindingValue
      }
  InstanceDeclarationNode instanceDeclaration ->
    mempty
      { moduleMetricInstanceDeclarationCount = 1
      }
      <> foldMap
        instanceMethodMetricSection
        (convertedInstanceMethods instanceDeclaration)
  TypeSignatureDeclaration _ ->
    mempty
  FixityDeclarationNode _ ->
    mempty
  OpaqueDeclaration {} ->
    mempty

instanceMethodMetricSection ::
  InstanceMethodSection ->
  ModuleMetricSection
instanceMethodMetricSection = \case
  TraversableInstanceMethod bindingValue ->
    mempty
      { moduleMetricTraversableInstanceMethodCount = 1,
        moduleMetricExpressionSection =
          convertedValueBindingMetrics bindingValue
      }
  ObstructedInstanceMethod _ ->
    mempty
      { moduleMetricObstructedInstanceMethodCount = 1
      }