parsley-core-1.7.0.0: src/ghc/Parsley/Internal/Frontend/Analysis/Inliner.hs
{-|
Module : Parsley.Internal.Frontend.Analysis.Inliner
Description : Decides whether to inline a let-bound parser.
License : BSD-3-Clause
Maintainer : Jamie Willis
Stability : experimental
Exposes a transformation which can be used to inline let-bindings into their use-sites.
@since 1.7.0.0
-}
module Parsley.Internal.Frontend.Analysis.Inliner (inliner) where
import Data.Ratio ((%))
import Parsley.Internal.Common.Indexed (Fix(..), cata)
import Parsley.Internal.Core.CombinatorAST (Combinator(..))
import Parsley.Internal.Core.Identifiers (MVar)
inlineThreshold :: Rational
inlineThreshold = 13 % 10
{-|
Annotate a tree with its cut-points. We assume a cut for let-bound parsers.
@since 1.7.0.0
-}
inliner :: Bool -> MVar a -> Fix Combinator a -> Fix Combinator a
inliner recu _ body | not recu, shouldInline body = body
inliner recu μ _ = In (Let recu μ)
shouldInline :: Fix Combinator a -> Bool
shouldInline = (< inlineThreshold) . getWeight . cata (InlineWeight . alg)
newtype InlineWeight a = InlineWeight { getWeight :: Rational }
-- Ideally these should mirror those in the backend inliner, how can we unify them?
alg :: Combinator InlineWeight a -> Rational
alg (Pure _) = 0
alg (Satisfy _) = 1
alg Empty = 0
alg Let{} = 2 % 3
alg (Try p) = getWeight p
alg (l :<|>: r) = 1 % 4 + 2 % 5 + getWeight l + getWeight r
alg (l :<*>: r) = 1 % 5 + getWeight l + getWeight r
alg (l :<*: r) = getWeight l + getWeight r
alg (l :*>: r) = getWeight l + getWeight r
alg (LookAhead c) = getWeight c
alg (NotFollowedBy p) = 1 % 4 + getWeight p
alg (Debug _ c) = 2 % 4 + getWeight c
alg (ChainPre op p) = 2 % 5 + 6 % 3 + getWeight op + getWeight p
alg (ChainPost p op) = 6 % 3 + getWeight op + getWeight p
alg (Branch b p q) = 1 % 3 + 2 % 5 + getWeight b + getWeight p + getWeight q
alg (Match p _ qs def) = fromIntegral (length qs + 1) % 3 + sum (map getWeight qs) + getWeight def + getWeight p
alg (MakeRegister _ l r) = 1 % 3 + getWeight l + getWeight r
alg (GetRegister _) = 1 % 3
alg (PutRegister _ c) = 1 % 3 + getWeight c
alg (MetaCombinator _ c) = getWeight c