phino-0.0.0.57: src/Locator.hs
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE RecordWildCards #-}
-- SPDX-FileCopyrightText: Copyright (c) 2025 Objectionary.com
-- SPDX-License-Identifier: MIT
module Locator (locatedExpression, withLocatedExpression) where
import AST
import Control.Exception (Exception, throwIO)
import Data.Functor ((<&>))
import Misc
import Printer (printExpression)
import Text.Printf (printf)
data LocatorException
= InvalidLocatorProvided {fqn :: Expression}
| CanNotFindObjectByLocator {fqn :: Expression}
deriving (Exception)
instance Show LocatorException where
show InvalidLocatorProvided{..} =
printf
"Invalid locator is provided. 'Q' or dispatch started with 'Q' expected, but got: '%s'"
(printExpression fqn)
show CanNotFindObjectByLocator{..} = printf "Can't find object by locator: '%s'" (printExpression fqn)
locatedExpression :: Expression -> Program -> IO Expression
locatedExpression ExGlobal (Program expr) = pure expr
locatedExpression locator (Program expr) = case fqnToAttrs locator of
Just attrs -> locatedExpression' expr attrs
_ -> invalidLocator locator
where
locatedExpression' :: Expression -> [Attribute] -> IO Expression
locatedExpression' expr' [] = pure expr'
locatedExpression' (ExFormation bds) [attr] = case locatedInBindings attr bds of
Just expr' -> pure expr'
_ -> cantFindBy locator
locatedExpression' (ExFormation bds) (attr : rest) = case locatedInBindings attr bds of
Just expr' -> locatedExpression' expr' rest
_ -> cantFindBy locator
locatedExpression' _ _ = cantFindBy locator
withLocatedExpression :: Expression -> Expression -> Program -> IO Program
withLocatedExpression ExGlobal tgt _ = pure (Program tgt)
withLocatedExpression locator target (Program expr) = case fqnToAttrs locator of
Just attrs -> Program <$> withLocatedExpression' expr attrs
_ -> invalidLocator locator
where
withLocatedExpression' :: Expression -> [Attribute] -> IO Expression
withLocatedExpression' (ExFormation bds) [attr] = case locatedInBindings attr bds of
Just _ -> pure (ExFormation (withReplacedExpression bds))
_ -> cantFindBy locator
where
withReplacedExpression :: [Binding] -> [Binding]
withReplacedExpression [] = []
withReplacedExpression (bd@(BiTau at _) : bds')
| at == attr = BiTau at target : bds'
| otherwise = bd : withReplacedExpression bds'
withReplacedExpression (bd@(BiVoid at) : bds')
| at == attr = BiTau at target : bds'
| otherwise = bd : withReplacedExpression bds'
withReplacedExpression (bd : bds') = bd : withReplacedExpression bds'
withLocatedExpression' (ExFormation bds) attrs = ExFormation <$> withLocatedBindings bds attrs
where
withLocatedBindings :: [Binding] -> [Attribute] -> IO [Binding]
withLocatedBindings (bd@(BiTau at expr') : rbds) attrs'@(at' : rattrs)
| at == at' = withLocatedExpression' expr' rattrs <&> (: rbds) . BiTau at
| otherwise = withLocatedBindings rbds attrs' <&> (:) bd
withLocatedBindings (bd : rbds) attrs' = (:) bd <$> withLocatedBindings rbds attrs'
withLocatedBindings [] _ = cantFindBy locator
withLocatedExpression' _ _ = cantFindBy locator
locatedInBindings :: Attribute -> [Binding] -> Maybe Expression
locatedInBindings _ [] = Nothing
locatedInBindings attr (BiTau attr' expr' : rest)
| attr == attr' = Just expr'
| otherwise = locatedInBindings attr rest
locatedInBindings attr (_ : rest) = locatedInBindings attr rest
invalidLocator :: Expression -> IO a
invalidLocator = throwIO <$> InvalidLocatorProvided
cantFindBy :: Expression -> IO a
cantFindBy = throwIO <$> CanNotFindObjectByLocator