News for hackers. Stuff that matters.
Re:Stack Graphs by billconan on Thursday December 09, 2021 @01:47PM (#29501283)
Thank you very much for this and for open sourcing it!

For production, is there a good database system that can index this graph structure?

for incremental update, how do you prune deprecated part of the graph (for example, removed/renamed files/functions?)

and for this example

(function_definition name: (identifier) @name) @function {

    node @function.def

    attr (@function.def) kind = "definition"

    attr (@function.def) symbol = @name

    edge @function.containing_scope -> @function.def
}

how can it guarantee the python shadowing rule? it doesn't seem to encode any order preference. does the code traverse the source file in the reverse order basically?

And, probably not closely related to stack graph, but about using tree-sitter for c/c++ understanding, how to handle the preprocessor?

because the c preprocessor can make the code look like a completely different language and mess up the parser.

And how to prune and simplify CST to AST at scale (supporting many languages)?

Re:Stack Graphs by dcreager on Thursday December 09, 2021 @01:54PM (#29501356)
> For production, is there a good database system that can index this graph structure?

For awhile, we were storing this in a (very large) MySQL database, sharded with Vitess. The sharding behavior worked great (since repo ID gives you a nice sharding key), but we found that it wasn't elastic enough for our needs, since we quickly filled up the available capacity of the machines that we had reserved.

Since then we've switched over to storing this data in Azure Blob Storage, basically using it as a glorified key/value store. We had to write custom logic for deciding how to structure our data so that we can efficiently write it at index time and read it at query time, but so far it's been working quite nicely!

> for incremental update, how do you prune deprecated part of the graph

Short version is that we're storing everything on a per-file basis. So whenever a file is changed, we generate a new stack graph snippet for that file. There might be lots of content in that stack graph that is identical to the stack graph of the previous version of the file, but we don't try to do any structural sharing more fine-grained than the file.

Right now we aren't going in any pruning old files that aren't being touched by any active queries, but we could. Or move it to a colder storage tier in Blob Storage, something like that. At least for now, the marginal costs of storing the data for longer aren't our cost bottleneck.

Re:Stack Graphs by randomswede on Monday December 13, 2021 @11:59AM (#29541432)
For at least some languages, it might even be important to have access to older versions of a file.

As a concrete example, Go imports (at least for module-enabled code) is version-locked and the HEAD of the referenced code may no longer be representative of the code that would actually end up being compiled.

On the other hand, just having an easy navigational tool to get to roughly the right place is a very good help.

Re:Stack Graphs by dcreager on Monday December 13, 2021 @08:38PM (#29547121)
Right now code nav on GitHub only works within a repository, and so every link you follow keeps you within the commit that you’re already viewing. As we move to cross-repo code nav, you’re right that it will be difficult to determine the right commit to take you to when following a cross-repo link.
Re:Stack Graphs by dcreager on Thursday December 09, 2021 @02:01PM (#29501475)
> And, probably not closely related to stack graph, but about using tree-sitter for c/c++ understanding, how to handle the preprocessor?

Ha yeah that's a good question. Some uses of the preprocessor won't be problematic ­— it would require deep token mangling, for instance, to really start to cause a problem. You can treat more basic `#ifdef` style conditional compilation as parsing/analyzing both sides and showing both as potential definitions. (And from there you could extend it further to try to identify (or define) "profiles" that have different preprocessor symbols defined, and use that to actually prune some of the results.)

Re:Stack Graphs by billconan on Thursday December 09, 2021 @02:10PM (#29501563)
Thank you very much for the answers! This is a great work!

I'm thinking maybe stack graph can be used to understand the preprocessor. finding the original toggle/condition that turns on/off a #ifdef block.

I heard a simple c++ hello world contains 5000 #defines introduced by standard libs. if stack graph can improve exhaustive search somehow, that would be awesome.

Re:Stack Graphs by dcreager on Thursday December 09, 2021 @02:03PM (#29501493)
> And how to prune and simplify CST to AST at scale (supporting many languages)?

We're not doing any pruning or CST→AST translation, we just operate directly on the CST. With the new graph DSL you should be able to implement something like that, since an AST is a tree, and a tree is one shape of graph that you could create. For our purposes, that isn't a meaningfully useful step, since we can just as easily generate the stack graph structures that we need directly from the CST we get from the tree-sitter grammar.

Re:Stack Graphs by dcreager on Thursday December 09, 2021 @01:57PM (#29501410)
> how can it guarantee the python shadowing rule? it doesn't seem to encode any order preference. does the code traverse the source file in the reverse order basically?

That snippet of graph DSL does not show the precedences being applied, but if you look at the diagram a bit earlier in the post, you'll see that some of edges do have precedence values applied. In the graph DSL, that would appear as an additional statement in the stanza:

    attr (@function.containing_scope -> @function.def) precedence = 1