From 96bdf7ba6b5324288da865c842ac9b890aa17198 Mon Sep 17 00:00:00 2001 From: OmarTawfik <15987992+OmarTawfik@users.noreply.github.com> Date: Wed, 11 Dec 2024 06:59:56 -0800 Subject: [PATCH] --- --- .../cargo/crate/src/runtime/bindings/mod.rs | 7 +- .../crate/src/runtime/compilation/unit.rs | 6 +- .../cargo/wasm/src/runtime/config.json.jinja2 | 50 ++++++ .../wasm/src/runtime/generated/config.json | 50 ++++++ .../src/runtime/interface/bindings.wit.jinja2 | 84 ++++++++++ .../runtime/interface/generated/bindings.wit | 84 ++++++++++ .../wasm/src/runtime/wrappers/bindings/mod.rs | 149 ++++++++++++++++- .../src/runtime/wrappers/compilation/mod.rs | 2 +- .../bindings/generated/public_api.txt | 48 ++++-- crates/metaslang/bindings/src/lib.rs | 155 +++++++++++++----- crates/metaslang/bindings/src/location/mod.rs | 37 +++++ .../graph_builder/generated/public_api.txt | 2 +- .../cargo/crate/generated/public_api.txt | 5 +- .../cargo/crate/src/generated/bindings/mod.rs | 7 +- .../crate/src/generated/compilation/unit.rs | 6 +- .../src/bindings_assertions/assertions.rs | 31 ++-- .../tests/src/bindings_output/renderer.rs | 13 +- .../wasm/src/generated/generated/config.json | 50 ++++++ .../interface/generated/bindings.wit | 84 ++++++++++ .../src/generated/wrappers/bindings/mod.rs | 149 ++++++++++++++++- .../src/generated/wrappers/compilation/mod.rs | 2 +- .../solidity/testing/sanctuary/src/tests.rs | 2 +- .../cargo/crate/src/generated/bindings/mod.rs | 7 +- .../crate/src/generated/compilation/unit.rs | 6 +- .../wasm/src/generated/generated/config.json | 50 ++++++ .../interface/generated/bindings.wit | 84 ++++++++++ .../src/generated/wrappers/bindings/mod.rs | 149 ++++++++++++++++- .../src/generated/wrappers/compilation/mod.rs | 2 +- 28 files changed, 1213 insertions(+), 108 deletions(-) create mode 100644 crates/metaslang/bindings/src/location/mod.rs diff --git a/crates/codegen/runtime/cargo/crate/src/runtime/bindings/mod.rs b/crates/codegen/runtime/cargo/crate/src/runtime/bindings/mod.rs index 7c451c1b9c..d7c00c6f39 100644 --- a/crates/codegen/runtime/cargo/crate/src/runtime/bindings/mod.rs +++ b/crates/codegen/runtime/cargo/crate/src/runtime/bindings/mod.rs @@ -12,8 +12,13 @@ use crate::cst::KindTypes; pub type BindingGraph = metaslang_bindings::BindingGraph; pub type Definition<'a> = metaslang_bindings::Definition<'a, KindTypes>; +pub type DefinitionsIterator<'a, I> = metaslang_bindings::DefinitionsIterator<'a, KindTypes, I>; pub type Reference<'a> = metaslang_bindings::Reference<'a, KindTypes>; -pub use metaslang_bindings::PathResolver; +pub type ReferencesIterator<'a, I> = metaslang_bindings::ReferencesIterator<'a, KindTypes, I>; +pub type BindingLocation = metaslang_bindings::BindingLocation; +pub type UserFileLocation = metaslang_bindings::UserFileLocation; + +pub use metaslang_bindings::{BuiltInLocation, PathResolver}; pub fn create_with_resolver( version: Version, diff --git a/crates/codegen/runtime/cargo/crate/src/runtime/compilation/unit.rs b/crates/codegen/runtime/cargo/crate/src/runtime/compilation/unit.rs index c7021229c7..9a7fdcf02c 100644 --- a/crates/codegen/runtime/cargo/crate/src/runtime/compilation/unit.rs +++ b/crates/codegen/runtime/cargo/crate/src/runtime/compilation/unit.rs @@ -13,7 +13,7 @@ use crate::cst::{Cursor, KindTypes}; pub struct CompilationUnit { language_version: Version, files: BTreeMap>, - binding_graph: OnceCell>, + binding_graph: OnceCell, } impl CompilationUnit { @@ -37,7 +37,7 @@ impl CompilationUnit { self.files.get(id).cloned() } - pub fn binding_graph(&self) -> &Rc { + pub fn binding_graph(&self) -> &BindingGraph { self.binding_graph.get_or_init(|| { let resolver = Resolver { files: self.files.clone(), @@ -50,7 +50,7 @@ impl CompilationUnit { binding_graph.add_user_file(id, file.create_tree_cursor()); } - Rc::new(binding_graph) + binding_graph }) } } diff --git a/crates/codegen/runtime/cargo/wasm/src/runtime/config.json.jinja2 b/crates/codegen/runtime/cargo/wasm/src/runtime/config.json.jinja2 index 3ebd1c9c73..9b9b535bdc 100644 --- a/crates/codegen/runtime/cargo/wasm/src/runtime/config.json.jinja2 +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/config.json.jinja2 @@ -1,5 +1,55 @@ { "mappings": { + "nomic-foundation:slang:bindings:definition.id()": { + "Function": { + "as_getter": true + } + }, + "nomic-foundation:slang:bindings:definition.name-location()": { + "Function": { + "as_getter": true + } + }, + "nomic-foundation:slang:bindings:definition.definiens-location()": { + "Function": { + "as_getter": true + } + }, + "nomic-foundation:slang:bindings:reference.id()": { + "Function": { + "as_getter": true + } + }, + "nomic-foundation:slang:bindings:reference.location()": { + "Function": { + "as_getter": true + } + }, + "nomic-foundation:slang:bindings:definitions-iterator": { + "Resource": { + "as_iterator": true + } + }, + "nomic-foundation:slang:bindings:references-iterator": { + "Resource": { + "as_iterator": true + } + }, + "nomic-foundation:slang:bindings:binding-location": { + "Variant": { + "as_direct_union_of_resource_classes": true + } + }, + "nomic-foundation:slang:bindings:user-file-location.file-id()": { + "Function": { + "as_getter": true + } + }, + "nomic-foundation:slang:bindings:user-file-location.cursor()": { + "Function": { + "as_getter": true + } + }, "nomic-foundation:slang:compilation:compilation-unit.language-version()": { "Function": { "as_getter": true diff --git a/crates/codegen/runtime/cargo/wasm/src/runtime/generated/config.json b/crates/codegen/runtime/cargo/wasm/src/runtime/generated/config.json index 3ebd1c9c73..9b9b535bdc 100644 --- a/crates/codegen/runtime/cargo/wasm/src/runtime/generated/config.json +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/generated/config.json @@ -1,5 +1,55 @@ { "mappings": { + "nomic-foundation:slang:bindings:definition.id()": { + "Function": { + "as_getter": true + } + }, + "nomic-foundation:slang:bindings:definition.name-location()": { + "Function": { + "as_getter": true + } + }, + "nomic-foundation:slang:bindings:definition.definiens-location()": { + "Function": { + "as_getter": true + } + }, + "nomic-foundation:slang:bindings:reference.id()": { + "Function": { + "as_getter": true + } + }, + "nomic-foundation:slang:bindings:reference.location()": { + "Function": { + "as_getter": true + } + }, + "nomic-foundation:slang:bindings:definitions-iterator": { + "Resource": { + "as_iterator": true + } + }, + "nomic-foundation:slang:bindings:references-iterator": { + "Resource": { + "as_iterator": true + } + }, + "nomic-foundation:slang:bindings:binding-location": { + "Variant": { + "as_direct_union_of_resource_classes": true + } + }, + "nomic-foundation:slang:bindings:user-file-location.file-id()": { + "Function": { + "as_getter": true + } + }, + "nomic-foundation:slang:bindings:user-file-location.cursor()": { + "Function": { + "as_getter": true + } + }, "nomic-foundation:slang:compilation:compilation-unit.language-version()": { "Function": { "as_getter": true diff --git a/crates/codegen/runtime/cargo/wasm/src/runtime/interface/bindings.wit.jinja2 b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/bindings.wit.jinja2 index 15e8cc9233..5130a77f5e 100644 --- a/crates/codegen/runtime/cargo/wasm/src/runtime/interface/bindings.wit.jinja2 +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/bindings.wit.jinja2 @@ -1,4 +1,88 @@ interface bindings { + use cst.{cursor}; + + /// A giant graph that contains name binding information for all source files within the compilation unit. + /// It stores cursors to all definitions and references, and can resolve the edges between them. resource binding-graph { + /// If the provided cursor points at a definition `Identifier`, it will return the + /// corresponding definition. Otherwise, it will return `undefined`. + definition-at: func(cursor: cursor) -> option; + + /// Returns an iterator over all definitions in the graph. + all-definitions: func() -> definitions-iterator; + + /// If the provided cursor points at a reference `Identifier`, it will return the + /// corresponding reference. Otherwise, it will return `undefined`. + reference-at: func(cursor: cursor) -> option; + + /// Returns an iterator over all references in the graph. + all-references: func() -> references-iterator; + } + + /// Represents a definition in the binding graph. + resource definition { + /// Returns a unique numerical identifier of the definition. + /// It is only valid for the lifetime of the binding graph. + /// It can change between multiple graphs, even for the same source code input. + id: func() -> u32; + + /// Returns the location of the definition's name. + /// For `contract X {}`, that is the location of the `X` `Identifier` node. + name-location: func() -> binding-location; + + /// Returns the location of the definition's definiens. + /// For `contract X {}`, that is the location of the parent `ContractDefinition` node. + definiens-location: func() -> binding-location; + } + + /// Represents a reference in the binding graph. + resource reference { + /// Returns a unique numerical identifier of the reference. + /// It is only valid for the lifetime of the binding graph. + /// It can change between multiple graphs, even for the same source code input. + id: func() -> u32; + + /// Returns the location of the reference. + /// For `new X()`, that is the location of the `X` `Identifier` node. + location: func() -> binding-location; + + /// Returns a list of all definitions related to this reference. + /// Most references have a single definition, but some have multiple, such as when a symbol + /// is imported from another file, and renamed (re-defined) in the current file. + find-definitions: func() -> list; + } + + /// Iterator over definitions in the binding graph. + resource definitions-iterator { + /// Returns the next definition in the iteration, or `undefined` if there are no more definitions. + next: func() -> option; + } + + /// Iterator over references in the binding graph. + resource references-iterator { + /// Returns the next reference in the iteration, or `undefined` if there are no more references. + next: func() -> option; + } + + /// Represents a location of a symbol (definition or reference) in the binding graph. + /// It can either be in a user file, or a built-in in the language. + variant binding-location { + /// Represents a location of a user-defined symbol in a user file. + user-file(user-file-location), + /// Represents a location of a built-in symbol in the language. + built-in(built-in-location) + } + + /// Represents a location of a user-defined symbol in a user file. + resource user-file-location { + /// Returns the ID of the file that contains the symbol. + file-id: func() -> string; + + /// Returns a cursor to the CST node that contains the symbol. + cursor: func() -> cursor; + } + + /// Represents a location of a built-in symbol in the language. + resource built-in-location { } } diff --git a/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/bindings.wit b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/bindings.wit index 66f34649d7..c21d621a22 100644 --- a/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/bindings.wit +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/bindings.wit @@ -1,6 +1,90 @@ // This file is generated automatically by infrastructure scripts. Please don't edit by hand. interface bindings { + use cst.{cursor}; + + /// A giant graph that contains name binding information for all source files within the compilation unit. + /// It stores cursors to all definitions and references, and can resolve the edges between them. resource binding-graph { + /// If the provided cursor points at a definition `Identifier`, it will return the + /// corresponding definition. Otherwise, it will return `undefined`. + definition-at: func(cursor: cursor) -> option; + + /// Returns an iterator over all definitions in the graph. + all-definitions: func() -> definitions-iterator; + + /// If the provided cursor points at a reference `Identifier`, it will return the + /// corresponding reference. Otherwise, it will return `undefined`. + reference-at: func(cursor: cursor) -> option; + + /// Returns an iterator over all references in the graph. + all-references: func() -> references-iterator; + } + + /// Represents a definition in the binding graph. + resource definition { + /// Returns a unique numerical identifier of the definition. + /// It is only valid for the lifetime of the binding graph. + /// It can change between multiple graphs, even for the same source code input. + id: func() -> u32; + + /// Returns the location of the definition's name. + /// For `contract X {}`, that is the location of the `X` `Identifier` node. + name-location: func() -> binding-location; + + /// Returns the location of the definition's definiens. + /// For `contract X {}`, that is the location of the parent `ContractDefinition` node. + definiens-location: func() -> binding-location; + } + + /// Represents a reference in the binding graph. + resource reference { + /// Returns a unique numerical identifier of the reference. + /// It is only valid for the lifetime of the binding graph. + /// It can change between multiple graphs, even for the same source code input. + id: func() -> u32; + + /// Returns the location of the reference. + /// For `new X()`, that is the location of the `X` `Identifier` node. + location: func() -> binding-location; + + /// Returns a list of all definitions related to this reference. + /// Most references have a single definition, but some have multiple, such as when a symbol + /// is imported from another file, and renamed (re-defined) in the current file. + find-definitions: func() -> list; + } + + /// Iterator over definitions in the binding graph. + resource definitions-iterator { + /// Returns the next definition in the iteration, or `undefined` if there are no more definitions. + next: func() -> option; + } + + /// Iterator over references in the binding graph. + resource references-iterator { + /// Returns the next reference in the iteration, or `undefined` if there are no more references. + next: func() -> option; + } + + /// Represents a location of a symbol (definition or reference) in the binding graph. + /// It can either be in a user file, or a built-in in the language. + variant binding-location { + /// Represents a location of a user-defined symbol in a user file. + user-file(user-file-location), + /// Represents a location of a built-in symbol in the language. + built-in(built-in-location) + } + + /// Represents a location of a user-defined symbol in a user file. + resource user-file-location { + /// Returns the ID of the file that contains the symbol. + file-id: func() -> string; + + /// Returns a cursor to the CST node that contains the symbol. + cursor: func() -> cursor; + } + + /// Represents a location of a built-in symbol in the language. + resource built-in-location { } } diff --git a/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/bindings/mod.rs b/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/bindings/mod.rs index 04ebfff765..e58afecf81 100644 --- a/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/bindings/mod.rs +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/bindings/mod.rs @@ -1,17 +1,38 @@ -use crate::wasm_crate::utils::define_rc_wrapper; +use std::rc::Rc; + +use crate::wasm_crate::utils::{ + define_rc_wrapper, define_refcell_wrapper, define_wrapper, FromFFI, IntoFFI, +}; mod ffi { pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::bindings::{ - BindingGraph, BindingGraphBorrow, Guest, GuestBindingGraph, + BindingGraph, BindingGraphBorrow, BindingLocation, BuiltInLocation, BuiltInLocationBorrow, + Definition, DefinitionBorrow, DefinitionsIterator, DefinitionsIteratorBorrow, Guest, + GuestBindingGraph, GuestBuiltInLocation, GuestDefinition, GuestDefinitionsIterator, + GuestReference, GuestReferencesIterator, GuestUserFileLocation, Reference, ReferenceBorrow, + ReferencesIterator, ReferencesIteratorBorrow, UserFileLocation, UserFileLocationBorrow, }; + pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::cst::Cursor; } mod rust { - pub use crate::rust_crate::bindings::BindingGraph; + pub use crate::rust_crate::bindings::{ + BindingGraph, BindingLocation, BuiltInLocation, Definition, DefinitionsIterator, Reference, + ReferencesIterator, UserFileLocation, + }; } impl ffi::Guest for crate::wasm_crate::World { type BindingGraph = BindingGraphWrapper; + + type Definition = DefinitionWrapper; + type DefinitionsIterator = DefinitionsIteratorWrapper; + + type Reference = ReferenceWrapper; + type ReferencesIterator = ReferencesIteratorWrapper; + + type UserFileLocation = UserFileLocationWrapper; + type BuiltInLocation = BuiltInLocationWrapper; } //================================================ @@ -20,5 +41,125 @@ impl ffi::Guest for crate::wasm_crate::World { // //================================================ -define_rc_wrapper! { BindingGraph { +define_wrapper! { BindingGraph { + fn definition_at(&self, cursor: ffi::Cursor) -> Option { + self._borrow_ffi().definition_at(cursor._into_ffi()).map(IntoFFI::_into_ffi) + } + + fn all_definitions(&self) -> ffi::DefinitionsIterator { + self._borrow_ffi().all_definitions()._into_ffi() + } + + fn reference_at(&self, cursor: ffi::Cursor) -> Option { + self._borrow_ffi().reference_at(cursor._into_ffi()).map(IntoFFI::_into_ffi) + } + + fn all_references(&self) -> ffi::ReferencesIterator { + self._borrow_ffi().all_references()._into_ffi() + } +} } + +//================================================ +// +// resource definition +// +//================================================ + +define_wrapper! { Definition { + fn id(&self) -> u32 { + self._borrow_ffi().id().try_into().unwrap() + } + + fn name_location(&self) -> ffi::BindingLocation { + self._borrow_ffi().name_location()._into_ffi() + } + + fn definiens_location(&self) -> ffi::BindingLocation { + self._borrow_ffi().definiens_location()._into_ffi() + } +} } + +//================================================ +// +// resource reference +// +//================================================ + +define_wrapper! { Reference { + fn id(&self) -> u32 { + self._borrow_ffi().id() + } + + fn location(&self) -> ffi::BindingLocation { + self._borrow_ffi().location()._into_ffi() + } + + fn find_definitions(&self) -> ffi::DefinitionsIterator { + self._borrow_ffi().find_definitions()._into_ffi() + } +} } + +//================================================ +// +// resource definitions-iterator +// +//================================================ + +define_refcell_wrapper! { DefinitionsIterator { + fn next(&self) -> Option { + self._borrow_mut_ffi().next().map(IntoFFI::_into_ffi) + } +} } + +//================================================ +// +// resource references-iterator +// +//================================================ + +define_refcell_wrapper! { ReferencesIterator { + fn next(&self) -> Option { + self._borrow_mut_ffi().next().map(IntoFFI::_into_ffi) + } +} } + +//================================================ +// +// variant binding-location +// +//================================================ + +impl IntoFFI for rust::BindingLocation { + #[inline] + fn _into_ffi(self) -> ffi::BindingLocation { + match self { + Self::BuiltIn(location) => ffi::BindingLocation::BuiltIn(location._into_ffi()), + Self::UserFile(location) => ffi::BindingLocation::UserFile(location._into_ffi()), + } + } +} + +//================================================ +// +// resource user-file-location +// +//================================================ + +define_wrapper! { UserFileLocation { + fn file_id(&self) -> String { + self._borrow_ffi().file_id().to_owned() + } + + fn cursor(&self) -> ffi::Cursor { + self._borrow_ffi().cursor()._into_ffi() + } +} } + +//================================================ +// +// resource built-in-location +// +//================================================ + +define_wrapper! { BuiltInLocation { } } diff --git a/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/compilation/mod.rs b/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/compilation/mod.rs index 9c4a244398..d9d7a2b5cc 100644 --- a/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/compilation/mod.rs +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/compilation/mod.rs @@ -96,7 +96,7 @@ define_rc_wrapper! { CompilationUnit { } fn binding_graph(&self) -> ffi::BindingGraph { - Rc::clone(self._borrow_ffi().binding_graph())._into_ffi() + self._borrow_ffi().binding_graph()._into_ffi() } } } diff --git a/crates/metaslang/bindings/generated/public_api.txt b/crates/metaslang/bindings/generated/public_api.txt index c2aba59a02..47a055df61 100644 --- a/crates/metaslang/bindings/generated/public_api.txt +++ b/crates/metaslang/bindings/generated/public_api.txt @@ -1,6 +1,12 @@ # This file is generated automatically by infrastructure scripts. Please don't edit by hand. pub mod metaslang_bindings +pub enum metaslang_bindings::BindingLocation +pub metaslang_bindings::BindingLocation::BuiltIn(metaslang_bindings::BuiltInLocation) +pub metaslang_bindings::BindingLocation::UserFile(metaslang_bindings::UserFileLocation) +impl metaslang_bindings::BindingLocation +pub fn metaslang_bindings::BindingLocation::built_in() -> Self +pub fn metaslang_bindings::BindingLocation::user_file(file_id: alloc::string::String, cursor: metaslang_cst::cursor::Cursor) -> Self pub enum metaslang_bindings::FileDescriptor pub metaslang_bindings::FileDescriptor::System(alloc::string::String) pub metaslang_bindings::FileDescriptor::User(alloc::string::String) @@ -12,24 +18,28 @@ pub fn metaslang_bindings::FileDescriptor::is_user_path(&self, path: &str) -> bo pub enum metaslang_bindings::ResolutionError<'a, KT: metaslang_cst::kinds::KindTypes + 'static> pub metaslang_bindings::ResolutionError::AmbiguousDefinitions(alloc::vec::Vec>) pub metaslang_bindings::ResolutionError::Unresolved -pub struct metaslang_bindings::Bindings -impl metaslang_bindings::Bindings -pub fn metaslang_bindings::Bindings::add_system_file(&mut self, file_path: &str, tree_cursor: metaslang_cst::cursor::Cursor) -pub fn metaslang_bindings::Bindings::add_user_file(&mut self, file_path: &str, tree_cursor: metaslang_cst::cursor::Cursor) -pub fn metaslang_bindings::Bindings::add_user_file_returning_graph(&mut self, file_path: &str, tree_cursor: metaslang_cst::cursor::Cursor) -> metaslang_graph_builder::graph::Graph -pub fn metaslang_bindings::Bindings::all_definitions(&self) -> impl core::iter::traits::iterator::Iterator> + '_ -pub fn metaslang_bindings::Bindings::all_references(&self) -> impl core::iter::traits::iterator::Iterator> + '_ -pub fn metaslang_bindings::Bindings::create(version: semver::Version, binding_rules: &str, path_resolver: alloc::sync::Arc<(dyn metaslang_bindings::PathResolver + core::marker::Sync + core::marker::Send)>) -> Self -pub fn metaslang_bindings::Bindings::definition_at(&self, cursor: &metaslang_cst::cursor::Cursor) -> core::option::Option> -pub fn metaslang_bindings::Bindings::get_context(&self) -> core::option::Option> -pub fn metaslang_bindings::Bindings::lookup_definition_by_name(&self, name: &str) -> core::option::Option> -pub fn metaslang_bindings::Bindings::reference_at(&self, cursor: &metaslang_cst::cursor::Cursor) -> core::option::Option> -pub fn metaslang_bindings::Bindings::set_context(&mut self, context: &metaslang_bindings::DefinitionHandle) +pub struct metaslang_bindings::BindingGraph +impl metaslang_bindings::BindingGraph +pub fn metaslang_bindings::BindingGraph::add_system_file(&mut self, file_path: &str, tree_cursor: metaslang_cst::cursor::Cursor) +pub fn metaslang_bindings::BindingGraph::add_user_file(&mut self, file_path: &str, tree_cursor: metaslang_cst::cursor::Cursor) +pub fn metaslang_bindings::BindingGraph::add_user_file_returning_graph(&mut self, file_path: &str, tree_cursor: metaslang_cst::cursor::Cursor) -> metaslang_graph_builder::graph::Graph +pub fn metaslang_bindings::BindingGraph::all_definitions(&self) -> impl core::iter::traits::iterator::Iterator> + '_ +pub fn metaslang_bindings::BindingGraph::all_references(&self) -> impl core::iter::traits::iterator::Iterator> + '_ +pub fn metaslang_bindings::BindingGraph::create(version: semver::Version, binding_rules: &str, path_resolver: alloc::rc::Rc>) -> Self +pub fn metaslang_bindings::BindingGraph::definition_at(&self, cursor: &metaslang_cst::cursor::Cursor) -> core::option::Option> +pub fn metaslang_bindings::BindingGraph::get_context(&self) -> core::option::Option> +pub fn metaslang_bindings::BindingGraph::lookup_definition_by_name(&self, name: &str) -> core::option::Option> +pub fn metaslang_bindings::BindingGraph::reference_at(&self, cursor: &metaslang_cst::cursor::Cursor) -> core::option::Option> +pub fn metaslang_bindings::BindingGraph::set_context(&mut self, context: &metaslang_bindings::DefinitionHandle) +pub struct metaslang_bindings::BuiltInLocation pub struct metaslang_bindings::Definition<'a, KT: metaslang_cst::kinds::KindTypes + 'static> impl<'a, KT: metaslang_cst::kinds::KindTypes + 'static> metaslang_bindings::Definition<'a, KT> -pub fn metaslang_bindings::Definition<'a, KT>::get_cursor(&self) -> core::option::Option> -pub fn metaslang_bindings::Definition<'a, KT>::get_definiens_cursor(&self) -> core::option::Option> +pub fn metaslang_bindings::Definition<'a, KT>::definiens_location(&self) -> metaslang_bindings::BindingLocation +pub fn metaslang_bindings::Definition<'a, KT>::get_cursor(&self) -> &metaslang_cst::cursor::Cursor +pub fn metaslang_bindings::Definition<'a, KT>::get_definiens_cursor(&self) -> &metaslang_cst::cursor::Cursor pub fn metaslang_bindings::Definition<'a, KT>::get_file(&self) -> metaslang_bindings::FileDescriptor +pub fn metaslang_bindings::Definition<'a, KT>::id(&self) -> usize +pub fn metaslang_bindings::Definition<'a, KT>::location(&self) -> metaslang_bindings::BindingLocation pub fn metaslang_bindings::Definition<'a, KT>::to_handle(self) -> metaslang_bindings::DefinitionHandle impl<'a, KT: core::clone::Clone + metaslang_cst::kinds::KindTypes + 'static> core::clone::Clone for metaslang_bindings::Definition<'a, KT> pub fn metaslang_bindings::Definition<'a, KT>::clone(&self) -> metaslang_bindings::Definition<'a, KT> @@ -46,14 +56,20 @@ pub struct metaslang_bindings::DefinitionHandle(_) pub struct metaslang_bindings::Reference<'a, KT: metaslang_cst::kinds::KindTypes + 'static> impl<'a, KT: metaslang_cst::kinds::KindTypes + 'static> metaslang_bindings::Reference<'a, KT> pub fn metaslang_bindings::Reference<'a, KT>::definitions(&self) -> alloc::vec::Vec> -pub fn metaslang_bindings::Reference<'a, KT>::get_cursor(&self) -> core::option::Option> +pub fn metaslang_bindings::Reference<'a, KT>::get_cursor(&self) -> &metaslang_cst::cursor::Cursor pub fn metaslang_bindings::Reference<'a, KT>::get_file(&self) -> metaslang_bindings::FileDescriptor +pub fn metaslang_bindings::Reference<'a, KT>::id(&self) -> usize pub fn metaslang_bindings::Reference<'a, KT>::jump_to_definition(&self) -> core::result::Result, metaslang_bindings::ResolutionError<'a, KT>> +pub fn metaslang_bindings::Reference<'a, KT>::location(&self) -> metaslang_bindings::BindingLocation impl<'a, KT: core::clone::Clone + metaslang_cst::kinds::KindTypes + 'static> core::clone::Clone for metaslang_bindings::Reference<'a, KT> pub fn metaslang_bindings::Reference<'a, KT>::clone(&self) -> metaslang_bindings::Reference<'a, KT> impl core::cmp::PartialEq for metaslang_bindings::Reference<'_, KT> pub fn metaslang_bindings::Reference<'_, KT>::eq(&self, other: &Self) -> bool impl core::fmt::Display for metaslang_bindings::Reference<'_, KT> pub fn metaslang_bindings::Reference<'_, KT>::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub struct metaslang_bindings::UserFileLocation +impl metaslang_bindings::UserFileLocation +pub fn metaslang_bindings::UserFileLocation::cursor(&self) -> &metaslang_cst::cursor::Cursor +pub fn metaslang_bindings::UserFileLocation::file_id(&self) -> &str pub trait metaslang_bindings::PathResolver pub fn metaslang_bindings::PathResolver::resolve_path(&self, context_path: &str, path_to_resolve: &metaslang_cst::cursor::Cursor) -> core::option::Option diff --git a/crates/metaslang/bindings/src/lib.rs b/crates/metaslang/bindings/src/lib.rs index f42ca38c0a..59bad4096f 100644 --- a/crates/metaslang/bindings/src/lib.rs +++ b/crates/metaslang/bindings/src/lib.rs @@ -1,4 +1,5 @@ mod builder; +mod location; mod resolver; use std::collections::{HashMap, HashSet}; @@ -19,6 +20,9 @@ type Builder<'a, KT> = builder::Builder<'a, KT>; type GraphHandle = stack_graphs::arena::Handle; type FileHandle = stack_graphs::arena::Handle; type CursorID = usize; + +pub use location::{BindingLocation, BuiltInLocation, UserFileLocation}; + pub struct DefinitionHandle(GraphHandle); #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -202,10 +206,15 @@ impl BindingGraph { } } - pub fn all_definitions(&self) -> impl Iterator> + '_ { - self.stack_graph - .iter_nodes() - .filter_map(|handle| self.to_definition(handle)) + pub fn all_definitions( + &self, + ) -> DefinitionsIterator<'_, KT, impl Iterator> + '_> { + DefinitionsIterator { + inner: self + .stack_graph + .iter_nodes() + .filter_map(|handle| self.to_definition(handle)), + } } fn to_reference(&self, handle: GraphHandle) -> Option> { @@ -219,10 +228,15 @@ impl BindingGraph { } } - pub fn all_references(&self) -> impl Iterator> + '_ { - self.stack_graph - .iter_nodes() - .filter_map(|handle| self.to_reference(handle)) + pub fn all_references( + &self, + ) -> ReferencesIterator<'_, KT, impl Iterator> + '_> { + ReferencesIterator { + inner: self + .stack_graph + .iter_nodes() + .filter_map(|handle| self.to_reference(handle)), + } } pub fn definition_at(&self, cursor: &Cursor) -> Option> { @@ -267,7 +281,7 @@ impl BindingGraph { pub fn lookup_definition_by_name(&self, name: &str) -> Option> { self.all_definitions() - .find(|definition| definition.get_cursor().unwrap().node().unparse() == name) + .find(|definition| definition.get_cursor().node().unparse() == name) } pub fn get_context(&self) -> Option> { @@ -366,15 +380,43 @@ pub struct Definition<'a, KT: KindTypes + 'static> { } impl<'a, KT: KindTypes + 'static> Definition<'a, KT> { - pub fn get_cursor(&self) -> Option> { - self.owner.cursors.get(&self.handle).cloned() + 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 + .cursors + .get(&self.handle) + .expect("Definition does not have a valid cursor") } - pub fn get_definiens_cursor(&self) -> Option> { + pub fn get_definiens_cursor(&self) -> &Cursor { self.owner .definitions_info .get(&self.handle) - .and_then(|info| info.definiens.clone()) + .expect("Definition does not have valid binding info") + .definiens + .as_ref() + .expect("Definiens does not have a valid cursor") } pub fn get_file(&self) -> FileDescriptor { @@ -408,19 +450,14 @@ impl<'a, KT: KindTypes + 'static> Definition<'a, KT> { impl Display for Definition<'_, KT> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.get_cursor() { - Some(cursor) => { - write!( - f, - "definition {}", - DisplayCursor { - cursor: &cursor, - file: self.get_file() - } - ) + write!( + f, + "definition {}", + DisplayCursor { + cursor: self.get_cursor(), + file: self.get_file() } - None => write!(f, "{}", self.handle.display(&self.owner.stack_graph)), - } + ) } } @@ -460,8 +497,24 @@ pub enum ResolutionError<'a, KT: KindTypes + 'static> { } impl<'a, KT: KindTypes + 'static> Reference<'a, KT> { - pub fn get_cursor(&self) -> Option> { - self.owner.cursors.get(&self.handle).cloned() + 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 + .cursors + .get(&self.handle) + .expect("Reference does not have a valid cursor") } pub fn get_file(&self) -> FileDescriptor { @@ -499,19 +552,14 @@ impl<'a, KT: KindTypes + 'static> Reference<'a, KT> { impl Display for Reference<'_, KT> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.get_cursor() { - Some(cursor) => { - write!( - f, - "reference {}", - DisplayCursor { - cursor: &cursor, - file: self.get_file() - } - ) + write!( + f, + "reference {}", + DisplayCursor { + cursor: self.get_cursor(), + file: self.get_file() } - None => write!(f, "{}", self.handle.display(&self.owner.stack_graph)), - } + ) } } @@ -522,3 +570,32 @@ impl PartialEq for Reference<'_, KT> { our_owner == other_owner && self.handle == other.handle } } + +pub struct DefinitionsIterator<'a, KT: KindTypes + 'static, I: Iterator>> +{ + inner: I, +} + +impl<'a, KT: KindTypes + 'static, I: Iterator>> Iterator + for DefinitionsIterator<'a, KT, I> +{ + type Item = Definition<'a, KT>; + + fn next(&mut self) -> Option { + self.inner.next() + } +} + +pub struct ReferencesIterator<'a, KT: KindTypes + 'static, I: Iterator>> { + inner: I, +} + +impl<'a, KT: KindTypes + 'static, I: Iterator>> Iterator + for ReferencesIterator<'a, KT, I> +{ + type Item = Reference<'a, KT>; + + fn next(&mut self) -> Option { + self.inner.next() + } +} diff --git a/crates/metaslang/bindings/src/location/mod.rs b/crates/metaslang/bindings/src/location/mod.rs new file mode 100644 index 0000000000..c8dde46413 --- /dev/null +++ b/crates/metaslang/bindings/src/location/mod.rs @@ -0,0 +1,37 @@ +use metaslang_cst::cursor::Cursor; +use metaslang_cst::kinds::KindTypes; + +pub enum BindingLocation { + UserFile(UserFileLocation), + BuiltIn(BuiltInLocation), +} + +impl BindingLocation { + pub fn user_file(file_id: String, cursor: Cursor) -> Self { + Self::UserFile(UserFileLocation { file_id, cursor }) + } + + pub fn built_in() -> Self { + Self::BuiltIn(BuiltInLocation {}) + } +} + +pub struct UserFileLocation { + file_id: String, + cursor: Cursor, +} + +impl UserFileLocation { + pub fn file_id(&self) -> &str { + &self.file_id + } + + pub fn cursor(&self) -> &Cursor { + &self.cursor + } +} + +pub struct BuiltInLocation { + // We are not exposing a `file_id` or a `cursor` here, because we don't expose the underlying `built_ins.sol` file yet. + // Still, we are using a dedicated type here to make it easier to map to the corresponding WIT variant. +} diff --git a/crates/metaslang/graph_builder/generated/public_api.txt b/crates/metaslang/graph_builder/generated/public_api.txt index 4d62231805..3010fc6ffc 100644 --- a/crates/metaslang/graph_builder/generated/public_api.txt +++ b/crates/metaslang/graph_builder/generated/public_api.txt @@ -599,7 +599,7 @@ impl metaslang_graph_builder::functions::Fu pub fn metaslang_graph_builder::functions::stdlib::IsNull::call(&self, _graph: &mut metaslang_graph_builder::graph::Graph, parameters: &mut dyn metaslang_graph_builder::functions::Parameters) -> core::result::Result pub struct metaslang_graph_builder::functions::Functions impl metaslang_graph_builder::functions::Functions -pub fn metaslang_graph_builder::functions::Functions::add(&mut self, name: metaslang_graph_builder::Identifier, function: F) where F: metaslang_graph_builder::functions::Function + core::marker::Send + core::marker::Sync + 'static +pub fn metaslang_graph_builder::functions::Functions::add(&mut self, name: metaslang_graph_builder::Identifier, function: F) where F: metaslang_graph_builder::functions::Function + 'static pub fn metaslang_graph_builder::functions::Functions::call(&self, name: &metaslang_graph_builder::Identifier, graph: &mut metaslang_graph_builder::graph::Graph, parameters: &mut dyn metaslang_graph_builder::functions::Parameters) -> core::result::Result pub fn metaslang_graph_builder::functions::Functions::new() -> metaslang_graph_builder::functions::Functions pub fn metaslang_graph_builder::functions::Functions::stdlib() -> metaslang_graph_builder::functions::Functions diff --git a/crates/solidity/outputs/cargo/crate/generated/public_api.txt b/crates/solidity/outputs/cargo/crate/generated/public_api.txt index 355ce7f18c..ef0cf06a96 100644 --- a/crates/solidity/outputs/cargo/crate/generated/public_api.txt +++ b/crates/solidity/outputs/cargo/crate/generated/public_api.txt @@ -3,10 +3,10 @@ pub mod slang_solidity pub mod slang_solidity::bindings pub use slang_solidity::bindings::PathResolver -pub fn slang_solidity::bindings::create_with_resolver(version: semver::Version, resolver: alloc::sync::Arc<(dyn metaslang_bindings::PathResolver + core::marker::Sync + core::marker::Send)>) -> slang_solidity::bindings::Bindings +pub fn slang_solidity::bindings::create_with_resolver(version: semver::Version, resolver: alloc::rc::Rc>) -> slang_solidity::bindings::BindingGraph pub fn slang_solidity::bindings::get_binding_rules() -> &'static str pub fn slang_solidity::bindings::get_built_ins(version: &semver::Version) -> &'static str -pub type slang_solidity::bindings::Bindings = metaslang_bindings::Bindings +pub type slang_solidity::bindings::BindingGraph = metaslang_bindings::BindingGraph pub type slang_solidity::bindings::Definition<'a> = metaslang_bindings::Definition<'a, slang_solidity::cst::KindTypes> pub type slang_solidity::bindings::Reference<'a> = metaslang_bindings::Reference<'a, slang_solidity::cst::KindTypes> pub mod slang_solidity::compilation @@ -14,6 +14,7 @@ pub struct slang_solidity::compilation::AddFileResponse pub slang_solidity::compilation::AddFileResponse::import_paths: alloc::vec::Vec pub struct slang_solidity::compilation::CompilationUnit impl slang_solidity::compilation::CompilationUnit +pub fn slang_solidity::compilation::CompilationUnit::binding_graph(&self) -> &alloc::rc::Rc pub fn slang_solidity::compilation::CompilationUnit::file(&self, id: &str) -> core::option::Option> pub fn slang_solidity::compilation::CompilationUnit::files(&self) -> alloc::vec::Vec> pub fn slang_solidity::compilation::CompilationUnit::language_version(&self) -> &semver::Version diff --git a/crates/solidity/outputs/cargo/crate/src/generated/bindings/mod.rs b/crates/solidity/outputs/cargo/crate/src/generated/bindings/mod.rs index 6c320c5737..e1712a184e 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/bindings/mod.rs +++ b/crates/solidity/outputs/cargo/crate/src/generated/bindings/mod.rs @@ -14,8 +14,13 @@ use crate::cst::KindTypes; pub type BindingGraph = metaslang_bindings::BindingGraph; pub type Definition<'a> = metaslang_bindings::Definition<'a, KindTypes>; +pub type DefinitionsIterator<'a, I> = metaslang_bindings::DefinitionsIterator<'a, KindTypes, I>; pub type Reference<'a> = metaslang_bindings::Reference<'a, KindTypes>; -pub use metaslang_bindings::PathResolver; +pub type ReferencesIterator<'a, I> = metaslang_bindings::ReferencesIterator<'a, KindTypes, I>; +pub type BindingLocation = metaslang_bindings::BindingLocation; +pub type UserFileLocation = metaslang_bindings::UserFileLocation; + +pub use metaslang_bindings::{BuiltInLocation, PathResolver}; pub fn create_with_resolver( version: Version, diff --git a/crates/solidity/outputs/cargo/crate/src/generated/compilation/unit.rs b/crates/solidity/outputs/cargo/crate/src/generated/compilation/unit.rs index acd812e692..4d2a98d951 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/compilation/unit.rs +++ b/crates/solidity/outputs/cargo/crate/src/generated/compilation/unit.rs @@ -15,7 +15,7 @@ use crate::cst::{Cursor, KindTypes}; pub struct CompilationUnit { language_version: Version, files: BTreeMap>, - binding_graph: OnceCell>, + binding_graph: OnceCell, } impl CompilationUnit { @@ -39,7 +39,7 @@ impl CompilationUnit { self.files.get(id).cloned() } - pub fn binding_graph(&self) -> &Rc { + pub fn binding_graph(&self) -> &BindingGraph { self.binding_graph.get_or_init(|| { let resolver = Resolver { files: self.files.clone(), @@ -52,7 +52,7 @@ impl CompilationUnit { binding_graph.add_user_file(id, file.create_tree_cursor()); } - Rc::new(binding_graph) + binding_graph }) } } diff --git a/crates/solidity/outputs/cargo/tests/src/bindings_assertions/assertions.rs b/crates/solidity/outputs/cargo/tests/src/bindings_assertions/assertions.rs index 2882e14d0e..d313df5fe5 100644 --- a/crates/solidity/outputs/cargo/tests/src/bindings_assertions/assertions.rs +++ b/crates/solidity/outputs/cargo/tests/src/bindings_assertions/assertions.rs @@ -320,7 +320,11 @@ pub fn check_assertions( ) -> Result { let mut failures: Vec = Vec::new(); - check_definitions(binding_graph, assertions.definitions.values(), &mut failures); + check_definitions( + binding_graph, + assertions.definitions.values(), + &mut failures, + ); check_references( binding_graph, version, @@ -374,7 +378,9 @@ fn check_references<'a>( failures: &mut Vec, ) { for assertion in references { - if let Err(failure) = check_reference_assertion(binding_graph, definitions, version, assertion) { + if let Err(failure) = + check_reference_assertion(binding_graph, definitions, version, assertion) + { failures.push(failure); } } @@ -411,11 +417,11 @@ fn check_reference_assertion( match (version_matches, id) { (true, None) => { if let Some(resolved_handle) = resolution { - let resolved_cursor = resolved_handle.get_cursor().unwrap(); + let resolved_cursor = resolved_handle.get_cursor(); let resolved_file = resolved_handle.get_file(); return Err(format!( "{assertion} failed: expected not to resolve, but instead resolved to {resolved}", - resolved = DisplayCursor(&resolved_cursor, resolved_file.get_path()) + resolved = DisplayCursor(resolved_cursor, resolved_file.get_path()) )); } } @@ -425,14 +431,15 @@ fn check_reference_assertion( "{assertion} failed: did not resolve or ambiguous resolution" )); }; - let resolved_cursor = resolved_handle.get_cursor().unwrap(); - let expected_handle = lookup_referenced_definition(binding_graph, definitions, assertion)?; - let expected_cursor = expected_handle.get_cursor().unwrap(); + let resolved_cursor = resolved_handle.get_cursor(); + let expected_handle = + lookup_referenced_definition(binding_graph, definitions, assertion)?; + let expected_cursor = expected_handle.get_cursor(); if expected_cursor != resolved_cursor { return Err(format!( "{assertion} failed: expected resolve to {expected}, but instead resolved to {resolved}", - resolved = DisplayCursor(&resolved_cursor, resolved_handle.get_file().get_path()), - expected = DisplayCursor(&expected_cursor, expected_handle.get_file().get_path()), + resolved = DisplayCursor(resolved_cursor, resolved_handle.get_file().get_path()), + expected = DisplayCursor(expected_cursor, expected_handle.get_file().get_path()), )); } } @@ -445,15 +452,15 @@ fn check_reference_assertion( } (false, Some(_)) => { if let Some(resolved_handle) = resolution { - let resolved_cursor = resolved_handle.get_cursor().unwrap(); + let resolved_cursor = resolved_handle.get_cursor(); let referenced_handle = lookup_referenced_definition(binding_graph, definitions, assertion)?; - let referenced_cursor = referenced_handle.get_cursor().unwrap(); + let referenced_cursor = referenced_handle.get_cursor(); if referenced_cursor == resolved_cursor { return Err(format!( "{assertion} failed: expected to not resolve to {resolved} in this version", resolved = - DisplayCursor(&resolved_cursor, resolved_handle.get_file().get_path()), + DisplayCursor(resolved_cursor, resolved_handle.get_file().get_path()), )); } } diff --git a/crates/solidity/outputs/cargo/tests/src/bindings_output/renderer.rs b/crates/solidity/outputs/cargo/tests/src/bindings_output/renderer.rs index 5854582a9a..423b7c9910 100644 --- a/crates/solidity/outputs/cargo/tests/src/bindings_output/renderer.rs +++ b/crates/solidity/outputs/cargo/tests/src/bindings_output/renderer.rs @@ -55,7 +55,7 @@ pub(crate) fn render_bindings( fn collect_all_definitions(binding_graph: &BindingGraph) -> Vec> { let mut definitions: Vec> = Vec::new(); for definition in binding_graph.all_definitions() { - if definition.get_file().is_user() && definition.get_cursor().is_some() { + if definition.get_file().is_user() { definitions.push(definition); } } @@ -86,15 +86,12 @@ fn build_report_for_part<'a>( .with_config(Config::default().with_color(false)); for (index, definition) in all_definitions.iter().enumerate() { - let Some(cursor) = definition.get_cursor() else { - continue; - }; if !definition.get_file().is_user_path(part.path) { continue; } let range = { - let range = cursor.text_range(); + let range = definition.get_cursor().text_range(); let start = part.contents[..range.start.utf8].chars().count(); let end = part.contents[..range.end.utf8].chars().count(); start..end @@ -107,12 +104,8 @@ fn build_report_for_part<'a>( let mut all_resolved = true; for reference in part_references { - let Some(cursor) = reference.get_cursor() else { - continue; - }; - let range = { - let range = cursor.text_range(); + let range = reference.get_cursor().text_range(); let start = part.contents[..range.start.utf8].chars().count(); let end = part.contents[..range.end.utf8].chars().count(); start..end diff --git a/crates/solidity/outputs/cargo/wasm/src/generated/generated/config.json b/crates/solidity/outputs/cargo/wasm/src/generated/generated/config.json index 3ebd1c9c73..9b9b535bdc 100644 --- a/crates/solidity/outputs/cargo/wasm/src/generated/generated/config.json +++ b/crates/solidity/outputs/cargo/wasm/src/generated/generated/config.json @@ -1,5 +1,55 @@ { "mappings": { + "nomic-foundation:slang:bindings:definition.id()": { + "Function": { + "as_getter": true + } + }, + "nomic-foundation:slang:bindings:definition.name-location()": { + "Function": { + "as_getter": true + } + }, + "nomic-foundation:slang:bindings:definition.definiens-location()": { + "Function": { + "as_getter": true + } + }, + "nomic-foundation:slang:bindings:reference.id()": { + "Function": { + "as_getter": true + } + }, + "nomic-foundation:slang:bindings:reference.location()": { + "Function": { + "as_getter": true + } + }, + "nomic-foundation:slang:bindings:definitions-iterator": { + "Resource": { + "as_iterator": true + } + }, + "nomic-foundation:slang:bindings:references-iterator": { + "Resource": { + "as_iterator": true + } + }, + "nomic-foundation:slang:bindings:binding-location": { + "Variant": { + "as_direct_union_of_resource_classes": true + } + }, + "nomic-foundation:slang:bindings:user-file-location.file-id()": { + "Function": { + "as_getter": true + } + }, + "nomic-foundation:slang:bindings:user-file-location.cursor()": { + "Function": { + "as_getter": true + } + }, "nomic-foundation:slang:compilation:compilation-unit.language-version()": { "Function": { "as_getter": true diff --git a/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/bindings.wit b/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/bindings.wit index 66f34649d7..c21d621a22 100644 --- a/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/bindings.wit +++ b/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/bindings.wit @@ -1,6 +1,90 @@ // This file is generated automatically by infrastructure scripts. Please don't edit by hand. interface bindings { + use cst.{cursor}; + + /// A giant graph that contains name binding information for all source files within the compilation unit. + /// It stores cursors to all definitions and references, and can resolve the edges between them. resource binding-graph { + /// If the provided cursor points at a definition `Identifier`, it will return the + /// corresponding definition. Otherwise, it will return `undefined`. + definition-at: func(cursor: cursor) -> option; + + /// Returns an iterator over all definitions in the graph. + all-definitions: func() -> definitions-iterator; + + /// If the provided cursor points at a reference `Identifier`, it will return the + /// corresponding reference. Otherwise, it will return `undefined`. + reference-at: func(cursor: cursor) -> option; + + /// Returns an iterator over all references in the graph. + all-references: func() -> references-iterator; + } + + /// Represents a definition in the binding graph. + resource definition { + /// Returns a unique numerical identifier of the definition. + /// It is only valid for the lifetime of the binding graph. + /// It can change between multiple graphs, even for the same source code input. + id: func() -> u32; + + /// Returns the location of the definition's name. + /// For `contract X {}`, that is the location of the `X` `Identifier` node. + name-location: func() -> binding-location; + + /// Returns the location of the definition's definiens. + /// For `contract X {}`, that is the location of the parent `ContractDefinition` node. + definiens-location: func() -> binding-location; + } + + /// Represents a reference in the binding graph. + resource reference { + /// Returns a unique numerical identifier of the reference. + /// It is only valid for the lifetime of the binding graph. + /// It can change between multiple graphs, even for the same source code input. + id: func() -> u32; + + /// Returns the location of the reference. + /// For `new X()`, that is the location of the `X` `Identifier` node. + location: func() -> binding-location; + + /// Returns a list of all definitions related to this reference. + /// Most references have a single definition, but some have multiple, such as when a symbol + /// is imported from another file, and renamed (re-defined) in the current file. + find-definitions: func() -> list; + } + + /// Iterator over definitions in the binding graph. + resource definitions-iterator { + /// Returns the next definition in the iteration, or `undefined` if there are no more definitions. + next: func() -> option; + } + + /// Iterator over references in the binding graph. + resource references-iterator { + /// Returns the next reference in the iteration, or `undefined` if there are no more references. + next: func() -> option; + } + + /// Represents a location of a symbol (definition or reference) in the binding graph. + /// It can either be in a user file, or a built-in in the language. + variant binding-location { + /// Represents a location of a user-defined symbol in a user file. + user-file(user-file-location), + /// Represents a location of a built-in symbol in the language. + built-in(built-in-location) + } + + /// Represents a location of a user-defined symbol in a user file. + resource user-file-location { + /// Returns the ID of the file that contains the symbol. + file-id: func() -> string; + + /// Returns a cursor to the CST node that contains the symbol. + cursor: func() -> cursor; + } + + /// Represents a location of a built-in symbol in the language. + resource built-in-location { } } diff --git a/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/bindings/mod.rs b/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/bindings/mod.rs index 3db806685d..8fdadc7874 100644 --- a/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/bindings/mod.rs +++ b/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/bindings/mod.rs @@ -1,19 +1,40 @@ // This file is generated automatically by infrastructure scripts. Please don't edit by hand. -use crate::wasm_crate::utils::define_rc_wrapper; +use std::rc::Rc; + +use crate::wasm_crate::utils::{ + define_rc_wrapper, define_refcell_wrapper, define_wrapper, FromFFI, IntoFFI, +}; mod ffi { pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::bindings::{ - BindingGraph, BindingGraphBorrow, Guest, GuestBindingGraph, + BindingGraph, BindingGraphBorrow, BindingLocation, BuiltInLocation, BuiltInLocationBorrow, + Definition, DefinitionBorrow, DefinitionsIterator, DefinitionsIteratorBorrow, Guest, + GuestBindingGraph, GuestBuiltInLocation, GuestDefinition, GuestDefinitionsIterator, + GuestReference, GuestReferencesIterator, GuestUserFileLocation, Reference, ReferenceBorrow, + ReferencesIterator, ReferencesIteratorBorrow, UserFileLocation, UserFileLocationBorrow, }; + pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::cst::Cursor; } mod rust { - pub use crate::rust_crate::bindings::BindingGraph; + pub use crate::rust_crate::bindings::{ + BindingGraph, BindingLocation, BuiltInLocation, Definition, DefinitionsIterator, Reference, + ReferencesIterator, UserFileLocation, + }; } impl ffi::Guest for crate::wasm_crate::World { type BindingGraph = BindingGraphWrapper; + + type Definition = DefinitionWrapper; + type DefinitionsIterator = DefinitionsIteratorWrapper; + + type Reference = ReferenceWrapper; + type ReferencesIterator = ReferencesIteratorWrapper; + + type UserFileLocation = UserFileLocationWrapper; + type BuiltInLocation = BuiltInLocationWrapper; } //================================================ @@ -22,5 +43,125 @@ impl ffi::Guest for crate::wasm_crate::World { // //================================================ -define_rc_wrapper! { BindingGraph { +define_wrapper! { BindingGraph { + fn definition_at(&self, cursor: ffi::Cursor) -> Option { + self._borrow_ffi().definition_at(cursor._into_ffi()).map(IntoFFI::_into_ffi) + } + + fn all_definitions(&self) -> ffi::DefinitionsIterator { + self._borrow_ffi().all_definitions()._into_ffi() + } + + fn reference_at(&self, cursor: ffi::Cursor) -> Option { + self._borrow_ffi().reference_at(cursor._into_ffi()).map(IntoFFI::_into_ffi) + } + + fn all_references(&self) -> ffi::ReferencesIterator { + self._borrow_ffi().all_references()._into_ffi() + } +} } + +//================================================ +// +// resource definition +// +//================================================ + +define_wrapper! { Definition { + fn id(&self) -> u32 { + self._borrow_ffi().id().try_into().unwrap() + } + + fn name_location(&self) -> ffi::BindingLocation { + self._borrow_ffi().name_location()._into_ffi() + } + + fn definiens_location(&self) -> ffi::BindingLocation { + self._borrow_ffi().definiens_location()._into_ffi() + } +} } + +//================================================ +// +// resource reference +// +//================================================ + +define_wrapper! { Reference { + fn id(&self) -> u32 { + self._borrow_ffi().id() + } + + fn location(&self) -> ffi::BindingLocation { + self._borrow_ffi().location()._into_ffi() + } + + fn find_definitions(&self) -> ffi::DefinitionsIterator { + self._borrow_ffi().find_definitions()._into_ffi() + } +} } + +//================================================ +// +// resource definitions-iterator +// +//================================================ + +define_refcell_wrapper! { DefinitionsIterator { + fn next(&self) -> Option { + self._borrow_mut_ffi().next().map(IntoFFI::_into_ffi) + } +} } + +//================================================ +// +// resource references-iterator +// +//================================================ + +define_refcell_wrapper! { ReferencesIterator { + fn next(&self) -> Option { + self._borrow_mut_ffi().next().map(IntoFFI::_into_ffi) + } +} } + +//================================================ +// +// variant binding-location +// +//================================================ + +impl IntoFFI for rust::BindingLocation { + #[inline] + fn _into_ffi(self) -> ffi::BindingLocation { + match self { + Self::BuiltIn(location) => ffi::BindingLocation::BuiltIn(location._into_ffi()), + Self::UserFile(location) => ffi::BindingLocation::UserFile(location._into_ffi()), + } + } +} + +//================================================ +// +// resource user-file-location +// +//================================================ + +define_wrapper! { UserFileLocation { + fn file_id(&self) -> String { + self._borrow_ffi().file_id().to_owned() + } + + fn cursor(&self) -> ffi::Cursor { + self._borrow_ffi().cursor()._into_ffi() + } +} } + +//================================================ +// +// resource built-in-location +// +//================================================ + +define_wrapper! { BuiltInLocation { } } diff --git a/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/compilation/mod.rs b/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/compilation/mod.rs index f8d7707dfb..7a93fe736d 100644 --- a/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/compilation/mod.rs +++ b/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/compilation/mod.rs @@ -98,7 +98,7 @@ define_rc_wrapper! { CompilationUnit { } fn binding_graph(&self) -> ffi::BindingGraph { - Rc::clone(self._borrow_ffi().binding_graph())._into_ffi() + self._borrow_ffi().binding_graph()._into_ffi() } } } diff --git a/crates/solidity/testing/sanctuary/src/tests.rs b/crates/solidity/testing/sanctuary/src/tests.rs index 95e053b011..edd3006fff 100644 --- a/crates/solidity/testing/sanctuary/src/tests.rs +++ b/crates/solidity/testing/sanctuary/src/tests.rs @@ -197,7 +197,7 @@ fn run_bindings_check( // We're not interested in the exact definition a reference resolves // to, so we lookup all of them and fail if we find none. if reference.definitions().is_empty() { - let cursor = reference.get_cursor().unwrap(); + let cursor = reference.get_cursor().to_owned(); unresolved.push(UnresolvedReference { cursor }); } } diff --git a/crates/testlang/outputs/cargo/crate/src/generated/bindings/mod.rs b/crates/testlang/outputs/cargo/crate/src/generated/bindings/mod.rs index 6c320c5737..e1712a184e 100644 --- a/crates/testlang/outputs/cargo/crate/src/generated/bindings/mod.rs +++ b/crates/testlang/outputs/cargo/crate/src/generated/bindings/mod.rs @@ -14,8 +14,13 @@ use crate::cst::KindTypes; pub type BindingGraph = metaslang_bindings::BindingGraph; pub type Definition<'a> = metaslang_bindings::Definition<'a, KindTypes>; +pub type DefinitionsIterator<'a, I> = metaslang_bindings::DefinitionsIterator<'a, KindTypes, I>; pub type Reference<'a> = metaslang_bindings::Reference<'a, KindTypes>; -pub use metaslang_bindings::PathResolver; +pub type ReferencesIterator<'a, I> = metaslang_bindings::ReferencesIterator<'a, KindTypes, I>; +pub type BindingLocation = metaslang_bindings::BindingLocation; +pub type UserFileLocation = metaslang_bindings::UserFileLocation; + +pub use metaslang_bindings::{BuiltInLocation, PathResolver}; pub fn create_with_resolver( version: Version, diff --git a/crates/testlang/outputs/cargo/crate/src/generated/compilation/unit.rs b/crates/testlang/outputs/cargo/crate/src/generated/compilation/unit.rs index acd812e692..4d2a98d951 100644 --- a/crates/testlang/outputs/cargo/crate/src/generated/compilation/unit.rs +++ b/crates/testlang/outputs/cargo/crate/src/generated/compilation/unit.rs @@ -15,7 +15,7 @@ use crate::cst::{Cursor, KindTypes}; pub struct CompilationUnit { language_version: Version, files: BTreeMap>, - binding_graph: OnceCell>, + binding_graph: OnceCell, } impl CompilationUnit { @@ -39,7 +39,7 @@ impl CompilationUnit { self.files.get(id).cloned() } - pub fn binding_graph(&self) -> &Rc { + pub fn binding_graph(&self) -> &BindingGraph { self.binding_graph.get_or_init(|| { let resolver = Resolver { files: self.files.clone(), @@ -52,7 +52,7 @@ impl CompilationUnit { binding_graph.add_user_file(id, file.create_tree_cursor()); } - Rc::new(binding_graph) + binding_graph }) } } diff --git a/crates/testlang/outputs/cargo/wasm/src/generated/generated/config.json b/crates/testlang/outputs/cargo/wasm/src/generated/generated/config.json index 3ebd1c9c73..9b9b535bdc 100644 --- a/crates/testlang/outputs/cargo/wasm/src/generated/generated/config.json +++ b/crates/testlang/outputs/cargo/wasm/src/generated/generated/config.json @@ -1,5 +1,55 @@ { "mappings": { + "nomic-foundation:slang:bindings:definition.id()": { + "Function": { + "as_getter": true + } + }, + "nomic-foundation:slang:bindings:definition.name-location()": { + "Function": { + "as_getter": true + } + }, + "nomic-foundation:slang:bindings:definition.definiens-location()": { + "Function": { + "as_getter": true + } + }, + "nomic-foundation:slang:bindings:reference.id()": { + "Function": { + "as_getter": true + } + }, + "nomic-foundation:slang:bindings:reference.location()": { + "Function": { + "as_getter": true + } + }, + "nomic-foundation:slang:bindings:definitions-iterator": { + "Resource": { + "as_iterator": true + } + }, + "nomic-foundation:slang:bindings:references-iterator": { + "Resource": { + "as_iterator": true + } + }, + "nomic-foundation:slang:bindings:binding-location": { + "Variant": { + "as_direct_union_of_resource_classes": true + } + }, + "nomic-foundation:slang:bindings:user-file-location.file-id()": { + "Function": { + "as_getter": true + } + }, + "nomic-foundation:slang:bindings:user-file-location.cursor()": { + "Function": { + "as_getter": true + } + }, "nomic-foundation:slang:compilation:compilation-unit.language-version()": { "Function": { "as_getter": true diff --git a/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/bindings.wit b/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/bindings.wit index 66f34649d7..c21d621a22 100644 --- a/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/bindings.wit +++ b/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/bindings.wit @@ -1,6 +1,90 @@ // This file is generated automatically by infrastructure scripts. Please don't edit by hand. interface bindings { + use cst.{cursor}; + + /// A giant graph that contains name binding information for all source files within the compilation unit. + /// It stores cursors to all definitions and references, and can resolve the edges between them. resource binding-graph { + /// If the provided cursor points at a definition `Identifier`, it will return the + /// corresponding definition. Otherwise, it will return `undefined`. + definition-at: func(cursor: cursor) -> option; + + /// Returns an iterator over all definitions in the graph. + all-definitions: func() -> definitions-iterator; + + /// If the provided cursor points at a reference `Identifier`, it will return the + /// corresponding reference. Otherwise, it will return `undefined`. + reference-at: func(cursor: cursor) -> option; + + /// Returns an iterator over all references in the graph. + all-references: func() -> references-iterator; + } + + /// Represents a definition in the binding graph. + resource definition { + /// Returns a unique numerical identifier of the definition. + /// It is only valid for the lifetime of the binding graph. + /// It can change between multiple graphs, even for the same source code input. + id: func() -> u32; + + /// Returns the location of the definition's name. + /// For `contract X {}`, that is the location of the `X` `Identifier` node. + name-location: func() -> binding-location; + + /// Returns the location of the definition's definiens. + /// For `contract X {}`, that is the location of the parent `ContractDefinition` node. + definiens-location: func() -> binding-location; + } + + /// Represents a reference in the binding graph. + resource reference { + /// Returns a unique numerical identifier of the reference. + /// It is only valid for the lifetime of the binding graph. + /// It can change between multiple graphs, even for the same source code input. + id: func() -> u32; + + /// Returns the location of the reference. + /// For `new X()`, that is the location of the `X` `Identifier` node. + location: func() -> binding-location; + + /// Returns a list of all definitions related to this reference. + /// Most references have a single definition, but some have multiple, such as when a symbol + /// is imported from another file, and renamed (re-defined) in the current file. + find-definitions: func() -> list; + } + + /// Iterator over definitions in the binding graph. + resource definitions-iterator { + /// Returns the next definition in the iteration, or `undefined` if there are no more definitions. + next: func() -> option; + } + + /// Iterator over references in the binding graph. + resource references-iterator { + /// Returns the next reference in the iteration, or `undefined` if there are no more references. + next: func() -> option; + } + + /// Represents a location of a symbol (definition or reference) in the binding graph. + /// It can either be in a user file, or a built-in in the language. + variant binding-location { + /// Represents a location of a user-defined symbol in a user file. + user-file(user-file-location), + /// Represents a location of a built-in symbol in the language. + built-in(built-in-location) + } + + /// Represents a location of a user-defined symbol in a user file. + resource user-file-location { + /// Returns the ID of the file that contains the symbol. + file-id: func() -> string; + + /// Returns a cursor to the CST node that contains the symbol. + cursor: func() -> cursor; + } + + /// Represents a location of a built-in symbol in the language. + resource built-in-location { } } diff --git a/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/bindings/mod.rs b/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/bindings/mod.rs index 3db806685d..8fdadc7874 100644 --- a/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/bindings/mod.rs +++ b/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/bindings/mod.rs @@ -1,19 +1,40 @@ // This file is generated automatically by infrastructure scripts. Please don't edit by hand. -use crate::wasm_crate::utils::define_rc_wrapper; +use std::rc::Rc; + +use crate::wasm_crate::utils::{ + define_rc_wrapper, define_refcell_wrapper, define_wrapper, FromFFI, IntoFFI, +}; mod ffi { pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::bindings::{ - BindingGraph, BindingGraphBorrow, Guest, GuestBindingGraph, + BindingGraph, BindingGraphBorrow, BindingLocation, BuiltInLocation, BuiltInLocationBorrow, + Definition, DefinitionBorrow, DefinitionsIterator, DefinitionsIteratorBorrow, Guest, + GuestBindingGraph, GuestBuiltInLocation, GuestDefinition, GuestDefinitionsIterator, + GuestReference, GuestReferencesIterator, GuestUserFileLocation, Reference, ReferenceBorrow, + ReferencesIterator, ReferencesIteratorBorrow, UserFileLocation, UserFileLocationBorrow, }; + pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::cst::Cursor; } mod rust { - pub use crate::rust_crate::bindings::BindingGraph; + pub use crate::rust_crate::bindings::{ + BindingGraph, BindingLocation, BuiltInLocation, Definition, DefinitionsIterator, Reference, + ReferencesIterator, UserFileLocation, + }; } impl ffi::Guest for crate::wasm_crate::World { type BindingGraph = BindingGraphWrapper; + + type Definition = DefinitionWrapper; + type DefinitionsIterator = DefinitionsIteratorWrapper; + + type Reference = ReferenceWrapper; + type ReferencesIterator = ReferencesIteratorWrapper; + + type UserFileLocation = UserFileLocationWrapper; + type BuiltInLocation = BuiltInLocationWrapper; } //================================================ @@ -22,5 +43,125 @@ impl ffi::Guest for crate::wasm_crate::World { // //================================================ -define_rc_wrapper! { BindingGraph { +define_wrapper! { BindingGraph { + fn definition_at(&self, cursor: ffi::Cursor) -> Option { + self._borrow_ffi().definition_at(cursor._into_ffi()).map(IntoFFI::_into_ffi) + } + + fn all_definitions(&self) -> ffi::DefinitionsIterator { + self._borrow_ffi().all_definitions()._into_ffi() + } + + fn reference_at(&self, cursor: ffi::Cursor) -> Option { + self._borrow_ffi().reference_at(cursor._into_ffi()).map(IntoFFI::_into_ffi) + } + + fn all_references(&self) -> ffi::ReferencesIterator { + self._borrow_ffi().all_references()._into_ffi() + } +} } + +//================================================ +// +// resource definition +// +//================================================ + +define_wrapper! { Definition { + fn id(&self) -> u32 { + self._borrow_ffi().id().try_into().unwrap() + } + + fn name_location(&self) -> ffi::BindingLocation { + self._borrow_ffi().name_location()._into_ffi() + } + + fn definiens_location(&self) -> ffi::BindingLocation { + self._borrow_ffi().definiens_location()._into_ffi() + } +} } + +//================================================ +// +// resource reference +// +//================================================ + +define_wrapper! { Reference { + fn id(&self) -> u32 { + self._borrow_ffi().id() + } + + fn location(&self) -> ffi::BindingLocation { + self._borrow_ffi().location()._into_ffi() + } + + fn find_definitions(&self) -> ffi::DefinitionsIterator { + self._borrow_ffi().find_definitions()._into_ffi() + } +} } + +//================================================ +// +// resource definitions-iterator +// +//================================================ + +define_refcell_wrapper! { DefinitionsIterator { + fn next(&self) -> Option { + self._borrow_mut_ffi().next().map(IntoFFI::_into_ffi) + } +} } + +//================================================ +// +// resource references-iterator +// +//================================================ + +define_refcell_wrapper! { ReferencesIterator { + fn next(&self) -> Option { + self._borrow_mut_ffi().next().map(IntoFFI::_into_ffi) + } +} } + +//================================================ +// +// variant binding-location +// +//================================================ + +impl IntoFFI for rust::BindingLocation { + #[inline] + fn _into_ffi(self) -> ffi::BindingLocation { + match self { + Self::BuiltIn(location) => ffi::BindingLocation::BuiltIn(location._into_ffi()), + Self::UserFile(location) => ffi::BindingLocation::UserFile(location._into_ffi()), + } + } +} + +//================================================ +// +// resource user-file-location +// +//================================================ + +define_wrapper! { UserFileLocation { + fn file_id(&self) -> String { + self._borrow_ffi().file_id().to_owned() + } + + fn cursor(&self) -> ffi::Cursor { + self._borrow_ffi().cursor()._into_ffi() + } +} } + +//================================================ +// +// resource built-in-location +// +//================================================ + +define_wrapper! { BuiltInLocation { } } diff --git a/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/compilation/mod.rs b/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/compilation/mod.rs index f8d7707dfb..7a93fe736d 100644 --- a/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/compilation/mod.rs +++ b/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/compilation/mod.rs @@ -98,7 +98,7 @@ define_rc_wrapper! { CompilationUnit { } fn binding_graph(&self) -> ffi::BindingGraph { - Rc::clone(self._borrow_ffi().binding_graph())._into_ffi() + self._borrow_ffi().binding_graph()._into_ffi() } } }