descript-lang-0.2.0.0: src/Descript/BasicInj/Process/Inspect/SymbolAt.hs
{-# LANGUAGE TypeFamilies #-}
module Descript.BasicInj.Process.Inspect.SymbolAt
( symbolAt
, symbolAt'
) where
import qualified Descript.BasicInj.Traverse.Term as T
import Descript.BasicInj.Traverse
import Descript.BasicInj.Data
import Descript.Misc
import Data.Monoid as M
import Data.Foldable
import Data.List
import qualified Data.List.NonEmpty as NonEmpty
data SymbolAt = SymbolAt Loc
instance Fold SymbolAt where
type Res SymbolAt = First (SymbolEnv SrcAnn)
type FAnn SymbolAt = SrcAnn
fonTerm T.ModulePath (SymbolAt loc) (ModulePath _ xs)
= fold $ zipWith (tryModulePathElemAt loc) (inits xs') xs'
where xs' = NonEmpty.toList xs
fonTerm T.RecordHead (SymbolAt loc) x = tryRecordHeadAt loc x
fonTerm T.RecordType (SymbolAt loc) (RecordType _ head' props)
= foldMap (tryPropertyKeyAt loc head') props
fonTerm T.GenRecord (SymbolAt loc) (Record _ head' props)
= foldMap (tryPropertyKeyAt loc head' . propertyKey) props
fonTerm T.PathElem (SymbolAt loc) (PathElem _ propKey' headKey')
= tryPropertyKeyAt loc headKey' propKey'
fonTerm _ _ _ = First Nothing -- mempty
-- | Finds the symbol at the given location, if it exists.
symbolAt :: Loc -> Source SrcAnn -> Maybe (SymbolEnv SrcAnn)
symbolAt = symbolAt' T.Source
-- | Finds the symbol at the given location, if it exists.
symbolAt' :: TTerm t -> Loc -> t SrcAnn -> Maybe (SymbolEnv SrcAnn)
symbolAt' term loc = getFirst . foldTerm term (SymbolAt loc)
tryModulePathElemAt :: Loc
-> [Symbol SrcAnn]
-> Symbol SrcAnn
-> First (SymbolEnv SrcAnn)
tryModulePathElemAt loc xs = fmap (EnvModulePathElem xs) . trySymbolAt loc
tryRecordHeadAt :: Loc
-> FSymbol SrcAnn
-> First (SymbolEnv SrcAnn)
tryRecordHeadAt loc (FSymbol scope sym)
= EnvRecordHead . FSymbol scope <$> trySymbolAt loc sym
tryPropertyKeyAt :: Loc
-> FSymbol SrcAnn
-> Symbol SrcAnn
-> First (SymbolEnv SrcAnn)
tryPropertyKeyAt loc head' = fmap (EnvPropertyKey head') . trySymbolAt loc
trySymbolAt :: Loc -> Symbol SrcAnn -> First (Symbol SrcAnn)
trySymbolAt loc sym
| loc `isInRange` srcRange (getAnn sym) = First $ Just sym
| otherwise = First Nothing