packages feed

hydra-0.8.0: src/main/haskell/Hydra/Tools/Accessors.hs

-- | Utilities for working with term accessors

module Hydra.Tools.Accessors where

import Hydra.Kernel

import qualified Data.List as L
import qualified Data.Map as M
import qualified Data.Set as S
import qualified Data.Maybe as Y


type AccessorPath = [TermAccessor]
data AccessorNode = AccessorNode Name String String deriving Show
data AccessorEdge = AccessorEdge AccessorNode AccessorPath AccessorNode deriving Show
data AccessorGraph = AccessorGraph [AccessorNode] [AccessorEdge] deriving Show

showTermAccessor :: TermAccessor -> Maybe String
showTermAccessor accessor = case accessor of
   TermAccessorAnnotatedSubject -> Nothing
   TermAccessorApplicationFunction -> Just "fun"
   TermAccessorApplicationArgument -> Just "arg"
   TermAccessorLambdaBody -> Just "body"
   TermAccessorListFold -> Nothing
   TermAccessorOptionalCasesNothing -> Just "nothing"
   TermAccessorOptionalCasesJust -> Just "just"
   TermAccessorUnionCasesDefault -> Just "default"
   TermAccessorUnionCasesBranch name -> Just $ "." ++ unName name
   TermAccessorLetEnvironment -> Just "in"
   TermAccessorLetBinding name -> Just $ unName name ++ "="
   TermAccessorListElement i -> idx i
   TermAccessorMapKey i -> idxSuff ".key" i
   TermAccessorMapValue i -> idxSuff ".value" i
   TermAccessorOptionalTerm -> Just "just"
   TermAccessorProductTerm i -> idx i
   TermAccessorRecordField name -> Just $ "." ++ unName name
   TermAccessorSetElement i -> idx i
   TermAccessorSumTerm -> Nothing
   TermAccessorTypeAbstractionBody -> Nothing
   TermAccessorTypeApplicationTerm -> Nothing
   TermAccessorTypedTerm -> Nothing
   TermAccessorInjectionTerm -> Nothing
   TermAccessorWrappedTerm -> Nothing
  where
--    idx i = Just $ "[" ++ show i ++ "]" -- TODO: restore this
    idx i = Nothing
    idxSuff suffix i = Y.maybe (Just suffix) Just $ fmap (\s -> s ++ suffix) $ idx i

termToAccessorGraph :: M.Map Namespace String -> Term -> AccessorGraph
termToAccessorGraph namespaces term = AccessorGraph nodesX edgesX
  where
    (nodesX, edgesX, _) = helper M.empty Nothing [] ([], [], S.empty) (dontCareAccessor, term)
    dontCareAccessor = TermAccessorAnnotatedSubject
    helper ids mroot path (nodes, edges, visited) (accessor, term) = case term of
        TermLet (Let bindings env) -> helper ids1 mroot nextPath (nodes2, edges2, visited2) (TermAccessorLetEnvironment, env)
          where
            (nodes2, edges2, visited2) = L.foldl addBinding (nodes1++nodes, edges, visited1) (L.zip nodes1 bindings)
              where
                addBinding (nodes, edges, visited) (root, (LetBinding name term1 _))
                    = helper ids1 (Just root) [] (nodes, edges, visited) (dontCareAccessor, term1)
            (nodes1, visited1, ids1) = L.foldl addBinding ([], visited, ids) (letBindingName <$> bindings)
              where
                addBinding (nodes, visited, ids) name =
                    ((node:nodes), S.insert uniqueLabel visited, M.insert name node ids)
                  where
                    node = AccessorNode name rawLabel uniqueLabel
                    rawLabel = toCompactName namespaces name
                    uniqueLabel = toUniqueLabel visited rawLabel
        TermVariable name -> case mroot of
          Nothing -> (nodes, edges, visited)
          Just root -> case M.lookup name ids of
            Nothing -> (nodes, edges, visited)
            Just node -> (nodes, edge:edges, visited)
              where
                edge = AccessorEdge root (L.reverse nextPath) node
        _ -> L.foldl (helper ids mroot nextPath) (nodes, edges, visited) $ subtermsWithAccessors term
      where
        nextPath = accessor:path

toUniqueLabel :: S.Set String -> String -> String
toUniqueLabel visited l = if S.member l visited then toUniqueLabel visited (l ++ "'") else l