From edf12f22138674abb52f260a9eb540f4a4e7c16e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustavo=20Gir=C3=A1ldez?= Date: Mon, 23 Dec 2024 17:27:36 -0500 Subject: [PATCH] Refactor: move bindings builder into its own module along with resolver and loader --- .../src/{ => builder}/loader/cancellation.rs | 0 .../src/{ => builder}/loader/functions.rs | 3 +- .../bindings/src/{ => builder}/loader/mod.rs | 8 +- crates/metaslang/bindings/src/builder/mod.rs | 233 +++++++++++++++++ .../{resolver/mod.rs => builder/resolver.rs} | 2 +- .../bindings/src/graph/definition.rs | 96 +++++++ .../{location/mod.rs => graph/location.rs} | 0 .../bindings/src/{resolved => graph}/mod.rs | 173 +------------ .../metaslang/bindings/src/graph/reference.rs | 81 ++++++ crates/metaslang/bindings/src/lib.rs | 242 +----------------- 10 files changed, 433 insertions(+), 405 deletions(-) rename crates/metaslang/bindings/src/{ => builder}/loader/cancellation.rs (100%) rename crates/metaslang/bindings/src/{ => builder}/loader/functions.rs (98%) rename crates/metaslang/bindings/src/{ => builder}/loader/mod.rs (99%) create mode 100644 crates/metaslang/bindings/src/builder/mod.rs rename crates/metaslang/bindings/src/{resolver/mod.rs => builder/resolver.rs} (99%) create mode 100644 crates/metaslang/bindings/src/graph/definition.rs rename crates/metaslang/bindings/src/{location/mod.rs => graph/location.rs} (100%) rename crates/metaslang/bindings/src/{resolved => graph}/mod.rs (51%) create mode 100644 crates/metaslang/bindings/src/graph/reference.rs diff --git a/crates/metaslang/bindings/src/loader/cancellation.rs b/crates/metaslang/bindings/src/builder/loader/cancellation.rs similarity index 100% rename from crates/metaslang/bindings/src/loader/cancellation.rs rename to crates/metaslang/bindings/src/builder/loader/cancellation.rs diff --git a/crates/metaslang/bindings/src/loader/functions.rs b/crates/metaslang/bindings/src/builder/loader/functions.rs similarity index 98% rename from crates/metaslang/bindings/src/loader/functions.rs rename to crates/metaslang/bindings/src/builder/loader/functions.rs index 27ff5d9aa3..6219d7e2aa 100644 --- a/crates/metaslang/bindings/src/loader/functions.rs +++ b/crates/metaslang/bindings/src/builder/loader/functions.rs @@ -63,7 +63,8 @@ mod resolver { use metaslang_graph_builder::graph::{Graph, Value}; use metaslang_graph_builder::ExecutionError; - use crate::{FileDescriptor, PathResolver}; + use crate::builder::FileDescriptor; + use crate::PathResolver; pub fn add_functions( functions: &mut Functions, diff --git a/crates/metaslang/bindings/src/loader/mod.rs b/crates/metaslang/bindings/src/builder/loader/mod.rs similarity index 99% rename from crates/metaslang/bindings/src/loader/mod.rs rename to crates/metaslang/bindings/src/builder/loader/mod.rs index 357ce1ee8c..56b679d0a6 100644 --- a/crates/metaslang/bindings/src/loader/mod.rs +++ b/crates/metaslang/bindings/src/builder/loader/mod.rs @@ -293,7 +293,7 @@ use stack_graphs::arena::Handle; use stack_graphs::graph::{File, Node, NodeID, StackGraph}; use thiserror::Error; -use crate::{DefinitionBindingInfo, ReferenceBindingInfo}; +use crate::builder::{DefinitionBindingInfo, ReferenceBindingInfo}; // Node type values static DROP_SCOPES_TYPE: &str = "drop_scopes"; @@ -392,7 +392,7 @@ pub(crate) struct Loader<'a, KT: KindTypes + 'static> { extension_hooks: HashSet>, } -pub(crate) struct BuildResult { +pub(crate) struct LoadResult { #[cfg(feature = "__private_testing_utils")] pub graph: Graph, pub cursors: HashMap, Cursor>, @@ -476,7 +476,7 @@ impl<'a, KT: KindTypes + 'static> Loader<'a, KT> { pub fn execute( mut self, cancellation_flag: &dyn CancellationFlag, - ) -> Result, BuildError> { + ) -> Result, BuildError> { let variables = self.build_global_variables(); let config = ExecutionConfig::new(self.functions, &variables) @@ -506,7 +506,7 @@ impl<'a, KT: KindTypes + 'static> Loader<'a, KT> { self.load(cancellation_flag)?; - Ok(BuildResult { + Ok(LoadResult { #[cfg(feature = "__private_testing_utils")] graph: self.graph, cursors: self.cursors, diff --git a/crates/metaslang/bindings/src/builder/mod.rs b/crates/metaslang/bindings/src/builder/mod.rs new file mode 100644 index 0000000000..4623345c25 --- /dev/null +++ b/crates/metaslang/bindings/src/builder/mod.rs @@ -0,0 +1,233 @@ +mod loader; +mod resolver; + +use std::collections::{HashMap, HashSet}; +use std::fmt::Debug; +use std::rc::Rc; + +use loader::{LoadResult, Loader}; +use metaslang_cst::cursor::Cursor; +use metaslang_cst::kinds::KindTypes; +use metaslang_graph_builder::ast::File; +use metaslang_graph_builder::functions::Functions; +use resolver::Resolver; +use semver::Version; +use stack_graphs::graph::StackGraph; + +pub(crate) type GraphHandle = stack_graphs::arena::Handle; +pub(crate) type FileHandle = stack_graphs::arena::Handle; +pub(crate) type CursorID = usize; + +pub use crate::graph::BindingGraph; + +pub(crate) struct DefinitionBindingInfo { + pub(crate) definiens: Cursor, + parents: Vec, + extension_scope: Option, + inherit_extensions: bool, +} + +pub(crate) struct ReferenceBindingInfo { + parents: Vec, +} + +pub struct BindingGraphBuilder { + graph_builder_file: File, + functions: Functions, + pub(crate) stack_graph: StackGraph, + pub(crate) cursors: HashMap>, + pub(crate) definitions_info: HashMap>, + pub(crate) references_info: HashMap, + pub(crate) cursor_to_definitions: HashMap, + pub(crate) cursor_to_references: HashMap, + extension_hooks: HashSet, +} + +#[derive(Clone)] +pub enum FileDescriptor { + User(String), + System(String), +} + +#[derive(Debug)] +pub(crate) struct FileDescriptorError; + +impl FileDescriptor { + // Internal functions to convert a FileDescriptor to and from a string for + // representation inside the stack graph + + pub(crate) fn as_string(&self) -> String { + match self { + Self::User(path) => format!("user:{path}"), + Self::System(path) => format!("system:{path}"), + } + } + + pub(crate) fn try_from(value: &str) -> Result { + value + .strip_prefix("user:") + .map(|path| FileDescriptor::User(path.into())) + .or_else(|| { + value + .strip_prefix("system:") + .map(|path| FileDescriptor::System(path.into())) + }) + .ok_or(FileDescriptorError) + } + + pub(crate) fn from(value: &str) -> Self { + Self::try_from(value) + .unwrap_or_else(|_| panic!("{value} should be a valid file descriptor")) + } + + pub fn get_path(&self) -> &str { + match self { + Self::User(path) => path, + Self::System(path) => path, + } + } + + pub fn is_system(&self) -> bool { + matches!(self, Self::System(_)) + } + + pub fn is_user(&self) -> bool { + matches!(self, Self::User(_)) + } + + pub fn is_user_path(&self, path: &str) -> bool { + matches!(self, Self::User(user_path) if user_path == path) + } +} + +pub trait PathResolver { + fn resolve_path(&self, context_path: &str, path_to_resolve: &Cursor) -> Option; +} + +impl BindingGraphBuilder { + pub fn create( + version: Version, + binding_rules: &str, + path_resolver: Rc>, + ) -> Self { + let graph_builder_file = + File::from_str(binding_rules).expect("Bindings stack graph builder parse error"); + let stack_graph = StackGraph::new(); + let functions = loader::default_functions(version, path_resolver); + + Self { + graph_builder_file, + functions, + stack_graph, + cursors: HashMap::new(), + definitions_info: HashMap::new(), + references_info: HashMap::new(), + cursor_to_definitions: HashMap::new(), + cursor_to_references: HashMap::new(), + extension_hooks: HashSet::new(), + } + } + + pub fn add_system_file(&mut self, file_path: &str, tree_cursor: Cursor) { + let file_kind = FileDescriptor::System(file_path.into()); + let file = self.stack_graph.get_or_create_file(&file_kind.as_string()); + _ = self.add_file_internal(file, tree_cursor); + } + + pub fn add_user_file(&mut self, file_path: &str, tree_cursor: Cursor) { + let file_kind = FileDescriptor::User(file_path.into()); + let file = self.stack_graph.get_or_create_file(&file_kind.as_string()); + _ = self.add_file_internal(file, tree_cursor); + } + + #[cfg(feature = "__private_testing_utils")] + pub fn add_user_file_returning_graph( + &mut self, + file_path: &str, + tree_cursor: Cursor, + ) -> metaslang_graph_builder::graph::Graph { + let file_kind = FileDescriptor::User(file_path.into()); + let file = self.stack_graph.get_or_create_file(&file_kind.as_string()); + let result = self.add_file_internal(file, tree_cursor); + result.graph + } + + fn add_file_internal(&mut self, file: FileHandle, tree_cursor: Cursor) -> LoadResult { + let loader = Loader::new( + &self.graph_builder_file, + &self.functions, + &mut self.stack_graph, + file, + tree_cursor, + ); + let mut result = loader + .execute(&loader::NoCancellation) + .expect("Internal error while building bindings"); + + for (handle, cursor) in result.cursors.drain() { + let cursor_id = cursor.node().id(); + if self.stack_graph[handle].is_definition() { + self.cursor_to_definitions.insert(cursor_id, handle); + } else { + self.cursor_to_references.insert(cursor_id, handle); + } + self.cursors.insert(handle, cursor); + } + self.definitions_info + .extend(result.definitions_info.drain()); + self.references_info.extend(result.references_info.drain()); + self.extension_hooks.extend(result.extension_hooks.drain()); + + result + } + + pub fn resolve(self) -> Rc> { + let resolver = Resolver::new(&self); + let resolved_references = resolver.resolve(); + BindingGraph::build(self, resolved_references) + } + + pub(crate) fn get_parents(&self, handle: GraphHandle) -> Vec { + if self.is_definition(handle) { + self.definitions_info + .get(&handle) + .map(|info| info.parents.clone()) + .unwrap_or_default() + } else { + self.references_info + .get(&handle) + .map(|info| info.parents.clone()) + .unwrap_or_default() + } + } + + fn is_definition(&self, handle: GraphHandle) -> bool { + self.stack_graph[handle].is_definition() + } + + fn is_reference(&self, handle: GraphHandle) -> bool { + self.stack_graph[handle].is_reference() + } + + fn get_extension_scope(&self, handle: GraphHandle) -> Option { + self.definitions_info + .get(&handle) + .and_then(|info| info.extension_scope) + } + + fn inherits_extensions(&self, handle: GraphHandle) -> bool { + self.definitions_info + .get(&handle) + .is_some_and(|info| info.inherit_extensions) + } + + fn get_file(&self, handle: GraphHandle) -> Option { + self.stack_graph[handle] + .file() + .map(|file| FileDescriptor::from(self.stack_graph[file].name())) + } + + pub(crate) fn is_extension_hook(&self, node_handle: GraphHandle) -> bool { + self.extension_hooks.contains(&node_handle) + } +} diff --git a/crates/metaslang/bindings/src/resolver/mod.rs b/crates/metaslang/bindings/src/builder/resolver.rs similarity index 99% rename from crates/metaslang/bindings/src/resolver/mod.rs rename to crates/metaslang/bindings/src/builder/resolver.rs index 974836349b..85244b993c 100644 --- a/crates/metaslang/bindings/src/resolver/mod.rs +++ b/crates/metaslang/bindings/src/builder/resolver.rs @@ -11,7 +11,7 @@ use stack_graphs::stitching::{ }; use stack_graphs::{CancellationError, NoCancellation}; -use crate::{BindingGraphBuilder, GraphHandle}; +use super::{BindingGraphBuilder, GraphHandle}; pub(crate) struct Resolver<'a, KT: KindTypes + 'static> { owner: &'a BindingGraphBuilder, diff --git a/crates/metaslang/bindings/src/graph/definition.rs b/crates/metaslang/bindings/src/graph/definition.rs new file mode 100644 index 0000000000..fdfb0574c6 --- /dev/null +++ b/crates/metaslang/bindings/src/graph/definition.rs @@ -0,0 +1,96 @@ +use std::fmt::{self, Debug, Display}; +use std::rc::Rc; + +use metaslang_cst::cursor::Cursor; +use metaslang_cst::kinds::KindTypes; + +use super::{BindingGraph, BindingLocation}; +use crate::builder::{FileDescriptor, GraphHandle}; +use crate::graph::DisplayCursor; + +#[derive(Clone)] +pub struct Definition { + pub(crate) owner: Rc>, + pub(crate) handle: GraphHandle, +} + +impl Definition { + pub fn id(&self) -> usize { + self.get_cursor().node().id() + } + + pub fn name_location(&self) -> BindingLocation { + match self.get_file() { + FileDescriptor::System(_) => BindingLocation::built_in(), + FileDescriptor::User(file_id) => { + BindingLocation::user_file(file_id, self.get_cursor().to_owned()) + } + } + } + + pub fn definiens_location(&self) -> BindingLocation { + match self.get_file() { + FileDescriptor::System(_) => BindingLocation::built_in(), + FileDescriptor::User(file_id) => { + BindingLocation::user_file(file_id, self.get_definiens_cursor().to_owned()) + } + } + } + + pub fn get_cursor(&self) -> &Cursor { + &self + .owner + .definitions + .get(&self.handle) + .expect("Definition handle is valid") + .cursor + } + + pub fn get_definiens_cursor(&self) -> &Cursor { + &self + .owner + .definitions + .get(&self.handle) + .expect("Definition handle is valid") + .definiens + } + + pub fn get_file(&self) -> FileDescriptor { + self.owner + .get_file( + self.owner + .definitions + .get(&self.handle) + .expect("Definition handle is valid") + .file, + ) + .expect("Definition does not have a valid file descriptor") + } +} + +impl Display for Definition { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "definition {}", + DisplayCursor { + cursor: self.get_cursor(), + file: self.get_file() + } + ) + } +} + +impl Debug for Definition { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{self}") + } +} + +impl PartialEq for Definition { + fn eq(&self, other: &Self) -> bool { + Rc::ptr_eq(&self.owner, &other.owner) && self.handle == other.handle + } +} + +impl Eq for Definition {} diff --git a/crates/metaslang/bindings/src/location/mod.rs b/crates/metaslang/bindings/src/graph/location.rs similarity index 100% rename from crates/metaslang/bindings/src/location/mod.rs rename to crates/metaslang/bindings/src/graph/location.rs diff --git a/crates/metaslang/bindings/src/resolved/mod.rs b/crates/metaslang/bindings/src/graph/mod.rs similarity index 51% rename from crates/metaslang/bindings/src/resolved/mod.rs rename to crates/metaslang/bindings/src/graph/mod.rs index 01dfff6048..855a87dff7 100644 --- a/crates/metaslang/bindings/src/resolved/mod.rs +++ b/crates/metaslang/bindings/src/graph/mod.rs @@ -1,13 +1,19 @@ +mod definition; +mod location; +mod reference; + use std::collections::{BTreeMap, HashMap}; -use std::fmt::{self, Debug, Display}; +use std::fmt; use std::rc::Rc; +pub use definition::Definition; +pub use location::{BindingLocation, BuiltInLocation, UserFileLocation}; use metaslang_cst::cursor::Cursor; use metaslang_cst::kinds::KindTypes; +pub use reference::Reference; -use crate::{ - BindingGraphBuilder, BindingLocation, CursorID, FileDescriptor, FileHandle, GraphHandle, -}; +use crate::builder::{CursorID, FileDescriptor, FileHandle, GraphHandle}; +use crate::BindingGraphBuilder; struct DefinitionInfo { file: FileHandle, @@ -151,162 +157,3 @@ impl<'a, KT: KindTypes + 'static> fmt::Display for DisplayCursor<'a, KT> { ) } } - -#[derive(Clone)] -pub struct Definition { - owner: Rc>, - handle: GraphHandle, -} - -impl Definition { - pub fn id(&self) -> usize { - self.get_cursor().node().id() - } - - pub fn name_location(&self) -> BindingLocation { - match self.get_file() { - FileDescriptor::System(_) => BindingLocation::built_in(), - FileDescriptor::User(file_id) => { - BindingLocation::user_file(file_id, self.get_cursor().to_owned()) - } - } - } - - pub fn definiens_location(&self) -> BindingLocation { - match self.get_file() { - FileDescriptor::System(_) => BindingLocation::built_in(), - FileDescriptor::User(file_id) => { - BindingLocation::user_file(file_id, self.get_definiens_cursor().to_owned()) - } - } - } - - pub fn get_cursor(&self) -> &Cursor { - &self - .owner - .definitions - .get(&self.handle) - .expect("Definition handle is valid") - .cursor - } - - pub fn get_definiens_cursor(&self) -> &Cursor { - &self - .owner - .definitions - .get(&self.handle) - .expect("Definition handle is valid") - .definiens - } - - pub fn get_file(&self) -> FileDescriptor { - self.owner - .get_file( - self.owner - .definitions - .get(&self.handle) - .expect("Definition handle is valid") - .file, - ) - .expect("Definition does not have a valid file descriptor") - } -} - -impl Display for Definition { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "definition {}", - DisplayCursor { - cursor: self.get_cursor(), - file: self.get_file() - } - ) - } -} - -impl Debug for Definition { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{self}") - } -} - -impl PartialEq for Definition { - fn eq(&self, other: &Self) -> bool { - Rc::ptr_eq(&self.owner, &other.owner) && self.handle == other.handle - } -} - -impl Eq for Definition {} - -#[derive(Clone)] -pub struct Reference { - owner: Rc>, - handle: GraphHandle, -} - -impl Reference { - pub fn id(&self) -> usize { - self.get_cursor().node().id() - } - - pub fn location(&self) -> BindingLocation { - match self.get_file() { - FileDescriptor::System(_) => BindingLocation::built_in(), - FileDescriptor::User(file_id) => { - BindingLocation::user_file(file_id, self.get_cursor().to_owned()) - } - } - } - - pub fn get_cursor(&self) -> &Cursor { - &self - .owner - .references - .get(&self.handle) - .expect("Reference handle is valid") - .cursor - } - - pub fn get_file(&self) -> FileDescriptor { - self.owner - .get_file( - self.owner - .references - .get(&self.handle) - .expect("Reference handle is valid") - .file, - ) - .expect("Reference does not have a valid file descriptor") - } - - pub fn definitions(&self) -> Vec> { - self.owner.resolved_references[&self.handle] - .iter() - .map(|handle| { - self.owner - .to_definition(*handle) - .expect("Resolved reference handle to be a definition") - }) - .collect() - } -} - -impl Display for Reference { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "reference {}", - DisplayCursor { - cursor: self.get_cursor(), - file: self.get_file() - } - ) - } -} - -impl PartialEq for Reference { - fn eq(&self, other: &Self) -> bool { - Rc::ptr_eq(&self.owner, &other.owner) && self.handle == other.handle - } -} diff --git a/crates/metaslang/bindings/src/graph/reference.rs b/crates/metaslang/bindings/src/graph/reference.rs new file mode 100644 index 0000000000..6131dc1e8a --- /dev/null +++ b/crates/metaslang/bindings/src/graph/reference.rs @@ -0,0 +1,81 @@ +use std::fmt::{self, Display}; +use std::rc::Rc; + +use metaslang_cst::cursor::Cursor; +use metaslang_cst::kinds::KindTypes; + +use super::{BindingGraph, BindingLocation, Definition}; +use crate::builder::{FileDescriptor, GraphHandle}; +use crate::graph::DisplayCursor; + +#[derive(Clone)] +pub struct Reference { + pub(crate) owner: Rc>, + pub(crate) handle: GraphHandle, +} + +impl Reference { + pub fn id(&self) -> usize { + self.get_cursor().node().id() + } + + pub fn location(&self) -> BindingLocation { + match self.get_file() { + FileDescriptor::System(_) => BindingLocation::built_in(), + FileDescriptor::User(file_id) => { + BindingLocation::user_file(file_id, self.get_cursor().to_owned()) + } + } + } + + pub fn get_cursor(&self) -> &Cursor { + &self + .owner + .references + .get(&self.handle) + .expect("Reference handle is valid") + .cursor + } + + pub fn get_file(&self) -> FileDescriptor { + self.owner + .get_file( + self.owner + .references + .get(&self.handle) + .expect("Reference handle is valid") + .file, + ) + .expect("Reference does not have a valid file descriptor") + } + + pub fn definitions(&self) -> Vec> { + self.owner.resolved_references[&self.handle] + .iter() + .map(|handle| { + self.owner + .to_definition(*handle) + .expect("Resolved reference handle to be a definition") + }) + .collect() + } +} + +impl Display for Reference { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "reference {}", + DisplayCursor { + cursor: self.get_cursor(), + file: self.get_file() + } + ) + } +} + +impl PartialEq for Reference { + fn eq(&self, other: &Self) -> bool { + Rc::ptr_eq(&self.owner, &other.owner) && self.handle == other.handle + } +} diff --git a/crates/metaslang/bindings/src/lib.rs b/crates/metaslang/bindings/src/lib.rs index f92eb89010..23aeeb700b 100644 --- a/crates/metaslang/bindings/src/lib.rs +++ b/crates/metaslang/bindings/src/lib.rs @@ -1,237 +1,7 @@ -mod loader; -mod location; -mod resolved; -mod resolver; +mod builder; +mod graph; -use std::collections::{HashMap, HashSet}; -use std::fmt::Debug; -use std::rc::Rc; - -use loader::BuildResult; -use metaslang_cst::cursor::Cursor; -use metaslang_cst::kinds::KindTypes; -use metaslang_graph_builder::ast::File; -use metaslang_graph_builder::functions::Functions; -use resolver::Resolver; -use semver::Version; -use stack_graphs::graph::StackGraph; - -type Loader<'a, KT> = loader::Loader<'a, KT>; -type GraphHandle = stack_graphs::arena::Handle; -type FileHandle = stack_graphs::arena::Handle; -type CursorID = usize; - -pub use location::{BindingLocation, BuiltInLocation, UserFileLocation}; -pub use resolved::{BindingGraph, Definition, Reference}; - -pub(crate) struct DefinitionBindingInfo { - definiens: Cursor, - parents: Vec, - extension_scope: Option, - inherit_extensions: bool, -} - -pub(crate) struct ReferenceBindingInfo { - parents: Vec, -} - -pub struct BindingGraphBuilder { - graph_builder_file: File, - functions: Functions, - stack_graph: StackGraph, - cursors: HashMap>, - definitions_info: HashMap>, - references_info: HashMap, - cursor_to_definitions: HashMap, - cursor_to_references: HashMap, - extension_hooks: HashSet, -} - -#[derive(Clone)] -pub enum FileDescriptor { - User(String), - System(String), -} - -#[derive(Debug)] -pub(crate) struct FileDescriptorError; - -impl FileDescriptor { - // Internal functions to convert a FileDescriptor to and from a string for - // representation inside the stack graph - - pub(crate) fn as_string(&self) -> String { - match self { - Self::User(path) => format!("user:{path}"), - Self::System(path) => format!("system:{path}"), - } - } - - pub(crate) fn try_from(value: &str) -> Result { - value - .strip_prefix("user:") - .map(|path| FileDescriptor::User(path.into())) - .or_else(|| { - value - .strip_prefix("system:") - .map(|path| FileDescriptor::System(path.into())) - }) - .ok_or(FileDescriptorError) - } - - pub(crate) fn from(value: &str) -> Self { - Self::try_from(value) - .unwrap_or_else(|_| panic!("{value} should be a valid file descriptor")) - } - - pub fn get_path(&self) -> &str { - match self { - Self::User(path) => path, - Self::System(path) => path, - } - } - - pub fn is_system(&self) -> bool { - matches!(self, Self::System(_)) - } - - pub fn is_user(&self) -> bool { - matches!(self, Self::User(_)) - } - - pub fn is_user_path(&self, path: &str) -> bool { - matches!(self, Self::User(user_path) if user_path == path) - } -} - -pub trait PathResolver { - fn resolve_path(&self, context_path: &str, path_to_resolve: &Cursor) -> Option; -} - -impl BindingGraphBuilder { - pub fn create( - version: Version, - binding_rules: &str, - path_resolver: Rc>, - ) -> Self { - let graph_builder_file = - File::from_str(binding_rules).expect("Bindings stack graph builder parse error"); - let stack_graph = StackGraph::new(); - let functions = loader::default_functions(version, path_resolver); - - Self { - graph_builder_file, - functions, - stack_graph, - cursors: HashMap::new(), - definitions_info: HashMap::new(), - references_info: HashMap::new(), - cursor_to_definitions: HashMap::new(), - cursor_to_references: HashMap::new(), - extension_hooks: HashSet::new(), - } - } - - pub fn add_system_file(&mut self, file_path: &str, tree_cursor: Cursor) { - let file_kind = FileDescriptor::System(file_path.into()); - let file = self.stack_graph.get_or_create_file(&file_kind.as_string()); - _ = self.add_file_internal(file, tree_cursor); - } - - pub fn add_user_file(&mut self, file_path: &str, tree_cursor: Cursor) { - let file_kind = FileDescriptor::User(file_path.into()); - let file = self.stack_graph.get_or_create_file(&file_kind.as_string()); - _ = self.add_file_internal(file, tree_cursor); - } - - #[cfg(feature = "__private_testing_utils")] - pub fn add_user_file_returning_graph( - &mut self, - file_path: &str, - tree_cursor: Cursor, - ) -> metaslang_graph_builder::graph::Graph { - let file_kind = FileDescriptor::User(file_path.into()); - let file = self.stack_graph.get_or_create_file(&file_kind.as_string()); - let result = self.add_file_internal(file, tree_cursor); - result.graph - } - - fn add_file_internal(&mut self, file: FileHandle, tree_cursor: Cursor) -> BuildResult { - let loader = Loader::new( - &self.graph_builder_file, - &self.functions, - &mut self.stack_graph, - file, - tree_cursor, - ); - let mut result = loader - .execute(&loader::NoCancellation) - .expect("Internal error while building bindings"); - - for (handle, cursor) in result.cursors.drain() { - let cursor_id = cursor.node().id(); - if self.stack_graph[handle].is_definition() { - self.cursor_to_definitions.insert(cursor_id, handle); - } else { - self.cursor_to_references.insert(cursor_id, handle); - } - self.cursors.insert(handle, cursor); - } - self.definitions_info - .extend(result.definitions_info.drain()); - self.references_info.extend(result.references_info.drain()); - self.extension_hooks.extend(result.extension_hooks.drain()); - - result - } - - pub fn resolve(self) -> Rc> { - let resolver = Resolver::new(&self); - let resolved_references = resolver.resolve(); - BindingGraph::build(self, resolved_references) - } - - fn get_parents(&self, handle: GraphHandle) -> Vec { - if self.is_definition(handle) { - self.definitions_info - .get(&handle) - .map(|info| info.parents.clone()) - .unwrap_or_default() - } else { - self.references_info - .get(&handle) - .map(|info| info.parents.clone()) - .unwrap_or_default() - } - } - - fn is_definition(&self, handle: GraphHandle) -> bool { - self.stack_graph[handle].is_definition() - } - - fn is_reference(&self, handle: GraphHandle) -> bool { - self.stack_graph[handle].is_reference() - } - - fn get_extension_scope(&self, handle: GraphHandle) -> Option { - self.definitions_info - .get(&handle) - .and_then(|info| info.extension_scope) - } - - fn inherits_extensions(&self, handle: GraphHandle) -> bool { - self.definitions_info - .get(&handle) - .is_some_and(|info| info.inherit_extensions) - } - - fn get_file(&self, handle: GraphHandle) -> Option { - self.stack_graph[handle] - .file() - .map(|file| FileDescriptor::from(self.stack_graph[file].name())) - } - - pub(crate) fn is_extension_hook(&self, node_handle: GraphHandle) -> bool { - self.extension_hooks.contains(&node_handle) - } -} +pub use builder::{BindingGraphBuilder, PathResolver}; +pub use graph::{ + BindingGraph, BindingLocation, BuiltInLocation, Definition, Reference, UserFileLocation, +};