Skip to content

Commit 3c4d1a6

Browse files
Merge pull request #438 from nohehf/fix/python-imports
2 parents 63e2d6e + c7f9fd9 commit 3c4d1a6

File tree

9 files changed

+123
-18
lines changed

9 files changed

+123
-18
lines changed

languages/tree-sitter-stack-graphs-python/src/stack-graphs.tsg

+4-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
;; ^^^^^^^^^^^^^^^^
1414

1515
global FILE_PATH
16+
global ROOT_PATH = ""
1617
global ROOT_NODE
1718
global JUMP_TO_SCOPE_NODE
1819

@@ -272,7 +273,9 @@ inherit .parent_module
272273
node grandparent_module_ref_node
273274
var grandparent_module_ref = grandparent_module_ref_node
274275

275-
scan FILE_PATH {
276+
; get the file path relative to the root path
277+
let rel_path = (replace FILE_PATH ROOT_PATH "")
278+
scan rel_path {
276279
"([^/]+)/"
277280
{
278281
node def_dot
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# ------ path: foo/bar/module.py -----------#
2+
# ------ global: ROOT_PATH=foo/bar -----------#
3+
4+
foo = 42
5+
6+
# ------ path: foo/bar/baz/module.py -----------#
7+
# ------ global: ROOT_PATH=foo/bar -----------#
8+
9+
bar = "hello"
10+
11+
# ------ path: foo/bar/main.py -------------#
12+
# ------ global: ROOT_PATH=foo/bar -----------#
13+
14+
from module import foo
15+
from baz.module import bar
16+
17+
print(foo)
18+
# ^ defined: 4, 14
19+
20+
print(bar)
21+
# ^ defined: 9, 15

tree-sitter-stack-graphs/src/cli/index.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ use crate::BuildError;
4242
use crate::CancelAfterDuration;
4343
use crate::CancellationFlag;
4444
use crate::NoCancellation;
45+
use crate::{FILE_PATH_VAR, ROOT_PATH_VAR};
4546

4647
#[derive(Args)]
4748
pub struct IndexArgs {
@@ -429,7 +430,16 @@ impl<'a> Indexer<'a> {
429430
) -> std::result::Result<(), BuildErrorWithSource<'b>> {
430431
let relative_source_path = source_path.strip_prefix(source_root).unwrap();
431432
if let Some(lc) = lcs.primary {
432-
let globals = Variables::new();
433+
let mut globals = Variables::new();
434+
435+
globals
436+
.add(FILE_PATH_VAR.into(), source_path.to_str().unwrap().into())
437+
.expect("failed to add file path variable");
438+
439+
globals
440+
.add(ROOT_PATH_VAR.into(), source_root.to_str().unwrap().into())
441+
.expect("failed to add root path variable");
442+
433443
lc.sgl
434444
.build_stack_graph_into(graph, file, source, &globals, cancellation_flag)
435445
.map_err(|inner| BuildErrorWithSource {

tree-sitter-stack-graphs/src/cli/test.rs

+12
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ use crate::test::Test;
4343
use crate::test::TestResult;
4444
use crate::CancelAfterDuration;
4545
use crate::CancellationFlag;
46+
use crate::FILE_PATH_VAR;
4647

4748
#[derive(Args)]
4849
#[clap(after_help = r#"PATH SPECIFICATIONS:
@@ -316,7 +317,18 @@ impl TestArgs {
316317
&mut Some(test_fragment.source.as_ref()),
317318
)? {
318319
globals.clear();
320+
319321
test_fragment.add_globals_to(&mut globals);
322+
323+
if globals.get(&FILE_PATH_VAR.into()).is_none() {
324+
globals
325+
.add(
326+
FILE_PATH_VAR.into(),
327+
test_fragment.path.to_str().unwrap().into(),
328+
)
329+
.expect("failed to add file path variable");
330+
}
331+
320332
lc.sgl.build_stack_graph_into(
321333
&mut test.graph,
322334
test_fragment.file,

tree-sitter-stack-graphs/src/lib.rs

+12-9
Original file line numberDiff line numberDiff line change
@@ -435,9 +435,16 @@ static SCOPE_ATTRS: Lazy<HashSet<&'static str>> =
435435
static PRECEDENCE_ATTR: &'static str = "precedence";
436436

437437
// Global variables
438-
static ROOT_NODE_VAR: &'static str = "ROOT_NODE";
439-
static JUMP_TO_SCOPE_NODE_VAR: &'static str = "JUMP_TO_SCOPE_NODE";
440-
static FILE_PATH_VAR: &'static str = "FILE_PATH";
438+
/// Name of the variable used to pass the root node.
439+
pub const ROOT_NODE_VAR: &'static str = "ROOT_NODE";
440+
/// Name of the variable used to pass the jump-to-scope node.
441+
pub const JUMP_TO_SCOPE_NODE_VAR: &'static str = "JUMP_TO_SCOPE_NODE";
442+
/// Name of the variable used to pass the file path.
443+
/// If a root path is given, it should be a descendant the root path.
444+
pub const FILE_PATH_VAR: &'static str = "FILE_PATH";
445+
/// Name of the variable used to pass the root path.
446+
/// If given, should be an ancestor of the file path.
447+
pub const ROOT_PATH_VAR: &'static str = "ROOT_PATH";
441448

442449
/// Holds information about how to construct stack graphs for a particular language.
443450
pub struct StackGraphLanguage {
@@ -635,22 +642,18 @@ impl<'a> Builder<'a> {
635642
let tree = parse_errors.into_tree();
636643

637644
let mut globals = Variables::nested(globals);
645+
638646
if globals.get(&ROOT_NODE_VAR.into()).is_none() {
639647
let root_node = self.inject_node(NodeID::root());
640648
globals
641649
.add(ROOT_NODE_VAR.into(), root_node.into())
642650
.expect("Failed to set ROOT_NODE");
643651
}
652+
644653
let jump_to_scope_node = self.inject_node(NodeID::jump_to());
645654
globals
646655
.add(JUMP_TO_SCOPE_NODE_VAR.into(), jump_to_scope_node.into())
647656
.expect("Failed to set JUMP_TO_SCOPE_NODE");
648-
if globals.get(&FILE_PATH_VAR.into()).is_none() {
649-
let file_name = self.stack_graph[self.file].to_string();
650-
globals
651-
.add(FILE_PATH_VAR.into(), file_name.into())
652-
.expect("Failed to set FILE_PATH");
653-
}
654657

655658
let mut config = ExecutionConfig::new(&self.sgl.functions, &globals)
656659
.lazy(true)

tree-sitter-stack-graphs/src/loader.rs

+22-2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ use tree_sitter_loader::Loader as TsLoader;
2929
use crate::CancellationFlag;
3030
use crate::FileAnalyzer;
3131
use crate::StackGraphLanguage;
32+
use crate::FILE_PATH_VAR;
33+
34+
const BUILTINS_FILENAME: &str = "<builtins>";
3235

3336
pub static DEFAULT_TSG_PATHS: Lazy<Vec<LoadPath>> =
3437
Lazy::new(|| vec![LoadPath::Grammar("queries/stack-graphs".into())]);
@@ -75,10 +78,18 @@ impl LanguageConfiguration {
7578
let mut builtins = StackGraph::new();
7679
if let Some((builtins_path, builtins_source)) = builtins_source {
7780
let mut builtins_globals = Variables::new();
81+
7882
if let Some(builtins_config) = builtins_config {
7983
Loader::load_globals_from_config_str(builtins_config, &mut builtins_globals)?;
8084
}
81-
let file = builtins.add_file("<builtins>").unwrap();
85+
86+
if builtins_globals.get(&FILE_PATH_VAR.into()).is_none() {
87+
builtins_globals
88+
.add(FILE_PATH_VAR.into(), BUILTINS_FILENAME.into())
89+
.expect("failed to add file path variable");
90+
}
91+
92+
let file = builtins.add_file(BUILTINS_FILENAME).unwrap();
8293
sgl.build_stack_graph_into(
8394
&mut builtins,
8495
file,
@@ -325,9 +336,18 @@ impl Loader {
325336
graph: &mut StackGraph,
326337
cancellation_flag: &dyn CancellationFlag,
327338
) -> Result<(), LoadError<'a>> {
328-
let file = graph.add_file(&path.to_string_lossy()).unwrap();
339+
let file_name = path.to_string_lossy();
340+
let file = graph.add_file(&file_name).unwrap();
329341
let mut globals = Variables::new();
342+
330343
Self::load_globals_from_config_str(&config, &mut globals)?;
344+
345+
if globals.get(&FILE_PATH_VAR.into()).is_none() {
346+
globals
347+
.add(FILE_PATH_VAR.into(), BUILTINS_FILENAME.into())
348+
.expect("failed to add file path variable");
349+
}
350+
331351
sgl.build_stack_graph_into(graph, file, &source, &globals, cancellation_flag)
332352
.map_err(|err| LoadError::Builtins {
333353
inner: err,

tree-sitter-stack-graphs/tests/it/builder.rs

+16-3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use stack_graphs::graph::StackGraph;
99
use tree_sitter_graph::Variables;
1010
use tree_sitter_stack_graphs::NoCancellation;
1111
use tree_sitter_stack_graphs::StackGraphLanguage;
12+
use tree_sitter_stack_graphs::FILE_PATH_VAR;
1213

1314
use crate::edges::check_stack_graph_edges;
1415
use crate::nodes::check_stack_graph_nodes;
@@ -22,12 +23,18 @@ fn can_support_preexisting_nodes() {
2223
"#;
2324
let python = "pass";
2425

26+
let file_name = "test.py";
27+
2528
let mut graph = StackGraph::new();
26-
let file = graph.get_or_create_file("test.py");
29+
let file = graph.get_or_create_file(file_name);
2730
let node_id = graph.new_node_id(file);
2831
let _preexisting_node = graph.add_scope_node(node_id, true).unwrap();
2932

30-
let globals = Variables::new();
33+
let mut globals = Variables::new();
34+
globals
35+
.add(FILE_PATH_VAR.into(), file_name.into())
36+
.expect("failed to add file path variable");
37+
3138
let language = StackGraphLanguage::from_str(tree_sitter_python::language(), tsg).unwrap();
3239
language
3340
.build_stack_graph_into(&mut graph, file, python, &globals, &NoCancellation)
@@ -45,15 +52,21 @@ fn can_support_injected_nodes() {
4552
"#;
4653
let python = "pass";
4754

55+
let file_name = "test.py";
56+
4857
let mut graph = StackGraph::new();
49-
let file = graph.get_or_create_file("test.py");
58+
let file = graph.get_or_create_file(file_name);
5059
let node_id = graph.new_node_id(file);
5160
let _preexisting_node = graph.add_scope_node(node_id, true).unwrap();
5261

5362
let language = StackGraphLanguage::from_str(tree_sitter_python::language(), tsg).unwrap();
5463
let mut builder = language.builder_into_stack_graph(&mut graph, file, python);
5564

5665
let mut globals = Variables::new();
66+
globals
67+
.add(FILE_PATH_VAR.into(), file_name.into())
68+
.expect("failed to add file path variable");
69+
5770
globals
5871
.add("EXT_NODE".into(), builder.inject_node(node_id).into())
5972
.expect("Failed to add EXT_NODE variable");

tree-sitter-stack-graphs/tests/it/main.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,16 @@
55
// Please see the LICENSE-APACHE or LICENSE-MIT files in this distribution for license details.
66
// ------------------------------------------------------------------------------------------------
77

8+
use std::path::Path;
9+
810
use stack_graphs::arena::Handle;
911
use stack_graphs::graph::File;
1012
use stack_graphs::graph::StackGraph;
1113
use tree_sitter_graph::Variables;
1214
use tree_sitter_stack_graphs::BuildError;
1315
use tree_sitter_stack_graphs::NoCancellation;
1416
use tree_sitter_stack_graphs::StackGraphLanguage;
17+
use tree_sitter_stack_graphs::FILE_PATH_VAR;
1518

1619
mod builder;
1720
mod edges;
@@ -23,11 +26,18 @@ pub(self) fn build_stack_graph(
2326
python_source: &str,
2427
tsg_source: &str,
2528
) -> Result<(StackGraph, Handle<File>), BuildError> {
29+
let file_name = "test.py";
2630
let language =
2731
StackGraphLanguage::from_str(tree_sitter_python::language(), tsg_source).unwrap();
2832
let mut graph = StackGraph::new();
29-
let file = graph.get_or_create_file("test.py");
30-
let globals = Variables::new();
33+
let file = graph.get_or_create_file(file_name);
34+
let mut globals = Variables::new();
35+
let source_path = Path::new(file_name);
36+
37+
globals
38+
.add(FILE_PATH_VAR.into(), source_path.to_str().unwrap().into())
39+
.expect("failed to add file path variable");
40+
3141
language.build_stack_graph_into(&mut graph, file, python_source, &globals, &NoCancellation)?;
3242
Ok((graph, file))
3343
}

tree-sitter-stack-graphs/tests/it/test.rs

+13
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
// Please see the LICENSE-APACHE or LICENSE-MIT files in this distribution for license details.
66
// ------------------------------------------------------------------------------------------------
77

8+
use crate::FILE_PATH_VAR;
89
use once_cell::sync::Lazy;
910
use pretty_assertions::assert_eq;
1011
use stack_graphs::arena::Handle;
@@ -94,10 +95,22 @@ fn check_test(
9495
expected_successes + expected_failures,
9596
assertion_count,
9697
);
98+
9799
let mut globals = Variables::new();
98100
for fragments in &test.fragments {
99101
globals.clear();
102+
100103
fragments.add_globals_to(&mut globals);
104+
105+
if globals.get(&FILE_PATH_VAR.into()).is_none() {
106+
globals
107+
.add(
108+
FILE_PATH_VAR.into(),
109+
fragments.path.to_str().unwrap().into(),
110+
)
111+
.expect("failed to add file path variable");
112+
}
113+
101114
build_stack_graph_into(
102115
&mut test.graph,
103116
fragments.file,

0 commit comments

Comments
 (0)