module SMR.Core.Exp.Push where import SMR.Core.Exp.Train import SMR.Core.Exp.Compounds import SMR.Core.Exp.Base -- | Push down any outermost substitution train to reveal the head constructor. pushHead :: Exp s p -> Maybe (Exp s p) pushHead xx = case xx of XRef _ -> Nothing XVar _ _ -> Nothing XAbs _ _ -> Nothing XApp _ _ -> Nothing XSub cs2 x2 -> pushTrain cs2 x2 XKey _ _ -> Nothing -- | Push down the left-most substitution train in an expression, -- or 'Nothing' if there isn't one. pushDeep :: Exp s p -> Maybe (Exp s p) pushDeep xx = case xx of XRef _ -> Nothing XVar _ _ -> Nothing XKey k1 x2 | Just x2' <- pushDeep x2 -> Just $ XKey k1 x2' | otherwise -> Nothing XApp x1 xs2 | Just x1' <- pushDeep x1 -> Just $ XApp x1' xs2 | Just xs2' <- pushDeepFirst xs2 -> Just $ XApp x1 xs2' | otherwise -> Nothing XAbs ns x -> case pushDeep x of Nothing -> Nothing Just x' -> Just (XAbs ns x') XSub cs1 x2 -> pushTrain cs1 x2 -- | Push down the first substiution train in the given list. pushDeepFirst :: [Exp s p] -> Maybe [Exp s p] pushDeepFirst [] = Nothing pushDeepFirst (x : xs) = case pushDeep x of Nothing | Just xs' <- pushDeepFirst xs -> Just (x : xs') | otherwise -> Nothing Just x' -> Just (x' : xs) -- | Push a substitution train down into an expression to reveal -- the head constructor. pushTrain :: [Car s p] -> Exp s p -> Maybe (Exp s p) pushTrain cs1 x2 = case x2 of -- Unfold macro under a substitution. -- Macro and symbol bodies are closed, -- so we can drop the substitution. XRef (RMac _) -> Just x2 XRef (RSym _) -> Just x2 XRef (RPrm _) -> Just x2 XRef (RNom _) -> Just x2 -- Reference to some other thing. XRef _ -> Nothing -- Apply the train to a variable. XVar name depth -> Just $ trainApplyVar cs1 name depth -- Push train under key. XKey k21 x22 -> Just $ XKey k21 (trainApply cs1 x22) -- Push train into both sides of an application. XApp x21 x22 -> Just $ XApp (trainApply cs1 x21) (map (trainApply cs1) x22) -- Push train under abstraction. XAbs ps21 x22 -> let ns21 = map nameOfParam ps21 cs1' = trainBump ns21 cs1 in Just $ XAbs ps21 (trainApply cs1' x22) -- Combine trains. XSub cs2 x22 -> Just $ trainApply (cs2 ++ cs1) x22