packages feed

moonlight-core-0.1.0.0: src-term/Moonlight/Core/Term/Database/Pattern.hs

module Moonlight.Core.Term.Database.Pattern where

import Data.Foldable (toList)
import Data.List.NonEmpty (NonEmpty (..))
import Data.Map.Strict qualified as Map
import Data.Traversable (mapAccumL)
import Moonlight.Core.Pattern
  ( Pattern (..),
    patternVariables,
  )
import Moonlight.Core.Term.Database.Types
import Prelude

compilePatternFreeJoinPlan ::
  Traversable f =>
  Pattern f ->
  PatternFreeJoinPlan f key
compilePatternFreeJoinPlan patternValue =
  compilePatternsFreeJoinPlan (patternValue :| [])
{-# INLINE compilePatternFreeJoinPlan #-}

compilePatternsFreeJoinPlan ::
  Traversable f =>
  NonEmpty (Pattern f) ->
  PatternFreeJoinPlan f key
compilePatternsFreeJoinPlan patterns =
  PatternFreeJoinPlan
    { patternFreeJoinPlan =
        FreeJoinPlan (reverse (compileAtoms finalState)),
      patternFreeJoinRoots = rootTerms,
      patternFreeJoinVariables = queryVarsByPatternVar
    }
  where
    patternVars =
      foldMap patternVariables patterns

    queryVarsByPatternVar =
      Map.fromSet AuthoredPatternVar patternVars

    initialState :: PatternCompileState f key
    initialState =
      PatternCompileState
        { nextGeneratedPatternNodeVar = 0,
          compileAtoms = []
        }

    (finalState, rootTerms) =
      mapAccumL compilePatternTerm initialState patterns
{-# INLINE compilePatternsFreeJoinPlan #-}

compilePatternTerm ::
  Traversable f =>
  PatternCompileState f key ->
  Pattern f ->
  (PatternCompileState f key, QueryTerm key)
compilePatternTerm state patternValue =
  case patternValue of
    PatternVar patternVar ->
      (state, QueryVariable (AuthoredPatternVar patternVar))
    PatternNode node ->
      let resultTerm =
            QueryVariable (GeneratedPatternNodeVar (nextGeneratedPatternNodeVar state))
          stateAfterResult =
            state {nextGeneratedPatternNodeVar = nextGeneratedPatternNodeVar state + 1}
          (stateAfterChildren, childTerms) =
            mapAccumL compilePatternTerm stateAfterResult node
          atom =
            QueryAtom
              { atomOperator = extractOperator node,
                atomResult = resultTerm,
                atomChildren = toList childTerms
              }
       in ( stateAfterChildren
              { compileAtoms = atom : compileAtoms stateAfterChildren
              },
            resultTerm
          )
{-# INLINE compilePatternTerm #-}