{-# LANGUAGE TypeOperators , DefaultSignatures , StandaloneDeriving , FlexibleContexts , FlexibleInstances , MultiParamTypeClasses , TypeFamilies , TemplateHaskell , OverloadedStrings , ConstraintKinds , LambdaCase , ViewPatterns , ScopedTypeVariables , UndecidableInstances #-} -- | A module for displaying the AST in a tree view. module Language.Haskell.Tools.ASTDebug where import Control.Reference import Data.Foldable import Data.List as List import Data.Maybe import Data.Sequence as Seq import GHC.Generics import Outputable import SrcLoc import DynFlags as GHC import Id as GHC import Name as GHC import RdrName as GHC import Type as GHC import Unique as GHC import Language.Haskell.Tools.AST import Language.Haskell.Tools.AST.SemaInfoTypes data DebugNode dom = TreeNode { _nodeLabel :: String , _nodeSubtree :: TreeDebugNode dom } | SimpleNode { _nodeLabel :: String , _nodeValue :: String } deriving instance Domain dom => Show (DebugNode dom) data TreeDebugNode dom = TreeDebugNode { _nodeName :: String , _nodeInfo :: SemanticInfoType dom , _children :: [DebugNode dom] } deriving instance Domain dom => Show (TreeDebugNode dom) data SemanticInfoType dom = DefaultInfoType { semaInfoTypeRng :: SrcSpan } | NameInfoType { semaInfoTypeName :: SemanticInfo' dom SameInfoNameCls , semaInfoTypeRng :: SrcSpan } | ExprInfoType { semaInfoTypeExpr :: SemanticInfo' dom SameInfoExprCls , semaInfoTypeRng :: SrcSpan } | ImportInfoType { semaInfoTypeImport :: SemanticInfo' dom SameInfoImportCls , semaInfoTypeRng :: SrcSpan } | ModuleInfoType { semaInfoTypeModule :: SemanticInfo' dom SameInfoModuleCls , semaInfoTypeRng :: SrcSpan } | ImplicitFieldInfoType { semaInfoTypeImplicitFld :: SemanticInfo' dom SameInfoWildcardCls , semaInfoTypeRng :: SrcSpan } deriving instance Domain dom => Show (SemanticInfoType dom) makeReferences ''DebugNode makeReferences ''TreeDebugNode type AssocSema dom = ( AssocData (SemanticInfo' dom SameInfoModuleCls), AssocData (SemanticInfo' dom SameInfoImportCls) , AssocData (SemanticInfo' dom SameInfoNameCls), AssocData (SemanticInfo' dom SameInfoExprCls) , AssocData (SemanticInfo' dom SameInfoWildcardCls) ) astDebug :: (ASTDebug e dom st, AssocSema dom) => e dom st -> String astDebug ast = toList (astDebugToJson (astDebug' ast)) astDebugToJson :: AssocSema dom => [DebugNode dom] -> Seq Char astDebugToJson nodes = fromList "[ " >< childrenJson >< fromList " ]" where treeNodes = List.filter (\case TreeNode {} -> True; _ -> False) nodes childrenJson = case map debugTreeNode treeNodes of first:rest -> first >< foldl (><) Seq.empty (fmap (fromList ", " ><) (fromList rest)) [] -> Seq.empty debugTreeNode (TreeNode "" s) = astDebugElemJson s debugTreeNode (TreeNode (dropWhile (=='_') -> l) s) = astDebugElemJson (nodeName .- (("" ++ l ++ ": ") ++) $ s) debugTreeNode (SimpleNode {}) = error "debugTreeNode: simple SimpleNode not allowed" astDebugElemJson :: AssocSema dom => TreeDebugNode dom -> Seq Char astDebugElemJson (TreeDebugNode name info children) = fromList "{ \"text\" : \"" >< fromList name >< fromList "\", \"state\" : { \"opened\" : true }, \"a_attr\" : { \"data-range\" : \"" >< fromList (shortShowSpan (semaInfoTypeRng info)) >< fromList "\", \"data-elems\" : \"" >< foldl (><) Seq.empty dataElems >< fromList "\", \"data-sema\" : \"" >< fromList (showSema info) >< fromList "\" }, \"children\" : " >< astDebugToJson children >< fromList " }" where dataElems = catMaybes (map (\case SimpleNode l v -> Just (fromList (formatScalarElem l v)); _ -> Nothing) children) formatScalarElem l v = "