-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comparison with haskell-indexer #2
Comments
Thanks! I'm aware of The main difference is the output data. The output of Now, I'm getting familiar with Kythe schema and As for creating the call graph for the |
Thanks for your explanations!
But why would that be? Your UI supports a Another question: It seems like currently one has to index every cabal package manually. |
References in references :: HashMap ExternalId (Set IdentifierSrcSpan)
newtype ExternalId = ExternalId
{ getExternalId :: T.Text
} deriving (Show, Eq, Ord, Generic, Data, Hashable, A.ToJSONKey)
data IdentifierSrcSpan = IdentifierSrcSpan
{ modulePath :: HaskellModulePath
, line :: Int
, startColumn :: Int
, endColumn :: Int
} deriving (Show, Eq, Ord, Generic, Data)
The function that fills the To be able to create a call graph we need to keep track of which function calls which one.
data XRef = XRef
{ xrefFile :: !AnalysedFile
, xrefModule :: !ModuleTick
, xrefDecls :: [Decl]
, xrefCrossRefs :: [TickReference]
, xrefRelations :: [Relation]
, xrefImports :: [ModuleTick]
}
deriving (Eq, Show)
-- | A Tick(et) is a globally unique identifier for some entity in the AST.
-- Not mandatory, but is ideally stable across multiple compilations.
--
-- Not related to GHC's SCC annotations (called ticks internally).
data Tick = Tick
{ tickSourcePath :: !SourcePath
, tickPkgModule :: !PkgModule
, tickThing :: !Text
-- ^ The unqualified name of the entity.
, tickSpan :: !(Maybe Span)
-- ^ Can be broader or just loosely connected to the physical location
-- of the entity in source. Should only be used for generating a unique
-- tick string. Use other spans in Decl for source linking.
, tickUniqueInModule :: !Bool
-- ^ If true, the generated unique name can omit the span.
-- This usually signals top levelness too.
-- TODO(robinpalotai): make the distinction clear? Rename?
, tickTermLevel :: !Bool
-- ^ Needed to disambiguate same name occuring in term and type level.
}
deriving (Eq, Ord, Show)
data TickReference = TickReference
{ refTargetTick :: !Tick
, refSourceSpan :: !Span
-- ^ The precise location of the reference. Frontends probably want to
-- make this a hyperlink on the UI.
, refHighLevelContext :: !(Maybe Tick)
-- ^ The context from which the reference originates. Theoretically a
-- frontend could infer the context (enclosing scope) from the reference
-- source span, but 1) it is not obvious how large context to choose,
-- and 2) since the compiler already has the scoping info, it is easier
-- for the indexer to emit it.
--
-- Here we pragmatically set the context to the current top-level
-- function, if any. On the UI, this might show up as the next element
-- in the call chain - see 'ReferenceKind'.
, refKind :: !ReferenceKind
} deriving (Eq, Show)
data ReferenceKind
= Ref -- ^ Reference
| Call -- ^ Function call
| TypeDecl -- ^ Usage of identifier in type declaration, left to "::"
deriving (Eq, Ord, Show)
Here About the automation: I have a small (quick-and-dirty) Haskell program that builds and indexes (using |
Author of haskell-indexer here. Thanks for the comparison so far! I'm really happy about multiple tools popping up in the same space, as it provides chance for knowledge exchange and healthy competition :) @nh2: about the callgraph, indeed the Now both haskell-code-explorer and haskell-indexer dives manually into the GHC AST 1 2, which as I learned not something you want to do (well, it's nice to get to know the GHC AST). The representation is too irregular, and version updates introduce smaller or larger changes. For a while I had plan to rebase the GHC backend on haskell-tools-ast, which promised a higher-level and less volatile API. But with HIEFiles coming maybe in GHC 8.8, it likely makes sense for both projects to migrate info extraction to HIE. Well, the proof of the pudding is trying to compile it, so who can tell, but... As for frontend, haskell-indexer only has kythe.io's debug frontend. You can see it work at stuff.codereview.me, but it is quite quirky. I should have a look if using haskell-code-explorer's UI as a generic Kythe frontend is feasible. As for why would one choose to emit Kythe format entries? My main motivation (apart from making Haskell xrefs available in Google CodeSearch) was that Kythe has indexers for other languages (so far C++, Java, Go, Protobuf are stable, some others like Python, JS in the experimental phase), and has a concept of cross-language references. So if executed well (which haskell-indexer does not do yet), one could get xrefs to FFI functions, protobufs, or establish a cross-language callgraph. |
@robinp Thank you for the explanations! Also, thank you for the Kythe-LSP/LSIF comparison (https://gist.github.com/robinp/76f9d3d91387da5162f773895d4e1d15). It really helps to understand how Kythe and LSP/LSIF relate to each other.
It is possible, but it would require to abstract out all Haskell-specific logic from both JS Web UI and HTTP API server. A bit of background info: My goals with haskell-code-explorer are to create a code-browsing tool that deeply understands Haskell and to experiment with code intelligence features that are Haskell-specific and are not considered 'standard' (not supported by LSP yet). As a result of this, Haskell-specific (or GHC-specific, since GHC is the de-facto standard Haskell compiler) logic is everywhere in the code of the Web UI. For example, the JS code responsible for syntax highlighting looks like this: if(idOcc.sort.tag === 'TypeId') {
color = colorTheme.typeColor;
} else if(idOcc.description === "HsLit" ||
idOcc.description === "HsOverLit"||
idOcc.description === "LitPat" ||
idOcc.description === "NPat" ||
idOcc.description === "NPlusKPat" ||
idOcc.description === "OverLit") {
color = colorTheme.literalColor;
} else {
/* *** */
} |
Hey, this looks really slick, great job!
There is a similar tool out there currently,
haskell-indexer
. Are you aware of it? If yes, could you shortly compare it to your approach? If no, could you summarise how yourhaskell-code-indexer
works? Is it also a wrapper aroundghc
, or a plugin, does it use a custom parser, or something else?We are currently building a tool that takes as input call graph information and lets you do queries on it (e.g. "give me all code paths from function
f
to functiong
): https://github.com/qrilka/haskell-navigationRight now we are based on
haskell-indexer
; perhaps it would make sense for us to be able to work on the output of your tool as well?The text was updated successfully, but these errors were encountered: