Skip to content
This repository was archived by the owner on Sep 9, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
41047cb
Add skeleton Ruby project
May 11, 2023
9731142
Add storage and visualization features as required features
May 11, 2023
ae49472
Add a literal and statement test
May 11, 2023
4ad6b0a
Scaffold module / class include test
May 12, 2023
7fc44fa
Use working example.rb file
May 12, 2023
a97f2e9
Revert "Add storage and visualization features as required features"
May 12, 2023
95934bb
Remove empty LICENSE file
May 12, 2023
afd5f1a
Require clap derive explicitly
May 12, 2023
86366c9
Use Ruby comment syntax
May 12, 2023
24a61c7
Make includes module test more interesting
May 12, 2023
9c7065e
Fist class def test
May 15, 2023
9d0dead
Skip unsupported tests
May 15, 2023
e5ff578
Support class variables
May 15, 2023
757c895
Merge remote-tracking branch 'origin/main' into rubies-are-forever
May 16, 2023
bfa742d
Merge remote-tracking branch 'origin/main' into rubies-are-forever
May 16, 2023
213f5a5
Add nested class test
May 16, 2023
93c00bb
Add edge from program lexical scope to the root node
May 16, 2023
e4eb597
Differentiate between class definitions using scoped names versus sin…
May 16, 2023
738541f
Add support for resolving ::Foo scoped constants
May 16, 2023
29ce3c8
Add convenience scripts for development
May 17, 2023
6f75947
Reorganize program to global scope connectivity
May 17, 2023
9e05d34
A bit of header styling
May 17, 2023
cc6cbf5
Factor out identifiers into seperate rules
May 17, 2023
e4639c5
Support root variable definitions
May 17, 2023
3d4321c
Always use same output file
May 17, 2023
8bcf821
Support visiblity between split class definitions
May 17, 2023
5affcd5
Add module support
May 17, 2023
fc63478
Add push / pop node resolution for `new` method calls on class constants
May 17, 2023
a68be21
Model class instantiation with `new` constructor method call
May 17, 2023
455e90c
Introduce static_defs and instance_defs scoped variables.
May 19, 2023
d9e7f52
Update tests to use consistent commenting style and additional assert…
May 19, 2023
d180b11
Remove `.lexical_defs`
May 22, 2023
d5f310c
Use `.{def,ref}_value`
May 22, 2023
ee48789
Implement local variables and lexical scoping
May 22, 2023
22812c9
Also allow dereferencing `::` through constants
May 22, 2023
2ef2114
Implement refinement
May 23, 2023
a7c61a4
Prefer local definitions over surrounding context
May 23, 2023
a347fd1
Use tree-sitter query predicates instead of conditional statements to…
May 23, 2023
4218062
Add skipped test that triggers resolution bug
May 24, 2023
db447f1
Prevent path searching within refinement subgraphs when calling conte…
May 24, 2023
83518c9
Merge remote-tracking branch 'origin/main' into rubies-are-forever
May 30, 2023
df77c87
Merge remote-tracking branch 'origin/main' into rubies-are-forever
Jun 8, 2023
8aeff0b
Merge remote-tracking branch 'origin/main' into rubies-are-forever
Oct 24, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Implement refinement
Refinements are part of modules that provide additional instance methods
on classes that can be brought into scope by `using` the module. Because
refinements are not globally available, method resolution must carry
scope of the call to allow finding refinements at the call site.

A detailed example of refinement with the corresponding stack graph is
included in `doc/refinement.png`.
  • Loading branch information
Hendrik van Antwerpen
Hendrik van Antwerpen committed May 23, 2023
commit 2ef2114b182eac5a8bb1a0dadd10546d2024acbe
2 changes: 2 additions & 0 deletions languages/tree-sitter-stack-graphs-ruby/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@ cli = ["anyhow", "clap", "tree-sitter-stack-graphs/cli"]
[dependencies]
anyhow = { version = "1.0", optional = true }
clap = { version = "4", optional = true, features = ["derive"] }
tree-sitter-graph = { version = "0.10.0" }
tree-sitter-stack-graphs = { version = "0.6.0", path = "../../tree-sitter-stack-graphs" }
tree-sitter-ruby = "0.20.0"
uuid = { version = "1.3", features = ["v4", "fast-rng"] }

