Skip to content
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

fix: python imports #438

Merged
merged 9 commits into from
Jun 2, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
;; ^^^^^^^^^^^^^^^^

global FILE_PATH
global ROOT_PATH = ""
global ROOT_NODE
global JUMP_TO_SCOPE_NODE

Expand Down Expand Up @@ -272,7 +273,9 @@ inherit .parent_module
node grandparent_module_ref_node
var grandparent_module_ref = grandparent_module_ref_node

scan FILE_PATH {
; get the file path relative to the root path
let rel_path = (replace FILE_PATH ROOT_PATH "")
scan rel_path {
"([^/]+)/"
{
node def_dot
Expand Down
21 changes: 21 additions & 0 deletions languages/tree-sitter-stack-graphs-python/test/root_path.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# ------ path: foo/bar/module.py -----------#
# ------ global: ROOT_PATH=foo/bar -----------#

foo = 42

# ------ path: foo/bar/baz/module.py -----------#
# ------ global: ROOT_PATH=foo/bar -----------#

bar = "hello"

# ------ path: foo/bar/main.py -------------#
# ------ global: ROOT_PATH=foo/bar -----------#

from module import foo
from baz.module import bar

print(foo)
# ^ defined: 4, 14

print(bar)
# ^ defined: 9, 15
12 changes: 11 additions & 1 deletion tree-sitter-stack-graphs/src/cli/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ use crate::BuildError;
use crate::CancelAfterDuration;
use crate::CancellationFlag;
use crate::NoCancellation;
use crate::{FILE_PATH_VAR, ROOT_PATH_VAR};

#[derive(Args)]
pub struct IndexArgs {
Expand Down Expand Up @@ -429,7 +430,16 @@ impl<'a> Indexer<'a> {
) -> std::result::Result<(), BuildErrorWithSource<'b>> {
let relative_source_path = source_path.strip_prefix(source_root).unwrap();
if let Some(lc) = lcs.primary {
let globals = Variables::new();
let mut globals = Variables::new();

globals
.add(FILE_PATH_VAR.into(), source_path.to_str().unwrap().into())
.expect("failed to add file path variable");

globals
.add(ROOT_PATH_VAR.into(), source_root.to_str().unwrap().into())
.expect("failed to add root path variable");

lc.sgl
.build_stack_graph_into(graph, file, source, &globals, cancellation_flag)
.map_err(|inner| BuildErrorWithSource {
Expand Down
10 changes: 10 additions & 0 deletions tree-sitter-stack-graphs/src/cli/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ use crate::test::Test;
use crate::test::TestResult;
use crate::CancelAfterDuration;
use crate::CancellationFlag;
use crate::FILE_PATH_VAR;

#[derive(Args)]
#[clap(after_help = r#"PATH SPECIFICATIONS:
Expand Down Expand Up @@ -316,6 +317,15 @@ impl TestArgs {
&mut Some(test_fragment.source.as_ref()),
)? {
globals.clear();

// Add FILE_PATH to variables
globals
.add(
FILE_PATH_VAR.into(),
test_fragment.path.to_str().unwrap().into(),
)
.expect("failed to add file path variable");

test_fragment.add_globals_to(&mut globals);
lc.sgl.build_stack_graph_into(
&mut test.graph,
Expand Down
14 changes: 8 additions & 6 deletions tree-sitter-stack-graphs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,7 @@ static PRECEDENCE_ATTR: &'static str = "precedence";
static ROOT_NODE_VAR: &'static str = "ROOT_NODE";
static JUMP_TO_SCOPE_NODE_VAR: &'static str = "JUMP_TO_SCOPE_NODE";
static FILE_PATH_VAR: &'static str = "FILE_PATH";
static ROOT_PATH_VAR: &'static str = "ROOT_PATH";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
static ROOT_NODE_VAR: &'static str = "ROOT_NODE";
static JUMP_TO_SCOPE_NODE_VAR: &'static str = "JUMP_TO_SCOPE_NODE";
static FILE_PATH_VAR: &'static str = "FILE_PATH";
static ROOT_PATH_VAR: &'static str = "ROOT_PATH";
/// Name of the variable used to pass the root node.
pub static ROOT_NODE_VAR: &'static str = "ROOT_NODE";
/// Name of the variable used to pass the jump-to-scope node.
pub static JUMP_TO_SCOPE_NODE_VAR: &'static str = "JUMP_TO_SCOPE_NODE";
/// Name of the variable used to pass the file path.
/// If a root path is given, it should be a descendant the root path.
pub static FILE_PATH_VAR: &'static str = "FILE_PATH";
/// Name of the variable used to pass the root path.
/// If given, should be an ancestor of the file path.
pub static ROOT_PATH_VAR: &'static str = "ROOT_PATH";

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made those consts


/// Holds information about how to construct stack graphs for a particular language.
pub struct StackGraphLanguage {
Expand Down Expand Up @@ -635,22 +636,23 @@ impl<'a> Builder<'a> {
let tree = parse_errors.into_tree();

let mut globals = Variables::nested(globals);

if globals.get(&ROOT_NODE_VAR.into()).is_none() {
let root_node = self.inject_node(NodeID::root());
globals
.add(ROOT_NODE_VAR.into(), root_node.into())
.expect("Failed to set ROOT_NODE");
}

let jump_to_scope_node = self.inject_node(NodeID::jump_to());
globals
.add(JUMP_TO_SCOPE_NODE_VAR.into(), jump_to_scope_node.into())
.expect("Failed to set JUMP_TO_SCOPE_NODE");
if globals.get(&FILE_PATH_VAR.into()).is_none() {
let file_name = self.stack_graph[self.file].to_string();
globals
.add(FILE_PATH_VAR.into(), file_name.into())
.expect("Failed to set FILE_PATH");
}

// FILE_PATH is mandatory
globals
.get(&FILE_PATH_VAR.into())
.expect("FILE_PATH not set");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know if this is the right approach. While FILE_PATH is required in all TSG's we actually use, there's nothing inherently here that requires it.

I'm thinking we might just keep the old code here. It will act as a fallback and we don't unnecessarily introduce a breaking change here.


let mut config = ExecutionConfig::new(&self.sgl.functions, &globals)
.lazy(true)
Expand Down
19 changes: 18 additions & 1 deletion tree-sitter-stack-graphs/src/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ use tree_sitter_loader::Loader as TsLoader;
use crate::CancellationFlag;
use crate::FileAnalyzer;
use crate::StackGraphLanguage;
use crate::FILE_PATH_VAR;

pub static DEFAULT_TSG_PATHS: Lazy<Vec<LoadPath>> =
Lazy::new(|| vec![LoadPath::Grammar("queries/stack-graphs".into())]);
Expand Down Expand Up @@ -75,6 +76,15 @@ impl LanguageConfiguration {
let mut builtins = StackGraph::new();
if let Some((builtins_path, builtins_source)) = builtins_source {
let mut builtins_globals = Variables::new();

let builtins_path_var = Path::new("<builtins>");
builtins_globals
.add(
FILE_PATH_VAR.into(),
builtins_path_var.to_str().unwrap().into(),
)
.expect("failed to add file path variable");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we're not using this anywhere else, I'd just inline `builtins_path_var here.

Suggested change
let builtins_path_var = Path::new("<builtins>");
builtins_globals
.add(
FILE_PATH_VAR.into(),
builtins_path_var.to_str().unwrap().into(),
)
.expect("failed to add file path variable");
builtins_globals
.add(
FILE_PATH_VAR.into(),
"<builtins>".into(),
)
.expect("failed to add file path variable");


if let Some(builtins_config) = builtins_config {
Loader::load_globals_from_config_str(builtins_config, &mut builtins_globals)?;
}
Expand Down Expand Up @@ -325,8 +335,15 @@ impl Loader {
graph: &mut StackGraph,
cancellation_flag: &dyn CancellationFlag,
) -> Result<(), LoadError<'a>> {
let file = graph.add_file(&path.to_string_lossy()).unwrap();
let file_name = path.to_string_lossy();
let file: stack_graphs::arena::Handle<stack_graphs::graph::File> =
graph.add_file(&file_name).unwrap();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the type annotation is necessary here, that should be possible to infer.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes my bad, probably miss-clicked on the annotation in my IDE

let mut globals = Variables::new();

globals
.add(FILE_PATH_VAR.into(), path.to_str().unwrap().into())
.expect("failed to add file path variable");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The builtins are a bit special and the actual path is not relevant. They are usually definitions that are implicitly defined, like a runtime library or something.

I'm not sure why we are using path here in add_file. I think we should be using "<builtins>" here as well, both in add_file and as the value in globals. As a little code cleanup we could define a top-level constant BUILTINS_FILENAME and replace the literals.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if having chevrons could cause issues (as it's not a standard path character I believe). But it was working as is so let's keep it


Self::load_globals_from_config_str(&config, &mut globals)?;
sgl.build_stack_graph_into(graph, file, &source, &globals, cancellation_flag)
.map_err(|err| LoadError::Builtins {
Expand Down
21 changes: 18 additions & 3 deletions tree-sitter-stack-graphs/tests/it/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@
// Please see the LICENSE-APACHE or LICENSE-MIT files in this distribution for license details.
// ------------------------------------------------------------------------------------------------

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keep this.

use std::path::Path;

use stack_graphs::graph::StackGraph;
use tree_sitter_graph::Variables;
use tree_sitter_stack_graphs::NoCancellation;
use tree_sitter_stack_graphs::StackGraphLanguage;

use crate::edges::check_stack_graph_edges;
use crate::nodes::check_stack_graph_nodes;
use crate::FILE_PATH_VAR;

#[test]
fn can_support_preexisting_nodes() {
Expand All @@ -22,12 +25,18 @@ fn can_support_preexisting_nodes() {
"#;
let python = "pass";

let file_name = "test.py";

let mut graph = StackGraph::new();
let file = graph.get_or_create_file("test.py");
let file = graph.get_or_create_file(file_name);
let node_id = graph.new_node_id(file);
let _preexisting_node = graph.add_scope_node(node_id, true).unwrap();

let globals = Variables::new();
let mut globals = Variables::new();
globals
.add(FILE_PATH_VAR.into(), file_name.into())
.expect("failed to add file path variable");

let language = StackGraphLanguage::from_str(tree_sitter_python::language(), tsg).unwrap();
language
.build_stack_graph_into(&mut graph, file, python, &globals, &NoCancellation)
Expand All @@ -45,15 +54,21 @@ fn can_support_injected_nodes() {
"#;
let python = "pass";

let file_name = "test.py";

let mut graph = StackGraph::new();
let file = graph.get_or_create_file("test.py");
let file = graph.get_or_create_file(file_name);
let node_id = graph.new_node_id(file);
let _preexisting_node = graph.add_scope_node(node_id, true).unwrap();

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

let mut globals = Variables::new();
globals
.add(FILE_PATH_VAR.into(), file_name.into())
.expect("failed to add file path variable");

globals
.add("EXT_NODE".into(), builder.inject_node(node_id).into())
.expect("Failed to add EXT_NODE variable");
Expand Down
16 changes: 14 additions & 2 deletions tree-sitter-stack-graphs/tests/it/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
// Please see the LICENSE-APACHE or LICENSE-MIT files in this distribution for license details.
// ------------------------------------------------------------------------------------------------

use std::path::Path;

use stack_graphs::arena::Handle;
use stack_graphs::graph::File;
use stack_graphs::graph::StackGraph;
Expand All @@ -13,6 +15,8 @@ use tree_sitter_stack_graphs::BuildError;
use tree_sitter_stack_graphs::NoCancellation;
use tree_sitter_stack_graphs::StackGraphLanguage;

static FILE_PATH_VAR: &'static str = "FILE_PATH";

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's make the constant in the crate public instead of redefining it here.

mod builder;
mod edges;
mod loader;
Expand All @@ -23,11 +27,19 @@ pub(self) fn build_stack_graph(
python_source: &str,
tsg_source: &str,
) -> Result<(StackGraph, Handle<File>), BuildError> {
let file_name = "test.py";
let language =
StackGraphLanguage::from_str(tree_sitter_python::language(), tsg_source).unwrap();
let mut graph = StackGraph::new();
let file = graph.get_or_create_file("test.py");
let globals = Variables::new();
let file = graph.get_or_create_file(file_name);
let mut globals = Variables::new();
let source_path = Path::new(file_name);

// The FILE_PATH_VAR is not accessible here
globals
.add(FILE_PATH_VAR.into(), source_path.to_str().unwrap().into())
.expect("failed to add file path variable");

language.build_stack_graph_into(&mut graph, file, python_source, &globals, &NoCancellation)?;
Ok((graph, file))
}
10 changes: 10 additions & 0 deletions tree-sitter-stack-graphs/tests/it/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// Please see the LICENSE-APACHE or LICENSE-MIT files in this distribution for license details.
// ------------------------------------------------------------------------------------------------

use crate::FILE_PATH_VAR;
use once_cell::sync::Lazy;
use pretty_assertions::assert_eq;
use stack_graphs::arena::Handle;
Expand Down Expand Up @@ -94,9 +95,18 @@ fn check_test(
expected_successes + expected_failures,
assertion_count,
);

let mut globals = Variables::new();
for fragments in &test.fragments {
globals.clear();

globals
.add(
FILE_PATH_VAR.into(),
fragments.path.to_str().unwrap().into(),
)
.expect("failed to add file path variable");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CI failure is probably because this is still before loading the globals from the test, which can set file path too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe adding a add_if_not_set (not sure about the naming) convenience function to Variables would be a nice addition. Let me fix this


fragments.add_globals_to(&mut globals);
build_stack_graph_into(
&mut test.graph,
Expand Down