[dev-dependencies]
anyhow = "1.0"
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 18 additions & 2 deletions languages/tree-sitter-stack-graphs-ruby/rust/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ pub fn language_configuration(cancellation_flag: &dyn CancellationFlag) -> Langu
pub fn try_language_configuration(
cancellation_flag: &dyn CancellationFlag,
) -> Result<LanguageConfiguration, LoadError> {
LanguageConfiguration::from_sources(
let mut lc = LanguageConfiguration::from_sources(
tree_sitter_ruby::language(),
Some(String::from("source.rb")),
None,
Expand All @@ -46,5 +46,21 @@ pub fn try_language_configuration(
Some(STACK_GRAPHS_BUILTINS_CONFIG),
FileAnalyzers::new(),
cancellation_flag,
)
)?;
lc.sgl.functions_mut().add("uuid".into(), UUID);
Ok(lc)
}

struct UUID;

impl tree_sitter_graph::functions::Function for UUID {
fn call(
&self,
_graph: &mut tree_sitter_graph::graph::Graph,
_source: &str,
parameters: &mut dyn tree_sitter_graph::functions::Parameters,
) -> Result<tree_sitter_graph::graph::Value, tree_sitter_graph::ExecutionError> {
parameters.finish()?;
Ok(uuid::Uuid::new_v4().to_string().into())
}
}
87 changes: 84 additions & 3 deletions languages/tree-sitter-stack-graphs-ruby/src/stack-graphs.tsg
Original file line number Diff line number Diff line change
Expand Up @@ -120,16 +120,52 @@ attribute node_symbol = node => symbol = (source-text node), source_n
edge @name.ref -> @class.lexical_scope
}

(class body:(_)@body) {
(class)@class {
node @class.instance
}

(class name:(_)@name)@class {
node dot
attr (dot) pop_symbol = "."

node def
attr (def) pop_symbol = "new"

edge @body.static_defs -> dot
edge @name.def_value -> dot
edge dot -> def
edge def -> @body.instance_defs
edge def -> @class.instance
}

(class body:(_)@body)@class {
edge @class.instance -> @body.instance_defs
}

(class name:(_)@name)@class {
let nonce = (uuid)

node refine_in
attr (refine_in) pop_scoped_symbol = "<refine-in>"
;
node push_nonce
attr (push_nonce) push_symbol = nonce
;
node using
attr (using) push_symbol = "<using>"
;
edge @class.instance -> refine_in
edge refine_in -> push_nonce
edge push_nonce -> using
edge using -> JUMP_TO_SCOPE_NODE

node refine
attr (refine) pop_scoped_symbol = "<refine>"
;
node pop_nonce
attr (pop_nonce) pop_symbol = nonce
;
edge @name.def_value -> refine
edge refine -> pop_nonce
edge pop_nonce -> JUMP_TO_SCOPE_NODE
}

[
Expand Down Expand Up @@ -235,6 +271,22 @@ attribute node_symbol = node => symbol = (source-text node), source_n
edge @recv.lexical_scope -> @call.lexical_scope
}

(call receiver:(_)@recv method:(_)@mthd_name)@call {
node dot
attr (dot) push_symbol = "."

node refine_scope
attr (refine_scope) is_endpoint
edge refine_scope -> @call.lexical_scope

node refine_in
attr (refine_in) push_scoped_symbol = "<refine-in>", scope = refine_scope

edge @mthd_name.ref -> dot
edge dot -> refine_in
edge refine_in -> @recv.value
}

(method name:(_)@name)@method {
node dot
attr (dot) pop_symbol = "."
Expand All @@ -246,6 +298,23 @@ attribute node_symbol = node => symbol = (source-text node), source_n
edge dot -> def
}

;; refine
(call method:(_)@refine arguments:(argument_list (_)@name) block:(do_block body:(_)@body))@call {
if (eq "refine" (source-text @refine)) {
node refine_scope
attr (refine_scope) is_endpoint

node refine
attr (refine) push_scoped_symbol = "<refine>", scope = refine_scope

edge @call.static_defs -> refine
edge refine -> @name.ref_value
edge @name.ref -> @call.lexical_scope

edge refine_scope -> @body.instance_defs
}
}

(singleton_method name:(_)@name)@method {
node dot
attr (dot) pop_symbol = "."
Expand All @@ -257,6 +326,18 @@ attribute node_symbol = node => symbol = (source-text node), source_n
edge dot -> def
}

;; using
(call method:(_)@using arguments:(argument_list (_)@name))@call {
if (eq "using" (source-text @using)) {
node using
attr (using) pop_symbol = "<using>"

edge @call.local_defs -> using
edge using -> @name.ref_value
edge @name.ref -> @call.lexical_scope
}
}

;; Identifiers
;; ^^^^^^^^^^^

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
class C
end

C.new.foo
# ^ defined: 1
# ^ defined:

module M
refine C do
def foo
end
end
end

C.new.foo
# ^ defined: 1
# ^ defined:

using M

C.new.foo
# ^ defined: 1
# ^ defined: 10