diff --git a/.changeset/fluffy-elephants-beg.md b/.changeset/fluffy-elephants-beg.md new file mode 100644 index 0000000000..0a4403c509 --- /dev/null +++ b/.changeset/fluffy-elephants-beg.md @@ -0,0 +1,5 @@ +--- +"@nomicfoundation/slang": minor +--- + +rename `parser/Parser.supportedVersions()` API to `utils/LanguageFacts.supportedVersions()`. diff --git a/.changeset/gentle-onions-drum.md b/.changeset/gentle-onions-drum.md new file mode 100644 index 0000000000..a9e3df2839 --- /dev/null +++ b/.changeset/gentle-onions-drum.md @@ -0,0 +1,5 @@ +--- +"@nomicfoundation/slang": minor +--- + +expose the `BingingGraph` API to allow querying definitions/references between source files. diff --git a/.changeset/pink-flowers-draw.md b/.changeset/pink-flowers-draw.md new file mode 100644 index 0000000000..0e013f2eaf --- /dev/null +++ b/.changeset/pink-flowers-draw.md @@ -0,0 +1,5 @@ +--- +"@nomicfoundation/slang": minor +--- + +add a `CompilationBuilder` API to incrementally load and resolve source files and their imports. diff --git a/.github/workflows/sanctuary.yml b/.github/workflows/sanctuary.yml index c79e2a3aea..b6665d52a7 100644 --- a/.github/workflows/sanctuary.yml +++ b/.github/workflows/sanctuary.yml @@ -22,8 +22,41 @@ on: default: false jobs: - sanctuary: + singleShard: runs-on: "ubuntu-22.04" # _SLANG_DEV_CONTAINER_BASE_IMAGE_ (keep in sync) + outputs: + __SLANG_SANCTUARY_SHARD_RESULTS__0: "${{ steps.output-shard-results.outputs.__SLANG_SANCTUARY_SHARD_RESULTS__0 }}" + __SLANG_SANCTUARY_SHARD_RESULTS__1: "${{ steps.output-shard-results.outputs.__SLANG_SANCTUARY_SHARD_RESULTS__1 }}" + __SLANG_SANCTUARY_SHARD_RESULTS__2: "${{ steps.output-shard-results.outputs.__SLANG_SANCTUARY_SHARD_RESULTS__2 }}" + __SLANG_SANCTUARY_SHARD_RESULTS__3: "${{ steps.output-shard-results.outputs.__SLANG_SANCTUARY_SHARD_RESULTS__3 }}" + __SLANG_SANCTUARY_SHARD_RESULTS__4: "${{ steps.output-shard-results.outputs.__SLANG_SANCTUARY_SHARD_RESULTS__4 }}" + __SLANG_SANCTUARY_SHARD_RESULTS__5: "${{ steps.output-shard-results.outputs.__SLANG_SANCTUARY_SHARD_RESULTS__5 }}" + __SLANG_SANCTUARY_SHARD_RESULTS__6: "${{ steps.output-shard-results.outputs.__SLANG_SANCTUARY_SHARD_RESULTS__6 }}" + __SLANG_SANCTUARY_SHARD_RESULTS__7: "${{ steps.output-shard-results.outputs.__SLANG_SANCTUARY_SHARD_RESULTS__7 }}" + __SLANG_SANCTUARY_SHARD_RESULTS__8: "${{ steps.output-shard-results.outputs.__SLANG_SANCTUARY_SHARD_RESULTS__8 }}" + __SLANG_SANCTUARY_SHARD_RESULTS__9: "${{ steps.output-shard-results.outputs.__SLANG_SANCTUARY_SHARD_RESULTS__9 }}" + __SLANG_SANCTUARY_SHARD_RESULTS__10: "${{ steps.output-shard-results.outputs.__SLANG_SANCTUARY_SHARD_RESULTS__10 }}" + __SLANG_SANCTUARY_SHARD_RESULTS__11: "${{ steps.output-shard-results.outputs.__SLANG_SANCTUARY_SHARD_RESULTS__11 }}" + __SLANG_SANCTUARY_SHARD_RESULTS__12: "${{ steps.output-shard-results.outputs.__SLANG_SANCTUARY_SHARD_RESULTS__12 }}" + __SLANG_SANCTUARY_SHARD_RESULTS__13: "${{ steps.output-shard-results.outputs.__SLANG_SANCTUARY_SHARD_RESULTS__13 }}" + __SLANG_SANCTUARY_SHARD_RESULTS__14: "${{ steps.output-shard-results.outputs.__SLANG_SANCTUARY_SHARD_RESULTS__14 }}" + __SLANG_SANCTUARY_SHARD_RESULTS__15: "${{ steps.output-shard-results.outputs.__SLANG_SANCTUARY_SHARD_RESULTS__15 }}" + __SLANG_SANCTUARY_SHARD_RESULTS__16: "${{ steps.output-shard-results.outputs.__SLANG_SANCTUARY_SHARD_RESULTS__16 }}" + __SLANG_SANCTUARY_SHARD_RESULTS__17: "${{ steps.output-shard-results.outputs.__SLANG_SANCTUARY_SHARD_RESULTS__17 }}" + __SLANG_SANCTUARY_SHARD_RESULTS__18: "${{ steps.output-shard-results.outputs.__SLANG_SANCTUARY_SHARD_RESULTS__18 }}" + __SLANG_SANCTUARY_SHARD_RESULTS__19: "${{ steps.output-shard-results.outputs.__SLANG_SANCTUARY_SHARD_RESULTS__19 }}" + __SLANG_SANCTUARY_SHARD_RESULTS__20: "${{ steps.output-shard-results.outputs.__SLANG_SANCTUARY_SHARD_RESULTS__20 }}" + __SLANG_SANCTUARY_SHARD_RESULTS__21: "${{ steps.output-shard-results.outputs.__SLANG_SANCTUARY_SHARD_RESULTS__21 }}" + __SLANG_SANCTUARY_SHARD_RESULTS__22: "${{ steps.output-shard-results.outputs.__SLANG_SANCTUARY_SHARD_RESULTS__22 }}" + __SLANG_SANCTUARY_SHARD_RESULTS__23: "${{ steps.output-shard-results.outputs.__SLANG_SANCTUARY_SHARD_RESULTS__23 }}" + __SLANG_SANCTUARY_SHARD_RESULTS__24: "${{ steps.output-shard-results.outputs.__SLANG_SANCTUARY_SHARD_RESULTS__24 }}" + __SLANG_SANCTUARY_SHARD_RESULTS__25: "${{ steps.output-shard-results.outputs.__SLANG_SANCTUARY_SHARD_RESULTS__25 }}" + __SLANG_SANCTUARY_SHARD_RESULTS__26: "${{ steps.output-shard-results.outputs.__SLANG_SANCTUARY_SHARD_RESULTS__26 }}" + __SLANG_SANCTUARY_SHARD_RESULTS__27: "${{ steps.output-shard-results.outputs.__SLANG_SANCTUARY_SHARD_RESULTS__27 }}" + __SLANG_SANCTUARY_SHARD_RESULTS__28: "${{ steps.output-shard-results.outputs.__SLANG_SANCTUARY_SHARD_RESULTS__28 }}" + __SLANG_SANCTUARY_SHARD_RESULTS__29: "${{ steps.output-shard-results.outputs.__SLANG_SANCTUARY_SHARD_RESULTS__29 }}" + __SLANG_SANCTUARY_SHARD_RESULTS__30: "${{ steps.output-shard-results.outputs.__SLANG_SANCTUARY_SHARD_RESULTS__30 }}" + __SLANG_SANCTUARY_SHARD_RESULTS__31: "${{ steps.output-shard-results.outputs.__SLANG_SANCTUARY_SHARD_RESULTS__31 }}" strategy: fail-fast: false # Continue running all shards even if some fail. @@ -45,9 +78,25 @@ jobs: - 13 - 14 - 15 + - 16 + - 17 + - 18 + - 19 + - 20 + - 21 + - 22 + - 23 + - 24 + - 25 + - 26 + - 27 + - 28 + - 29 + - 30 + - 31 env: - SHARDS_COUNT: 16 # Length of the 'shard_index' array above. + SHARDS_COUNT: 32 # Length of the 'shard_index' array above. steps: - name: "Checkout Repository" @@ -59,4 +108,28 @@ jobs: - name: "infra run solidity_testing_sanctuary" uses: "./.github/actions/devcontainer/run" with: - runCmd: "./scripts/bin/infra run --release --bin solidity_testing_sanctuary -- --shards-count ${{ env.SHARDS_COUNT }} --shard-index ${{ matrix.shard_index }} ${{ inputs.check_bindings == true && '--check-bindings' || '' }} ${{ inputs.chain }} ${{ inputs.network }}" + runCmd: "./scripts/bin/infra run --release --bin solidity_testing_sanctuary -- test --shards-count ${{ env.SHARDS_COUNT }} --shard-index ${{ matrix.shard_index }} ${{ inputs.check_bindings == true && '--check-bindings' || '' }} ${{ inputs.chain }} ${{ inputs.network }}" + + - name: "Write shard results to output" + if: "!cancelled()" + id: "output-shard-results" + run: 'echo "__SLANG_SANCTUARY_SHARD_RESULTS__${{ matrix.shard_index }}=$(cat target/__SLANG_SANCTUARY_SHARD_RESULTS__.json)" >> "$GITHUB_OUTPUT"' + + combinedResults: + runs-on: "ubuntu-22.04" # _SLANG_DEV_CONTAINER_BASE_IMAGE_ (keep in sync) + needs: "singleShard" + if: "!cancelled()" + steps: + - name: "Checkout Repository" + uses: "actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683" + + - name: "Restore Cache" + uses: "./.github/actions/cache/restore" + + - name: "Output shards results" + run: "echo '${{ toJSON(needs.singleShard.outputs) }}' > __SLANG_SANCTUARY_MATRIX_RESULTS__.json" + + - name: "Show combined results" + uses: "./.github/actions/devcontainer/run" + with: + runCmd: "./scripts/bin/infra run --bin solidity_testing_sanctuary -- show-combined-results __SLANG_SANCTUARY_MATRIX_RESULTS__.json" diff --git a/crates/codegen/runtime/cargo/crate/Cargo.toml b/crates/codegen/runtime/cargo/crate/Cargo.toml index dea69d8bb6..b15b372050 100644 --- a/crates/codegen/runtime/cargo/crate/Cargo.toml +++ b/crates/codegen/runtime/cargo/crate/Cargo.toml @@ -12,6 +12,7 @@ description = "Cargo runtime copied over by codegen" default = [] __experimental_bindings_api = ["dep:metaslang_bindings"] __private_ariadne_errors = ["dep:ariadne"] +__private_compilation_api = [] __private_testing_utils = [] [build-dependencies] diff --git a/crates/codegen/runtime/cargo/crate/src/extensions/bindings/mod.rs b/crates/codegen/runtime/cargo/crate/src/extensions/bindings/mod.rs new file mode 100644 index 0000000000..eee8b7880f --- /dev/null +++ b/crates/codegen/runtime/cargo/crate/src/extensions/bindings/mod.rs @@ -0,0 +1,12 @@ +use semver::Version; + +use crate::bindings::BindingGraph; +use crate::parser::ParserInitializationError; + +#[allow(clippy::needless_pass_by_value)] +pub fn add_built_ins( + _binding_graph: &mut BindingGraph, + _version: Version, +) -> Result<(), ParserInitializationError> { + unreachable!("Built-ins are Solidity-specific") +} diff --git a/crates/codegen/runtime/cargo/crate/src/extensions/compilation/mod.rs b/crates/codegen/runtime/cargo/crate/src/extensions/compilation/mod.rs new file mode 100644 index 0000000000..ddbb6d5a87 --- /dev/null +++ b/crates/codegen/runtime/cargo/crate/src/extensions/compilation/mod.rs @@ -0,0 +1,15 @@ +use crate::cst::Cursor; + +pub struct ImportPathsExtractor; + +impl ImportPathsExtractor { + pub fn new() -> Self { + Self + } + + #[allow(clippy::unused_self)] + #[allow(clippy::needless_pass_by_value)] + pub fn extract(&self, _: Cursor) -> Vec { + unreachable!("Import paths are Solidity-specific") + } +} diff --git a/crates/codegen/runtime/cargo/crate/src/extensions/mod.rs b/crates/codegen/runtime/cargo/crate/src/extensions/mod.rs new file mode 100644 index 0000000000..78402f8764 --- /dev/null +++ b/crates/codegen/runtime/cargo/crate/src/extensions/mod.rs @@ -0,0 +1,8 @@ +#[cfg(all( + feature = "__experimental_bindings_api", + feature = "__private_compilation_api" +))] +pub mod compilation; + +#[cfg(feature = "__experimental_bindings_api")] +pub mod bindings; diff --git a/crates/codegen/runtime/cargo/crate/src/lib.rs b/crates/codegen/runtime/cargo/crate/src/lib.rs index 115e9459b8..87bdec06cd 100644 --- a/crates/codegen/runtime/cargo/crate/src/lib.rs +++ b/crates/codegen/runtime/cargo/crate/src/lib.rs @@ -2,6 +2,7 @@ // The final code (generated in output crates) is checked for dead-code anyways. #![allow(dead_code, unused_imports)] +mod extensions; mod runtime; pub use runtime::*; diff --git a/crates/codegen/runtime/cargo/crate/src/runtime/bindings/built_ins.rs.jinja2 b/crates/codegen/runtime/cargo/crate/src/runtime/bindings/built_ins.rs.jinja2 index 856f983808..c28f4643e8 100644 --- a/crates/codegen/runtime/cargo/crate/src/runtime/bindings/built_ins.rs.jinja2 +++ b/crates/codegen/runtime/cargo/crate/src/runtime/bindings/built_ins.rs.jinja2 @@ -1,7 +1,8 @@ use semver::Version; +// TODO: This should be moved to the Solidity-specific 'extensions' sub-module. #[allow(unused_variables)] -pub fn get_contents(version: &Version) -> &'static str { +pub fn get_built_ins_contents(version: &Version) -> &'static str { {%- if not rendering_in_stubs -%} {%- for version in model.bindings.built_ins_versions %} {%- if not loop.first -%} diff --git a/crates/codegen/runtime/cargo/crate/src/runtime/bindings/generated/built_ins.rs b/crates/codegen/runtime/cargo/crate/src/runtime/bindings/generated/built_ins.rs index f7337ecff2..e956dd160a 100644 --- a/crates/codegen/runtime/cargo/crate/src/runtime/bindings/generated/built_ins.rs +++ b/crates/codegen/runtime/cargo/crate/src/runtime/bindings/generated/built_ins.rs @@ -2,7 +2,8 @@ use semver::Version; +// TODO: This should be moved to the Solidity-specific 'extensions' sub-module. #[allow(unused_variables)] -pub fn get_contents(version: &Version) -> &'static str { +pub fn get_built_ins_contents(version: &Version) -> &'static str { unreachable!("Built-ins not defined in stubs") } 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 3769f5d1b1..4766b80e6c 100644 --- a/crates/codegen/runtime/cargo/crate/src/runtime/bindings/mod.rs +++ b/crates/codegen/runtime/cargo/crate/src/runtime/bindings/mod.rs @@ -2,31 +2,46 @@ mod binding_rules; #[path = "generated/built_ins.rs"] -mod built_ins; +pub mod built_ins; -use std::sync::Arc; +use std::rc::Rc; -use metaslang_bindings::{self, PathResolver}; use semver::Version; use crate::cst::KindTypes; -pub type Bindings = metaslang_bindings::Bindings; +pub type BindingGraph = metaslang_bindings::BindingGraph; pub type Definition<'a> = metaslang_bindings::Definition<'a, KindTypes>; pub type Reference<'a> = metaslang_bindings::Reference<'a, KindTypes>; +pub type BindingLocation = metaslang_bindings::BindingLocation; +pub type UserFileLocation = metaslang_bindings::UserFileLocation; + +pub use metaslang_bindings::{BuiltInLocation, PathResolver}; + +use crate::parser::ParserInitializationError; + +#[derive(thiserror::Error, Debug)] +pub enum BindingGraphInitializationError { + #[error(transparent)] + ParserInitialization(#[from] ParserInitializationError), +} pub fn create_with_resolver( version: Version, - resolver: Arc, -) -> Bindings { - Bindings::create(version, binding_rules::BINDING_RULES_SOURCE, resolver) + resolver: Rc>, +) -> Result { + let mut binding_graph = BindingGraph::create( + version.clone(), + binding_rules::BINDING_RULES_SOURCE, + resolver, + ); + + crate::extensions::bindings::add_built_ins(&mut binding_graph, version)?; + + Ok(binding_graph) } #[cfg(feature = "__private_testing_utils")] pub fn get_binding_rules() -> &'static str { binding_rules::BINDING_RULES_SOURCE } - -pub fn get_built_ins(version: &semver::Version) -> &'static str { - built_ins::get_contents(version) -} diff --git a/crates/codegen/runtime/cargo/crate/src/runtime/compilation/file.rs b/crates/codegen/runtime/cargo/crate/src/runtime/compilation/file.rs new file mode 100644 index 0000000000..07693c8335 --- /dev/null +++ b/crates/codegen/runtime/cargo/crate/src/runtime/compilation/file.rs @@ -0,0 +1,45 @@ +use std::collections::BTreeMap; + +use metaslang_cst::text_index::TextIndex; + +use crate::cst::{Cursor, Node}; + +#[derive(Clone)] +pub struct File { + id: String, + tree: Node, + + resolved_imports: BTreeMap, +} + +impl File { + pub(super) fn new(id: String, tree: Node) -> Self { + Self { + id, + tree, + + resolved_imports: BTreeMap::new(), + } + } + + pub fn id(&self) -> &str { + &self.id + } + + pub fn tree(&self) -> &Node { + &self.tree + } + + pub fn create_tree_cursor(&self) -> Cursor { + self.tree.clone().cursor_with_offset(TextIndex::ZERO) + } + + pub(super) fn resolve_import(&mut self, import_path: &Cursor, destination_file_id: String) { + self.resolved_imports + .insert(import_path.node().id(), destination_file_id); + } + + pub(super) fn resolved_import(&self, import_path: &Cursor) -> Option<&String> { + self.resolved_imports.get(&import_path.node().id()) + } +} diff --git a/crates/codegen/runtime/cargo/crate/src/runtime/compilation/internal_builder.rs b/crates/codegen/runtime/cargo/crate/src/runtime/compilation/internal_builder.rs new file mode 100644 index 0000000000..bdda575510 --- /dev/null +++ b/crates/codegen/runtime/cargo/crate/src/runtime/compilation/internal_builder.rs @@ -0,0 +1,93 @@ +use std::collections::BTreeMap; +use std::rc::Rc; + +use metaslang_cst::nodes::Node; +use semver::Version; + +use crate::compilation::{CompilationUnit, File}; +use crate::cst::Cursor; +use crate::extensions::compilation::ImportPathsExtractor; +use crate::parser::{Parser, ParserInitializationError}; + +pub struct InternalCompilationBuilder { + parser: Parser, + imports: ImportPathsExtractor, + files: BTreeMap, +} + +#[derive(thiserror::Error, Debug)] +pub enum CompilationInitializationError { + #[error(transparent)] + ParserInitialization(#[from] ParserInitializationError), +} + +impl InternalCompilationBuilder { + pub fn create(language_version: Version) -> Result { + let parser = Parser::create(language_version)?; + + Ok(Self { + parser, + imports: ImportPathsExtractor::new(), + files: BTreeMap::new(), + }) + } + + pub fn add_file(&mut self, id: String, contents: &str) -> AddFileResponse { + if self.files.contains_key(&id) { + // Already added. No need to process it again: + return AddFileResponse { + import_paths: vec![], + }; + } + + let parse_output = self.parser.parse(Parser::ROOT_KIND, contents); + + let import_paths = self.imports.extract(parse_output.create_tree_cursor()); + + let file = File::new( + id.clone(), + Node::Nonterminal(Rc::clone(parse_output.tree())), + ); + self.files.insert(id, file); + + AddFileResponse { import_paths } + } + + pub fn resolve_import( + &mut self, + source_file_id: &str, + import_path: &Cursor, + destination_file_id: String, + ) -> Result<(), ResolveImportError> { + self.files + .get_mut(source_file_id) + .ok_or_else(|| ResolveImportError::SourceFileNotFound(source_file_id.to_owned()))? + .resolve_import(import_path, destination_file_id); + + Ok(()) + } + + pub fn build(&self) -> CompilationUnit { + let language_version = self.parser.language_version().to_owned(); + + let files = self + .files + .iter() + .map(|(id, file)| (id.to_owned(), Rc::new(file.to_owned()))) + .collect(); + + CompilationUnit::new(language_version, files) + } +} + +pub struct AddFileResponse { + pub import_paths: Vec, +} + +#[derive(thiserror::Error, Debug)] +pub enum ResolveImportError { + #[error( + "Source file not found: '{0}'. Make sure to add it first, before resolving its imports." + )] + SourceFileNotFound(String), +} diff --git a/crates/codegen/runtime/cargo/crate/src/runtime/compilation/mod.rs b/crates/codegen/runtime/cargo/crate/src/runtime/compilation/mod.rs new file mode 100644 index 0000000000..09d9cef65e --- /dev/null +++ b/crates/codegen/runtime/cargo/crate/src/runtime/compilation/mod.rs @@ -0,0 +1,7 @@ +mod file; +mod internal_builder; +mod unit; + +pub use file::File; +pub use internal_builder::{AddFileResponse, InternalCompilationBuilder}; +pub use unit::CompilationUnit; diff --git a/crates/codegen/runtime/cargo/crate/src/runtime/compilation/unit.rs b/crates/codegen/runtime/cargo/crate/src/runtime/compilation/unit.rs new file mode 100644 index 0000000000..aea2d3cd9c --- /dev/null +++ b/crates/codegen/runtime/cargo/crate/src/runtime/compilation/unit.rs @@ -0,0 +1,69 @@ +use std::cell::OnceCell; +use std::collections::BTreeMap; +use std::rc::Rc; + +use semver::Version; + +use crate::bindings::{ + create_with_resolver, BindingGraph, BindingGraphInitializationError, PathResolver, +}; +use crate::compilation::File; +use crate::cst::{Cursor, KindTypes}; + +pub struct CompilationUnit { + language_version: Version, + files: BTreeMap>, + binding_graph: OnceCell, BindingGraphInitializationError>>, +} + +impl CompilationUnit { + pub(super) fn new(language_version: Version, files: BTreeMap>) -> Self { + Self { + language_version, + files, + binding_graph: OnceCell::new(), + } + } + + pub fn language_version(&self) -> &Version { + &self.language_version + } + + pub fn files(&self) -> Vec> { + self.files.values().cloned().collect() + } + + pub fn file(&self, id: &str) -> Option> { + self.files.get(id).cloned() + } + + pub fn binding_graph(&self) -> &Result, BindingGraphInitializationError> { + self.binding_graph.get_or_init(|| { + let resolver = Resolver { + files: self.files.clone(), + }; + + let mut binding_graph = + create_with_resolver(self.language_version.clone(), Rc::new(resolver))?; + + for (id, file) in &self.files { + binding_graph.add_user_file(id, file.create_tree_cursor()); + } + + Ok(Rc::new(binding_graph)) + }) + } +} + +struct Resolver { + files: BTreeMap>, +} + +impl PathResolver for Resolver { + fn resolve_path(&self, context_path: &str, path_to_resolve: &Cursor) -> Option { + self.files + .get(context_path)? + .resolved_import(path_to_resolve) + .cloned() + } +} diff --git a/crates/codegen/runtime/cargo/crate/src/runtime/mod.rs b/crates/codegen/runtime/cargo/crate/src/runtime/mod.rs index 6856966831..b1ff783ba1 100644 --- a/crates/codegen/runtime/cargo/crate/src/runtime/mod.rs +++ b/crates/codegen/runtime/cargo/crate/src/runtime/mod.rs @@ -1,5 +1,11 @@ #[cfg(feature = "__experimental_bindings_api")] pub mod bindings; +#[cfg(all( + feature = "__experimental_bindings_api", + feature = "__private_compilation_api" +))] +pub mod compilation; pub mod cst; pub mod diagnostic; pub mod parser; +pub mod utils; diff --git a/crates/codegen/runtime/cargo/crate/src/runtime/parser/generated/parser.rs b/crates/codegen/runtime/cargo/crate/src/runtime/parser/generated/parser.rs index d155877f4a..bc7976769f 100644 --- a/crates/codegen/runtime/cargo/crate/src/runtime/parser/generated/parser.rs +++ b/crates/codegen/runtime/cargo/crate/src/runtime/parser/generated/parser.rs @@ -27,10 +27,11 @@ use crate::parser::scanner_macros::{ scan_not_followed_by, scan_one_or_more, scan_optional, scan_sequence, scan_zero_or_more, }; use crate::parser::ParseOutput; +use crate::utils::LanguageFacts; #[derive(Debug)] pub struct Parser { - pub version: Version, + language_version: Version, } #[derive(thiserror::Error, Debug)] @@ -40,22 +41,25 @@ pub enum ParserInitializationError { } impl Parser { - pub const SUPPORTED_VERSIONS: &'static [Version] = &[]; - pub const ROOT_KIND: NonterminalKind = NonterminalKind::Stub1; - pub fn create(version: Version) -> std::result::Result { - if Self::SUPPORTED_VERSIONS.binary_search(&version).is_ok() { - Ok(Self { version }) + pub fn create( + language_version: Version, + ) -> std::result::Result { + if LanguageFacts::SUPPORTED_VERSIONS + .binary_search(&language_version) + .is_ok() + { + Ok(Self { language_version }) } else { Err(ParserInitializationError::UnsupportedLanguageVersion( - version, + language_version, )) } } - pub fn version(&self) -> &Version { - &self.version + pub fn language_version(&self) -> &Version { + &self.language_version } pub fn parse(&self, kind: NonterminalKind, input: &str) -> ParseOutput { diff --git a/crates/codegen/runtime/cargo/crate/src/runtime/parser/parse_output.rs b/crates/codegen/runtime/cargo/crate/src/runtime/parser/parse_output.rs index 76a7961e75..d395732cd2 100644 --- a/crates/codegen/runtime/cargo/crate/src/runtime/parser/parse_output.rs +++ b/crates/codegen/runtime/cargo/crate/src/runtime/parser/parse_output.rs @@ -3,15 +3,15 @@ use std::rc::Rc; use crate::cst::{Cursor, NonterminalNode, TextIndex}; use crate::parser::ParseError; -#[derive(Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq)] pub struct ParseOutput { - pub(crate) parse_tree: Rc, + pub(crate) tree: Rc, pub(crate) errors: Vec, } impl ParseOutput { pub fn tree(&self) -> &Rc { - &self.parse_tree + &self.tree } pub fn errors(&self) -> &Vec { @@ -24,6 +24,6 @@ impl ParseOutput { /// Creates a cursor that starts at the root of the parse tree. pub fn create_tree_cursor(&self) -> Cursor { - Rc::clone(&self.parse_tree).cursor_with_offset(TextIndex::ZERO) + Rc::clone(&self.tree).cursor_with_offset(TextIndex::ZERO) } } diff --git a/crates/codegen/runtime/cargo/crate/src/runtime/parser/parser.rs.jinja2 b/crates/codegen/runtime/cargo/crate/src/runtime/parser/parser.rs.jinja2 index e6b5215d4a..ec4b39e366 100644 --- a/crates/codegen/runtime/cargo/crate/src/runtime/parser/parser.rs.jinja2 +++ b/crates/codegen/runtime/cargo/crate/src/runtime/parser/parser.rs.jinja2 @@ -11,6 +11,7 @@ use semver::Version; use crate::cst; +use crate::utils::LanguageFacts; use crate::cst::{ EdgeLabel, IsLexicalContext, LexicalContext, LexicalContextType, NonterminalKind, TerminalKind, }; @@ -37,7 +38,7 @@ pub struct Parser { {%- endfor -%} {%- endif -%} - pub version: Version, + language_version: Version, } #[derive(thiserror::Error, Debug)] @@ -47,34 +48,26 @@ pub enum ParserInitializationError { } impl Parser { - pub const SUPPORTED_VERSIONS: &'static [Version] = &[ - {%- if not rendering_in_stubs -%} - {% for version in model.all_language_versions %} - Version::new({{ version | split(pat=".") | join(sep=", ") }}), - {% endfor %} - {%- endif -%} - ]; - pub const ROOT_KIND: NonterminalKind = NonterminalKind::{{ model.kinds.root_kind }}; - pub fn create(version: Version) -> std::result::Result { - if Self::SUPPORTED_VERSIONS.binary_search(&version).is_ok() { + pub fn create(language_version: Version) -> std::result::Result { + if LanguageFacts::SUPPORTED_VERSIONS.binary_search(&language_version).is_ok() { Ok(Self { {%- if not rendering_in_stubs -%} {%- for version in model.breaking_language_versions %} - version_is_at_least_{{ version | replace(from=".", to="_") }}: Version::new({{ version | split(pat=".") | join(sep=", ") }}) <= version, + version_is_at_least_{{ version | replace(from=".", to="_") }}: Version::new({{ version | split(pat=".") | join(sep=", ") }}) <= language_version, {%- endfor -%} {%- endif -%} - version, + language_version, }) } else { - Err(ParserInitializationError::UnsupportedLanguageVersion(version)) + Err(ParserInitializationError::UnsupportedLanguageVersion(language_version)) } } - pub fn version(&self) -> &Version { - &self.version + pub fn language_version(&self) -> &Version { + &self.language_version } {%- if not rendering_in_stubs -%} diff --git a/crates/codegen/runtime/cargo/crate/src/runtime/parser/parser_support/parser_function.rs b/crates/codegen/runtime/cargo/crate/src/runtime/parser/parser_support/parser_function.rs index 65354536be..f0e2448df5 100644 --- a/crates/codegen/runtime/cargo/crate/src/runtime/parser/parser_support/parser_function.rs +++ b/crates/codegen/runtime/cargo/crate/src/runtime/parser/parser_support/parser_function.rs @@ -89,7 +89,7 @@ where let node = Node::terminal(kind, input.to_string()); trivia_nodes.push(Edge::anonymous(node)); ParseOutput { - parse_tree: Rc::new(NonterminalNode::new(expected, trivia_nodes)), + tree: Rc::new(NonterminalNode::new(expected, trivia_nodes)), errors: vec![ParseError::new( start..start + input.into(), no_match.expected_terminals, @@ -153,17 +153,17 @@ where )); ParseOutput { - parse_tree: Rc::new(NonterminalNode::new(topmost_node.kind, new_children)), + tree: Rc::new(NonterminalNode::new(topmost_node.kind, new_children)), errors, } } else { - let parse_tree = topmost_node; + let tree = topmost_node; let errors = stream.into_errors(); // Sanity check: Make sure that succesful parse is equivalent to not having any invalid nodes debug_assert_eq!( errors.is_empty(), - Rc::clone(&parse_tree) + Rc::clone(&tree) .cursor_with_offset(TextIndex::ZERO) .remaining_nodes() .all(|edge| edge @@ -172,7 +172,7 @@ where .is_none()) ); - ParseOutput { parse_tree, errors } + ParseOutput { tree, errors } } } } diff --git a/crates/codegen/runtime/cargo/crate/src/runtime/utils/generated/language_facts.rs b/crates/codegen/runtime/cargo/crate/src/runtime/utils/generated/language_facts.rs new file mode 100644 index 0000000000..12af5c1f2e --- /dev/null +++ b/crates/codegen/runtime/cargo/crate/src/runtime/utils/generated/language_facts.rs @@ -0,0 +1,11 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +use semver::Version; + +pub struct LanguageFacts; + +impl LanguageFacts { + pub const NAME: &'static str = "CodegenRuntime"; + + pub const SUPPORTED_VERSIONS: &'static [Version] = &[]; +} diff --git a/crates/codegen/runtime/cargo/crate/src/runtime/utils/language_facts.rs.jinja2 b/crates/codegen/runtime/cargo/crate/src/runtime/utils/language_facts.rs.jinja2 new file mode 100644 index 0000000000..fe91f6ae7f --- /dev/null +++ b/crates/codegen/runtime/cargo/crate/src/runtime/utils/language_facts.rs.jinja2 @@ -0,0 +1,13 @@ +use semver::Version; + +pub struct LanguageFacts; + +impl LanguageFacts { + pub const NAME: &'static str = "{{ model.language_name }}"; + + pub const SUPPORTED_VERSIONS: &'static [Version] = &[ + {% for version in model.all_language_versions %} + Version::new({{ version | split(pat=".") | join(sep=", ") }}), + {% endfor %} + ]; +} diff --git a/crates/codegen/runtime/cargo/crate/src/runtime/utils/mod.rs b/crates/codegen/runtime/cargo/crate/src/runtime/utils/mod.rs new file mode 100644 index 0000000000..924814eded --- /dev/null +++ b/crates/codegen/runtime/cargo/crate/src/runtime/utils/mod.rs @@ -0,0 +1,4 @@ +#[path = "generated/language_facts.rs"] +mod language_facts; + +pub use language_facts::LanguageFacts; diff --git a/crates/codegen/runtime/cargo/wasm/Cargo.toml b/crates/codegen/runtime/cargo/wasm/Cargo.toml index bd8bcc7a90..65a9a1c454 100644 --- a/crates/codegen/runtime/cargo/wasm/Cargo.toml +++ b/crates/codegen/runtime/cargo/wasm/Cargo.toml @@ -17,7 +17,10 @@ codegen_runtime_generator = { workspace = true } infra_utils = { workspace = true } [dependencies] -codegen_runtime_cargo_crate = { workspace = true } +codegen_runtime_cargo_crate = { workspace = true, features = [ + "__experimental_bindings_api", + "__private_compilation_api", +] } paste = { workspace = true } semver = { workspace = true } serde_json = { workspace = true } diff --git a/crates/codegen/runtime/cargo/wasm/src/runtime/bindings.rs.jinja2 b/crates/codegen/runtime/cargo/wasm/src/runtime/bindgen.rs.jinja2 similarity index 100% rename from crates/codegen/runtime/cargo/wasm/src/runtime/bindings.rs.jinja2 rename to crates/codegen/runtime/cargo/wasm/src/runtime/bindgen.rs.jinja2 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 395999cccb..3444eb9169 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,65 @@ { "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: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 + } + }, + "nomic-foundation:slang:compilation:compilation-unit.binding-graph()": { + "Function": { + "as_getter": true + } + }, + "nomic-foundation:slang:compilation:file.id()": { + "Function": { + "as_getter": true + } + }, + "nomic-foundation:slang:compilation:file.tree()": { + "Function": { + "as_getter": true + } + }, "nomic-foundation:slang:cst:terminal-kind": { "Enum": { "as_typescript_enum": true @@ -105,7 +165,7 @@ "as_iterator": true } }, - "nomic-foundation:slang:parser:parser.version()": { + "nomic-foundation:slang:parser:parser.language-version()": { "Function": { "as_getter": true } diff --git a/crates/codegen/runtime/cargo/wasm/src/runtime/generated/bindings.rs b/crates/codegen/runtime/cargo/wasm/src/runtime/generated/bindgen.rs similarity index 100% rename from crates/codegen/runtime/cargo/wasm/src/runtime/generated/bindings.rs rename to crates/codegen/runtime/cargo/wasm/src/runtime/generated/bindgen.rs 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 395999cccb..3444eb9169 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,65 @@ { "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: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 + } + }, + "nomic-foundation:slang:compilation:compilation-unit.binding-graph()": { + "Function": { + "as_getter": true + } + }, + "nomic-foundation:slang:compilation:file.id()": { + "Function": { + "as_getter": true + } + }, + "nomic-foundation:slang:compilation:file.tree()": { + "Function": { + "as_getter": true + } + }, "nomic-foundation:slang:cst:terminal-kind": { "Enum": { "as_typescript_enum": true @@ -105,7 +165,7 @@ "as_iterator": true } }, - "nomic-foundation:slang:parser:parser.version()": { + "nomic-foundation:slang:parser:parser.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 new file mode 100644 index 0000000000..d1586c4fdb --- /dev/null +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/bindings.wit.jinja2 @@ -0,0 +1,70 @@ +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: borrow) -> option; + + /// If the provided cursor points at a reference `Identifier`, it will return the + /// corresponding reference. Otherwise, it will return `undefined`. + reference-at: func(cursor: borrow) -> option; + } + + /// 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. + definitions: func() -> list; + } + + /// 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/compilation.wit.jinja2 b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/compilation.wit.jinja2 new file mode 100644 index 0000000000..1436368ad1 --- /dev/null +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/compilation.wit.jinja2 @@ -0,0 +1,66 @@ +interface compilation { + use bindings.{binding-graph}; + use cst.{node, cursor}; + + /// A builder for creating compilation units. + /// Allows incrementally building a transitive list of all files and their imports. + /// + /// This is an internal API, and exposed via a public `CompilationBuilder` wrapper class written in TypeScript. + /// This allows storing/invoking user supplied callbacks in TypeScript, rather than Rust, which has its limitations. + resource internal-compilation-builder { + /// Creates a new compilation builder for the specified language version. + create: static func(language-version: string) -> result; + + /// Adds a source file to the compilation unit. + add-file: func(id: string, contents: string) -> add-file-response; + + /// Resolves an import in the source file to the destination file. + resolve-import: func(source-file-id: string, import-path: borrow, destination-file-id: string) -> result<_, string>; + + /// Builds and returns the final compilation unit. + build: func() -> compilation-unit; + } + + /// Contains information about imports found in an added source file. + record add-file-response { + /// List of cursors to any import paths found in the file. + import-paths: list, + } + + /// A complete compilation unit is a complete view over all compilation inputs: + /// + /// - All source files, stored as CSTs. + /// - Name binding graph that exposes relationships between definitions and references in these files. + /// - Any relevant compilation options. + /// + /// It also exposes utilities to traverse the compilation unit and query it. + resource compilation-unit { + /// Returns the language version this compilation unit is configured for. + language-version: func() -> string; + + /// Returns a list of all files in the compilation unit. + files: func() -> list; + + /// Returns the file with the specified ID, if it exists. + file: func(id: string) -> option; + + /// Calculates name binding information for all source files within the compilation unit. + /// Returns a graph that contains all found definitions and their references. + /// + /// Note: building this graph is an expensive operation. + /// It is done lazily on the first access, and cached thereafter. + binding-graph: func() -> result; + } + + /// A single source file in the compilation unit. + resource file { + /// Returns the unique identifier of this file. + id: func() -> string; + + /// Returns the syntax tree of this file. + tree: func() -> node; + + /// Creates a cursor for traversing the syntax tree of this file. + create-tree-cursor: func() -> cursor; + } +} 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 new file mode 100644 index 0000000000..1721afc82d --- /dev/null +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/bindings.wit @@ -0,0 +1,72 @@ +// 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: borrow) -> option; + + /// If the provided cursor points at a reference `Identifier`, it will return the + /// corresponding reference. Otherwise, it will return `undefined`. + reference-at: func(cursor: borrow) -> option; + } + + /// 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. + definitions: func() -> list; + } + + /// 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/compilation.wit b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/compilation.wit new file mode 100644 index 0000000000..c9db286d76 --- /dev/null +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/compilation.wit @@ -0,0 +1,68 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +interface compilation { + use bindings.{binding-graph}; + use cst.{node, cursor}; + + /// A builder for creating compilation units. + /// Allows incrementally building a transitive list of all files and their imports. + /// + /// This is an internal API, and exposed via a public `CompilationBuilder` wrapper class written in TypeScript. + /// This allows storing/invoking user supplied callbacks in TypeScript, rather than Rust, which has its limitations. + resource internal-compilation-builder { + /// Creates a new compilation builder for the specified language version. + create: static func(language-version: string) -> result; + + /// Adds a source file to the compilation unit. + add-file: func(id: string, contents: string) -> add-file-response; + + /// Resolves an import in the source file to the destination file. + resolve-import: func(source-file-id: string, import-path: borrow, destination-file-id: string) -> result<_, string>; + + /// Builds and returns the final compilation unit. + build: func() -> compilation-unit; + } + + /// Contains information about imports found in an added source file. + record add-file-response { + /// List of cursors to any import paths found in the file. + import-paths: list, + } + + /// A complete compilation unit is a complete view over all compilation inputs: + /// + /// - All source files, stored as CSTs. + /// - Name binding graph that exposes relationships between definitions and references in these files. + /// - Any relevant compilation options. + /// + /// It also exposes utilities to traverse the compilation unit and query it. + resource compilation-unit { + /// Returns the language version this compilation unit is configured for. + language-version: func() -> string; + + /// Returns a list of all files in the compilation unit. + files: func() -> list; + + /// Returns the file with the specified ID, if it exists. + file: func(id: string) -> option; + + /// Calculates name binding information for all source files within the compilation unit. + /// Returns a graph that contains all found definitions and their references. + /// + /// Note: building this graph is an expensive operation. + /// It is done lazily on the first access, and cached thereafter. + binding-graph: func() -> result; + } + + /// A single source file in the compilation unit. + resource file { + /// Returns the unique identifier of this file. + id: func() -> string; + + /// Returns the syntax tree of this file. + tree: func() -> node; + + /// Creates a cursor for traversing the syntax tree of this file. + create-tree-cursor: func() -> cursor; + } +} diff --git a/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/parser.wit b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/parser.wit index 42b61577d4..6eca8e01ae 100644 --- a/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/parser.wit +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/parser.wit @@ -10,15 +10,11 @@ interface parser { /// This represents the starting point for parsing a complete source file. root-kind: static func() -> nonterminal-kind; - /// Returns a list of language versions supported by this parser. - /// Each version string represents a specific grammar configuration. - supported-versions: static func() -> list; - /// Creates a new parser instance for the specified language version. - create: static func(version: string) -> result; + create: static func(language-version: string) -> result; /// Returns the language version this parser instance is configured for. - version: func() -> string; + language-version: func() -> string; /// Parses the input string starting from the specified nonterminal kind. parse: func(kind: nonterminal-kind, input: string) -> parse-output; diff --git a/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/utils.wit b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/utils.wit new file mode 100644 index 0000000000..9bb93e160f --- /dev/null +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/utils.wit @@ -0,0 +1,9 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +interface utils { + /// Provides information about the supported language versions and the grammar. + resource language-facts { + /// Returns a list of language versions supported by Slang, sorted ascendingly. + supported-versions: static func() -> list; + } +} diff --git a/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/world.wit b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/world.wit index c5e1378860..bb9b7b10be 100644 --- a/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/world.wit +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/world.wit @@ -4,6 +4,9 @@ package nomic-foundation:slang; world slang { export ast; + export bindings; + export compilation; export cst; export parser; + export utils; } diff --git a/crates/codegen/runtime/cargo/wasm/src/runtime/interface/parser.wit.jinja2 b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/parser.wit.jinja2 index 484c013563..ebe1e15d83 100644 --- a/crates/codegen/runtime/cargo/wasm/src/runtime/interface/parser.wit.jinja2 +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/parser.wit.jinja2 @@ -8,15 +8,11 @@ interface parser { /// This represents the starting point for parsing a complete source file. root-kind: static func() -> nonterminal-kind; - /// Returns a list of language versions supported by this parser. - /// Each version string represents a specific grammar configuration. - supported-versions: static func() -> list; - /// Creates a new parser instance for the specified language version. - create: static func(version: string) -> result; + create: static func(language-version: string) -> result; /// Returns the language version this parser instance is configured for. - version: func() -> string; + language-version: func() -> string; /// Parses the input string starting from the specified nonterminal kind. parse: func(kind: nonterminal-kind, input: string) -> parse-output; diff --git a/crates/codegen/runtime/cargo/wasm/src/runtime/interface/utils.wit.jinja2 b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/utils.wit.jinja2 new file mode 100644 index 0000000000..7becc47d08 --- /dev/null +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/utils.wit.jinja2 @@ -0,0 +1,7 @@ +interface utils { + /// Provides information about the supported language versions and the grammar. + resource language-facts { + /// Returns a list of language versions supported by Slang, sorted ascendingly. + supported-versions: static func() -> list; + } +} diff --git a/crates/codegen/runtime/cargo/wasm/src/runtime/interface/world.wit.jinja2 b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/world.wit.jinja2 index 395b2ec702..fe488e5c0f 100644 --- a/crates/codegen/runtime/cargo/wasm/src/runtime/interface/world.wit.jinja2 +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/world.wit.jinja2 @@ -2,6 +2,9 @@ package nomic-foundation:slang; world slang { export ast; + export bindings; + export compilation; export cst; export parser; + export utils; } diff --git a/crates/codegen/runtime/cargo/wasm/src/runtime/mod.rs b/crates/codegen/runtime/cargo/wasm/src/runtime/mod.rs index ed55e0e62e..bf7b06b7f7 100644 --- a/crates/codegen/runtime/cargo/wasm/src/runtime/mod.rs +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/mod.rs @@ -1,8 +1,8 @@ -#[path = "./generated/bindings.rs"] -mod bindings; +#[path = "./generated/bindgen.rs"] +mod bindgen; mod utils; mod wrappers; struct World; -crate::wasm_crate::bindings::export!(World with_types_in crate::wasm_crate::bindings); +crate::wasm_crate::bindgen::export!(World with_types_in crate::wasm_crate::bindgen); diff --git a/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/ast/mod.rs b/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/ast/mod.rs index 10b4fb6b87..b6bcb389e2 100644 --- a/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/ast/mod.rs +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/ast/mod.rs @@ -4,10 +4,10 @@ mod selectors; use crate::wasm_crate::utils::IntoFFI; mod ffi { - pub use crate::wasm_crate::bindings::exports::nomic_foundation::slang::ast::{ + pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::ast::{ Guest, GuestSelectors, }; - pub use crate::wasm_crate::bindings::exports::nomic_foundation::slang::cst::{ + pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::cst::{ Node, NonterminalNodeBorrow, }; } 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 new file mode 100644 index 0000000000..c093fb0b7c --- /dev/null +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/bindings/mod.rs @@ -0,0 +1,174 @@ +use crate::wasm_crate::utils::{define_rc_wrapper, define_wrapper, IntoFFI}; + +mod ffi { + pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::bindings::{ + BindingGraph, BindingGraphBorrow, BindingLocation, BuiltInLocation, BuiltInLocationBorrow, + CursorBorrow, Definition, DefinitionBorrow, Guest, GuestBindingGraph, GuestBuiltInLocation, + GuestDefinition, GuestReference, GuestUserFileLocation, Reference, ReferenceBorrow, + UserFileLocation, UserFileLocationBorrow, + }; + pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::cst::Cursor; +} + +mod rust { + pub use crate::rust_crate::bindings::{ + BindingGraph, BindingLocation, BuiltInLocation, UserFileLocation, + }; + + /// TODO: This is a work-around for the fact that `metaslang_bindings` internals (handles, locators, etc...) are exposed. + /// We should clean this when we finally publish `__experimental_bindings_api`. + /// That means removing the types below, and using the original types instead. + #[derive(Debug, Clone)] + pub struct Definition { + pub id: usize, + pub name_location: BindingLocation, + pub definiens_location: BindingLocation, + } + + impl From> for Definition { + fn from(definition: crate::rust_crate::bindings::Definition<'_>) -> Self { + Self { + id: definition.id(), + name_location: definition.name_location(), + definiens_location: definition.definiens_location(), + } + } + } + + /// TODO: This is a work-around for the fact that `metaslang_bindings` internals (handles, locators, etc...) are exposed. + /// We should clean this when we finally publish `__experimental_bindings_api`. + /// That means removing the types below, and using the original types instead. + #[derive(Debug, Clone)] + pub struct Reference { + pub id: usize, + pub location: BindingLocation, + pub definitions: Vec, + } + + impl From> for Reference { + fn from(reference: crate::rust_crate::bindings::Reference<'_>) -> Self { + Self { + id: reference.id(), + location: reference.location(), + definitions: reference + .definitions() + .into_iter() + .map(Into::into) + .collect(), + } + } + } +} + +impl ffi::Guest for crate::wasm_crate::World { + type BindingGraph = BindingGraphWrapper; + + type Definition = DefinitionWrapper; + type Reference = ReferenceWrapper; + + type UserFileLocation = UserFileLocationWrapper; + type BuiltInLocation = BuiltInLocationWrapper; +} + +//================================================ +// +// resource binding-graph +// +//================================================ + +define_rc_wrapper! { BindingGraph { + fn definition_at(&self, cursor: ffi::CursorBorrow<'_>) -> Option { + self._borrow_ffi() + .definition_at(&cursor._borrow_ffi()) + .map(rust::Definition::from) + .map(IntoFFI::_into_ffi) + } + + fn reference_at(&self, cursor: ffi::CursorBorrow<'_>) -> Option { + self._borrow_ffi() + .reference_at(&cursor._borrow_ffi()) + .map(rust::Reference::from) + .map(IntoFFI::_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.clone()._into_ffi() + } + + fn definiens_location(&self) -> ffi::BindingLocation { + self._borrow_ffi().definiens_location.clone()._into_ffi() + } +} } + +//================================================ +// +// resource reference +// +//================================================ + +define_wrapper! { Reference { + fn id(&self) -> u32 { + self._borrow_ffi().id.try_into().unwrap() + } + + fn location(&self) -> ffi::BindingLocation { + self._borrow_ffi().location.clone()._into_ffi() + } + + fn definitions(&self) -> Vec { + self._borrow_ffi().definitions.iter().cloned().map(IntoFFI::_into_ffi).collect() + } +} } + +//================================================ +// +// 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().to_owned()._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 new file mode 100644 index 0000000000..3ecc07023c --- /dev/null +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/compilation/mod.rs @@ -0,0 +1,120 @@ +use std::rc::Rc; + +use semver::Version; + +use crate::wasm_crate::utils::{define_rc_wrapper, define_refcell_wrapper, IntoFFI}; + +mod ffi { + pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::bindings::BindingGraph; + pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::compilation::{ + AddFileResponse, CompilationUnit, CompilationUnitBorrow, CursorBorrow, File, FileBorrow, + Guest, GuestCompilationUnit, GuestFile, GuestInternalCompilationBuilder, + InternalCompilationBuilder, InternalCompilationBuilderBorrow, + }; + pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::cst::{Cursor, Node}; +} + +mod rust { + pub use crate::rust_crate::compilation::{ + AddFileResponse, CompilationUnit, File, InternalCompilationBuilder, + }; +} + +impl ffi::Guest for crate::wasm_crate::World { + type InternalCompilationBuilder = InternalCompilationBuilderWrapper; + type CompilationUnit = CompilationUnitWrapper; + type File = FileWrapper; +} + +//================================================ +// +// resource internal-compilation-builder +// +//================================================ + +define_refcell_wrapper! { InternalCompilationBuilder { + fn create(language_version: String) -> Result { + let language_version = Version::parse(&language_version).map_err(|e| e.to_string())?; + + rust::InternalCompilationBuilder::create(language_version) + .map(IntoFFI::_into_ffi) + .map_err(|e| e.to_string()) + } + + fn add_file(&self, id: String, contents: String) -> ffi::AddFileResponse { + self._borrow_mut_ffi() + .add_file(id, &contents) + ._into_ffi() + } + + fn resolve_import(&self, source_file_id: String, import_path: ffi::CursorBorrow<'_>, destination_file_id: String) -> Result<(), String> { + self._borrow_mut_ffi() + .resolve_import(&source_file_id, &import_path._borrow_ffi(), destination_file_id) + .map_err(|e| e.to_string()) + } + + fn build(&self) -> ffi::CompilationUnit { + Rc::new(self._borrow_ffi().build())._into_ffi() + } +} } + +//================================================ +// +// record add-file-response +// +//================================================ + +impl IntoFFI for rust::AddFileResponse { + #[inline] + fn _into_ffi(self) -> ffi::AddFileResponse { + let Self { import_paths } = self; + + ffi::AddFileResponse { + import_paths: import_paths.into_iter().map(IntoFFI::_into_ffi).collect(), + } + } +} + +//================================================ +// +// resource compilation-unit +// +//================================================ + +define_rc_wrapper! { CompilationUnit { + fn language_version(&self) -> String { + self._borrow_ffi().language_version().to_string() + } + + fn files(&self) -> Vec { + self._borrow_ffi().files().into_iter().map(IntoFFI::_into_ffi).collect() + } + + fn file(&self, id: String) -> Option { + self._borrow_ffi().file(&id).map(IntoFFI::_into_ffi) + } + + fn binding_graph(&self) -> Result { + self._borrow_ffi().binding_graph().as_ref().map(Rc::clone).map(IntoFFI::_into_ffi).map_err(|e| e.to_string()) + } +} } + +//================================================ +// +// resource file +// +//================================================ + +define_rc_wrapper! { File { + fn id(&self) -> String { + self._borrow_ffi().id().to_owned() + } + + fn tree(&self) -> ffi::Node { + self._borrow_ffi().tree().to_owned()._into_ffi() + } + + fn create_tree_cursor(&self) -> ffi::Cursor { + self._borrow_ffi().create_tree_cursor()._into_ffi() + } +} } diff --git a/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/cst/mod.rs b/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/cst/mod.rs index c0e31cdba3..0f93bf33a1 100644 --- a/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/cst/mod.rs +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/cst/mod.rs @@ -5,7 +5,7 @@ use crate::wasm_crate::utils::{ }; mod ffi { - pub use crate::wasm_crate::bindings::exports::nomic_foundation::slang::cst::{ + pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::cst::{ AncestorsIterator, AncestorsIteratorBorrow, Cursor, CursorBorrow, CursorIterator, CursorIteratorBorrow, Edge, EdgeLabel, Guest, GuestAncestorsIterator, GuestCursor, GuestCursorIterator, GuestNonterminalNode, GuestQuery, GuestQueryMatchIterator, diff --git a/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/mod.rs b/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/mod.rs index 26cb73d858..f477b99957 100644 --- a/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/mod.rs +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/mod.rs @@ -1,3 +1,6 @@ mod ast; +mod bindings; +mod compilation; mod cst; mod parser; +mod utils; diff --git a/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/parser/mod.rs b/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/parser/mod.rs index d02394a852..c783de47bd 100644 --- a/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/parser/mod.rs +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/parser/mod.rs @@ -3,10 +3,10 @@ use std::rc::Rc; use crate::wasm_crate::utils::{define_wrapper, FromFFI, IntoFFI}; mod ffi { - pub use crate::wasm_crate::bindings::exports::nomic_foundation::slang::cst::{ + pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::cst::{ Cursor, NonterminalNode, TextRange, }; - pub use crate::wasm_crate::bindings::exports::nomic_foundation::slang::parser::{ + pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::parser::{ Guest, GuestParseError, GuestParseOutput, GuestParser, NonterminalKind, ParseError, ParseErrorBorrow, ParseOutput, ParseOutputBorrow, Parser, ParserBorrow, }; @@ -33,22 +33,15 @@ define_wrapper! { Parser { rust::Parser::ROOT_KIND._into_ffi() } - fn supported_versions() -> Vec { - rust::Parser::SUPPORTED_VERSIONS - .iter() - .map(|v| v.to_string()) - .collect() - } - - fn create(version: String) -> Result { - semver::Version::parse(&version) - .map_err(|_| format!("Invalid semantic version: '{version}'")) + fn create(language_version: String) -> Result { + semver::Version::parse(&language_version) + .map_err(|_| format!("Invalid semantic version: '{language_version}'")) .and_then(|version| rust::Parser::create(version).map_err(|e| e.to_string())) .map(IntoFFI::_into_ffi) } - fn version(&self) -> String { - self._borrow_ffi().version.to_string() + fn language_version(&self) -> String { + self._borrow_ffi().language_version().to_string() } fn parse(&self, kind: ffi::NonterminalKind, input: String) -> ffi::ParseOutput { diff --git a/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/utils/mod.rs b/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/utils/mod.rs new file mode 100644 index 0000000000..a621d61d36 --- /dev/null +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/utils/mod.rs @@ -0,0 +1,30 @@ +use crate::wasm_crate::utils::define_wrapper; + +mod ffi { + pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::utils::{ + Guest, GuestLanguageFacts, LanguageFacts, LanguageFactsBorrow, + }; +} + +mod rust { + pub use crate::rust_crate::utils::LanguageFacts; +} + +impl ffi::Guest for crate::wasm_crate::World { + type LanguageFacts = LanguageFactsWrapper; +} + +//================================================ +// +// resource language-facts +// +//================================================ + +define_wrapper! { LanguageFacts { + fn supported_versions() -> Vec { + rust::LanguageFacts::SUPPORTED_VERSIONS + .iter() + .map(|v| v.to_string()) + .collect() + } +} } diff --git a/crates/codegen/runtime/generator/src/lib.rs b/crates/codegen/runtime/generator/src/lib.rs index 786747c84c..1c47a92c6f 100644 --- a/crates/codegen/runtime/generator/src/lib.rs +++ b/crates/codegen/runtime/generator/src/lib.rs @@ -63,6 +63,7 @@ struct ModelWrapper { #[derive(Serialize)] struct RuntimeModel { slang_version: Version, + language_name: String, all_language_versions: BTreeSet, breaking_language_versions: BTreeSet, @@ -76,6 +77,7 @@ impl RuntimeModel { fn from_language(language: &Rc) -> Result { Ok(Self { slang_version: CargoWorkspace::local_version()?, + language_name: language.name.to_string(), all_language_versions: language.versions.iter().cloned().collect(), breaking_language_versions: language.collect_breaking_versions(), @@ -91,6 +93,7 @@ impl Default for RuntimeModel { fn default() -> Self { Self { slang_version: Version::new(0, 0, 0), + language_name: "CodegenRuntime".to_string(), all_language_versions: BTreeSet::default(), breaking_language_versions: BTreeSet::default(), diff --git a/crates/codegen/runtime/npm/package/package.json b/crates/codegen/runtime/npm/package/package.json index 00c41a6001..86c8e58339 100644 --- a/crates/codegen/runtime/npm/package/package.json +++ b/crates/codegen/runtime/npm/package/package.json @@ -6,8 +6,11 @@ "exports": { ".": "./target/generated/index.mjs", "./ast": "./target/generated/ast/index.mjs", + "./bindings": "./target/generated/bindings/index.mjs", + "./compilation": "./target/generated/compilation/index.mjs", "./cst": "./target/generated/cst/index.mjs", - "./parser": "./target/generated/parser/index.mjs" + "./parser": "./target/generated/parser/index.mjs", + "./utils": "./target/generated/utils/index.mjs" }, "__dependencies_comment__": "__SLANG_NPM_PACKAGE_DEPENDENCIES__ (keep in sync)", "dependencies": { diff --git a/crates/codegen/runtime/npm/package/src/runtime/bindings/index.mts b/crates/codegen/runtime/npm/package/src/runtime/bindings/index.mts new file mode 100644 index 0000000000..f5855d023e --- /dev/null +++ b/crates/codegen/runtime/npm/package/src/runtime/bindings/index.mts @@ -0,0 +1,21 @@ +import * as generated from "../../../wasm/index.mjs"; + +export const BindingGraph = generated.bindings.BindingGraph; +export type BindingGraph = generated.bindings.BindingGraph; + +export const Definition = generated.bindings.Definition; +export type Definition = generated.bindings.Definition; + +export const Reference = generated.bindings.Reference; +export type Reference = generated.bindings.Reference; + +export type BindingLocation = generated.bindings.BindingLocation; + +export const BindingLocationType = generated.bindings.BindingLocationType; +export type BindingLocationType = generated.bindings.BindingLocationType; + +export const UserFileLocation = generated.bindings.UserFileLocation; +export type UserFileLocation = generated.bindings.UserFileLocation; + +export const BuiltInLocation = generated.bindings.BuiltInLocation; +export type BuiltInLocation = generated.bindings.BuiltInLocation; diff --git a/crates/codegen/runtime/npm/package/src/runtime/compilation/builder.mts b/crates/codegen/runtime/npm/package/src/runtime/compilation/builder.mts new file mode 100644 index 0000000000..029be84e07 --- /dev/null +++ b/crates/codegen/runtime/npm/package/src/runtime/compilation/builder.mts @@ -0,0 +1,112 @@ +import { Cursor } from "../cst/index.mjs"; +import { CompilationUnit } from "./index.mjs"; + +import * as generated from "../../../wasm/index.mjs"; + +const InternalCompilationBuilder = generated.compilation.InternalCompilationBuilder; +type InternalCompilationBuilder = generated.compilation.InternalCompilationBuilder; + +/** + * User-provided options and callbacks necessary for the `CompilationBuilder` class to perform its job. + */ +export interface CompilationBuilderConfig { + /** + * The language version to parse files with. + */ + languageVersion: string; + + /** + * Callback used by this builder to load the contents of a file. + * + * The user is responsible for fetching the file from the filesystem. + * If the file is not found, the callback should return undefined. + * Any errors thrown by the callback will be propagated to the caller. + */ + readFile: (fileId: string) => Promise; + + /** + * Callback used by this builder to resolve an import path. + * For example, if a source file contains the following statement: + * + * ```solidity + * import {Foo} from "foo.sol"; + * ``` + * + * Then the API will invoke the callback with a cursor pointing to the `"foo.sol"` string literal. + * + * The user is responsible for resolving it to a file in the compilation, and return its ID. + * If the callback returns `undefined`, the import will stay unresolved. + * Any errors thrown by the callback will be propagated to the caller. + */ + resolveImport: (sourceFileId: string, importPath: Cursor) => Promise; +} + +/** + * A builder for creating compilation units. + * Allows incrementally building a list of all files and their imports. + */ +export class CompilationBuilder { + private readonly seenFiles: Set = new Set(); + + private constructor( + private readonly internalBuilder: InternalCompilationBuilder, + + /** + * The user-supplied configuration. + */ + public readonly config: CompilationBuilderConfig, + ) {} + + /** + * Creates a new compilation builder for the specified language version. + */ + public static create(config: CompilationBuilderConfig): CompilationBuilder { + const internalBuilder = InternalCompilationBuilder.create(config.languageVersion); + return new CompilationBuilder(internalBuilder, config); + } + + /** + * Adds a source file to the compilation unit. + * Typically, users only need to add the "root" file, which contains the main contract they are trying to analyze. + * Any files that are imported by the root file will be discovered and loaded automatically by the config callbacks. + * + * Adding multiple files (roots) is supported. For example, an IDE can choose to add all NPM dependencies, + * regardless of whether they are imported or not, to be able to query the definitions there. + * + * Adding a file that has already been added is a no-op. + */ + public async addFile(id: string): Promise { + if (this.seenFiles.has(id)) { + return; + } else { + this.seenFiles.add(id); + } + + const contents = await this.config.readFile(id); + if (contents === undefined) { + return; + } + + const { importPaths } = this.internalBuilder.addFile(id, contents); + + await Promise.all( + importPaths.map(async (importPath) => { + const destinationFileId = await this.config.resolveImport(id, importPath); + if (destinationFileId === undefined) { + return; + } + + this.internalBuilder.resolveImport(id, importPath, destinationFileId); + + await this.addFile(destinationFileId); + }), + ); + } + + /** + * Builds and returns the final compilation unit. + */ + public build(): CompilationUnit { + return this.internalBuilder.build(); + } +} diff --git a/crates/codegen/runtime/npm/package/src/runtime/compilation/index.mts b/crates/codegen/runtime/npm/package/src/runtime/compilation/index.mts new file mode 100644 index 0000000000..ef9fb5201e --- /dev/null +++ b/crates/codegen/runtime/npm/package/src/runtime/compilation/index.mts @@ -0,0 +1,14 @@ +import * as generated from "../../../wasm/index.mjs"; +import * as builder from "./builder.mjs"; + +// This is a wrapper around 'generated.compilation.InternalCompilationBuilder': +export const CompilationBuilder = builder.CompilationBuilder; +export type CompilationBuilder = builder.CompilationBuilder; + +export type CompilationBuilderConfig = builder.CompilationBuilderConfig; + +export const CompilationUnit = generated.compilation.CompilationUnit; +export type CompilationUnit = generated.compilation.CompilationUnit; + +export const File = generated.compilation.File; +export type File = generated.compilation.File; diff --git a/crates/codegen/runtime/npm/package/src/runtime/cst/index.mts b/crates/codegen/runtime/npm/package/src/runtime/cst/index.mts index 4ad2bc383b..2d6ef2a414 100644 --- a/crates/codegen/runtime/npm/package/src/runtime/cst/index.mts +++ b/crates/codegen/runtime/npm/package/src/runtime/cst/index.mts @@ -48,10 +48,9 @@ export type TextIndex = generated.cst.TextIndex; export type TextRange = generated.cst.TextRange; -/* - * Helpers: +/** + * Asserts that this node is a `NonterminalNode` with the provided kind and text. */ - export function assertIsNonterminalNode( node: unknown, kind?: NonterminalKind, @@ -70,6 +69,9 @@ export function assertIsNonterminalNode( } } +/** + * Asserts that this node is a `TerminalKind` with the provided kind and text. + */ export function assertIsTerminalNode(node: unknown, kind?: TerminalKind, text?: string): asserts node is TerminalNode { if (!(node instanceof TerminalNode)) { throw new Error("Node provided is not a TerminalNode."); diff --git a/crates/codegen/runtime/npm/package/src/runtime/index.mts b/crates/codegen/runtime/npm/package/src/runtime/index.mts index 92781586e8..12fb24e0b1 100644 --- a/crates/codegen/runtime/npm/package/src/runtime/index.mts +++ b/crates/codegen/runtime/npm/package/src/runtime/index.mts @@ -1,3 +1,6 @@ export * as ast from "./ast/index.mjs"; +export * as bindings from "./bindings/index.mjs"; +export * as compilation from "./compilation/index.mjs"; export * as cst from "./cst/index.mjs"; export * as parser from "./parser/index.mjs"; +export * as utils from "./utils/index.mjs"; diff --git a/crates/codegen/runtime/npm/package/src/runtime/utils/index.mts b/crates/codegen/runtime/npm/package/src/runtime/utils/index.mts new file mode 100644 index 0000000000..fbf07b806d --- /dev/null +++ b/crates/codegen/runtime/npm/package/src/runtime/utils/index.mts @@ -0,0 +1,4 @@ +import * as generated from "../../../wasm/index.mjs"; + +export const LanguageFacts = generated.utils.LanguageFacts; +export type LanguageFacts = generated.utils.LanguageFacts; diff --git a/crates/codegen/runtime/npm/package/wasm/generated/codegen_runtime_cargo_wasm.component.d.ts b/crates/codegen/runtime/npm/package/wasm/generated/codegen_runtime_cargo_wasm.component.d.ts index c7614866dd..959f0ad174 100644 --- a/crates/codegen/runtime/npm/package/wasm/generated/codegen_runtime_cargo_wasm.component.d.ts +++ b/crates/codegen/runtime/npm/package/wasm/generated/codegen_runtime_cargo_wasm.component.d.ts @@ -2,7 +2,13 @@ import { NomicFoundationSlangCst } from "./interfaces/nomic-foundation-slang-cst.js"; import { NomicFoundationSlangAst } from "./interfaces/nomic-foundation-slang-ast.js"; +import { NomicFoundationSlangBindings } from "./interfaces/nomic-foundation-slang-bindings.js"; +import { NomicFoundationSlangCompilation } from "./interfaces/nomic-foundation-slang-compilation.js"; import { NomicFoundationSlangParser } from "./interfaces/nomic-foundation-slang-parser.js"; +import { NomicFoundationSlangUtils } from "./interfaces/nomic-foundation-slang-utils.js"; export * as cst from "./interfaces/nomic-foundation-slang-cst.js"; export * as ast from "./interfaces/nomic-foundation-slang-ast.js"; +export * as bindings from "./interfaces/nomic-foundation-slang-bindings.js"; +export * as compilation from "./interfaces/nomic-foundation-slang-compilation.js"; export * as parser from "./interfaces/nomic-foundation-slang-parser.js"; +export * as utils from "./interfaces/nomic-foundation-slang-utils.js"; diff --git a/crates/codegen/runtime/npm/package/wasm/generated/interfaces/nomic-foundation-slang-bindings.d.ts b/crates/codegen/runtime/npm/package/wasm/generated/interfaces/nomic-foundation-slang-bindings.d.ts new file mode 100644 index 0000000000..b2b0d4dc94 --- /dev/null +++ b/crates/codegen/runtime/npm/package/wasm/generated/interfaces/nomic-foundation-slang-bindings.d.ts @@ -0,0 +1,153 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +export namespace NomicFoundationSlangBindings { + export { BindingGraph }; + export { Definition }; + export { Reference }; + export { UserFileLocation }; + export { BuiltInLocation }; + export { BindingLocation }; + export { BindingLocationType }; +} +import type { Cursor } from "./nomic-foundation-slang-cst.js"; +export { Cursor }; +/** + * 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. + */ +export type BindingLocation = UserFileLocation | BuiltInLocation; +export enum BindingLocationType { + UserFileLocation = "UserFileLocation", + BuiltInLocation = "BuiltInLocation", +} + +/** + * 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. + */ +export class BindingGraph { + /** + * If the provided cursor points at a definition `Identifier`, it will return the + * corresponding definition. Otherwise, it will return `undefined`. + */ + definitionAt(cursor: Cursor): Definition | undefined; + /** + * If the provided cursor points at a reference `Identifier`, it will return the + * corresponding reference. Otherwise, it will return `undefined`. + */ + referenceAt(cursor: Cursor): Reference | undefined; +} + +/** + * Represents a location of a built-in symbol in the language. + */ +export class BuiltInLocation { + /** + * The variant of `BindingLocationType` that corresponds to this class. + */ + readonly type = BindingLocationType.BuiltInLocation; + + /** + * Coerce this variant to a `BuiltInLocation`, or `undefined` if this is not the correct type. + */ + asBuiltInLocation(): this; + + /** + * Return `true` if this object is an instance of `BuiltInLocation`. + */ + isBuiltInLocation(): this is BuiltInLocation; + + /** + * Coerce this variant to a `UserFileLocation`, or `undefined` if this is not the correct type. + */ + asUserFileLocation(): undefined; + + /** + * Return `true` if this object is an instance of `UserFileLocation`. + */ + isUserFileLocation(): false; +} + +/** + * Represents a definition in the binding graph. + */ +export class 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. + */ + get id(): number; + /** + * Returns the location of the definition's name. + * For `contract X {}`, that is the location of the `X` `Identifier` node. + */ + get nameLocation(): BindingLocation; + /** + * Returns the location of the definition's definiens. + * For `contract X {}`, that is the location of the parent `ContractDefinition` node. + */ + get definiensLocation(): BindingLocation; +} + +/** + * Represents a reference in the binding graph. + */ +export class 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. + */ + get id(): number; + /** + * Returns the location of the reference. + * For `new X()`, that is the location of the `X` `Identifier` node. + */ + get location(): BindingLocation; + /** + * 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. + */ + definitions(): Definition[]; +} + +/** + * Represents a location of a user-defined symbol in a user file. + */ +export class UserFileLocation { + /** + * The variant of `BindingLocationType` that corresponds to this class. + */ + readonly type = BindingLocationType.UserFileLocation; + + /** + * Coerce this variant to a `UserFileLocation`, or `undefined` if this is not the correct type. + */ + asUserFileLocation(): this; + + /** + * Return `true` if this object is an instance of `UserFileLocation`. + */ + isUserFileLocation(): this is UserFileLocation; + + /** + * Coerce this variant to a `BuiltInLocation`, or `undefined` if this is not the correct type. + */ + asBuiltInLocation(): undefined; + + /** + * Return `true` if this object is an instance of `BuiltInLocation`. + */ + isBuiltInLocation(): false; + + /** + * Returns the ID of the file that contains the symbol. + */ + get fileId(): string; + /** + * Returns a cursor to the CST node that contains the symbol. + */ + get cursor(): Cursor; +} diff --git a/crates/codegen/runtime/npm/package/wasm/generated/interfaces/nomic-foundation-slang-compilation.d.ts b/crates/codegen/runtime/npm/package/wasm/generated/interfaces/nomic-foundation-slang-compilation.d.ts new file mode 100644 index 0000000000..3c1a6831c1 --- /dev/null +++ b/crates/codegen/runtime/npm/package/wasm/generated/interfaces/nomic-foundation-slang-compilation.d.ts @@ -0,0 +1,98 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +export namespace NomicFoundationSlangCompilation { + export { InternalCompilationBuilder }; + export { CompilationUnit }; + export { File }; +} +import type { BindingGraph } from "./nomic-foundation-slang-bindings.js"; +export { BindingGraph }; +import type { Node } from "./nomic-foundation-slang-cst.js"; +export { Node }; +import type { Cursor } from "./nomic-foundation-slang-cst.js"; +export { Cursor }; +/** + * Contains information about imports found in an added source file. + */ +export interface AddFileResponse { + /** + * List of cursors to any import paths found in the file. + */ + importPaths: Cursor[]; +} + +/** + * A complete compilation unit is a complete view over all compilation inputs: + * + * - All source files, stored as CSTs. + * - Name binding graph that exposes relationships between definitions and references in these files. + * - Any relevant compilation options. + * + * It also exposes utilities to traverse the compilation unit and query it. + */ +export class CompilationUnit { + /** + * Returns the language version this compilation unit is configured for. + */ + get languageVersion(): string; + /** + * Returns a list of all files in the compilation unit. + */ + files(): File[]; + /** + * Returns the file with the specified ID, if it exists. + */ + file(id: string): File | undefined; + /** + * Calculates name binding information for all source files within the compilation unit. + * Returns a graph that contains all found definitions and their references. + * + * Note: building this graph is an expensive operation. + * It is done lazily on the first access, and cached thereafter. + */ + get bindingGraph(): BindingGraph; +} + +/** + * A single source file in the compilation unit. + */ +export class File { + /** + * Returns the unique identifier of this file. + */ + get id(): string; + /** + * Returns the syntax tree of this file. + */ + get tree(): Node; + /** + * Creates a cursor for traversing the syntax tree of this file. + */ + createTreeCursor(): Cursor; +} + +/** + * A builder for creating compilation units. + * Allows incrementally building a transitive list of all files and their imports. + * + * This is an internal API, and exposed via a public `CompilationBuilder` wrapper class written in TypeScript. + * This allows storing/invoking user supplied callbacks in TypeScript, rather than Rust, which has its limitations. + */ +export class InternalCompilationBuilder { + /** + * Creates a new compilation builder for the specified language version. + */ + static create(languageVersion: string): InternalCompilationBuilder; + /** + * Adds a source file to the compilation unit. + */ + addFile(id: string, contents: string): AddFileResponse; + /** + * Resolves an import in the source file to the destination file. + */ + resolveImport(sourceFileId: string, importPath: Cursor, destinationFileId: string): void; + /** + * Builds and returns the final compilation unit. + */ + build(): CompilationUnit; +} diff --git a/crates/codegen/runtime/npm/package/wasm/generated/interfaces/nomic-foundation-slang-parser.d.ts b/crates/codegen/runtime/npm/package/wasm/generated/interfaces/nomic-foundation-slang-parser.d.ts index ba8ffd64a0..07fe4156a6 100644 --- a/crates/codegen/runtime/npm/package/wasm/generated/interfaces/nomic-foundation-slang-parser.d.ts +++ b/crates/codegen/runtime/npm/package/wasm/generated/interfaces/nomic-foundation-slang-parser.d.ts @@ -65,19 +65,14 @@ export class Parser { * This represents the starting point for parsing a complete source file. */ static rootKind(): NonterminalKind; - /** - * Returns a list of language versions supported by this parser. - * Each version string represents a specific grammar configuration. - */ - static supportedVersions(): string[]; /** * Creates a new parser instance for the specified language version. */ - static create(version: string): Parser; + static create(languageVersion: string): Parser; /** * Returns the language version this parser instance is configured for. */ - get version(): string; + get languageVersion(): string; /** * Parses the input string starting from the specified nonterminal kind. */ diff --git a/crates/codegen/runtime/npm/package/wasm/generated/interfaces/nomic-foundation-slang-utils.d.ts b/crates/codegen/runtime/npm/package/wasm/generated/interfaces/nomic-foundation-slang-utils.d.ts new file mode 100644 index 0000000000..0a3e19de1c --- /dev/null +++ b/crates/codegen/runtime/npm/package/wasm/generated/interfaces/nomic-foundation-slang-utils.d.ts @@ -0,0 +1,15 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +export namespace NomicFoundationSlangUtils { + export { LanguageFacts }; +} + +/** + * Provides information about the supported language versions and the grammar. + */ +export class LanguageFacts { + /** + * Returns a list of language versions supported by Slang, sorted ascendingly. + */ + static supportedVersions(): string[]; +} diff --git a/crates/metaslang/bindings/generated/public_api.txt b/crates/metaslang/bindings/generated/public_api.txt index f98a7e4582..e0fe3e3212 100644 --- a/crates/metaslang/bindings/generated/public_api.txt +++ b/crates/metaslang/bindings/generated/public_api.txt @@ -1,6 +1,16 @@ # 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 +impl core::clone::Clone for metaslang_bindings::BindingLocation +pub fn metaslang_bindings::BindingLocation::clone(&self) -> metaslang_bindings::BindingLocation +impl core::fmt::Debug for metaslang_bindings::BindingLocation +pub fn metaslang_bindings::BindingLocation::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result pub enum metaslang_bindings::FileDescriptor pub metaslang_bindings::FileDescriptor::System(alloc::string::String) pub metaslang_bindings::FileDescriptor::User(alloc::string::String) @@ -12,24 +22,31 @@ 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::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 +impl core::clone::Clone for metaslang_bindings::BuiltInLocation +pub fn metaslang_bindings::BuiltInLocation::clone(&self) -> metaslang_bindings::BuiltInLocation +impl core::fmt::Debug for metaslang_bindings::BuiltInLocation +pub fn metaslang_bindings::BuiltInLocation::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result 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>::name_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 +63,24 @@ 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>::jump_to_definition(&self) -> core::result::Result, metaslang_bindings::ResolutionError<'a, KT>> +pub fn metaslang_bindings::Reference<'a, KT>::id(&self) -> usize +pub fn metaslang_bindings::Reference<'a, KT>::location(&self) -> metaslang_bindings::BindingLocation +pub fn metaslang_bindings::Reference<'a, KT>::resolve_definition(&self) -> core::result::Result, metaslang_bindings::ResolutionError<'a, KT>> 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 trait metaslang_bindings::PathResolver -pub fn metaslang_bindings::PathResolver::resolve_path(&self, context_path: &str, path_to_resolve: &str) -> core::option::Option +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 +impl core::clone::Clone for metaslang_bindings::UserFileLocation +pub fn metaslang_bindings::UserFileLocation::clone(&self) -> metaslang_bindings::UserFileLocation +impl core::fmt::Debug for metaslang_bindings::UserFileLocation +pub fn metaslang_bindings::UserFileLocation::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +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/builder/functions.rs b/crates/metaslang/bindings/src/builder/functions.rs index 5bdab61182..27ff5d9aa3 100644 --- a/crates/metaslang/bindings/src/builder/functions.rs +++ b/crates/metaslang/bindings/src/builder/functions.rs @@ -1,4 +1,4 @@ -use std::sync::Arc; +use std::rc::Rc; use metaslang_cst::kinds::KindTypes; use metaslang_graph_builder::functions::Functions; @@ -8,7 +8,7 @@ use crate::PathResolver; pub fn default_functions( version: Version, - path_resolver: Arc, + path_resolver: Rc>, ) -> Functions { let mut functions = Functions::stdlib(); version::add_version_functions(&mut functions, version); @@ -56,7 +56,7 @@ mod version { } mod resolver { - use std::sync::Arc; + use std::rc::Rc; use metaslang_cst::kinds::KindTypes; use metaslang_graph_builder::functions::{Function, Functions, Parameters}; @@ -67,24 +67,24 @@ mod resolver { pub fn add_functions( functions: &mut Functions, - path_resolver: Arc, + path_resolver: Rc>, ) { functions.add("resolve-path".into(), ResolvePath { path_resolver }); functions.add("is-system-file".into(), IsSystemFile {}); } - struct ResolvePath { - path_resolver: Arc, + struct ResolvePath { + path_resolver: Rc>, } - impl Function for ResolvePath { + impl Function for ResolvePath { fn call( &self, - _graph: &mut Graph, + graph: &mut Graph, parameters: &mut dyn Parameters, ) -> Result { let context_path = parameters.param()?.into_string()?; - let path_to_resolve = parameters.param()?.into_string()?; + let path_to_resolve = &graph[parameters.param()?.as_syntax_node_ref()?]; parameters.finish()?; let context_file_descriptor = FileDescriptor::try_from(&context_path); @@ -101,13 +101,14 @@ mod resolver { let resolved_path = self .path_resolver .as_ref() - .resolve_path(&context_user_path, &path_to_resolve) + .resolve_path(&context_user_path, path_to_resolve) .map_or_else( || { // In case we cannot resolve the path, we return a special value that is unique // per context/path pait. This way, we can still run incrementally and resolve // other symbols in the file: - format!("__SLANG_UNRESOLVED_PATH__{context_path}__{path_to_resolve}__") + let node_id = path_to_resolve.node().id(); + format!("__SLANG_UNRESOLVED_PATH__{context_path}__{node_id}__") }, |resolved_path| FileDescriptor::User(resolved_path).as_string(), ); diff --git a/crates/metaslang/bindings/src/builder/mod.rs b/crates/metaslang/bindings/src/builder/mod.rs index 3a27e9b1cc..f768302d52 100644 --- a/crates/metaslang/bindings/src/builder/mod.rs +++ b/crates/metaslang/bindings/src/builder/mod.rs @@ -130,7 +130,7 @@ //! To do this, add a `source_node` attribute, whose value is a syntax node capture: //! //! ``` skip -//! @func [FunctionDefinition ... [FunctionName @id [Identifier]] ...] { +//! @func [FunctionDefinition [FunctionName @id [Identifier]]] { //! node def //! attr (def) type = "pop_symbol", symbol = (source-text @id), source_node = @func, is_definition //! } @@ -161,7 +161,7 @@ //! `syntax_type` attribute, whose value is a string indicating the syntax type. //! //! ``` skip -//! @func [FunctionDefinition ... [FunctionName @id [Identifier]] ...] { +//! @func [FunctionDefinition [FunctionName @id [Identifier]]] { //! node def //! ; ... //! attr (def) syntax_type = "function" @@ -175,7 +175,7 @@ //! `definiens_node` attribute, whose value is a syntax node that spans the definiens. //! //! ``` skip -//! @func [FunctionDefinition ... [FunctionName @id [Identifier]] ... @body [FunctionBody] ...] { +//! @func [FunctionDefinition [FunctionName @id [Identifier]] @body [FunctionBody]] { //! node def //! ; ... //! attr (def) definiens_node = @body @@ -189,7 +189,7 @@ //! To connect two stack graph nodes, use the `edge` statement to add an edge between them: //! //! ``` skip -//! @func [FunctionDefinition ... [FunctionName @id [Identifier]] ...] { +//! @func [FunctionDefinition [FunctionName @id [Identifier]]] { //! node def //! attr (def) type = "pop_symbol", symbol = (source-text @id), source_node = @func, is_definition //! node body @@ -201,7 +201,7 @@ //! you can add a `precedence` attribute to each edge to indicate which paths are prioritized: //! //! ``` skip -//! @func [FunctionDefinition ... [FunctionName @id [Identifier]] ...] { +//! @func [FunctionDefinition [FunctionName @id [Identifier]]] { //! node def //! attr (def) type = "pop_symbol", symbol = (source-text @id), source_node = @func, is_definition //! node body @@ -220,7 +220,7 @@ //! ``` skip //! global ROOT_NODE //! -//! @func [FunctionDefinition ... [FunctionName @id [Identifier]] ...] { +//! @func [FunctionDefinition [FunctionName @id [Identifier]]] { //! node def //! attr (def) type = "pop_symbol", symbol = (source-text @id), source_node = @func, is_definition //! edge ROOT_NODE -> def @@ -235,7 +235,7 @@ //! a scope node with a kind as follows: //! //! ``` skip -//! @func [FunctionDefinition ... [FunctionName @id [Identifier]] ...] { +//! @func [FunctionDefinition [FunctionName @id [Identifier]]] { //! ; ... //! node param_scope //! attr (param_scope) debug_kind = "param_scope" @@ -243,6 +243,72 @@ //! } //! ``` //! +//! ### Other node attributes introduced in Slang's usage of stack-graphs +//! +//! #### `tag` attribute +//! +//! This is used to attach a specific meaning to the node, to alter the ranking +//! algorithm used when attempting to disambiguate between multiple definitions +//! found for a reference. This is an optional string attribute. +//! +//! Possible values: +//! +//! - "alias": marks a definition node as a semantic alias of another definition +//! (eg. an import alias) +//! +//! - "c3": used to mark a function/method definition to be a candidate in +//! disambiguation using the C3 linearisation algorithm. In order for C3 +//! linearisation to be possible, type hierarchy attributes need to be provided +//! as well (see `parents` attribute below). +//! +//! - "super": marks a reference as a call to super virtual call. This modifies +//! the C3 linearisation algorithm by eliminating the candidates that are at +//! or further down the hierarchy of where the reference occurs. To determine +//! where the reference occurs, we also use the `parents` attribute. +//! +//! #### `parents` attribute +//! +//! Is used to convey semantic hierarchy. Can be applied to both definitions and +//! references. It's an optional, list of graph nodes attribute. +//! +//! For references it can indicate in which language context the reference +//! occurs (eg. in which method or class). For definitions it can indicate the +//! enclosing type of the definition, or parent classes in a class hierarchy. +//! The parent handles themselves can refer to definitions or references. In the +//! later case, generally speaking they will need to be resolved at resolution +//! time in order to be useful. +//! +//! #### `export_node` and `import_nodes` +//! +//! These are used to define static fixed edges to add via `set_context()`. +//! Using `set_context()` will modify the underlying stack graph by inserting +//! edges from the `import_nodes` of all parents (resolved recursively) of the +//! given context, to the `export_node` associated with the context. +//! +//! This can be used to inject virtual method implementations defined in +//! subclasses in the scope of their parent classes, which are otherwise +//! lexically inaccessible. +//! +//! `export_node` is an optional graph node attribute, and `import_nodes` is an +//! optional list of graph nodes. Both apply only to definition nodes. +//! +//! #### `extension_hook`, `extension_scope` and `inherit_extensions` +//! +//! These attributes enable the bindings API to resolve extension methods by +//! injecting specific scopes at potentially unrelated (lexically speaking) +//! nodes in the stack graph. Availability and application of extension scopes +//! depend on the call site (ie. the reference node). Thus, the extension scope +//! to (potentially) apply when resolving a reference is computed by looking up +//! the `parents` of the reference and then querying those parent nodes for +//! their `extension_scope` (an optional scope node). Any extension providing +//! node can also have the `inherit_extensions` attribute (a boolean) which +//! indicates that the algorithm should recurse and resolve its parents to +//! further look for other extensions scopes. +//! +//! Finally, the attribute `extension_hook` defines where in the graph should +//! these extension scopes be injected. This is typically the root lexical +//! scope. This attribute applies to any scope node and is boolean. +//! mod cancellation; mod functions; @@ -282,6 +348,9 @@ static IS_DEFINITION_ATTR: &str = "is_definition"; static IS_ENDPOINT_ATTR: &str = "is_endpoint"; static IS_EXPORTED_ATTR: &str = "is_exported"; static IS_REFERENCE_ATTR: &str = "is_reference"; +static EXTENSION_HOOK_ATTR: &str = "extension_hook"; +static EXTENSION_SCOPE_ATTR: &str = "extension_scope"; +static INHERIT_EXTENSIONS_ATTR: &str = "inherit_extensions"; static PARENTS_ATTR: &str = "parents"; static SCOPE_ATTR: &str = "scope"; static SOURCE_NODE_ATTR: &str = "source_node"; @@ -302,6 +371,8 @@ static POP_SCOPED_SYMBOL_ATTRS: Lazy> = Lazy::new(|| { EXPORT_NODE_ATTR, IMPORT_NODES_ATTR, SYNTAX_TYPE_ATTR, + EXTENSION_SCOPE_ATTR, + INHERIT_EXTENSIONS_ATTR, ]) }); static POP_SYMBOL_ATTRS: Lazy> = Lazy::new(|| { @@ -315,6 +386,8 @@ static POP_SYMBOL_ATTRS: Lazy> = Lazy::new(|| { EXPORT_NODE_ATTR, IMPORT_NODES_ATTR, SYNTAX_TYPE_ATTR, + EXTENSION_SCOPE_ATTR, + INHERIT_EXTENSIONS_ATTR, ]) }); static PUSH_SCOPED_SYMBOL_ATTRS: Lazy> = Lazy::new(|| { @@ -336,8 +409,14 @@ static PUSH_SYMBOL_ATTRS: Lazy> = Lazy::new(|| { PARENTS_ATTR, ]) }); -static SCOPE_ATTRS: Lazy> = - Lazy::new(|| HashSet::from([TYPE_ATTR, IS_EXPORTED_ATTR, IS_ENDPOINT_ATTR])); +static SCOPE_ATTRS: Lazy> = Lazy::new(|| { + HashSet::from([ + TYPE_ATTR, + IS_EXPORTED_ATTR, + IS_ENDPOINT_ATTR, + EXTENSION_HOOK_ATTR, + ]) +}); // Edge attribute names static PRECEDENCE_ATTR: &str = "precedence"; @@ -362,6 +441,7 @@ pub(crate) struct Builder<'a, KT: KindTypes + 'static> { cursors: HashMap, Cursor>, definitions_info: HashMap, DefinitionBindingInfo>, references_info: HashMap, ReferenceBindingInfo>, + extension_hooks: HashSet>, } pub(crate) struct BuildResult { @@ -370,6 +450,8 @@ pub(crate) struct BuildResult { pub cursors: HashMap, Cursor>, pub definitions_info: HashMap, DefinitionBindingInfo>, pub references_info: HashMap, ReferenceBindingInfo>, + // Nodes where we want to inject extensions + pub extension_hooks: HashSet>, } impl<'a, KT: KindTypes + 'static> Builder<'a, KT> { @@ -392,6 +474,7 @@ impl<'a, KT: KindTypes + 'static> Builder<'a, KT> { cursors: HashMap::new(), definitions_info: HashMap::new(), references_info: HashMap::new(), + extension_hooks: HashSet::new(), } } @@ -480,6 +563,7 @@ impl<'a, KT: KindTypes + 'static> Builder<'a, KT> { cursors: self.cursors, definitions_info: self.definitions_info, references_info: self.references_info, + extension_hooks: self.extension_hooks, }) } @@ -896,6 +980,15 @@ impl<'a, KT: KindTypes> Builder<'a, KT> { None => Vec::new(), }; + let extension_scope = match node.attributes.get(EXTENSION_SCOPE_ATTR) { + Some(extension_scope) => { + Some(self.node_handle_for_graph_node(extension_scope.as_graph_node_ref()?)) + } + None => None, + }; + + let inherit_extensions = Self::load_flag(node, INHERIT_EXTENSIONS_ATTR)?; + self.definitions_info.insert( node_handle, DefinitionBindingInfo { @@ -904,6 +997,8 @@ impl<'a, KT: KindTypes> Builder<'a, KT> { parents, export_node, import_nodes, + extension_scope, + inherit_extensions, }, ); } else if stack_graph_node.is_reference() { @@ -911,6 +1006,10 @@ impl<'a, KT: KindTypes> Builder<'a, KT> { .insert(node_handle, ReferenceBindingInfo { tag, parents }); } + if Self::load_flag(node, EXTENSION_HOOK_ATTR)? { + self.extension_hooks.insert(node_handle); + } + Ok(()) } diff --git a/crates/metaslang/bindings/src/lib.rs b/crates/metaslang/bindings/src/lib.rs index ccc855fca5..e830f97004 100644 --- a/crates/metaslang/bindings/src/lib.rs +++ b/crates/metaslang/bindings/src/lib.rs @@ -1,17 +1,18 @@ mod builder; +mod location; mod resolver; use std::collections::{HashMap, HashSet}; use std::fmt::{self, Debug, Display}; use std::hash::Hash; -use std::sync::Arc; +use std::rc::Rc; use builder::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 resolver::{ResolveOptions, Resolver}; use semver::Version; use stack_graphs::graph::StackGraph; @@ -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)] @@ -32,10 +36,10 @@ pub(crate) struct DefinitionBindingInfo { definiens: Option>, tag: Option, parents: Vec, - #[allow(dead_code)] export_node: Option, - #[allow(dead_code)] import_nodes: Vec, + extension_scope: Option, + inherit_extensions: bool, } pub(crate) struct ReferenceBindingInfo { @@ -43,7 +47,7 @@ pub(crate) struct ReferenceBindingInfo { parents: Vec, } -pub struct Bindings { +pub struct BindingGraph { graph_builder_file: File, functions: Functions, stack_graph: StackGraph, @@ -53,6 +57,7 @@ pub struct Bindings { cursor_to_definitions: HashMap, cursor_to_references: HashMap, context: Option, + extension_hooks: HashSet, } pub enum FileDescriptor { @@ -111,15 +116,15 @@ impl FileDescriptor { } } -pub trait PathResolver { - fn resolve_path(&self, context_path: &str, path_to_resolve: &str) -> Option; +pub trait PathResolver { + fn resolve_path(&self, context_path: &str, path_to_resolve: &Cursor) -> Option; } -impl Bindings { +impl BindingGraph { pub fn create( version: Version, binding_rules: &str, - path_resolver: Arc, + path_resolver: Rc>, ) -> Self { let graph_builder_file = File::from_str(binding_rules).expect("Bindings stack graph builder parse error"); @@ -136,6 +141,7 @@ impl Bindings { cursor_to_definitions: HashMap::new(), cursor_to_references: HashMap::new(), context: None, + extension_hooks: HashSet::new(), } } @@ -187,6 +193,7 @@ impl Bindings { 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 } @@ -254,22 +261,12 @@ impl Bindings { if self.stack_graph[*handle].is_definition() { self.to_definition(*handle) } else { - // TODO: what should we do if the parent reference - // cannot be resolved at this point? - self.to_reference(*handle) - .unwrap() - .jump_to_definition() - .ok() + self.to_reference(*handle)?.non_recursive_resolve().ok() } }) .collect() } - pub fn lookup_definition_by_name(&self, name: &str) -> Option> { - self.all_definitions() - .find(|definition| definition.get_cursor().unwrap().node().unparse() == name) - } - pub fn get_context(&self) -> Option> { self.context.and_then(|handle| self.to_definition(handle)) } @@ -338,6 +335,10 @@ impl Bindings { } results } + + pub(crate) fn is_extension_hook(&self, node_handle: GraphHandle) -> bool { + self.extension_hooks.contains(&node_handle) + } } struct DisplayCursor<'a, KT: KindTypes + 'static> { @@ -361,20 +362,48 @@ impl<'a, KT: KindTypes + 'static> fmt::Display for DisplayCursor<'a, KT> { #[derive(Clone)] pub struct Definition<'a, KT: KindTypes + 'static> { - owner: &'a Bindings, + owner: &'a BindingGraph, handle: GraphHandle, } 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 get_definiens_cursor(&self) -> Option> { + 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) -> &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 { @@ -401,6 +430,20 @@ impl<'a, KT: KindTypes + 'static> Definition<'a, KT> { .unwrap_or_default() } + pub(crate) fn get_extension_scope(&self) -> Option { + self.owner + .definitions_info + .get(&self.handle) + .and_then(|info| info.extension_scope) + } + + pub(crate) fn inherit_extensions(&self) -> bool { + self.owner + .definitions_info + .get(&self.handle) + .map_or(false, |info| info.inherit_extensions) + } + pub fn to_handle(self) -> DefinitionHandle { DefinitionHandle(self.handle) } @@ -408,19 +451,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)), - } + ) } } @@ -432,8 +470,8 @@ impl Debug for Definition<'_, KT> { impl PartialEq for Definition<'_, KT> { fn eq(&self, other: &Self) -> bool { - let our_owner: *const Bindings = self.owner; - let other_owner: *const Bindings = other.owner; + let our_owner: *const BindingGraph = self.owner; + let other_owner: *const BindingGraph = other.owner; our_owner == other_owner && self.handle == other.handle } } @@ -442,7 +480,7 @@ impl Eq for Definition<'_, KT> {} impl Hash for Definition<'_, KT> { fn hash(&self, state: &mut H) { - let owner: *const Bindings = self.owner; + let owner: *const BindingGraph = self.owner; owner.hash(state); self.handle.hash(state); } @@ -450,7 +488,7 @@ impl Hash for Definition<'_, KT> { #[derive(Clone)] pub struct Reference<'a, KT: KindTypes + 'static> { - owner: &'a Bindings, + owner: &'a BindingGraph, handle: GraphHandle, } @@ -460,8 +498,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 { @@ -471,12 +525,20 @@ impl<'a, KT: KindTypes + 'static> Reference<'a, KT> { .expect("Reference does not have a valid file descriptor") } - pub fn jump_to_definition(&self) -> Result, ResolutionError<'a, KT>> { - Resolver::build_for(self).first() + pub fn resolve_definition(&self) -> Result, ResolutionError<'a, KT>> { + Resolver::build_for(self, ResolveOptions::Full).first() } pub fn definitions(&self) -> Vec> { - Resolver::build_for(self).all() + Resolver::build_for(self, ResolveOptions::Full).all() + } + + pub(crate) fn non_recursive_resolve( + &self, + ) -> Result, ResolutionError<'a, KT>> { + // This was likely originated from a full resolution call, so cut + // recursion here by restricting the resolution algorithm. + Resolver::build_for(self, ResolveOptions::NonRecursive).first() } pub(crate) fn has_tag(&self, tag: Tag) -> bool { @@ -499,26 +561,21 @@ 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)), - } + ) } } impl PartialEq for Reference<'_, KT> { fn eq(&self, other: &Self) -> bool { - let our_owner: *const Bindings = self.owner; - let other_owner: *const Bindings = other.owner; + let our_owner: *const BindingGraph = self.owner; + let other_owner: *const BindingGraph = other.owner; our_owner == other_owner && self.handle == other.handle } } diff --git a/crates/metaslang/bindings/src/location/mod.rs b/crates/metaslang/bindings/src/location/mod.rs new file mode 100644 index 0000000000..914a12169d --- /dev/null +++ b/crates/metaslang/bindings/src/location/mod.rs @@ -0,0 +1,40 @@ +use metaslang_cst::cursor::Cursor; +use metaslang_cst::kinds::KindTypes; + +#[derive(Debug, Clone)] +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 {}) + } +} + +#[derive(Debug, Clone)] +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 + } +} + +#[derive(Debug, Clone)] +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/bindings/src/resolver/mod.rs b/crates/metaslang/bindings/src/resolver/mod.rs index 46a92cdc0f..bcd01dc3b7 100644 --- a/crates/metaslang/bindings/src/resolver/mod.rs +++ b/crates/metaslang/bindings/src/resolver/mod.rs @@ -1,11 +1,15 @@ -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::iter::once; use metaslang_cst::kinds::KindTypes; +use stack_graphs::graph::{Degree, Edge, StackGraph}; use stack_graphs::partial::{PartialPath, PartialPaths}; -use stack_graphs::stitching::{ForwardPartialPathStitcher, GraphEdgeCandidates, StitcherConfig}; +use stack_graphs::stitching::{ + ForwardCandidates, ForwardPartialPathStitcher, GraphEdgeCandidates, GraphEdges, StitcherConfig, +}; +use stack_graphs::CancellationError; -use crate::{Bindings, Definition, Reference, ResolutionError, Tag}; +use crate::{BindingGraph, Definition, FileHandle, GraphHandle, Reference, ResolutionError, Tag}; mod c3; @@ -33,10 +37,17 @@ mod c3; /// applied to definitions pointing to virtual methods. /// pub(crate) struct Resolver<'a, KT: KindTypes + 'static> { - owner: &'a Bindings, + owner: &'a BindingGraph, reference: Reference<'a, KT>, partials: PartialPaths, results: Vec>, + options: ResolveOptions, +} + +#[derive(Copy, Clone, Eq, PartialEq)] +pub(crate) enum ResolveOptions { + Full, + NonRecursive, } struct ResolvedPath<'a, KT: KindTypes + 'static> { @@ -51,13 +62,79 @@ impl<'a, KT: KindTypes + 'static> ResolvedPath<'a, KT> { } } +/// Candidates for the forward stitching resolution process. This will inject +/// edges to the the given extensions scopes at extension hook nodes when asked +/// for forward candidates (ie. `get_forward_candidates`) by the resolution +/// algorithm. Other than that, it's exactly the same as `GraphEdgeCandidates`. +struct ResolverCandidates<'a, KT: KindTypes + 'static> { + owner: &'a BindingGraph, + partials: &'a mut PartialPaths, + file: Option, + edges: GraphEdges, + extensions: &'a [GraphHandle], +} + +impl<'a, KT: KindTypes + 'static> ResolverCandidates<'a, KT> { + pub fn new( + owner: &'a BindingGraph, + partials: &'a mut PartialPaths, + file: Option, + extensions: &'a [GraphHandle], + ) -> Self { + Self { + owner, + partials, + file, + edges: GraphEdges, + extensions, + } + } +} + +impl ForwardCandidates + for ResolverCandidates<'_, KT> +{ + fn get_forward_candidates(&mut self, path: &PartialPath, result: &mut R) + where + R: std::iter::Extend, + { + let node = path.end_node; + result.extend(self.owner.stack_graph.outgoing_edges(node).filter(|e| { + self.file + .map_or(true, |file| self.owner.stack_graph[e.sink].is_in_file(file)) + })); + + if self.owner.is_extension_hook(node) { + // Inject edges from the extension hook node to each extension scope + let mut extension_edges = Vec::new(); + for extension in self.extensions { + extension_edges.push(Edge { + source: node, + sink: *extension, + precedence: 0, + }); + } + result.extend(extension_edges); + } + } + + fn get_joining_candidate_degree(&self, path: &PartialPath) -> Degree { + self.owner.stack_graph.incoming_edge_degree(path.end_node) + } + + fn get_graph_partials_and_db(&mut self) -> (&StackGraph, &mut PartialPaths, &GraphEdges) { + (&self.owner.stack_graph, self.partials, &self.edges) + } +} + impl<'a, KT: KindTypes + 'static> Resolver<'a, KT> { - pub fn build_for(reference: &Reference<'a, KT>) -> Self { + pub fn build_for(reference: &Reference<'a, KT>, options: ResolveOptions) -> Self { let mut resolver = Self { owner: reference.owner, reference: reference.clone(), partials: PartialPaths::new(), results: Vec::new(), + options, }; resolver.resolve(); resolver @@ -65,30 +142,70 @@ impl<'a, KT: KindTypes + 'static> Resolver<'a, KT> { fn resolve(&mut self) { let mut reference_paths = Vec::new(); - ForwardPartialPathStitcher::find_all_complete_partial_paths( - &mut GraphEdgeCandidates::new(&self.owner.stack_graph, &mut self.partials, None), - once(self.reference.handle), - StitcherConfig::default(), - &stack_graphs::NoCancellation, - |_graph, _paths, path| { - reference_paths.push(path.clone()); - }, - ) - .expect("should never be cancelled"); + if self.options == ResolveOptions::Full { + let ref_parents = self.reference.resolve_parents(); + let mut extensions = HashSet::new(); + for parent in &ref_parents { + if let Some(extension_scope) = parent.get_extension_scope() { + extensions.insert(extension_scope); + } + if parent.inherit_extensions() { + #[allow(clippy::mutable_key_type)] + let grand_parents = Self::resolve_parents_all(parent.clone()); + for grand_parent in grand_parents.values().flatten() { + if let Some(extension_scope) = grand_parent.get_extension_scope() { + extensions.insert(extension_scope); + } + } + } + } + let extensions = extensions.drain().collect::>(); + + ForwardPartialPathStitcher::find_all_complete_partial_paths( + &mut ResolverCandidates::new(self.owner, &mut self.partials, None, &extensions), + once(self.reference.handle), + StitcherConfig::default(), + &stack_graphs::NoCancellation, + |_graph, _paths, path| { + reference_paths.push(path.clone()); + }, + ) + .expect("Should never be cancelled"); + } else { + ForwardPartialPathStitcher::find_all_complete_partial_paths( + &mut GraphEdgeCandidates::new(&self.owner.stack_graph, &mut self.partials, None), + once(self.reference.handle), + StitcherConfig::default(), + &stack_graphs::NoCancellation, + |_graph, _paths, path| { + reference_paths.push(path.clone()); + }, + ) + .expect("Should never be cancelled"); + }; + + let mut added_nodes = HashSet::new(); for reference_path in &reference_paths { - if reference_paths - .iter() - .all(|other| !other.shadows(&mut self.partials, reference_path)) + let end_node = reference_path.end_node; + + // There may be duplicate ending nodes with different + // post-conditions in the scope stack, but we only care about the + // definition itself. Hence we need to check for uniqueness. + if !added_nodes.contains(&end_node) + && reference_paths + .iter() + .all(|other| !other.shadows(&mut self.partials, reference_path)) { self.results.push(ResolvedPath { definition: self .owner - .to_definition(reference_path.end_node) + .to_definition(end_node) .expect("path to end in a definition node"), partial_path: reference_path.clone(), score: 0.0, }); + added_nodes.insert(end_node); } } } @@ -130,7 +247,9 @@ impl<'a, KT: KindTypes + 'static> Resolver<'a, KT> { } self.mark_down_aliases(); self.mark_down_built_ins(); - self.rank_c3_methods(); + if self.options == ResolveOptions::Full { + self.rank_c3_methods(); + } self.results.sort_by(|a, b| b.score.total_cmp(&a.score)); } 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/metaslang/graph_builder/src/functions.rs b/crates/metaslang/graph_builder/src/functions.rs index 2777d29e0c..04bd964dcf 100644 --- a/crates/metaslang/graph_builder/src/functions.rs +++ b/crates/metaslang/graph_builder/src/functions.rs @@ -8,7 +8,7 @@ //! Functions that can be called by graph DSL files use std::collections::HashMap; -use std::sync::Arc; +use std::rc::Rc; use metaslang_cst::kinds::KindTypes; @@ -86,7 +86,7 @@ where /// A library of named functions. #[derive(Default)] pub struct Functions { - functions: HashMap + Send + Sync>>, + functions: HashMap>>, } impl Functions { @@ -144,9 +144,9 @@ impl Functions { /// Adds a new function to this library. pub fn add(&mut self, name: Identifier, function: F) where - F: Function + Send + Sync + 'static, + F: Function + 'static, { - self.functions.insert(name, Arc::new(function)); + self.functions.insert(name, Rc::new(function)); } /// Calls a named function, returning an error if there is no function with that name. diff --git a/crates/solidity/inputs/language/bindings/rules.msgb b/crates/solidity/inputs/language/bindings/rules.msgb index 0e341a683b..0033e7f90e 100644 --- a/crates/solidity/inputs/language/bindings/rules.msgb +++ b/crates/solidity/inputs/language/bindings/rules.msgb @@ -22,6 +22,11 @@ inherit .enclosing_def inherit .parent_scope inherit .lexical_scope +; Used to resolve extension methods for `using for *` directives +; This is used as a minor optimization to avoid introducing new possible paths +; when there are no `using for *` directives in the contract. +inherit .star_extension + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Source unit (aka .sol file) @@ -62,14 +67,22 @@ inherit .lexical_scope ;; inherited) for contracts to resolve bases (both in inheritance lists and ;; override specifiers) let @source_unit.parent_scope = @source_unit.lexical_scope + + ; This is used to indicate the resolution algorithm that here's where it + ; should inject any possible extension scopes + attr (@source_unit.lexical_scope) extension_hook + + ; Provide a default star extension sink node that gets inherited. This is + ; connected to from expressions, and those can potentially happen anywhere. + node @source_unit.star_extension } ;; Top-level definitions... @source_unit [SourceUnit [SourceUnitMembers [SourceUnitMember @unit_member ( [ContractDefinition] - | [InterfaceDefinition] | [LibraryDefinition] + | [InterfaceDefinition] | [StructDefinition] | [EnumDefinition] | [FunctionDefinition] @@ -79,9 +92,12 @@ inherit .lexical_scope | [EventDefinition] )] ]] { - edge @unit_member.lexical_scope -> @source_unit.lexical_scope edge @source_unit.lexical_scope -> @unit_member.def edge @source_unit.defs -> @unit_member.def + + ; In the general case, the lexical scope of the definition connects directly + ; to the source unit's + edge @unit_member.lexical_scope -> @source_unit.lexical_scope } ;; Special case for built-ins: we want to export all symbols in the contract: @@ -94,13 +110,14 @@ inherit .lexical_scope [SourceUnitMember @contract [ContractDefinition name: ["%BuiltIns%"]]] ]] { if (is-system-file FILE_PATH) { - edge @source_unit.defs -> @contract.members - edge @source_unit.defs -> @contract.type_members - edge @source_unit.defs -> @contract.state_vars + edge @source_unit.defs -> @contract.instance } } @source_unit [SourceUnit [SourceUnitMembers [SourceUnitMember @using [UsingDirective]]]] { + ; TODO: this is the hook for top-level extensions, but this should connect to + ; an extensions scope that gets pushed to the scope stack, as in the case of + ; contracts/libraries (defined further down below). edge @source_unit.lexical_scope -> @using.def } @@ -111,7 +128,7 @@ inherit .lexical_scope edge @source_unit.defs -> @using.def } -;; ... and imports +;; Import connections to the source unit @source_unit [SourceUnit [SourceUnitMembers [SourceUnitMember [ImportDirective [ImportClause @import ( @@ -131,21 +148,29 @@ inherit .lexical_scope ;;; Imports ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -[ImportClause [_ @path path: [StringLiteral]]] { +[ImportClause + [_ + path: [StringLiteral + @path ([DoubleQuotedStringLiteral] | [SingleQuotedStringLiteral]) + ] + ] +] { ;; This node represents the imported file and the @path.import node is used by ;; all subsequent import rules node @path.import - scan (source-text @path) { - "^\\s*[\"'](.+)[\"']\\s*$" { - let resolved_path = (resolve-path FILE_PATH $1) - attr (@path.import) push_symbol = resolved_path - } - } + + let resolved_path = (resolve-path FILE_PATH @path) + attr (@path.import) push_symbol = resolved_path + edge @path.import -> ROOT_NODE } ;;; `import ` -@import [PathImport @path path: [StringLiteral] .] { +@import [PathImport + path: [StringLiteral + @path ([DoubleQuotedStringLiteral] | [SingleQuotedStringLiteral]) + ] +] { ;; This is the "lexical" connection, which makes all symbols exported from the ;; imported source unit available for resolution globally at this' source unit ;; scope @@ -154,8 +179,10 @@ inherit .lexical_scope ;;; `import as ` @import [PathImport - @path path: [StringLiteral] - alias: [ImportAlias @alias [Identifier]] + path: [StringLiteral + @path ([DoubleQuotedStringLiteral] | [SingleQuotedStringLiteral]) + ] + alias: [ImportAlias @alias [Identifier]] ] { node def attr (def) node_definition = @alias @@ -173,8 +200,10 @@ inherit .lexical_scope ;;; `import * as from ` @import [NamedImport - alias: [ImportAlias @alias [Identifier]] - @path path: [StringLiteral] + alias: [ImportAlias @alias [Identifier]] + path: [StringLiteral + @path ([DoubleQuotedStringLiteral] | [SingleQuotedStringLiteral]) + ] ] { node def attr (def) node_definition = @alias @@ -192,8 +221,10 @@ inherit .lexical_scope ;;; `import { [as ] ...} from ` @import [ImportDeconstruction - symbols: [ImportDeconstructionSymbols @symbol [ImportDeconstructionSymbol]] - @path path: [StringLiteral] + symbols: [ImportDeconstructionSymbols @symbol [ImportDeconstructionSymbol]] + path: [StringLiteral + @path ([DoubleQuotedStringLiteral] | [SingleQuotedStringLiteral]) + ] ] { ;; We define these intermediate nodes for convenience only, to make the ;; queries simpler in the two rules below @@ -250,28 +281,32 @@ inherit .lexical_scope ;; interface), aka the source unit edge @type_name.push_end -> heir.parent_scope - ;; Make base members accesible as our own members - node member - attr (member) push_symbol = "." - - node typeof - attr (typeof) push_symbol = "@typeof" - - edge heir.members -> member - edge member -> typeof - edge typeof -> @type_name.push_begin - - ;; Make base defs (eg. enums and structs) accessible as our own - node type_member - attr (type_member) push_symbol = "." + ; Access instance members of the inherited contract/interface, from the + ; instance scope of the inheriting contract/interface + node instance + attr (instance) push_symbol = "@instance" + edge heir.instance -> instance + edge instance -> @type_name.push_begin - edge heir.type_members -> type_member - edge type_member -> @type_name.push_begin + ; Base members can also be accessed (from the instance scope) qualified with + ; the base name (eg. `Base.something`) + node member_pop + attr (member_pop) pop_symbol = "." + edge heir.instance -> @type_name.pop_begin + edge @type_name.pop_end -> member_pop + edge member_pop -> instance - ; Resolve the "super" keyword to the inherited type - edge heir.super -> @type_name.push_begin + ; Base namespace-like members (ie. enums, structs, etc) are also accessible as + ; our own namespace members + node ns_member + attr (ns_member) push_symbol = "." + edge heir.ns -> ns_member + edge ns_member -> @type_name.push_begin } +;; The next couple of rules setup a `.parent_refs` attribute to use in the +;; resolution algorithm to perform linearisation of a contract hierarchy. + ;; NOTE: we use anchors here to prevent the query engine from returning all the ;; sublists of possible parents @specifier [InheritanceSpecifier [InheritanceTypes . @parents [_]+ .]] { @@ -294,38 +329,35 @@ inherit .lexical_scope ;;; Contracts ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -@contract [ContractDefinition] { +@contract [ContractDefinition @name name: [Identifier]] { node @contract.lexical_scope - node @contract.super_scope + node @contract.extensions node @contract.def node @contract.members - node @contract.type_members + node @contract.ns node @contract.modifiers - node @contract.state_vars + node @contract.instance - edge @contract.lexical_scope -> @contract.members - edge @contract.lexical_scope -> @contract.type_members - edge @contract.lexical_scope -> @contract.state_vars + attr (@contract.def) node_definition = @name + attr (@contract.def) definiens_node = @contract + ; The .extensions node is where `using` directives will hook the definitions + attr (@contract.def) extension_scope = @contract.extensions - ;; Modifiers are available as a contract type members through a special '@modifier' symbol - node modifier - attr (modifier) pop_symbol = "@modifier" - edge @contract.type_members -> modifier - edge modifier -> @contract.modifiers + edge @contract.lexical_scope -> @contract.instance - let @contract.enclosing_def = @contract.def -} + ; Instance scope can also see members and our namespace definitions + edge @contract.instance -> @contract.members + edge @contract.instance -> @contract.ns -@contract [ContractDefinition @name name: [Identifier]] { - attr (@contract.def) node_definition = @name - attr (@contract.def) definiens_node = @contract + let @contract.enclosing_def = @contract.def - ;; "instance" like access path - ;; we have two distinct paths: @typeof -> . for accesses to variables of the contract's type - ;; and () -> . for accesses through a `new` invocation (or casting) + ;; External "instance" scope access: either member access through a variable + ;; of the contract's type, or through calling (which happens on `new` + ;; invocations or casting). These should access only externally accessible + ;; members, such as functions and public variables. node member attr (member) pop_symbol = "." - edge member -> @contract.members + edge member -> @contract.instance node type_def attr (type_def) pop_symbol = "@typeof" @@ -337,81 +369,148 @@ inherit .lexical_scope edge @contract.def -> call edge call -> member - ;; "namespace" like access path - node type_member - attr (type_member) pop_symbol = "." - edge @contract.def -> type_member - edge type_member -> @contract.type_members - - ;; Define "this" and connect it to the contract definition + ;; "namespace" scope access + node ns_member + attr (ns_member) pop_symbol = "." + edge @contract.def -> ns_member + edge ns_member -> @contract.ns + + ; Finally there's an @instance guarded path used by derived contracts to + ; access instance accessible members + node instance + attr (instance) pop_symbol = "@instance" + edge @contract.def -> instance + edge instance -> @contract.instance + + ; "this" keyword is available in our lexical scope and can access any + ; externally available member node this attr (this) pop_symbol = "this" - edge this -> member - - ;; ... and make it available in the contract's lexical scope edge @contract.lexical_scope -> this + edge this -> member - ; Resolve the "this" keyword to the contract itself - node name_push - attr (name_push) push_symbol = (source-text @name) - edge this -> name_push - edge name_push -> @contract.lexical_scope - - ;; Define "super" effectively as if it was a state variable of a type connected by our super_scope - ;; super_scope will later connect to the base contract defs directly - node @contract.super - attr (@contract.super) pop_symbol = "super" - - node super_typeof - attr (super_typeof) push_symbol = "@typeof" - - edge @contract.super -> super_typeof - edge super_typeof -> @contract.super_scope - - ;; Finally make "super" available in the contract's lexical scope for function bodies to use - edge @contract.lexical_scope -> @contract.super + ;; Modifiers are available as a contract type members through a special '@modifier' guard + node modifier + attr (modifier) pop_symbol = "@modifier" + edge @contract.ns -> modifier + edge modifier -> @contract.modifiers - ; NOTE: The keyword "super" itself resolves to each of its parent contracts. - ; See the related rules in the InheritanceSpecifier section above. + ; There may be attached functions to our type. For the general case of + ; variables of our type, that's already handled via normal lexical scope + ; resolution. But for casting/`new` invocations that we resolve through the + ; `()` guard above, we need to explicitly jump to the extension scope from + ; here to attempt resolving the attached function. We cannot jump back to the + ; parent scope because that would create a cycle in the graph. + node push_typeof + attr (push_typeof) push_symbol = "@typeof" + node push_name + attr (push_name) push_symbol = (source-text @name) + node hook + attr (hook) extension_hook + + edge call -> push_typeof + edge push_typeof -> push_name + edge push_name -> hook - ;; This defines the sink of edges added from base contracts when setting this - ;; contract as the compilation context - attr (@contract.def) export_node = @contract.members + if (version-matches "< 0.5.0") { + ; For Solidity < 0.5.0 `this` also acts like an `address` + node address_ref + attr (address_ref) push_symbol = "%address" + node address_typeof + attr (address_typeof) push_symbol = "@typeof" + edge this -> address_typeof + edge address_typeof -> address_ref + edge address_ref -> @contract.lexical_scope + } - ;; This node will eventually connect to the contract's members being compiled - ;; and grants access to definitions in that contract and all its parents - ;; (recursively) - node super_import - attr (super_import) pop_symbol = "." - edge @contract.super -> super_import + ; This is the connection point to resolve attached functions by `using for *` + node @contract.star_extension + attr (@contract.star_extension) push_symbol = "@*" - ;; This defines the source side of edges added to base contracts when setting - ;; a contract as compilation context; this allows this contract (a base) to - ;; access virtual methods in any sub-contract defined in the hierarchy - attr (@contract.def) import_nodes = [@contract.lexical_scope, super_import] + if (version-matches "< 0.7.0") { + ; For Solidity < 0.7.0 using directives are inherited, so we need to connect + ; always For newer versions, this connection only happens when there is a + ; `using for *` directive in the contract (see rule below) + edge @contract.star_extension -> @contract.lexical_scope + } ; Path to resolve the built-in type for type() expressions node type - attr (type) pop_symbol = "%type" + attr (type) pop_symbol = "@type" node type_contract_type - attr (type_contract_type) push_symbol = "%typeContractType" + attr (type_contract_type) push_symbol = "%ContractTypeType" edge @contract.def -> type edge type -> type_contract_type - edge type_contract_type -> @contract.lexical_scope + edge type_contract_type -> @contract.parent_scope + + ; The following defines the connection nodes the resolution algorithm uses + ; *only when setting a compilation context/target*. + + ; This attribute defines the sink of edges added from base contracts when + ; setting this contract as the compilation context, and should provide access + ; to anything that can be reached through `super`. The instance scope is a bit + ; too broad, but `.members` is too narrow as it doesn't allow navigation to + ; parent contracts (and from the base we need to be able to reach all + ; contracts in the hierarchy). + attr (@contract.def) export_node = @contract.instance + + ; This node will eventually connect to the contract's members being compiled + ; and grants access to definitions in that contract and all its parents + ; (recursively). It only makes sense if `super` is defined (ie. if we have + ; parents), but we define it here to be able to use it in the declaration of + ; import nodes. This is the dual of the export_node above. + node @contract.super_import + attr (@contract.super_import) pop_symbol = "." + + ; This defines the source side of edges added to base contracts when setting + ; a contract as compilation context; this allows this contract (a base) to + ; access virtual methods in any sub-contract defined in the hierarchy (both + ; with and without `super`, hence the two connection points). + attr (@contract.def) import_nodes = [@contract.lexical_scope, @contract.super_import] } @contract [ContractDefinition @specifier [InheritanceSpecifier]] { + ; The `.heir` scoped variable allows the rules for `InheritanceSpecifier` + ; above to connect the instance scope of this contract to the parents. let @specifier.heir = @contract attr (@contract.def) parents = @specifier.parent_refs + if (version-matches "< 0.7.0") { + attr (@contract.def) inherit_extensions + } + + ; The rest of these statements deal with defining and connecting the `super` + ; keyword path. + + ; `super_scope` is where we hook all references to our parent contracts + node @contract.super_scope + + ; Define "super" in the lexical scope + node @contract.super + attr (@contract.super) pop_symbol = "super" + edge @contract.lexical_scope -> @contract.super + + ; This connects `super` to exported scopes from all contracts in the hierarchy + ; when setting a contract compilation target (see more detailed description + ; above on the definition of the `super_import` node). + edge @contract.super -> @contract.super_import + + ; Then connect it through an `@instance` guard to the parent contracts through + ; `super_scope`. This allows "instance"-like access to members of parents + ; through `super`. + node super_instance + attr (super_instance) push_symbol = "@instance" + edge @contract.super_import -> super_instance + edge super_instance -> @contract.super_scope } @contract [ContractDefinition [InheritanceSpecifier [InheritanceTypes [InheritanceType @type_name [IdentifierPath]] ]]] { - ;; The base contract defs are directly accesible through our special super scope + ;; The base contract defs are directly accesible through our super scope edge @contract.super_scope -> @type_name.push_begin } +; Pure definitions that cannot contain expressions @contract [ContractDefinition [ContractMembers [ContractMember @member ( [EnumDefinition] @@ -419,12 +518,23 @@ inherit .lexical_scope | [EventDefinition] | [ErrorDefinition] | [UserDefinedValueTypeDefinition] - | [FunctionDefinition] + )] +]] { + edge @member.lexical_scope -> @contract.lexical_scope +} + +; Definitions that can contain expressions need two scopes: +; - normal lexical scope for resolving types +; - extended scope (extended by using directives) for resolving expressions +@contract [ContractDefinition [ContractMembers + [ContractMember @member ( + [FunctionDefinition] | [ConstructorDefinition] - | [StateVariableDefinition] | [ModifierDefinition] | [FallbackFunctionDefinition] | [ReceiveFunctionDefinition] + | [UnnamedFunctionDefinition] + | [StateVariableDefinition] )] ]] { edge @member.lexical_scope -> @contract.lexical_scope @@ -433,7 +543,8 @@ inherit .lexical_scope @contract [ContractDefinition [ContractMembers [ContractMember @using [UsingDirective]] ]] { - edge @contract.lexical_scope -> @using.def + ; Hook the using definition in the extensions scope + edge @contract.extensions -> @using.def } @contract [ContractDefinition [ContractMembers @@ -445,13 +556,20 @@ inherit .lexical_scope | [UserDefinedValueTypeDefinition] )] ]] { - edge @contract.type_members -> @member.def + ; These definition go into the "namespace" scope and are accessible externally + ; via qualified naming (eg. `Contract.MyStruct`) + edge @contract.ns -> @member.def } @contract [ContractDefinition [ContractMembers [ContractMember @state_var [StateVariableDefinition]] ]] { - edge @contract.state_vars -> @state_var.def + ; State variables are available to derived contracts. + ; TODO: this also exposes private state variables to derived contracts, but we + ; can't easily filter them because we don't have negative assertions in our + ; query language (we would need to modify this query for anything *not* + ; containing a `PrivateKeyword` node) + edge @contract.instance -> @state_var.def } ;; Public state variables are also exposed as external member functions @@ -480,13 +598,15 @@ inherit .lexical_scope [FunctionAttributes [FunctionAttribute ([ExternalKeyword] | [PublicKeyword])]] ]] ]] { - ; public or external functions are also accessible through the contract type - edge @contract.type_members -> @function.def + ; Public or external functions are also accessible through the contract type + ; (to retrieve their `.selector` for example) + edge @contract.ns -> @function.def } @contract [ContractDefinition members: [ContractMembers [ContractMember @modifier [ModifierDefinition]] ]] { + ; Modifiers live in their own special scope edge @contract.modifiers -> @modifier.def ;; This may prioritize this definition (when there are multiple options) @@ -495,6 +615,15 @@ inherit .lexical_scope attr (@modifier.def) parents = [@contract.def] } +@contract [ContractDefinition [ContractMembers [ContractMember + [UsingDirective [UsingTarget [Asterisk]]] +]]] { + ; Connect the star extension node to the resolution extended scope if there is + ; a `using for *` directive in the contract + edge @contract.star_extension -> @contract.lexical_scope +} + +; This applies to both state variables and function definitions @override [OverrideSpecifier [OverridePathsDeclaration [OverridePaths @base_ident [IdentifierPath] ]]] { @@ -507,26 +636,29 @@ inherit .lexical_scope ;;; Interfaces ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -@interface [InterfaceDefinition] { +@interface [InterfaceDefinition @name name: [Identifier]] { node @interface.lexical_scope node @interface.def node @interface.members - node @interface.type_members + node @interface.ns + node @interface.instance - edge @interface.lexical_scope -> @interface.members - edge @interface.lexical_scope -> @interface.type_members -} - -@interface [InterfaceDefinition @name name: [Identifier]] { attr (@interface.def) node_definition = @name attr (@interface.def) definiens_node = @interface - ;; "instance" like access path - ;; we have two distinct paths: @typeof -> . for accesses to variables of the contract's type - ;; and () -> . for accesses through a `new` invocation (or casting) + edge @interface.lexical_scope -> @interface.instance + + ; The extensions node is required for the inheritance rules, but not used in interfaces + let @interface.extensions = (node) + + edge @interface.instance -> @interface.members + edge @interface.instance -> @interface.ns + + ;; External "instance" like access path, to access members of a variable of + ;; the interface's type or through a casting call. node member attr (member) pop_symbol = "." - edge member -> @interface.members + edge member -> @interface.instance node typeof attr (typeof) pop_symbol = "@typeof" @@ -538,28 +670,46 @@ inherit .lexical_scope edge @interface.def -> call edge call -> member + ; From a call we may need to resolve using the extensions scope, in case there's + ; a `using` directive on our type. This path ends up jumping to scope just to + ; handle that case. + node push_typeof + attr (push_typeof) push_symbol = "@typeof" + node push_name + attr (push_name) push_symbol = (source-text @name) + edge call -> push_typeof + edge push_typeof -> push_name + node hook + attr (hook) extension_hook + edge push_name -> hook + ; edge push_name -> JUMP_TO_SCOPE_NODE + ;; "namespace" like access path - node type_member - attr (type_member) pop_symbol = "." - edge @interface.def -> type_member - edge type_member -> @interface.type_members + node ns_member + attr (ns_member) pop_symbol = "." + edge @interface.def -> ns_member + edge ns_member -> @interface.ns + + ; Finally there's guarded `@instance` path used by derived contracts to access + ; instance accessible members + node instance + attr (instance) pop_symbol = "@instance" + edge @interface.def -> instance + edge instance -> @interface.instance ; Path to resolve the built-in type for type() expressions node type - attr (type) pop_symbol = "%type" + attr (type) pop_symbol = "@type" node type_interface_type - attr (type_interface_type) push_symbol = "%typeInterfaceType" + attr (type_interface_type) push_symbol = "%InterfaceTypeType" edge @interface.def -> type edge type -> type_interface_type - edge type_interface_type -> @interface.lexical_scope + edge type_interface_type -> @interface.parent_scope } @interface [InterfaceDefinition @specifier [InheritanceSpecifier]] { let @specifier.heir = @interface attr (@interface.def) parents = @specifier.parent_refs - - ; Define a dummy "super" node required by the rules for InheritanceSpecifier - node @interface.super } @interface [InterfaceDefinition [InterfaceMembers @@ -573,7 +723,7 @@ inherit .lexical_scope )] ]] { edge @member.lexical_scope -> @interface.lexical_scope - edge @interface.type_members -> @member.def + edge @interface.ns -> @member.def } ;; Allow references (eg. variables of the interface type) to the interface to @@ -581,14 +731,13 @@ inherit .lexical_scope @interface [InterfaceDefinition members: [InterfaceMembers item: [ContractMember @function variant: [FunctionDefinition]] ]] { - edge @function.lexical_scope -> @interface.lexical_scope edge @interface.members -> @function.def } [InterfaceDefinition [InterfaceMembers [ContractMember @using [UsingDirective]]]] { ; using directives are not allowed in interfaces, but the grammar allows them ; so we need to create an artificial node here to connect to created edges from - ; the internal nodes + ; the instance nodes let @using.lexical_scope = (node) } @@ -597,38 +746,50 @@ inherit .lexical_scope ;;; Libraries ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -@library [LibraryDefinition] { +@library [LibraryDefinition @name name: [Identifier]] { node @library.lexical_scope + node @library.extensions node @library.def - node @library.members - - edge @library.lexical_scope -> @library.members -} + node @library.ns + node @library.modifiers -@library [LibraryDefinition @name name: [Identifier]] { attr (@library.def) node_definition = @name attr (@library.def) definiens_node = @library + ; The .extensions node is where `using` directives will hook the definitions + attr (@library.def) extension_scope = @library.extensions + + edge @library.lexical_scope -> @library.ns + + let @library.enclosing_def = @library.def node member attr (member) pop_symbol = "." edge @library.def -> member + edge member -> @library.ns - edge member -> @library.members + ; Access to modifiers is guarded by a @modifier symbol + node modifier + attr (modifier) pop_symbol = "@modifier" + edge @library.ns -> modifier + edge modifier -> @library.modifiers ; Path to resolve the built-in type for type() expressions (same as contracts) node type - attr (type) pop_symbol = "%type" + attr (type) pop_symbol = "@type" node type_library_type - attr (type_library_type) push_symbol = "%typeContractType" + attr (type_library_type) push_symbol = "%ContractTypeType" edge @library.def -> type edge type -> type_library_type edge type_library_type -> @library.lexical_scope + + ; This is the connection point to resolve attached functions by `using for *` + node @library.star_extension + attr (@library.star_extension) push_symbol = "@*" } @library [LibraryDefinition [LibraryMembers [ContractMember @member ( - [FunctionDefinition] - | [EnumDefinition] + [EnumDefinition] | [StructDefinition] | [EventDefinition] | [ErrorDefinition] @@ -636,31 +797,54 @@ inherit .lexical_scope )] ]] { edge @member.lexical_scope -> @library.lexical_scope - edge @library.members -> @member.def + edge @library.ns -> @member.def +} + +@library [LibraryDefinition [LibraryMembers + [ContractMember @member ( + [FunctionDefinition] + | [StateVariableDefinition [StateVariableAttributes [StateVariableAttribute [ConstantKeyword]]]] + )] +]] { + edge @member.lexical_scope -> @library.lexical_scope + edge @library.ns -> @member.def +} + +@library [LibraryDefinition [LibraryMembers + [ContractMember @modifier [ModifierDefinition]] +]] { + edge @library.modifiers -> @modifier.def + edge @modifier.lexical_scope -> @library.lexical_scope } @library [LibraryDefinition [LibraryMembers [ContractMember @using [UsingDirective]] ]] { - edge @library.lexical_scope -> @using.def + ; Expose the using directive from the extensions scope + edge @library.extensions -> @using.def } +@library [LibraryDefinition [LibraryMembers [ContractMember + [UsingDirective [UsingTarget [Asterisk]]] +]]] { + ; Connect the star extension node to the resolution extended scope if there is + ; a `using for *` directive in the library + edge @library.star_extension -> @library.lexical_scope +} ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Using directives ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; The UsingDirective node requires the enclosing context to setup a -;; .lexical_scope scoped variable for it to resolve both targets and subjects. - @using [UsingDirective] { ; This node acts as a definition in the sense that provides an entry point ; that pops the target type and pushes the library/functions to attach to the ; target type node @using.def - ; This internal node connects the other end of the popping path starting at - ; .def and resolves for the library/functions in the directive + ; This internal node connects the definition side of the clause to the target + ; for resolution, and allows handling the multiple cases of `using` syntax + ; easily node @using.clause } @@ -704,12 +888,18 @@ inherit .lexical_scope ; pop the type symbols to connect to the attached function (via @using.clause) node typeof attr (typeof) pop_symbol = "@typeof" + node cast + attr (cast) pop_symbol = "()" - edge @using.def -> @type_name.pop_begin + ; We connect to all_pop_begin to be able to resolve both qualified and + ; unqualified instances of the target type + edge @using.def -> @type_name.all_pop_begin edge @type_name.pop_end -> typeof edge typeof -> @using.clause + edge @type_name.pop_end -> cast + edge cast -> @using.clause - ; resolve the target type of the directive + ; resolve the target type of the directive on the lexical scope edge @type_name.type_ref -> @using.lexical_scope } @@ -726,7 +916,7 @@ inherit .lexical_scope ;;; Type names ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; TypeName nodes should define two scoped variables: +;; TypeName nodes should define these scoped variables: ;; ;; - @type_name.type_ref represents the node in the graph where we're ready to ;; resolve the type, and thus should generally be connected to a (lexical) @@ -735,12 +925,19 @@ inherit .lexical_scope ;; - @type_name.output represents the other end of the type and corresponds to a ;; state where the type has already been resolved so we can, for example ;; resolve its members (sink node, outside edges connect *to* here). +;; +;; - @type_name.pop_begin, @type_name.pop_end are used in a definition context, +;; ie. when we need to pop the type name symbol(s) from the symbol stack. +;; Additionally, @type_name.all_pop_begin links to each symbol in a typename +;; (ie. in an identifier path typename), which allows referring to a type both +;; qualified and unqualified. @type_name [TypeName @elementary [ElementaryType]] { let @type_name.type_ref = @elementary.ref let @type_name.output = @elementary.ref let @type_name.pop_begin = @elementary.pop let @type_name.pop_end = @elementary.pop + let @type_name.all_pop_begin = @elementary.pop } @type_name [TypeName @id_path [IdentifierPath]] { @@ -755,6 +952,7 @@ inherit .lexical_scope let @type_name.pop_begin = @id_path.pop_begin let @type_name.pop_end = @id_path.pop_end + let @type_name.all_pop_begin = @id_path.all_pop_begin } @type_name [TypeName @type_variant ([ArrayTypeName] | [FunctionType])] { @@ -762,6 +960,7 @@ inherit .lexical_scope let @type_name.output = @type_variant.output let @type_name.pop_begin = @type_variant.pop_begin let @type_name.pop_end = @type_variant.pop_end + let @type_name.all_pop_begin = @type_variant.pop_begin } @type_name [TypeName @mapping [MappingType]] { @@ -769,6 +968,7 @@ inherit .lexical_scope let @type_name.output = @mapping.output let @type_name.pop_begin = @mapping.pop_begin let @type_name.pop_end = @mapping.pop_end + let @type_name.all_pop_begin = @mapping.pop_begin } @@ -783,76 +983,130 @@ inherit .lexical_scope node @elementary.pop attr (@elementary.pop) pop_symbol = @elementary.symbol + + ; These variables are a bit redundant, but necessary to easily use elementary + ; types as mapping keys + let @elementary.pop_begin = @elementary.pop + let @elementary.pop_end = @elementary.pop + let @elementary.all_pop_begin = @elementary.pop + + let @elementary.push_begin = @elementary.ref + let @elementary.push_end = @elementary.ref +} + +@elementary [ElementaryType [AddressType]] { + let @elementary.symbol = "%address" } -@elementary [ElementaryType variant: [AddressType @address [AddressKeyword]]] { - let @elementary.symbol = (format "%{}" (source-text @address)) +@elementary [ElementaryType [BoolKeyword]] { + let @elementary.symbol = "%bool" } -@elementary [ElementaryType @keyword ( - [BoolKeyword] - | [ByteKeyword] - | [BytesKeyword] - | [StringKeyword] - | [IntKeyword] - | [UintKeyword] - | [FixedKeyword] - | [UfixedKeyword] -)] { +@elementary [ElementaryType [ByteKeyword]] { + let @elementary.symbol = "%byte" +} + +@elementary [ElementaryType @keyword [BytesKeyword]] { let @elementary.symbol = (format "%{}" (source-text @keyword)) } +@elementary [ElementaryType [StringKeyword]] { + let @elementary.symbol = "%string" +} + +@elementary [ElementaryType @keyword [IntKeyword]] { + let symbol = (source-text @keyword) + if (eq symbol "int") { + let @elementary.symbol = "%int256" + } else { + let @elementary.symbol = (format "%{}" symbol) + } +} + +@elementary [ElementaryType @keyword [UintKeyword]] { + let symbol = (source-text @keyword) + if (eq symbol "uint") { + let @elementary.symbol = "%uint256" + } else { + let @elementary.symbol = (format "%{}" symbol) + } +} + +@elementary [ElementaryType @keyword [FixedKeyword]] { + let symbol = (source-text @keyword) + if (eq symbol "fixed") { + let @elementary.symbol = "%fixed128x18" + } else { + let @elementary.symbol = (format "%{}" symbol) + } +} + +@elementary [ElementaryType @keyword [UfixedKeyword]] { + let symbol = (source-text @keyword) + if (eq symbol "ufixed") { + let @elementary.symbol = "%ufixed128x18" + } else { + let @elementary.symbol = (format "%{}" symbol) + } +} + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Mappings ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -@mapping [MappingType] { +@mapping [MappingType + [MappingKey [MappingKeyType @key_type ([IdentifierPath] | [ElementaryType])]] + [MappingValue @value_type [TypeName]] +] { node @mapping.lexical_scope node @mapping.output -} - -@mapping [MappingType [MappingKey [MappingKeyType @key_ident [IdentifierPath]]]] { - ; resolve key type - edge @key_ident.push_end -> @mapping.lexical_scope -} -@mapping [MappingType [MappingValue @value_type [TypeName]]] { - ; for mapping types we don't need to push the type itself, because we don't need it (yet) - ; ditto for the pop path, because a mapping type cannot be the target of a using directive + ; Define the pushing path of the mapping type + ; ValueType <- top of the symbol stack + ; KeyType + ; %mapping <- bottom of the symbol stack + node mapping + attr (mapping) push_symbol = "%Mapping" + edge @mapping.output -> mapping + edge mapping -> @key_type.push_begin + edge @key_type.push_end -> @value_type.output + + ; Both key and value types need to be resolved + edge @value_type.type_ref -> @mapping.lexical_scope + edge @key_type.push_end -> @mapping.lexical_scope - ; The mapping's type exposes the `%index` (ie. `[]`) operator that returns the value type - ; This is similar to arrays, only in that case we have a built-in type where - ; we can define an index function. For mappings we hard-code in the rules directly. + ; The mapping's type exposes the `[]` operator that returns the value type. node typeof_input attr (typeof_input) pop_symbol = "@typeof" - - node index_member - attr (index_member) pop_symbol = "." - node index - attr (index) pop_symbol = "%index" - node index_call - attr (index_call) pop_symbol = "()" + edge @mapping.output -> typeof_input node typeof_output attr (typeof_output) push_symbol = "@typeof" - - edge @mapping.output -> typeof_input - edge typeof_input -> index_member - edge index_member -> index - edge index -> index_call - edge index_call -> typeof_output edge typeof_output -> @value_type.output - ; resolve the value type through our scope - edge @value_type.type_ref -> @mapping.lexical_scope + node index + attr (index) pop_symbol = "[]" + edge typeof_input -> index + edge index -> typeof_output + + ; Special case for mapping public state variables: they can be called + ; like a function with a key, and it's effectively the same as indexing it. + node getter_call + attr (getter_call) pop_symbol = "@as_getter" + edge typeof_input -> getter_call + edge getter_call -> typeof_output + + ; Now we define the "definition" route (aka. the pop route), to use in `using` directives only + ; This is the reverse of the pushing path above (to the `.output` node) + node pop_mapping + attr (pop_mapping) pop_symbol = "%Mapping" - ; We use the value_type's definition path as our own because it's needed when - ; a mapping is the target of a `using` directive. It's not correct, but we - ; don't have the analog referencing path either. let @mapping.pop_begin = @value_type.pop_begin - let @mapping.pop_end = @value_type.pop_end + edge @value_type.pop_end -> @key_type.pop_begin + edge @key_type.pop_end -> pop_mapping + let @mapping.pop_end = pop_mapping } @@ -866,47 +1120,69 @@ inherit .lexical_scope } @array [ArrayTypeName [TypeName] index: [Expression]] { - let @array.type = "%arrayFixed" + let @array.type_symbol = "%FixedArray" } @array [ArrayTypeName [OpenBracket] . [CloseBracket]] { - let @array.type = "%array" + let @array.type_symbol = "%Array" } @array [ArrayTypeName @type_name [TypeName]] { - ; First define the normal, reference route: - - ; We first push the array type `%array`, which should connect to two distinct paths: - ; 1. the typed path, which will use a jump scope entry to resolve the element type - ; 2. the hard-coded path to connect to any `using` directive + ; Define the pushing path of the array type + ; ValueType <- top of the symbol stack + ; %array / %arrayFixed <- bottom of the symbol stack node array - attr (array) push_symbol = @array.type + attr (array) push_symbol = @array.type_symbol edge @array.output -> array + edge array -> @type_name.output - ; For the first path, we need to define a scope jump entry for resolving the element type of the array - node entry - attr (entry) is_exported - node element - attr (element) pop_symbol = "%element" - edge entry -> element - edge element -> @type_name.output + ; Resolve the value type itself + edge @type_name.type_ref -> @array.lexical_scope + ; And also the "type erased" array type so we can resolve built-in members + edge array -> @array.lexical_scope - ; And then the path itself - node params - attr (params) push_scoped_symbol = "<>", scope = entry - edge array -> params + ; Define the path to resolve index access (aka the `[]` operator) - ; Second path, for `using` directives - edge array -> @type_name.output + node typeof_input + attr (typeof_input) pop_symbol = "@typeof" + edge @array.output -> typeof_input - ; Finally, both ends connect to our lexical scope - edge params -> @array.lexical_scope - edge @type_name.type_ref -> @array.lexical_scope + node typeof_output + attr (typeof_output) push_symbol = "@typeof" + edge typeof_output -> @type_name.output + + node index + attr (index) pop_symbol = "[]" + edge typeof_input -> index + edge index -> typeof_output + + ; Special case for public state variables of type array: they can be called + ; like a function with an index, and it's effectively the same as indexing the + ; array. + node getter_call + attr (getter_call) pop_symbol = "@as_getter" + edge typeof_input -> getter_call + edge getter_call -> typeof_output + + ; Define the special `.push()` built-in that returns the element type (for Solidity >= 0.6.0) + if (version-matches ">= 0.6.0") { + node built_in_member + attr (built_in_member) pop_symbol = "." + node push_built_in + attr (push_built_in) pop_symbol = "push" + node built_in_call + attr (built_in_call) pop_symbol = "()" + + edge typeof_input -> built_in_member + edge built_in_member -> push_built_in + edge push_built_in -> built_in_call + edge built_in_call -> typeof_output + } ; Now we define the "definition" route (aka. the pop route), to use in `using` directives only ; This is essentially the reverse of the second path above node pop_array - attr (pop_array) pop_symbol = @array.type + attr (pop_array) pop_symbol = @array.type_symbol let @array.pop_begin = @type_name.pop_begin edge @type_name.pop_end -> pop_array @@ -921,10 +1197,10 @@ inherit .lexical_scope @ftype [FunctionType @attrs [FunctionTypeAttributes]] { ; Compute the built-in type of the function ; %functionExternal provides access to .selector and .address - var type = "%function" + var type_symbol = "%Function" scan (source-text @attrs) { "external" { - set type = "%functionExternal" + set type_symbol = "%ExternalFunction" } } @@ -934,14 +1210,14 @@ inherit .lexical_scope ; This path pushes the function type to the symbol stack ; TODO: add parameter and return types to distinguish between different function types node function_type - attr (function_type) push_symbol = type + attr (function_type) push_symbol = type_symbol edge @ftype.output -> function_type edge function_type -> @ftype.lexical_scope ; the pop path for the using directive node pop_function_type - attr (pop_function_type) pop_symbol = type + attr (pop_function_type) pop_symbol = type_symbol let @ftype.pop_begin = pop_function_type let @ftype.pop_end = pop_function_type @@ -958,8 +1234,9 @@ inherit .lexical_scope @ftype [FunctionType [ReturnsDeclaration [ParametersDeclaration [Parameters . @param [Parameter] .]] ]] { - ; variables of a function type type can be "called" and resolve to the type of - ; the return parameter + ; Variables of a function type type can be "called" and resolve to the type of + ; the return parameter. This is only valid if the function returns a single + ; value. node typeof attr (typeof) pop_symbol = "@typeof" @@ -986,14 +1263,22 @@ inherit .lexical_scope ;; @id_path.pop_end. ;; ;; NOTE: most of the time, and unless this identifier path is the target of a -;; using directive this path will not be used and will form a disconnected -;; graph component. We currently have no way of determining when this path is -;; necessary, so we always construct it. +;; using directive this second path will not be used and will form a +;; disconnected graph component. We currently have no way of determining when +;; this path is necessary, so we always construct it. ;; ;; Additionally the IdentifierPath defines another scoped variable ;; @id_path.rightmost_identifier which corresponds to the identifier in the last -;; position in the path, from left to right. Useful for the using directive to -;; be able to pop the name of the attached function. +;; position in the path, from left to right. This is used in the using directive +;; rules to be able to pop the name of the attached function. + +@id_path [IdentifierPath] { + ; This node connects to all parts of the path, for popping. This allows to + ; connect at any point of the path. Useful for `using` directives when the + ; target type is fully qualified but we want to resolve for the unqualified + ; name. + node @id_path.all_pop_begin +} @id_path [IdentifierPath @name [Identifier]] { node @name.ref @@ -1002,6 +1287,8 @@ inherit .lexical_scope node @name.pop attr (@name.pop) pop_symbol = (source-text @name) + + edge @id_path.all_pop_begin -> @name.pop } @id_path [IdentifierPath @name [Identifier] .] { @@ -1069,10 +1356,10 @@ inherit .lexical_scope } @function [FunctionDefinition @attrs [FunctionAttributes]] { - var function_type = "%function" + var type_symbol = "%Function" scan (source-text @attrs) { "\\b(public|external)\\b" { - set function_type = "%functionExternal" + set type_symbol = "%ExternalFunction" } } @@ -1084,7 +1371,7 @@ inherit .lexical_scope node typeof attr (typeof) push_symbol = "@typeof" node type_function - attr (type_function) push_symbol = function_type + attr (type_function) push_symbol = type_symbol edge @function.def -> typeof edge typeof -> type_function edge type_function -> @function.lexical_scope @@ -1149,12 +1436,39 @@ inherit .lexical_scope edge @name.push_end -> modifier edge modifier -> @modifier.lexical_scope + + ; This allows resolving @name in the more general scope in constructors (since + ; calling a parent constructor is parsed as a modifier invocation) + let @modifier.identifier = @name.push_end } @modifier [ModifierInvocation @args [ArgumentsDeclaration]] { edge @args.lexical_scope -> @modifier.lexical_scope } +;;; Unnamed functions (deprecated) +@unnamed_function [UnnamedFunctionDefinition] { + node @unnamed_function.lexical_scope +} + +@unnamed_function [UnnamedFunctionDefinition @params parameters: [ParametersDeclaration]] { + edge @params.lexical_scope -> @unnamed_function.lexical_scope + + edge @unnamed_function.lexical_scope -> @params.defs + attr (@unnamed_function.lexical_scope -> @params.defs) precedence = 1 +} + +@unnamed_function [UnnamedFunctionDefinition [FunctionBody @block [Block]]] { + edge @block.lexical_scope -> @unnamed_function.lexical_scope +} + +@unnamed_function [UnnamedFunctionDefinition + [UnnamedFunctionAttributes [UnnamedFunctionAttribute @modifier [ModifierInvocation]]] +] { + edge @modifier.lexical_scope -> @unnamed_function.lexical_scope +} + + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Constructors @@ -1186,6 +1500,7 @@ inherit .lexical_scope @modifier [ModifierInvocation] ]]] { edge @modifier.lexical_scope -> @constructor.lexical_scope + edge @modifier.identifier -> @constructor.lexical_scope } @contract [ContractDefinition [ContractMembers [ContractMember @@ -1195,7 +1510,9 @@ inherit .lexical_scope edge @contract.def -> @constructor.def } -;; Solidity < 0.5.0 constructors were declared as functions of the contract's name +;; Solidity < 0.5.0 constructors +;; They were declared as functions of the contract's name + @contract [ContractDefinition @contract_name [Identifier] [ContractMembers [ContractMember [FunctionDefinition @@ -1211,6 +1528,21 @@ inherit .lexical_scope } } +[ContractDefinition + @contract_name [Identifier] + [ContractMembers [ContractMember @function [FunctionDefinition + [FunctionName @function_name [Identifier]] + [FunctionAttributes [FunctionAttribute @modifier [ModifierInvocation]]] + ]]] +] { + if (version-matches "< 0.5.0") { + if (eq (source-text @contract_name) (source-text @function_name)) { + ; Parent constructor calls are parsed as modifier invocations + edge @modifier.identifier -> @function.lexical_scope + } + } +} + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Fallback and receive functions @@ -1386,7 +1718,6 @@ inherit .lexical_scope @expr_stmt [ExpressionStatement] { node @expr_stmt.lexical_scope - node @expr_stmt.defs } @@ -1394,32 +1725,46 @@ inherit .lexical_scope @stmt [Statement @var_decl [VariableDeclarationStatement]] { edge @var_decl.lexical_scope -> @stmt.lexical_scope - edge @stmt.defs -> @var_decl.defs + edge @stmt.defs -> @var_decl.def } @var_decl [VariableDeclarationStatement] { node @var_decl.lexical_scope - node @var_decl.defs + node @var_decl.def } @var_decl [VariableDeclarationStatement [VariableDeclarationType @var_type [TypeName]] @name name: [Identifier] ] { - node def - attr (def) node_definition = @name - attr (def) definiens_node = @var_decl + attr (@var_decl.def) node_definition = @name + attr (@var_decl.def) definiens_node = @var_decl - edge @var_decl.defs -> def edge @var_type.type_ref -> @var_decl.lexical_scope node typeof attr (typeof) push_symbol = "@typeof" - edge def -> typeof + edge @var_decl.def -> typeof edge typeof -> @var_type.output } +@var_decl [VariableDeclarationStatement + [VariableDeclarationType [VarKeyword]] + @name name: [Identifier] +] { + attr (@var_decl.def) node_definition = @name + attr (@var_decl.def) definiens_node = @var_decl +} + +@var_decl [VariableDeclarationStatement + [VariableDeclarationType [VarKeyword]] + [VariableDeclarationValue @value [Expression]] +] { + edge @var_decl.def -> @value.output +} + + ;;; Tuple deconstruction statements @@ -1493,11 +1838,20 @@ inherit .lexical_scope ;; For loops @stmt [Statement [ForStatement - initialization: [ForStatementInitialization - @init_stmt ([ExpressionStatement] - | [VariableDeclarationStatement] - | [TupleDeconstructionStatement]) - ] + initialization: [ForStatementInitialization @init_stmt [ExpressionStatement]] +]] { + edge @init_stmt.lexical_scope -> @stmt.lexical_scope +} + +@stmt [Statement [ForStatement + initialization: [ForStatementInitialization @init_stmt [VariableDeclarationStatement]] +]] { + edge @init_stmt.lexical_scope -> @stmt.lexical_scope + edge @stmt.init_defs -> @init_stmt.def +} + +@stmt [Statement [ForStatement + initialization: [ForStatementInitialization @init_stmt [TupleDeconstructionStatement]] ]] { edge @init_stmt.lexical_scope -> @stmt.lexical_scope edge @stmt.init_defs -> @init_stmt.defs @@ -1647,11 +2001,36 @@ inherit .lexical_scope edge @type_name.type_ref -> @state_var.lexical_scope - node typeof - attr (typeof) push_symbol = "@typeof" + node @state_var.typeof + attr (@state_var.typeof) push_symbol = "@typeof" - edge @state_var.def -> typeof - edge typeof -> @type_name.output + edge @state_var.def -> @state_var.typeof + edge @state_var.typeof -> @type_name.output +} + +@state_var [StateVariableDefinition + [StateVariableAttributes [StateVariableAttribute [PublicKeyword]]] +] { + ; Public state variables are used as functions when invoked from an external contract + node call + attr (call) pop_symbol = "()" + + ; In the general case using the getter can bind to the state variable's type + edge @state_var.def -> call + edge call -> @state_var.typeof + + ; Some complex types generate special getters (ie. arrays and mappings index + ; their contents, structs flatten most of their fields and return a tuple) + node getter + attr (getter) push_symbol = "@as_getter" + edge call -> getter + edge getter -> @state_var.typeof +} + +@state_var [StateVariableDefinition + [StateVariableDefinitionValue @value [Expression]] +] { + let @value.lexical_scope = @state_var.lexical_scope } @@ -1659,13 +2038,11 @@ inherit .lexical_scope ;;; Enum definitions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -@enum [EnumDefinition] { +@enum [EnumDefinition @name name: [Identifier]] { node @enum.lexical_scope node @enum.def node @enum.members -} -@enum [EnumDefinition @name name: [Identifier]] { attr (@enum.def) node_definition = @name attr (@enum.def) definiens_node = @enum @@ -1677,9 +2054,9 @@ inherit .lexical_scope ; Path to resolve the built-in type for enums (which is the same as for integer types) node type - attr (type) pop_symbol = "%type" + attr (type) pop_symbol = "@type" node type_enum_type - attr (type_enum_type) push_symbol = "%typeIntType" + attr (type_enum_type) push_symbol = "%IntTypeType" edge @enum.def -> type edge type -> type_enum_type edge type_enum_type -> @enum.lexical_scope @@ -1700,73 +2077,61 @@ inherit .lexical_scope ;;; Structure definitions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -@struct [StructDefinition] { +@struct [StructDefinition @name name: [Identifier]] { node @struct.lexical_scope node @struct.def node @struct.members -} - -@struct [StructDefinition @name name: [Identifier]] { - ; Since we use structs to define built-in types and some of them (ie. array) - ; have have a parametric type, we define two distinct paths to define a - ; struct: - ; 1. the normal, non parametric path, should drop scopes in the scope stack first of all - ; 2. the parametric path, that pops a scope to resolve the parametric type - ; Both of these connect to the node that pops the struct identifier symbol - - ; First the normal path - node struct_drop - attr (struct_drop) type = "drop_scopes" - edge @struct.def -> struct_drop - - ; Second path, pops the scope - node typed_params - attr (typed_params) pop_scoped_symbol = "<>" - edge @struct.def -> typed_params - - ; Connect both to the struct identifier - node def - attr (def) node_definition = @name - attr (def) definiens_node = @struct - edge struct_drop -> def - edge typed_params -> def - ; On the other end, to properly close the second path we need to jump to the popped scope - ; (this is why on the other path we drop scopes) - edge @struct.lexical_scope -> JUMP_TO_SCOPE_NODE + attr (@struct.def) node_definition = @name + attr (@struct.def) definiens_node = @struct ; Now connect normally to the struct members - node type_def - attr (type_def) pop_symbol = "@typeof" + node @struct.typeof + attr (@struct.typeof) pop_symbol = "@typeof" node member attr (member) pop_symbol = "." - edge def -> type_def - edge type_def -> member + edge @struct.def -> @struct.typeof + edge @struct.typeof -> member edge member -> @struct.members ; Bind member names when using construction with named arguments node param_names attr (param_names) pop_symbol = "@param_names" - edge def -> param_names + edge @struct.def -> param_names edge param_names -> @struct.members + + ; Used as a function call (ie. casting), should bind to itself + node call + attr (call) pop_symbol = "()" + edge @struct.def -> call + edge call -> member } @struct [StructDefinition [StructMembers @member item: [StructMember @type_name [TypeName] @name name: [Identifier]] ]] { - node def - attr (def) node_definition = @name - attr (def) definiens_node = @member + node @member.def + attr (@member.def) node_definition = @name + attr (@member.def) definiens_node = @member - edge @struct.members -> def + edge @struct.members -> @member.def edge @type_name.type_ref -> @struct.lexical_scope - node typeof - attr (typeof) push_symbol = "@typeof" + node @member.typeof + attr (@member.typeof) push_symbol = "@typeof" - edge def -> typeof - edge typeof -> @type_name.output + edge @member.def -> @member.typeof + edge @member.typeof -> @type_name.output +} + +@struct [StructDefinition [StructMembers . @first_member [StructMember]]] { + ; As a public getter result, the value returned is a tuple with all our fields flattened + ; We only care about the first member for name binding, since tuples are not real types + node getter_call + attr (getter_call) pop_symbol = "@as_getter" + edge @struct.typeof -> getter_call + edge getter_call -> @first_member.typeof } @@ -1819,6 +2184,15 @@ inherit .lexical_scope node @error.params attr (@error.params) pop_symbol = "@param_names" edge @error.def -> @error.params + + ; Bind to built-in errorType for accessing built-in member `.selector` + node typeof + attr (typeof) push_symbol = "@typeof" + node error_type + attr (error_type) push_symbol = "%ErrorType" + edge @error.def -> typeof + edge typeof -> error_type + edge error_type -> @error.lexical_scope } @error [ErrorDefinition [ErrorParametersDeclaration [ErrorParameters @@ -1862,17 +2236,59 @@ inherit .lexical_scope edge @type_name.type_ref -> @constant.lexical_scope } -@user_type [UserDefinedValueTypeDefinition] { +@user_type [UserDefinedValueTypeDefinition @name [Identifier] @value_type [ElementaryType]] { node @user_type.lexical_scope node @user_type.def -} -@user_type [UserDefinedValueTypeDefinition @name [Identifier]] { - node def - attr (def) node_definition = @name - attr (def) definiens_node = @user_type + attr (@user_type.def) node_definition = @name + attr (@user_type.def) definiens_node = @user_type - edge @user_type.def -> def + ; Provide member resolution through the built-in `%userTypeType` + ; Because the built-in is defined as a struct, we need to push an extra `@typeof` + node member_guard + attr (member_guard) pop_symbol = "." + node member + attr (member) push_symbol = "." + node typeof + attr (typeof) push_symbol = "@typeof" + node user_type_type + attr (user_type_type) push_symbol = "%UserDefinedValueType" + + edge @user_type.def -> member_guard + edge member_guard -> member + edge member -> typeof + edge typeof -> user_type_type + edge user_type_type -> @user_type.lexical_scope + + ; Hard-code built-in functions `wrap` and `unwrap` in order to be able to + ; resolve their return types + node wrap + attr (wrap) pop_symbol = "wrap" + node wrap_call + attr (wrap_call) pop_symbol = "()" + node wrap_typeof + attr (wrap_typeof) push_symbol = "@typeof" + + edge member_guard -> wrap + edge wrap -> wrap_call + edge wrap_call -> wrap_typeof + edge wrap_typeof -> @value_type.ref + edge @value_type.ref -> @user_type.lexical_scope + + node unwrap + attr (unwrap) pop_symbol = "unwrap" + node unwrap_call + attr (unwrap_call) pop_symbol = "()" + node unwrap_typeof + attr (unwrap_typeof) push_symbol = "@typeof" + node type_ref + attr (type_ref) push_symbol = (source-text @name) + + edge member_guard -> unwrap + edge unwrap -> unwrap_call + edge unwrap_call -> unwrap_typeof + edge unwrap_typeof -> type_ref + edge type_ref -> @user_type.lexical_scope } @@ -1892,9 +2308,7 @@ inherit .lexical_scope } ;; Identifier expressions -@expr [Expression @name ( - variant: [Identifier] | variant: [SuperKeyword] | variant: [ThisKeyword] -)] { +@expr [Expression @name [Identifier]] { node ref attr (ref) node_reference = @name attr (ref) parents = [@expr.enclosing_def] @@ -1903,6 +2317,14 @@ inherit .lexical_scope edge @expr.output -> ref } +@expr [Expression @keyword ([ThisKeyword] | [SuperKeyword])] { + ; This is almost equivalent to the above rule, except it doesn't generate a reference + node keyword + attr (keyword) push_symbol = (source-text @keyword) + edge keyword -> @expr.lexical_scope + edge @expr.output -> keyword +} + ;; Member access expressions @expr [Expression [MemberAccessExpression @operand operand: [Expression] @@ -1921,10 +2343,7 @@ inherit .lexical_scope edge @expr.output -> @name.ref ; Shortcut path for expressions inside contracts with using X for * directives - node star - attr (star) push_symbol = "@*" - edge member -> star - edge star -> @expr.lexical_scope + edge member -> @expr.star_extension } ;; Special case: member accesses to `super` are tagged with "super" to rank @@ -1936,21 +2355,31 @@ inherit .lexical_scope attr (@name.ref) tag = "super" } +;; Elementary types used as expressions (eg. for type casting, or for built-ins like `string.concat`) +@expr [Expression @type [ElementaryType]] { + edge @expr.output -> @type.ref + edge @type.ref -> @expr.lexical_scope + + ; Elementary types can also be used for casting; instead of defining built-in + ; struct for each available elementary type, we define a special path here + node call + attr (call) pop_symbol = "()" + node typeof + attr (typeof) push_symbol = "@typeof" + edge @expr.output -> call + edge call -> typeof + edge typeof -> @type.ref +} + ;; Index access expressions @expr [Expression [IndexAccessExpression @operand operand: [Expression] ]] { - node index_call - attr (index_call) push_symbol = "()" node index - attr (index) push_symbol = "%index" - node index_member - attr (index_member) push_symbol = "." + attr (index) push_symbol = "[]" - edge @expr.output -> index_call - edge index_call -> index - edge index -> index_member - edge index_member -> @operand.output + edge @expr.output -> index + edge index -> @operand.output } ;; Type expressions @@ -1963,7 +2392,7 @@ inherit .lexical_scope node typeof attr (typeof) push_symbol = "@typeof" node type - attr (type) push_symbol = "%typeIntType" + attr (type) push_symbol = "%IntTypeType" edge @type_expr.output -> typeof edge typeof -> type @@ -1975,7 +2404,7 @@ inherit .lexical_scope node typeof attr (typeof) push_symbol = "@typeof" node type - attr (type) push_symbol = "%type" + attr (type) push_symbol = "@type" edge @type_expr.output -> typeof edge typeof -> type @@ -2039,7 +2468,7 @@ inherit .lexical_scope attr (@options.refs) push_symbol = "@param_names" node call_options - attr (call_options) push_symbol = "%callOptions" + attr (call_options) push_symbol = "%CallOptions" edge @options.refs -> call_options edge call_options -> @expr.lexical_scope @@ -2053,6 +2482,137 @@ inherit .lexical_scope } +;;; Payable +; These work like `address`, should they should bind to `%address` +@expr [Expression [PayableKeyword]] { + node ref + attr (ref) push_symbol = "%address" + + edge ref -> @expr.lexical_scope + edge @expr.output -> ref +} + + +;;; Tuple expressions + +; Parenthesized expressions are parsed as tuples of a single value +@expr [Expression [TupleExpression [TupleValues . [TupleValue @operand [Expression]] .]]] { + edge @expr.output -> @operand.output +} + +;;; Arithmetic, bitwise & logical operators, etc + +; Bind to the left operand only: assignment expressions +@expr [Expression [_ + @left_operand left_operand: [Expression] + ( + [Equal] + | [BarEqual] + | [PlusEqual] + | [MinusEqual] + | [CaretEqual] + | [SlashEqual] + | [PercentEqual] + | [AsteriskEqual] + | [AmpersandEqual] + | [LessThanLessThanEqual] + | [GreaterThanGreaterThanEqual] + | [GreaterThanGreaterThanGreaterThanEqual] + ) +]] { + edge @expr.output -> @left_operand.output +} + +; Unary operators postfix +@expr [Expression [_ + @operand operand: [Expression] + ([PlusPlus] | [MinusMinus]) +]] { + edge @expr.output -> @operand.output +} + +; Unary operators prefix +@expr [Expression [_ + ([PlusPlus] | [MinusMinus] | [Tilde] | [Bang] | [Minus] | [Plus]) + @operand operand: [Expression] +]] { + edge @expr.output -> @operand.output +} + +; Bind to both operands: logical and/or, arithmetic, bit-wise expressions +@expr [Expression [_ + @left_operand left_operand: [Expression] + ( + [BarBar] + | [AmpersandAmpersand] + + | [Plus] + | [Minus] + | [Asterisk] + | [Slash] + | [Percent] + | [AsteriskAsterisk] + + | [Bar] + | [Caret] + | [Ampersand] + + | [LessThanLessThan] + | [GreaterThanGreaterThan] + | [GreaterThanGreaterThanGreaterThan] + ) + @right_operand right_operand: [Expression] +]] { + edge @expr.output -> @left_operand.output + edge @expr.output -> @right_operand.output +} + +; Comparison operators bind to bool type +@expr [Expression [_ + ( + [EqualEqual] + | [BangEqual] + | [LessThan] + | [GreaterThan] + | [LessThanEqual] + | [GreaterThanEqual] + ) +]] { + node typeof + attr (typeof) push_symbol = "@typeof" + node bool + attr (bool) push_symbol = "%bool" + edge @expr.output -> typeof + edge typeof -> bool + edge bool -> @expr.lexical_scope +} + +; Ternary conditional expression binds to both branches +@expr [Expression [ConditionalExpression + @true_expression true_expression: [Expression] + @false_expression false_expression: [Expression] +]] { + edge @expr.output -> @true_expression.output + edge @expr.output -> @false_expression.output +} + + +;;; Literal Address Expressions +@expr [Expression [HexNumberExpression @hex_literal [HexLiteral]]] { + scan (source-text @hex_literal) { + "0x[0-9a-fA-F]{40}" { + ; Treat it as a valid address + node typeof + attr (typeof) push_symbol = "@typeof" + node address + attr (address) push_symbol = "%address" + edge @expr.output -> typeof + edge typeof -> address + edge address -> @expr.lexical_scope + } + } +} + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Yul @@ -2162,6 +2722,38 @@ inherit .lexical_scope ;; parameters) are functions (ie. the body of the function doesn't have access ;; to any outside variables) edge @fundef.lexical_scope -> @block.function_defs + ; Exception: but outside constants *are* available, so we provide a guarded + ; access to the parent lexical scope. This guard will be popped to link to + ; available constants. + node yul_function_guard + attr (yul_function_guard) push_symbol = "@in_yul_function" + edge @fundef.lexical_scope -> yul_function_guard + edge yul_function_guard -> @block.lexical_scope +} + +;; Constants need to be available inside Yul functions. This is an exception +;; since no other external identifiers are, so the path is guarded. We create a +;; scope in the source unit, contracts and libraries, and guard it from the +;; lexical scope, so we can link constant definitions here. See the dual path in +;; the rule above. +@constant_container ([SourceUnit] | [ContractDefinition] | [LibraryDefinition]) { + node @constant_container.yul_functions_guarded_scope + attr (@constant_container.yul_functions_guarded_scope) pop_symbol = "@in_yul_function" + edge @constant_container.lexical_scope -> @constant_container.yul_functions_guarded_scope +} + +;; Make top-level constants available inside Yul functions +@source_unit [SourceUnit [SourceUnitMembers [SourceUnitMember @constant [ConstantDefinition]]]] { + edge @source_unit.yul_functions_guarded_scope -> @constant.def +} + +;; Ditto for contracts, interfaces and libraries +@contract [_ members: [_ [ContractMember + @constant [StateVariableDefinition + [StateVariableAttributes [StateVariableAttribute [ConstantKeyword]]] + ] +]]] { + edge @contract.yul_functions_guarded_scope -> @constant.def } @fundef [YulFunctionDefinition @@ -2277,11 +2869,60 @@ inherit .lexical_scope node @path.lexical_scope } -@path [YulPath @name [YulIdentifier]] { +@path [YulPath . @name [YulIdentifier]] { node ref attr (ref) node_reference = @name edge ref -> @path.lexical_scope + + if (version-matches "< 0.7.0") { + ; Before Solidity 0.7.0 storage variables' `.offset` and `.slot` were + ; accessed by suffixing the name with `_offset` and `_slot` + scan (source-text @name) { + "^(.*)_(slot|offset|length)$" { + let symbol = $0 + let without_suffix = $1 + let suffix = $2 + + ; We bind the whole symbol to the built-in field for the known cases + node pop_ref + attr (pop_ref) pop_symbol = symbol + node push_suffixless + attr (push_suffixless) push_symbol = suffix + node member_of + attr (member_of) push_symbol = "." + node typeof + attr (typeof) push_symbol = "@typeof" + node yul_external + attr (yul_external) push_symbol = "%YulExternal" + + edge ref -> pop_ref + edge pop_ref -> push_suffixless + edge push_suffixless -> member_of + edge member_of -> typeof + edge typeof -> yul_external + edge yul_external -> @path.lexical_scope + } + } + } +} + +@path [YulPath [Period] @member [YulIdentifier] .] { + ; Yul variable members only apply to external variables and hence are + ; automatically bound to a special %YulExternal built-in + node ref + attr (ref) node_reference = @member + node member_of + attr (member_of) push_symbol = "." + node typeof + attr (typeof) push_symbol = "@typeof" + node yul_external + attr (yul_external) push_symbol = "%YulExternal" + + edge ref -> member_of + edge member_of -> typeof + edge typeof -> yul_external + edge yul_external -> @path.lexical_scope } @expr [YulExpression @funcall [YulFunctionCallExpression]] { diff --git a/crates/solidity/inputs/language/src/definition.rs b/crates/solidity/inputs/language/src/definition.rs index 9fe81048ce..a4feaa287a 100644 --- a/crates/solidity/inputs/language/src/definition.rs +++ b/crates/solidity/inputs/language/src/definition.rs @@ -4,7 +4,7 @@ codegen_language_macros::compile!(Language( name = Solidity, documentation_dir = "crates/solidity/inputs/language/docs", binding_rules_file = "crates/solidity/inputs/language/bindings/rules.msgb", - file_extension = ".sol", + file_extension = ".sol", // TODO: This should be moved to the Solidity-specific 'extensions' sub-module. root_item = SourceUnit, // TODO(#1020): Define the end-of-file trivia explicitly rather than // implicitly reusing the leading trivia in the generater parser code. @@ -6751,42 +6751,45 @@ codegen_language_macros::compile!(Language( enabled = Till("0.5.0") ), BuiltInType( - name = "$abiType", + name = "$AbiType", fields = [], functions = [ BuiltInFunction( name = "decode", - parameters = ["bytes memory", "$args"], - return_type = "$args", + parameters = ["bytes memory encodedData", "$Type[] encodedTypesTuple"], + return_type = "$Any[]", enabled = From("0.5.0") ), BuiltInFunction( name = "encode", - parameters = ["$args"], + parameters = ["$Any[] valuesToEncode"], return_type = "bytes memory", enabled = From("0.4.22") ), BuiltInFunction( name = "encodeCall", - parameters = ["function()", "$args"], + parameters = [ + "function() functionPointer", + "$Any[] functionArgumentsTuple" + ], return_type = "bytes memory", enabled = From("0.8.11") ), BuiltInFunction( name = "encodePacked", - parameters = ["$args"], + parameters = ["$Any[] valuesToEncode"], return_type = "bytes memory", enabled = From("0.4.22") ), BuiltInFunction( name = "encodeWithSelector", - parameters = ["bytes4 selector", "$args"], + parameters = ["bytes4 selector", "$Any[] functionArgumentsTuple"], return_type = "bytes memory", enabled = From("0.4.22") ), BuiltInFunction( name = "encodeWithSignature", - parameters = ["string memory", "$args"], + parameters = ["string memory signature", "$Any[] valuesToEncode"], return_type = "bytes memory", enabled = From("0.4.22") ) @@ -6832,7 +6835,7 @@ codegen_language_macros::compile!(Language( ), BuiltInFunction( name = "send", - parameters = ["uint256"], + parameters = ["uint256 amount"], return_type = "bool" ), BuiltInFunction( @@ -6841,49 +6844,40 @@ codegen_language_macros::compile!(Language( return_type = "bool, bytes memory", enabled = From("0.5.0") ), - BuiltInFunction(name = "transfer", parameters = ["uint256"]) + BuiltInFunction(name = "transfer", parameters = ["uint256 amount"]) ] ), BuiltInType( - name = "$array", + name = "$Array", fields = [BuiltInField(definition = "uint length")], functions = [ - BuiltInFunction( - name = "$index", - parameters = ["uint"], - return_type = "$element" - ), BuiltInFunction( name = "push", parameters = [], - return_type = "$element", + return_type = "$ValueType", enabled = From("0.6.0") ), BuiltInFunction( name = "push", - parameters = ["$element"], + parameters = ["$ValueType element"], return_type = "uint", enabled = Till("0.6.0") ), BuiltInFunction( name = "push", - parameters = ["$element"], + parameters = ["$ValueType element"], enabled = From("0.6.0") ), BuiltInFunction(name = "pop", parameters = []) ] ), BuiltInType( - name = "$arrayFixed", + name = "$FixedArray", fields = [BuiltInField(definition = "uint length")], - functions = [BuiltInFunction( - name = "$index", - parameters = ["uint"], - return_type = "$element" - )] + functions = [] ), BuiltInType( - name = "$blockType", + name = "$BlockType", fields = [ BuiltInField(definition = "uint basefee", enabled = From("0.8.7")), BuiltInField(definition = "uint blobbasefee", enabled = From("0.8.24")), @@ -6904,15 +6898,20 @@ codegen_language_macros::compile!(Language( ), BuiltInType( name = "$bytes", + fields = [BuiltInField(definition = "uint length")], + functions = [] + ), + BuiltInType( + name = "$BytesType", fields = [], functions = [BuiltInFunction( name = "concat", - parameters = ["$args"], + parameters = ["bytes[] bytesToConcatenate"], return_type = "bytes memory" )] ), BuiltInType( - name = "$callOptions", + name = "$CallOptions", fields = [ BuiltInField(definition = "uint gas"), BuiltInField(definition = "uint salt"), @@ -6922,28 +6921,52 @@ codegen_language_macros::compile!(Language( enabled = From("0.6.2") ), BuiltInType( - name = "$functionExternal", + name = "$ErrorType", + fields = [BuiltInField(definition = "bytes4 selector")], + functions = [], + enabled = From("0.8.4") + ), + BuiltInType( + name = "$Function", + fields = [], + functions = [ + BuiltInFunction( + name = "gas", + parameters = ["uint amount"], + return_type = "function()", + enabled = Till("0.7.0") + ), + BuiltInFunction( + name = "value", + parameters = ["uint amount"], + return_type = "function()", + enabled = Till("0.7.0") + ) + ] + ), + BuiltInType( + name = "$ExternalFunction", fields = [ - BuiltInField(definition = "$address address", enabled = From("0.8.2")), - BuiltInField(definition = "$selector selector", enabled = From("0.4.17")) + BuiltInField(definition = "address address", enabled = From("0.8.2")), + BuiltInField(definition = "bytes4 selector", enabled = From("0.4.17")) ], functions = [ BuiltInFunction( name = "gas", - parameters = ["uint"], - return_type = "$function", + parameters = ["uint amount"], + return_type = "function()", enabled = Till("0.7.0") ), BuiltInFunction( name = "value", - parameters = ["uint"], - return_type = "$function", + parameters = ["uint amount"], + return_type = "function()", enabled = Till("0.7.0") ) ] ), BuiltInType( - name = "$msgType", + name = "$MessageType", fields = [ BuiltInField(definition = "bytes data"), BuiltInField(definition = "uint256 gas", enabled = Till("0.5.0")), @@ -6958,16 +6981,16 @@ codegen_language_macros::compile!(Language( functions = [] ), BuiltInType( - name = "$string", + name = "$StringType", fields = [], functions = [BuiltInFunction( name = "concat", - parameters = ["$args"], + parameters = ["string[] stringsToConcatenate"], return_type = "string memory" )] ), BuiltInType( - name = "$txType", + name = "$TransactionType", fields = [ BuiltInField(definition = "uint gasprice"), BuiltInField( @@ -6979,7 +7002,7 @@ codegen_language_macros::compile!(Language( functions = [] ), BuiltInType( - name = "$typeContractType", + name = "$ContractTypeType", fields = [ BuiltInField(definition = "string name"), BuiltInField(definition = "bytes creationCode", enabled = From("0.5.3")), @@ -6989,7 +7012,7 @@ codegen_language_macros::compile!(Language( functions = [] ), BuiltInType( - name = "$typeInterfaceType", + name = "$InterfaceTypeType", fields = [ BuiltInField(definition = "string name"), BuiltInField(definition = "bytes4 interfaceId", enabled = From("0.6.7")) @@ -6997,18 +7020,48 @@ codegen_language_macros::compile!(Language( functions = [] ), BuiltInType( - name = "$typeIntType", + name = "$IntTypeType", fields = [ BuiltInField(definition = "int min", enabled = From("0.6.8")), BuiltInField(definition = "int max", enabled = From("0.6.8")) ], functions = [] ), - BuiltInVariable(definition = "$function $placeholder"), - BuiltInVariable(definition = "$abiType abi"), - BuiltInVariable(definition = "$blockType block"), - BuiltInVariable(definition = "$msgType msg"), + BuiltInType( + name = "$UserDefinedValueType", + fields = [], + functions = [ + BuiltInFunction( + name = "wrap", + parameters = ["$WrappedType elementaryType"], + return_type = "$UserType" + ), + BuiltInFunction( + name = "unwrap", + parameters = ["$UserType userType"], + return_type = "$WrappedType" + ) + ], + enabled = From("0.8.8") + ), + BuiltInType( + name = "$YulExternal", + fields = [ + // These apply to state and storage variables + BuiltInField(definition = "uint slot"), + BuiltInField(definition = "uint offset"), + // Dynamic calldata arrays also have a length + BuiltInField(definition = "uint length") + ], + functions = [] + ), + BuiltInVariable(definition = "$Function $placeholder"), + BuiltInVariable(definition = "$AbiType abi"), + BuiltInVariable(definition = "$BlockType block"), + BuiltInVariable(definition = "$BytesType $bytes"), + BuiltInVariable(definition = "$MessageType msg"), BuiltInVariable(definition = "uint now", enabled = Till("0.7.0")), - BuiltInVariable(definition = "$txType tx") + BuiltInVariable(definition = "$StringType $string"), + BuiltInVariable(definition = "$TransactionType tx") ] )); diff --git a/crates/solidity/outputs/cargo/crate/Cargo.toml b/crates/solidity/outputs/cargo/crate/Cargo.toml index 3519125a2c..7e1508fdf2 100644 --- a/crates/solidity/outputs/cargo/crate/Cargo.toml +++ b/crates/solidity/outputs/cargo/crate/Cargo.toml @@ -32,6 +32,7 @@ categories = [ default = [] __experimental_bindings_api = ["dep:metaslang_bindings"] __private_ariadne_errors = ["dep:ariadne"] +__private_compilation_api = [] __private_testing_utils = [] [build-dependencies] # __REMOVE_THIS_LINE_DURING_CARGO_PUBLISH__ diff --git a/crates/solidity/outputs/cargo/crate/generated/public_api.txt b/crates/solidity/outputs/cargo/crate/generated/public_api.txt index 0b273298c0..20741305c1 100644 --- a/crates/solidity/outputs/cargo/crate/generated/public_api.txt +++ b/crates/solidity/outputs/cargo/crate/generated/public_api.txt @@ -2,12 +2,49 @@ pub mod slang_solidity pub mod slang_solidity::bindings -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 use slang_solidity::bindings::BuiltInLocation +pub use slang_solidity::bindings::PathResolver +pub mod slang_solidity::bindings::built_ins +pub fn slang_solidity::bindings::built_ins::get_built_ins_contents(version: &semver::Version) -> &'static str +pub enum slang_solidity::bindings::BindingGraphInitializationError +pub slang_solidity::bindings::BindingGraphInitializationError::ParserInitialization(slang_solidity::parser::ParserInitializationError) +impl core::convert::From for slang_solidity::bindings::BindingGraphInitializationError +pub fn slang_solidity::bindings::BindingGraphInitializationError::from(source: slang_solidity::parser::ParserInitializationError) -> Self +impl core::error::Error for slang_solidity::bindings::BindingGraphInitializationError +pub fn slang_solidity::bindings::BindingGraphInitializationError::source(&self) -> core::option::Option<&(dyn core::error::Error + 'static)> +impl core::fmt::Debug for slang_solidity::bindings::BindingGraphInitializationError +pub fn slang_solidity::bindings::BindingGraphInitializationError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::fmt::Display for slang_solidity::bindings::BindingGraphInitializationError +pub fn slang_solidity::bindings::BindingGraphInitializationError::fmt(&self, __formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn slang_solidity::bindings::create_with_resolver(version: semver::Version, resolver: alloc::rc::Rc>) -> core::result::Result 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::BindingLocation = metaslang_bindings::location::BindingLocation 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 type slang_solidity::bindings::UserFileLocation = metaslang_bindings::location::UserFileLocation +pub mod slang_solidity::compilation +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) -> &core::result::Result, slang_solidity::bindings::BindingGraphInitializationError> +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 +pub struct slang_solidity::compilation::File +impl slang_solidity::compilation::File +pub fn slang_solidity::compilation::File::create_tree_cursor(&self) -> slang_solidity::cst::Cursor +pub fn slang_solidity::compilation::File::id(&self) -> &str +pub fn slang_solidity::compilation::File::tree(&self) -> &slang_solidity::cst::Node +impl core::clone::Clone for slang_solidity::compilation::File +pub fn slang_solidity::compilation::File::clone(&self) -> slang_solidity::compilation::File +pub struct slang_solidity::compilation::InternalCompilationBuilder +impl slang_solidity::compilation::InternalCompilationBuilder +pub fn slang_solidity::compilation::InternalCompilationBuilder::add_file(&mut self, id: alloc::string::String, contents: &str) -> slang_solidity::compilation::AddFileResponse +pub fn slang_solidity::compilation::InternalCompilationBuilder::build(&self) -> slang_solidity::compilation::CompilationUnit +pub fn slang_solidity::compilation::InternalCompilationBuilder::create(language_version: semver::Version) -> core::result::Result +pub fn slang_solidity::compilation::InternalCompilationBuilder::resolve_import(&mut self, source_file_id: &str, import_path: &slang_solidity::cst::Cursor, destination_file_id: alloc::string::String) -> core::result::Result<(), ResolveImportError> pub mod slang_solidity::cst pub use slang_solidity::cst::EdgeLabelExtensions pub use slang_solidity::cst::NonterminalKindExtensions @@ -886,6 +923,8 @@ pub fn slang_solidity::diagnostic::render for slang_solidity::bindings::BindingGraphInitializationError +pub fn slang_solidity::bindings::BindingGraphInitializationError::from(source: slang_solidity::parser::ParserInitializationError) -> Self impl core::error::Error for slang_solidity::parser::ParserInitializationError impl core::fmt::Debug for slang_solidity::parser::ParserInitializationError pub fn slang_solidity::parser::ParserInitializationError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -915,19 +954,23 @@ pub fn slang_solidity::parser::ParseOutput::create_tree_cursor(&self) -> slang_s pub fn slang_solidity::parser::ParseOutput::errors(&self) -> &alloc::vec::Vec pub fn slang_solidity::parser::ParseOutput::is_valid(&self) -> bool pub fn slang_solidity::parser::ParseOutput::tree(&self) -> &alloc::rc::Rc +impl core::clone::Clone for slang_solidity::parser::ParseOutput +pub fn slang_solidity::parser::ParseOutput::clone(&self) -> slang_solidity::parser::ParseOutput impl core::cmp::PartialEq for slang_solidity::parser::ParseOutput pub fn slang_solidity::parser::ParseOutput::eq(&self, other: &slang_solidity::parser::ParseOutput) -> bool impl core::fmt::Debug for slang_solidity::parser::ParseOutput pub fn slang_solidity::parser::ParseOutput::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl core::marker::StructuralPartialEq for slang_solidity::parser::ParseOutput pub struct slang_solidity::parser::Parser -pub slang_solidity::parser::Parser::version: semver::Version impl slang_solidity::parser::Parser pub const slang_solidity::parser::Parser::ROOT_KIND: slang_solidity::cst::NonterminalKind -pub const slang_solidity::parser::Parser::SUPPORTED_VERSIONS: &'static [semver::Version] -pub fn slang_solidity::parser::Parser::create(version: semver::Version) -> core::result::Result +pub fn slang_solidity::parser::Parser::create(language_version: semver::Version) -> core::result::Result +pub fn slang_solidity::parser::Parser::language_version(&self) -> &semver::Version pub fn slang_solidity::parser::Parser::parse(&self, kind: slang_solidity::cst::NonterminalKind, input: &str) -> slang_solidity::parser::ParseOutput -pub fn slang_solidity::parser::Parser::version(&self) -> &semver::Version impl core::fmt::Debug for slang_solidity::parser::Parser pub fn slang_solidity::parser::Parser::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result -pub fn slang_solidity::transform_built_ins_node(node: &slang_solidity::cst::Node) -> slang_solidity::cst::Node +pub mod slang_solidity::utils +pub struct slang_solidity::utils::LanguageFacts +impl slang_solidity::utils::LanguageFacts +pub const slang_solidity::utils::LanguageFacts::NAME: &'static str +pub const slang_solidity::utils::LanguageFacts::SUPPORTED_VERSIONS: &'static [semver::Version] diff --git a/crates/solidity/outputs/cargo/crate/src/extensions/bindings/mod.rs b/crates/solidity/outputs/cargo/crate/src/extensions/bindings/mod.rs new file mode 100644 index 0000000000..5380535fea --- /dev/null +++ b/crates/solidity/outputs/cargo/crate/src/extensions/bindings/mod.rs @@ -0,0 +1,60 @@ +use std::rc::Rc; + +use metaslang_cst::text_index::TextIndex; +use semver::Version; + +use crate::bindings::built_ins::get_built_ins_contents; +use crate::bindings::BindingGraph; +use crate::cst::{Edge, Node, NonterminalNode, TerminalKind, TerminalNode}; +use crate::parser::{Parser, ParserInitializationError}; + +pub fn add_built_ins( + binding_graph: &mut BindingGraph, + version: Version, +) -> Result<(), ParserInitializationError> { + let source = get_built_ins_contents(&version); + let parser = Parser::create(version)?; + let parse_output = parser.parse(Parser::ROOT_KIND, source); + + let built_ins_cursor = transform(&Node::Nonterminal(Rc::clone(parse_output.tree()))) + .cursor_with_offset(TextIndex::ZERO); + + binding_graph.add_system_file("built_ins.sol", built_ins_cursor); + Ok(()) +} + +fn transform(node: &Node) -> Node { + match node { + Node::Nonterminal(nonterminal) => { + let NonterminalNode { + kind, + text_len, + children, + } = nonterminal.as_ref(); + let children = children + .iter() + .map(|edge| Edge { + label: edge.label, + node: transform(&edge.node), + }) + .collect(); + let nonterminal = Rc::new(NonterminalNode { + kind: *kind, + text_len: *text_len, + children, + }); + Node::Nonterminal(nonterminal) + } + Node::Terminal(terminal) => { + let TerminalNode { kind, text } = terminal.as_ref(); + let terminal = match terminal.as_ref().kind { + TerminalKind::Identifier => Rc::new(TerminalNode { + kind: *kind, + text: text.replace('$', "%"), + }), + _ => Rc::clone(terminal), + }; + Node::Terminal(terminal) + } + } +} diff --git a/crates/solidity/outputs/cargo/crate/src/extensions/compilation/mod.rs b/crates/solidity/outputs/cargo/crate/src/extensions/compilation/mod.rs new file mode 100644 index 0000000000..0ba82a945c --- /dev/null +++ b/crates/solidity/outputs/cargo/crate/src/extensions/compilation/mod.rs @@ -0,0 +1,109 @@ +use crate::cst::{Cursor, Query}; + +pub struct ImportPathsExtractor { + queries: Vec, +} + +impl ImportPathsExtractor { + pub fn new() -> Self { + Self { + queries: [ + "[PathImport + path: [StringLiteral + @variant ([DoubleQuotedStringLiteral] | [SingleQuotedStringLiteral]) + ] + ]", + "[NamedImport + path: [StringLiteral + @variant ([DoubleQuotedStringLiteral] | [SingleQuotedStringLiteral]) + ] + ]", + "[ImportDeconstruction + path: [StringLiteral + @variant ([DoubleQuotedStringLiteral] | [SingleQuotedStringLiteral]) + ] + ]", + ] + .into_iter() + .map(|text| Query::parse(text).unwrap()) + .collect(), + } + } + + pub fn extract(&self, cursor: Cursor) -> Vec { + cursor + .query(self.queries.clone()) + .flat_map(|query_match| query_match.captures) + .flat_map(|(match_name, cursors)| { + assert_eq!(match_name, "variant"); + cursors + }) + .collect() + } +} + +#[cfg(test)] +mod tests { + use semver::Version; + + use crate::parser::Parser; + + #[test] + pub fn path_import() { + run( + r#" + import "foo-double"; + import "bar-double" as bar; + + import 'foo-single'; + import 'bar-single' as bar; + + "#, + &[ + "\"foo-double\"", + "\"bar-double\"", + "\'foo-single\'", + "\'bar-single\'", + ], + ); + } + + #[test] + pub fn named_import() { + run( + r#" + import * as foo from "foo-double"; + + import * as foo from 'foo-single'; + "#, + &["\"foo-double\"", "\'foo-single\'"], + ); + } + + #[test] + pub fn import_deconstruction() { + run( + r#" + import {a, b} from "foo-double"; + + import {a, b} from 'foo-single'; + "#, + &["\"foo-double\"", "\'foo-single\'"], + ); + } + + fn run(source: &str, expected: &[&str]) { + let parser = Parser::create(Version::new(0, 8, 0)).unwrap(); + let parse_output = parser.parse(Parser::ROOT_KIND, source); + + let imports = super::ImportPathsExtractor::new(); + + let actual: Vec<_> = imports + .extract(parse_output.create_tree_cursor()) + .into_iter() + .map(|cursor| cursor.node().unparse()) + .collect(); + + assert_eq!(actual, expected.to_vec()); + } +} diff --git a/crates/solidity/outputs/cargo/crate/src/extensions/mod.rs b/crates/solidity/outputs/cargo/crate/src/extensions/mod.rs new file mode 100644 index 0000000000..78402f8764 --- /dev/null +++ b/crates/solidity/outputs/cargo/crate/src/extensions/mod.rs @@ -0,0 +1,8 @@ +#[cfg(all( + feature = "__experimental_bindings_api", + feature = "__private_compilation_api" +))] +pub mod compilation; + +#[cfg(feature = "__experimental_bindings_api")] +pub mod bindings; diff --git a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/binding_rules.rs b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/binding_rules.rs index 63e0862896..4817a55eb7 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/binding_rules.rs +++ b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/binding_rules.rs @@ -27,6 +27,11 @@ inherit .enclosing_def inherit .parent_scope inherit .lexical_scope +; Used to resolve extension methods for `using for *` directives +; This is used as a minor optimization to avoid introducing new possible paths +; when there are no `using for *` directives in the contract. +inherit .star_extension + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Source unit (aka .sol file) @@ -67,14 +72,22 @@ inherit .lexical_scope ;; inherited) for contracts to resolve bases (both in inheritance lists and ;; override specifiers) let @source_unit.parent_scope = @source_unit.lexical_scope + + ; This is used to indicate the resolution algorithm that here's where it + ; should inject any possible extension scopes + attr (@source_unit.lexical_scope) extension_hook + + ; Provide a default star extension sink node that gets inherited. This is + ; connected to from expressions, and those can potentially happen anywhere. + node @source_unit.star_extension } ;; Top-level definitions... @source_unit [SourceUnit [SourceUnitMembers [SourceUnitMember @unit_member ( [ContractDefinition] - | [InterfaceDefinition] | [LibraryDefinition] + | [InterfaceDefinition] | [StructDefinition] | [EnumDefinition] | [FunctionDefinition] @@ -84,9 +97,12 @@ inherit .lexical_scope | [EventDefinition] )] ]] { - edge @unit_member.lexical_scope -> @source_unit.lexical_scope edge @source_unit.lexical_scope -> @unit_member.def edge @source_unit.defs -> @unit_member.def + + ; In the general case, the lexical scope of the definition connects directly + ; to the source unit's + edge @unit_member.lexical_scope -> @source_unit.lexical_scope } ;; Special case for built-ins: we want to export all symbols in the contract: @@ -99,13 +115,14 @@ inherit .lexical_scope [SourceUnitMember @contract [ContractDefinition name: ["%BuiltIns%"]]] ]] { if (is-system-file FILE_PATH) { - edge @source_unit.defs -> @contract.members - edge @source_unit.defs -> @contract.type_members - edge @source_unit.defs -> @contract.state_vars + edge @source_unit.defs -> @contract.instance } } @source_unit [SourceUnit [SourceUnitMembers [SourceUnitMember @using [UsingDirective]]]] { + ; TODO: this is the hook for top-level extensions, but this should connect to + ; an extensions scope that gets pushed to the scope stack, as in the case of + ; contracts/libraries (defined further down below). edge @source_unit.lexical_scope -> @using.def } @@ -116,7 +133,7 @@ inherit .lexical_scope edge @source_unit.defs -> @using.def } -;; ... and imports +;; Import connections to the source unit @source_unit [SourceUnit [SourceUnitMembers [SourceUnitMember [ImportDirective [ImportClause @import ( @@ -136,21 +153,29 @@ inherit .lexical_scope ;;; Imports ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -[ImportClause [_ @path path: [StringLiteral]]] { +[ImportClause + [_ + path: [StringLiteral + @path ([DoubleQuotedStringLiteral] | [SingleQuotedStringLiteral]) + ] + ] +] { ;; This node represents the imported file and the @path.import node is used by ;; all subsequent import rules node @path.import - scan (source-text @path) { - "^\\s*[\"'](.+)[\"']\\s*$" { - let resolved_path = (resolve-path FILE_PATH $1) - attr (@path.import) push_symbol = resolved_path - } - } + + let resolved_path = (resolve-path FILE_PATH @path) + attr (@path.import) push_symbol = resolved_path + edge @path.import -> ROOT_NODE } ;;; `import ` -@import [PathImport @path path: [StringLiteral] .] { +@import [PathImport + path: [StringLiteral + @path ([DoubleQuotedStringLiteral] | [SingleQuotedStringLiteral]) + ] +] { ;; This is the "lexical" connection, which makes all symbols exported from the ;; imported source unit available for resolution globally at this' source unit ;; scope @@ -159,8 +184,10 @@ inherit .lexical_scope ;;; `import as ` @import [PathImport - @path path: [StringLiteral] - alias: [ImportAlias @alias [Identifier]] + path: [StringLiteral + @path ([DoubleQuotedStringLiteral] | [SingleQuotedStringLiteral]) + ] + alias: [ImportAlias @alias [Identifier]] ] { node def attr (def) node_definition = @alias @@ -178,8 +205,10 @@ inherit .lexical_scope ;;; `import * as from ` @import [NamedImport - alias: [ImportAlias @alias [Identifier]] - @path path: [StringLiteral] + alias: [ImportAlias @alias [Identifier]] + path: [StringLiteral + @path ([DoubleQuotedStringLiteral] | [SingleQuotedStringLiteral]) + ] ] { node def attr (def) node_definition = @alias @@ -197,8 +226,10 @@ inherit .lexical_scope ;;; `import { [as ] ...} from ` @import [ImportDeconstruction - symbols: [ImportDeconstructionSymbols @symbol [ImportDeconstructionSymbol]] - @path path: [StringLiteral] + symbols: [ImportDeconstructionSymbols @symbol [ImportDeconstructionSymbol]] + path: [StringLiteral + @path ([DoubleQuotedStringLiteral] | [SingleQuotedStringLiteral]) + ] ] { ;; We define these intermediate nodes for convenience only, to make the ;; queries simpler in the two rules below @@ -255,28 +286,32 @@ inherit .lexical_scope ;; interface), aka the source unit edge @type_name.push_end -> heir.parent_scope - ;; Make base members accesible as our own members - node member - attr (member) push_symbol = "." - - node typeof - attr (typeof) push_symbol = "@typeof" - - edge heir.members -> member - edge member -> typeof - edge typeof -> @type_name.push_begin - - ;; Make base defs (eg. enums and structs) accessible as our own - node type_member - attr (type_member) push_symbol = "." + ; Access instance members of the inherited contract/interface, from the + ; instance scope of the inheriting contract/interface + node instance + attr (instance) push_symbol = "@instance" + edge heir.instance -> instance + edge instance -> @type_name.push_begin - edge heir.type_members -> type_member - edge type_member -> @type_name.push_begin + ; Base members can also be accessed (from the instance scope) qualified with + ; the base name (eg. `Base.something`) + node member_pop + attr (member_pop) pop_symbol = "." + edge heir.instance -> @type_name.pop_begin + edge @type_name.pop_end -> member_pop + edge member_pop -> instance - ; Resolve the "super" keyword to the inherited type - edge heir.super -> @type_name.push_begin + ; Base namespace-like members (ie. enums, structs, etc) are also accessible as + ; our own namespace members + node ns_member + attr (ns_member) push_symbol = "." + edge heir.ns -> ns_member + edge ns_member -> @type_name.push_begin } +;; The next couple of rules setup a `.parent_refs` attribute to use in the +;; resolution algorithm to perform linearisation of a contract hierarchy. + ;; NOTE: we use anchors here to prevent the query engine from returning all the ;; sublists of possible parents @specifier [InheritanceSpecifier [InheritanceTypes . @parents [_]+ .]] { @@ -299,38 +334,35 @@ inherit .lexical_scope ;;; Contracts ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -@contract [ContractDefinition] { +@contract [ContractDefinition @name name: [Identifier]] { node @contract.lexical_scope - node @contract.super_scope + node @contract.extensions node @contract.def node @contract.members - node @contract.type_members + node @contract.ns node @contract.modifiers - node @contract.state_vars + node @contract.instance - edge @contract.lexical_scope -> @contract.members - edge @contract.lexical_scope -> @contract.type_members - edge @contract.lexical_scope -> @contract.state_vars + attr (@contract.def) node_definition = @name + attr (@contract.def) definiens_node = @contract + ; The .extensions node is where `using` directives will hook the definitions + attr (@contract.def) extension_scope = @contract.extensions - ;; Modifiers are available as a contract type members through a special '@modifier' symbol - node modifier - attr (modifier) pop_symbol = "@modifier" - edge @contract.type_members -> modifier - edge modifier -> @contract.modifiers + edge @contract.lexical_scope -> @contract.instance - let @contract.enclosing_def = @contract.def -} + ; Instance scope can also see members and our namespace definitions + edge @contract.instance -> @contract.members + edge @contract.instance -> @contract.ns -@contract [ContractDefinition @name name: [Identifier]] { - attr (@contract.def) node_definition = @name - attr (@contract.def) definiens_node = @contract + let @contract.enclosing_def = @contract.def - ;; "instance" like access path - ;; we have two distinct paths: @typeof -> . for accesses to variables of the contract's type - ;; and () -> . for accesses through a `new` invocation (or casting) + ;; External "instance" scope access: either member access through a variable + ;; of the contract's type, or through calling (which happens on `new` + ;; invocations or casting). These should access only externally accessible + ;; members, such as functions and public variables. node member attr (member) pop_symbol = "." - edge member -> @contract.members + edge member -> @contract.instance node type_def attr (type_def) pop_symbol = "@typeof" @@ -342,81 +374,148 @@ inherit .lexical_scope edge @contract.def -> call edge call -> member - ;; "namespace" like access path - node type_member - attr (type_member) pop_symbol = "." - edge @contract.def -> type_member - edge type_member -> @contract.type_members - - ;; Define "this" and connect it to the contract definition + ;; "namespace" scope access + node ns_member + attr (ns_member) pop_symbol = "." + edge @contract.def -> ns_member + edge ns_member -> @contract.ns + + ; Finally there's an @instance guarded path used by derived contracts to + ; access instance accessible members + node instance + attr (instance) pop_symbol = "@instance" + edge @contract.def -> instance + edge instance -> @contract.instance + + ; "this" keyword is available in our lexical scope and can access any + ; externally available member node this attr (this) pop_symbol = "this" - edge this -> member - - ;; ... and make it available in the contract's lexical scope edge @contract.lexical_scope -> this + edge this -> member - ; Resolve the "this" keyword to the contract itself - node name_push - attr (name_push) push_symbol = (source-text @name) - edge this -> name_push - edge name_push -> @contract.lexical_scope - - ;; Define "super" effectively as if it was a state variable of a type connected by our super_scope - ;; super_scope will later connect to the base contract defs directly - node @contract.super - attr (@contract.super) pop_symbol = "super" - - node super_typeof - attr (super_typeof) push_symbol = "@typeof" - - edge @contract.super -> super_typeof - edge super_typeof -> @contract.super_scope - - ;; Finally make "super" available in the contract's lexical scope for function bodies to use - edge @contract.lexical_scope -> @contract.super + ;; Modifiers are available as a contract type members through a special '@modifier' guard + node modifier + attr (modifier) pop_symbol = "@modifier" + edge @contract.ns -> modifier + edge modifier -> @contract.modifiers - ; NOTE: The keyword "super" itself resolves to each of its parent contracts. - ; See the related rules in the InheritanceSpecifier section above. + ; There may be attached functions to our type. For the general case of + ; variables of our type, that's already handled via normal lexical scope + ; resolution. But for casting/`new` invocations that we resolve through the + ; `()` guard above, we need to explicitly jump to the extension scope from + ; here to attempt resolving the attached function. We cannot jump back to the + ; parent scope because that would create a cycle in the graph. + node push_typeof + attr (push_typeof) push_symbol = "@typeof" + node push_name + attr (push_name) push_symbol = (source-text @name) + node hook + attr (hook) extension_hook + + edge call -> push_typeof + edge push_typeof -> push_name + edge push_name -> hook - ;; This defines the sink of edges added from base contracts when setting this - ;; contract as the compilation context - attr (@contract.def) export_node = @contract.members + if (version-matches "< 0.5.0") { + ; For Solidity < 0.5.0 `this` also acts like an `address` + node address_ref + attr (address_ref) push_symbol = "%address" + node address_typeof + attr (address_typeof) push_symbol = "@typeof" + edge this -> address_typeof + edge address_typeof -> address_ref + edge address_ref -> @contract.lexical_scope + } - ;; This node will eventually connect to the contract's members being compiled - ;; and grants access to definitions in that contract and all its parents - ;; (recursively) - node super_import - attr (super_import) pop_symbol = "." - edge @contract.super -> super_import + ; This is the connection point to resolve attached functions by `using for *` + node @contract.star_extension + attr (@contract.star_extension) push_symbol = "@*" - ;; This defines the source side of edges added to base contracts when setting - ;; a contract as compilation context; this allows this contract (a base) to - ;; access virtual methods in any sub-contract defined in the hierarchy - attr (@contract.def) import_nodes = [@contract.lexical_scope, super_import] + if (version-matches "< 0.7.0") { + ; For Solidity < 0.7.0 using directives are inherited, so we need to connect + ; always For newer versions, this connection only happens when there is a + ; `using for *` directive in the contract (see rule below) + edge @contract.star_extension -> @contract.lexical_scope + } ; Path to resolve the built-in type for type() expressions node type - attr (type) pop_symbol = "%type" + attr (type) pop_symbol = "@type" node type_contract_type - attr (type_contract_type) push_symbol = "%typeContractType" + attr (type_contract_type) push_symbol = "%ContractTypeType" edge @contract.def -> type edge type -> type_contract_type - edge type_contract_type -> @contract.lexical_scope + edge type_contract_type -> @contract.parent_scope + + ; The following defines the connection nodes the resolution algorithm uses + ; *only when setting a compilation context/target*. + + ; This attribute defines the sink of edges added from base contracts when + ; setting this contract as the compilation context, and should provide access + ; to anything that can be reached through `super`. The instance scope is a bit + ; too broad, but `.members` is too narrow as it doesn't allow navigation to + ; parent contracts (and from the base we need to be able to reach all + ; contracts in the hierarchy). + attr (@contract.def) export_node = @contract.instance + + ; This node will eventually connect to the contract's members being compiled + ; and grants access to definitions in that contract and all its parents + ; (recursively). It only makes sense if `super` is defined (ie. if we have + ; parents), but we define it here to be able to use it in the declaration of + ; import nodes. This is the dual of the export_node above. + node @contract.super_import + attr (@contract.super_import) pop_symbol = "." + + ; This defines the source side of edges added to base contracts when setting + ; a contract as compilation context; this allows this contract (a base) to + ; access virtual methods in any sub-contract defined in the hierarchy (both + ; with and without `super`, hence the two connection points). + attr (@contract.def) import_nodes = [@contract.lexical_scope, @contract.super_import] } @contract [ContractDefinition @specifier [InheritanceSpecifier]] { + ; The `.heir` scoped variable allows the rules for `InheritanceSpecifier` + ; above to connect the instance scope of this contract to the parents. let @specifier.heir = @contract attr (@contract.def) parents = @specifier.parent_refs + if (version-matches "< 0.7.0") { + attr (@contract.def) inherit_extensions + } + + ; The rest of these statements deal with defining and connecting the `super` + ; keyword path. + + ; `super_scope` is where we hook all references to our parent contracts + node @contract.super_scope + + ; Define "super" in the lexical scope + node @contract.super + attr (@contract.super) pop_symbol = "super" + edge @contract.lexical_scope -> @contract.super + + ; This connects `super` to exported scopes from all contracts in the hierarchy + ; when setting a contract compilation target (see more detailed description + ; above on the definition of the `super_import` node). + edge @contract.super -> @contract.super_import + + ; Then connect it through an `@instance` guard to the parent contracts through + ; `super_scope`. This allows "instance"-like access to members of parents + ; through `super`. + node super_instance + attr (super_instance) push_symbol = "@instance" + edge @contract.super_import -> super_instance + edge super_instance -> @contract.super_scope } @contract [ContractDefinition [InheritanceSpecifier [InheritanceTypes [InheritanceType @type_name [IdentifierPath]] ]]] { - ;; The base contract defs are directly accesible through our special super scope + ;; The base contract defs are directly accesible through our super scope edge @contract.super_scope -> @type_name.push_begin } +; Pure definitions that cannot contain expressions @contract [ContractDefinition [ContractMembers [ContractMember @member ( [EnumDefinition] @@ -424,12 +523,23 @@ inherit .lexical_scope | [EventDefinition] | [ErrorDefinition] | [UserDefinedValueTypeDefinition] - | [FunctionDefinition] + )] +]] { + edge @member.lexical_scope -> @contract.lexical_scope +} + +; Definitions that can contain expressions need two scopes: +; - normal lexical scope for resolving types +; - extended scope (extended by using directives) for resolving expressions +@contract [ContractDefinition [ContractMembers + [ContractMember @member ( + [FunctionDefinition] | [ConstructorDefinition] - | [StateVariableDefinition] | [ModifierDefinition] | [FallbackFunctionDefinition] | [ReceiveFunctionDefinition] + | [UnnamedFunctionDefinition] + | [StateVariableDefinition] )] ]] { edge @member.lexical_scope -> @contract.lexical_scope @@ -438,7 +548,8 @@ inherit .lexical_scope @contract [ContractDefinition [ContractMembers [ContractMember @using [UsingDirective]] ]] { - edge @contract.lexical_scope -> @using.def + ; Hook the using definition in the extensions scope + edge @contract.extensions -> @using.def } @contract [ContractDefinition [ContractMembers @@ -450,13 +561,20 @@ inherit .lexical_scope | [UserDefinedValueTypeDefinition] )] ]] { - edge @contract.type_members -> @member.def + ; These definition go into the "namespace" scope and are accessible externally + ; via qualified naming (eg. `Contract.MyStruct`) + edge @contract.ns -> @member.def } @contract [ContractDefinition [ContractMembers [ContractMember @state_var [StateVariableDefinition]] ]] { - edge @contract.state_vars -> @state_var.def + ; State variables are available to derived contracts. + ; TODO: this also exposes private state variables to derived contracts, but we + ; can't easily filter them because we don't have negative assertions in our + ; query language (we would need to modify this query for anything *not* + ; containing a `PrivateKeyword` node) + edge @contract.instance -> @state_var.def } ;; Public state variables are also exposed as external member functions @@ -485,13 +603,15 @@ inherit .lexical_scope [FunctionAttributes [FunctionAttribute ([ExternalKeyword] | [PublicKeyword])]] ]] ]] { - ; public or external functions are also accessible through the contract type - edge @contract.type_members -> @function.def + ; Public or external functions are also accessible through the contract type + ; (to retrieve their `.selector` for example) + edge @contract.ns -> @function.def } @contract [ContractDefinition members: [ContractMembers [ContractMember @modifier [ModifierDefinition]] ]] { + ; Modifiers live in their own special scope edge @contract.modifiers -> @modifier.def ;; This may prioritize this definition (when there are multiple options) @@ -500,6 +620,15 @@ inherit .lexical_scope attr (@modifier.def) parents = [@contract.def] } +@contract [ContractDefinition [ContractMembers [ContractMember + [UsingDirective [UsingTarget [Asterisk]]] +]]] { + ; Connect the star extension node to the resolution extended scope if there is + ; a `using for *` directive in the contract + edge @contract.star_extension -> @contract.lexical_scope +} + +; This applies to both state variables and function definitions @override [OverrideSpecifier [OverridePathsDeclaration [OverridePaths @base_ident [IdentifierPath] ]]] { @@ -512,26 +641,29 @@ inherit .lexical_scope ;;; Interfaces ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -@interface [InterfaceDefinition] { +@interface [InterfaceDefinition @name name: [Identifier]] { node @interface.lexical_scope node @interface.def node @interface.members - node @interface.type_members + node @interface.ns + node @interface.instance - edge @interface.lexical_scope -> @interface.members - edge @interface.lexical_scope -> @interface.type_members -} - -@interface [InterfaceDefinition @name name: [Identifier]] { attr (@interface.def) node_definition = @name attr (@interface.def) definiens_node = @interface - ;; "instance" like access path - ;; we have two distinct paths: @typeof -> . for accesses to variables of the contract's type - ;; and () -> . for accesses through a `new` invocation (or casting) + edge @interface.lexical_scope -> @interface.instance + + ; The extensions node is required for the inheritance rules, but not used in interfaces + let @interface.extensions = (node) + + edge @interface.instance -> @interface.members + edge @interface.instance -> @interface.ns + + ;; External "instance" like access path, to access members of a variable of + ;; the interface's type or through a casting call. node member attr (member) pop_symbol = "." - edge member -> @interface.members + edge member -> @interface.instance node typeof attr (typeof) pop_symbol = "@typeof" @@ -543,28 +675,46 @@ inherit .lexical_scope edge @interface.def -> call edge call -> member + ; From a call we may need to resolve using the extensions scope, in case there's + ; a `using` directive on our type. This path ends up jumping to scope just to + ; handle that case. + node push_typeof + attr (push_typeof) push_symbol = "@typeof" + node push_name + attr (push_name) push_symbol = (source-text @name) + edge call -> push_typeof + edge push_typeof -> push_name + node hook + attr (hook) extension_hook + edge push_name -> hook + ; edge push_name -> JUMP_TO_SCOPE_NODE + ;; "namespace" like access path - node type_member - attr (type_member) pop_symbol = "." - edge @interface.def -> type_member - edge type_member -> @interface.type_members + node ns_member + attr (ns_member) pop_symbol = "." + edge @interface.def -> ns_member + edge ns_member -> @interface.ns + + ; Finally there's guarded `@instance` path used by derived contracts to access + ; instance accessible members + node instance + attr (instance) pop_symbol = "@instance" + edge @interface.def -> instance + edge instance -> @interface.instance ; Path to resolve the built-in type for type() expressions node type - attr (type) pop_symbol = "%type" + attr (type) pop_symbol = "@type" node type_interface_type - attr (type_interface_type) push_symbol = "%typeInterfaceType" + attr (type_interface_type) push_symbol = "%InterfaceTypeType" edge @interface.def -> type edge type -> type_interface_type - edge type_interface_type -> @interface.lexical_scope + edge type_interface_type -> @interface.parent_scope } @interface [InterfaceDefinition @specifier [InheritanceSpecifier]] { let @specifier.heir = @interface attr (@interface.def) parents = @specifier.parent_refs - - ; Define a dummy "super" node required by the rules for InheritanceSpecifier - node @interface.super } @interface [InterfaceDefinition [InterfaceMembers @@ -578,7 +728,7 @@ inherit .lexical_scope )] ]] { edge @member.lexical_scope -> @interface.lexical_scope - edge @interface.type_members -> @member.def + edge @interface.ns -> @member.def } ;; Allow references (eg. variables of the interface type) to the interface to @@ -586,14 +736,13 @@ inherit .lexical_scope @interface [InterfaceDefinition members: [InterfaceMembers item: [ContractMember @function variant: [FunctionDefinition]] ]] { - edge @function.lexical_scope -> @interface.lexical_scope edge @interface.members -> @function.def } [InterfaceDefinition [InterfaceMembers [ContractMember @using [UsingDirective]]]] { ; using directives are not allowed in interfaces, but the grammar allows them ; so we need to create an artificial node here to connect to created edges from - ; the internal nodes + ; the instance nodes let @using.lexical_scope = (node) } @@ -602,38 +751,50 @@ inherit .lexical_scope ;;; Libraries ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -@library [LibraryDefinition] { +@library [LibraryDefinition @name name: [Identifier]] { node @library.lexical_scope + node @library.extensions node @library.def - node @library.members - - edge @library.lexical_scope -> @library.members -} + node @library.ns + node @library.modifiers -@library [LibraryDefinition @name name: [Identifier]] { attr (@library.def) node_definition = @name attr (@library.def) definiens_node = @library + ; The .extensions node is where `using` directives will hook the definitions + attr (@library.def) extension_scope = @library.extensions + + edge @library.lexical_scope -> @library.ns + + let @library.enclosing_def = @library.def node member attr (member) pop_symbol = "." edge @library.def -> member + edge member -> @library.ns - edge member -> @library.members + ; Access to modifiers is guarded by a @modifier symbol + node modifier + attr (modifier) pop_symbol = "@modifier" + edge @library.ns -> modifier + edge modifier -> @library.modifiers ; Path to resolve the built-in type for type() expressions (same as contracts) node type - attr (type) pop_symbol = "%type" + attr (type) pop_symbol = "@type" node type_library_type - attr (type_library_type) push_symbol = "%typeContractType" + attr (type_library_type) push_symbol = "%ContractTypeType" edge @library.def -> type edge type -> type_library_type edge type_library_type -> @library.lexical_scope + + ; This is the connection point to resolve attached functions by `using for *` + node @library.star_extension + attr (@library.star_extension) push_symbol = "@*" } @library [LibraryDefinition [LibraryMembers [ContractMember @member ( - [FunctionDefinition] - | [EnumDefinition] + [EnumDefinition] | [StructDefinition] | [EventDefinition] | [ErrorDefinition] @@ -641,31 +802,54 @@ inherit .lexical_scope )] ]] { edge @member.lexical_scope -> @library.lexical_scope - edge @library.members -> @member.def + edge @library.ns -> @member.def +} + +@library [LibraryDefinition [LibraryMembers + [ContractMember @member ( + [FunctionDefinition] + | [StateVariableDefinition [StateVariableAttributes [StateVariableAttribute [ConstantKeyword]]]] + )] +]] { + edge @member.lexical_scope -> @library.lexical_scope + edge @library.ns -> @member.def +} + +@library [LibraryDefinition [LibraryMembers + [ContractMember @modifier [ModifierDefinition]] +]] { + edge @library.modifiers -> @modifier.def + edge @modifier.lexical_scope -> @library.lexical_scope } @library [LibraryDefinition [LibraryMembers [ContractMember @using [UsingDirective]] ]] { - edge @library.lexical_scope -> @using.def + ; Expose the using directive from the extensions scope + edge @library.extensions -> @using.def } +@library [LibraryDefinition [LibraryMembers [ContractMember + [UsingDirective [UsingTarget [Asterisk]]] +]]] { + ; Connect the star extension node to the resolution extended scope if there is + ; a `using for *` directive in the library + edge @library.star_extension -> @library.lexical_scope +} ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Using directives ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; The UsingDirective node requires the enclosing context to setup a -;; .lexical_scope scoped variable for it to resolve both targets and subjects. - @using [UsingDirective] { ; This node acts as a definition in the sense that provides an entry point ; that pops the target type and pushes the library/functions to attach to the ; target type node @using.def - ; This internal node connects the other end of the popping path starting at - ; .def and resolves for the library/functions in the directive + ; This internal node connects the definition side of the clause to the target + ; for resolution, and allows handling the multiple cases of `using` syntax + ; easily node @using.clause } @@ -709,12 +893,18 @@ inherit .lexical_scope ; pop the type symbols to connect to the attached function (via @using.clause) node typeof attr (typeof) pop_symbol = "@typeof" + node cast + attr (cast) pop_symbol = "()" - edge @using.def -> @type_name.pop_begin + ; We connect to all_pop_begin to be able to resolve both qualified and + ; unqualified instances of the target type + edge @using.def -> @type_name.all_pop_begin edge @type_name.pop_end -> typeof edge typeof -> @using.clause + edge @type_name.pop_end -> cast + edge cast -> @using.clause - ; resolve the target type of the directive + ; resolve the target type of the directive on the lexical scope edge @type_name.type_ref -> @using.lexical_scope } @@ -731,7 +921,7 @@ inherit .lexical_scope ;;; Type names ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; TypeName nodes should define two scoped variables: +;; TypeName nodes should define these scoped variables: ;; ;; - @type_name.type_ref represents the node in the graph where we're ready to ;; resolve the type, and thus should generally be connected to a (lexical) @@ -740,12 +930,19 @@ inherit .lexical_scope ;; - @type_name.output represents the other end of the type and corresponds to a ;; state where the type has already been resolved so we can, for example ;; resolve its members (sink node, outside edges connect *to* here). +;; +;; - @type_name.pop_begin, @type_name.pop_end are used in a definition context, +;; ie. when we need to pop the type name symbol(s) from the symbol stack. +;; Additionally, @type_name.all_pop_begin links to each symbol in a typename +;; (ie. in an identifier path typename), which allows referring to a type both +;; qualified and unqualified. @type_name [TypeName @elementary [ElementaryType]] { let @type_name.type_ref = @elementary.ref let @type_name.output = @elementary.ref let @type_name.pop_begin = @elementary.pop let @type_name.pop_end = @elementary.pop + let @type_name.all_pop_begin = @elementary.pop } @type_name [TypeName @id_path [IdentifierPath]] { @@ -760,6 +957,7 @@ inherit .lexical_scope let @type_name.pop_begin = @id_path.pop_begin let @type_name.pop_end = @id_path.pop_end + let @type_name.all_pop_begin = @id_path.all_pop_begin } @type_name [TypeName @type_variant ([ArrayTypeName] | [FunctionType])] { @@ -767,6 +965,7 @@ inherit .lexical_scope let @type_name.output = @type_variant.output let @type_name.pop_begin = @type_variant.pop_begin let @type_name.pop_end = @type_variant.pop_end + let @type_name.all_pop_begin = @type_variant.pop_begin } @type_name [TypeName @mapping [MappingType]] { @@ -774,6 +973,7 @@ inherit .lexical_scope let @type_name.output = @mapping.output let @type_name.pop_begin = @mapping.pop_begin let @type_name.pop_end = @mapping.pop_end + let @type_name.all_pop_begin = @mapping.pop_begin } @@ -788,76 +988,130 @@ inherit .lexical_scope node @elementary.pop attr (@elementary.pop) pop_symbol = @elementary.symbol + + ; These variables are a bit redundant, but necessary to easily use elementary + ; types as mapping keys + let @elementary.pop_begin = @elementary.pop + let @elementary.pop_end = @elementary.pop + let @elementary.all_pop_begin = @elementary.pop + + let @elementary.push_begin = @elementary.ref + let @elementary.push_end = @elementary.ref +} + +@elementary [ElementaryType [AddressType]] { + let @elementary.symbol = "%address" } -@elementary [ElementaryType variant: [AddressType @address [AddressKeyword]]] { - let @elementary.symbol = (format "%{}" (source-text @address)) +@elementary [ElementaryType [BoolKeyword]] { + let @elementary.symbol = "%bool" } -@elementary [ElementaryType @keyword ( - [BoolKeyword] - | [ByteKeyword] - | [BytesKeyword] - | [StringKeyword] - | [IntKeyword] - | [UintKeyword] - | [FixedKeyword] - | [UfixedKeyword] -)] { +@elementary [ElementaryType [ByteKeyword]] { + let @elementary.symbol = "%byte" +} + +@elementary [ElementaryType @keyword [BytesKeyword]] { let @elementary.symbol = (format "%{}" (source-text @keyword)) } +@elementary [ElementaryType [StringKeyword]] { + let @elementary.symbol = "%string" +} + +@elementary [ElementaryType @keyword [IntKeyword]] { + let symbol = (source-text @keyword) + if (eq symbol "int") { + let @elementary.symbol = "%int256" + } else { + let @elementary.symbol = (format "%{}" symbol) + } +} + +@elementary [ElementaryType @keyword [UintKeyword]] { + let symbol = (source-text @keyword) + if (eq symbol "uint") { + let @elementary.symbol = "%uint256" + } else { + let @elementary.symbol = (format "%{}" symbol) + } +} + +@elementary [ElementaryType @keyword [FixedKeyword]] { + let symbol = (source-text @keyword) + if (eq symbol "fixed") { + let @elementary.symbol = "%fixed128x18" + } else { + let @elementary.symbol = (format "%{}" symbol) + } +} + +@elementary [ElementaryType @keyword [UfixedKeyword]] { + let symbol = (source-text @keyword) + if (eq symbol "ufixed") { + let @elementary.symbol = "%ufixed128x18" + } else { + let @elementary.symbol = (format "%{}" symbol) + } +} + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Mappings ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -@mapping [MappingType] { +@mapping [MappingType + [MappingKey [MappingKeyType @key_type ([IdentifierPath] | [ElementaryType])]] + [MappingValue @value_type [TypeName]] +] { node @mapping.lexical_scope node @mapping.output -} - -@mapping [MappingType [MappingKey [MappingKeyType @key_ident [IdentifierPath]]]] { - ; resolve key type - edge @key_ident.push_end -> @mapping.lexical_scope -} -@mapping [MappingType [MappingValue @value_type [TypeName]]] { - ; for mapping types we don't need to push the type itself, because we don't need it (yet) - ; ditto for the pop path, because a mapping type cannot be the target of a using directive + ; Define the pushing path of the mapping type + ; ValueType <- top of the symbol stack + ; KeyType + ; %mapping <- bottom of the symbol stack + node mapping + attr (mapping) push_symbol = "%Mapping" + edge @mapping.output -> mapping + edge mapping -> @key_type.push_begin + edge @key_type.push_end -> @value_type.output + + ; Both key and value types need to be resolved + edge @value_type.type_ref -> @mapping.lexical_scope + edge @key_type.push_end -> @mapping.lexical_scope - ; The mapping's type exposes the `%index` (ie. `[]`) operator that returns the value type - ; This is similar to arrays, only in that case we have a built-in type where - ; we can define an index function. For mappings we hard-code in the rules directly. + ; The mapping's type exposes the `[]` operator that returns the value type. node typeof_input attr (typeof_input) pop_symbol = "@typeof" - - node index_member - attr (index_member) pop_symbol = "." - node index - attr (index) pop_symbol = "%index" - node index_call - attr (index_call) pop_symbol = "()" + edge @mapping.output -> typeof_input node typeof_output attr (typeof_output) push_symbol = "@typeof" - - edge @mapping.output -> typeof_input - edge typeof_input -> index_member - edge index_member -> index - edge index -> index_call - edge index_call -> typeof_output edge typeof_output -> @value_type.output - ; resolve the value type through our scope - edge @value_type.type_ref -> @mapping.lexical_scope + node index + attr (index) pop_symbol = "[]" + edge typeof_input -> index + edge index -> typeof_output + + ; Special case for mapping public state variables: they can be called + ; like a function with a key, and it's effectively the same as indexing it. + node getter_call + attr (getter_call) pop_symbol = "@as_getter" + edge typeof_input -> getter_call + edge getter_call -> typeof_output + + ; Now we define the "definition" route (aka. the pop route), to use in `using` directives only + ; This is the reverse of the pushing path above (to the `.output` node) + node pop_mapping + attr (pop_mapping) pop_symbol = "%Mapping" - ; We use the value_type's definition path as our own because it's needed when - ; a mapping is the target of a `using` directive. It's not correct, but we - ; don't have the analog referencing path either. let @mapping.pop_begin = @value_type.pop_begin - let @mapping.pop_end = @value_type.pop_end + edge @value_type.pop_end -> @key_type.pop_begin + edge @key_type.pop_end -> pop_mapping + let @mapping.pop_end = pop_mapping } @@ -871,47 +1125,69 @@ inherit .lexical_scope } @array [ArrayTypeName [TypeName] index: [Expression]] { - let @array.type = "%arrayFixed" + let @array.type_symbol = "%FixedArray" } @array [ArrayTypeName [OpenBracket] . [CloseBracket]] { - let @array.type = "%array" + let @array.type_symbol = "%Array" } @array [ArrayTypeName @type_name [TypeName]] { - ; First define the normal, reference route: - - ; We first push the array type `%array`, which should connect to two distinct paths: - ; 1. the typed path, which will use a jump scope entry to resolve the element type - ; 2. the hard-coded path to connect to any `using` directive + ; Define the pushing path of the array type + ; ValueType <- top of the symbol stack + ; %array / %arrayFixed <- bottom of the symbol stack node array - attr (array) push_symbol = @array.type + attr (array) push_symbol = @array.type_symbol edge @array.output -> array + edge array -> @type_name.output - ; For the first path, we need to define a scope jump entry for resolving the element type of the array - node entry - attr (entry) is_exported - node element - attr (element) pop_symbol = "%element" - edge entry -> element - edge element -> @type_name.output + ; Resolve the value type itself + edge @type_name.type_ref -> @array.lexical_scope + ; And also the "type erased" array type so we can resolve built-in members + edge array -> @array.lexical_scope - ; And then the path itself - node params - attr (params) push_scoped_symbol = "<>", scope = entry - edge array -> params + ; Define the path to resolve index access (aka the `[]` operator) - ; Second path, for `using` directives - edge array -> @type_name.output + node typeof_input + attr (typeof_input) pop_symbol = "@typeof" + edge @array.output -> typeof_input - ; Finally, both ends connect to our lexical scope - edge params -> @array.lexical_scope - edge @type_name.type_ref -> @array.lexical_scope + node typeof_output + attr (typeof_output) push_symbol = "@typeof" + edge typeof_output -> @type_name.output + + node index + attr (index) pop_symbol = "[]" + edge typeof_input -> index + edge index -> typeof_output + + ; Special case for public state variables of type array: they can be called + ; like a function with an index, and it's effectively the same as indexing the + ; array. + node getter_call + attr (getter_call) pop_symbol = "@as_getter" + edge typeof_input -> getter_call + edge getter_call -> typeof_output + + ; Define the special `.push()` built-in that returns the element type (for Solidity >= 0.6.0) + if (version-matches ">= 0.6.0") { + node built_in_member + attr (built_in_member) pop_symbol = "." + node push_built_in + attr (push_built_in) pop_symbol = "push" + node built_in_call + attr (built_in_call) pop_symbol = "()" + + edge typeof_input -> built_in_member + edge built_in_member -> push_built_in + edge push_built_in -> built_in_call + edge built_in_call -> typeof_output + } ; Now we define the "definition" route (aka. the pop route), to use in `using` directives only ; This is essentially the reverse of the second path above node pop_array - attr (pop_array) pop_symbol = @array.type + attr (pop_array) pop_symbol = @array.type_symbol let @array.pop_begin = @type_name.pop_begin edge @type_name.pop_end -> pop_array @@ -926,10 +1202,10 @@ inherit .lexical_scope @ftype [FunctionType @attrs [FunctionTypeAttributes]] { ; Compute the built-in type of the function ; %functionExternal provides access to .selector and .address - var type = "%function" + var type_symbol = "%Function" scan (source-text @attrs) { "external" { - set type = "%functionExternal" + set type_symbol = "%ExternalFunction" } } @@ -939,14 +1215,14 @@ inherit .lexical_scope ; This path pushes the function type to the symbol stack ; TODO: add parameter and return types to distinguish between different function types node function_type - attr (function_type) push_symbol = type + attr (function_type) push_symbol = type_symbol edge @ftype.output -> function_type edge function_type -> @ftype.lexical_scope ; the pop path for the using directive node pop_function_type - attr (pop_function_type) pop_symbol = type + attr (pop_function_type) pop_symbol = type_symbol let @ftype.pop_begin = pop_function_type let @ftype.pop_end = pop_function_type @@ -963,8 +1239,9 @@ inherit .lexical_scope @ftype [FunctionType [ReturnsDeclaration [ParametersDeclaration [Parameters . @param [Parameter] .]] ]] { - ; variables of a function type type can be "called" and resolve to the type of - ; the return parameter + ; Variables of a function type type can be "called" and resolve to the type of + ; the return parameter. This is only valid if the function returns a single + ; value. node typeof attr (typeof) pop_symbol = "@typeof" @@ -991,14 +1268,22 @@ inherit .lexical_scope ;; @id_path.pop_end. ;; ;; NOTE: most of the time, and unless this identifier path is the target of a -;; using directive this path will not be used and will form a disconnected -;; graph component. We currently have no way of determining when this path is -;; necessary, so we always construct it. +;; using directive this second path will not be used and will form a +;; disconnected graph component. We currently have no way of determining when +;; this path is necessary, so we always construct it. ;; ;; Additionally the IdentifierPath defines another scoped variable ;; @id_path.rightmost_identifier which corresponds to the identifier in the last -;; position in the path, from left to right. Useful for the using directive to -;; be able to pop the name of the attached function. +;; position in the path, from left to right. This is used in the using directive +;; rules to be able to pop the name of the attached function. + +@id_path [IdentifierPath] { + ; This node connects to all parts of the path, for popping. This allows to + ; connect at any point of the path. Useful for `using` directives when the + ; target type is fully qualified but we want to resolve for the unqualified + ; name. + node @id_path.all_pop_begin +} @id_path [IdentifierPath @name [Identifier]] { node @name.ref @@ -1007,6 +1292,8 @@ inherit .lexical_scope node @name.pop attr (@name.pop) pop_symbol = (source-text @name) + + edge @id_path.all_pop_begin -> @name.pop } @id_path [IdentifierPath @name [Identifier] .] { @@ -1074,10 +1361,10 @@ inherit .lexical_scope } @function [FunctionDefinition @attrs [FunctionAttributes]] { - var function_type = "%function" + var type_symbol = "%Function" scan (source-text @attrs) { "\\b(public|external)\\b" { - set function_type = "%functionExternal" + set type_symbol = "%ExternalFunction" } } @@ -1089,7 +1376,7 @@ inherit .lexical_scope node typeof attr (typeof) push_symbol = "@typeof" node type_function - attr (type_function) push_symbol = function_type + attr (type_function) push_symbol = type_symbol edge @function.def -> typeof edge typeof -> type_function edge type_function -> @function.lexical_scope @@ -1154,12 +1441,39 @@ inherit .lexical_scope edge @name.push_end -> modifier edge modifier -> @modifier.lexical_scope + + ; This allows resolving @name in the more general scope in constructors (since + ; calling a parent constructor is parsed as a modifier invocation) + let @modifier.identifier = @name.push_end } @modifier [ModifierInvocation @args [ArgumentsDeclaration]] { edge @args.lexical_scope -> @modifier.lexical_scope } +;;; Unnamed functions (deprecated) +@unnamed_function [UnnamedFunctionDefinition] { + node @unnamed_function.lexical_scope +} + +@unnamed_function [UnnamedFunctionDefinition @params parameters: [ParametersDeclaration]] { + edge @params.lexical_scope -> @unnamed_function.lexical_scope + + edge @unnamed_function.lexical_scope -> @params.defs + attr (@unnamed_function.lexical_scope -> @params.defs) precedence = 1 +} + +@unnamed_function [UnnamedFunctionDefinition [FunctionBody @block [Block]]] { + edge @block.lexical_scope -> @unnamed_function.lexical_scope +} + +@unnamed_function [UnnamedFunctionDefinition + [UnnamedFunctionAttributes [UnnamedFunctionAttribute @modifier [ModifierInvocation]]] +] { + edge @modifier.lexical_scope -> @unnamed_function.lexical_scope +} + + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Constructors @@ -1191,6 +1505,7 @@ inherit .lexical_scope @modifier [ModifierInvocation] ]]] { edge @modifier.lexical_scope -> @constructor.lexical_scope + edge @modifier.identifier -> @constructor.lexical_scope } @contract [ContractDefinition [ContractMembers [ContractMember @@ -1200,7 +1515,9 @@ inherit .lexical_scope edge @contract.def -> @constructor.def } -;; Solidity < 0.5.0 constructors were declared as functions of the contract's name +;; Solidity < 0.5.0 constructors +;; They were declared as functions of the contract's name + @contract [ContractDefinition @contract_name [Identifier] [ContractMembers [ContractMember [FunctionDefinition @@ -1216,6 +1533,21 @@ inherit .lexical_scope } } +[ContractDefinition + @contract_name [Identifier] + [ContractMembers [ContractMember @function [FunctionDefinition + [FunctionName @function_name [Identifier]] + [FunctionAttributes [FunctionAttribute @modifier [ModifierInvocation]]] + ]]] +] { + if (version-matches "< 0.5.0") { + if (eq (source-text @contract_name) (source-text @function_name)) { + ; Parent constructor calls are parsed as modifier invocations + edge @modifier.identifier -> @function.lexical_scope + } + } +} + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Fallback and receive functions @@ -1391,7 +1723,6 @@ inherit .lexical_scope @expr_stmt [ExpressionStatement] { node @expr_stmt.lexical_scope - node @expr_stmt.defs } @@ -1399,32 +1730,46 @@ inherit .lexical_scope @stmt [Statement @var_decl [VariableDeclarationStatement]] { edge @var_decl.lexical_scope -> @stmt.lexical_scope - edge @stmt.defs -> @var_decl.defs + edge @stmt.defs -> @var_decl.def } @var_decl [VariableDeclarationStatement] { node @var_decl.lexical_scope - node @var_decl.defs + node @var_decl.def } @var_decl [VariableDeclarationStatement [VariableDeclarationType @var_type [TypeName]] @name name: [Identifier] ] { - node def - attr (def) node_definition = @name - attr (def) definiens_node = @var_decl + attr (@var_decl.def) node_definition = @name + attr (@var_decl.def) definiens_node = @var_decl - edge @var_decl.defs -> def edge @var_type.type_ref -> @var_decl.lexical_scope node typeof attr (typeof) push_symbol = "@typeof" - edge def -> typeof + edge @var_decl.def -> typeof edge typeof -> @var_type.output } +@var_decl [VariableDeclarationStatement + [VariableDeclarationType [VarKeyword]] + @name name: [Identifier] +] { + attr (@var_decl.def) node_definition = @name + attr (@var_decl.def) definiens_node = @var_decl +} + +@var_decl [VariableDeclarationStatement + [VariableDeclarationType [VarKeyword]] + [VariableDeclarationValue @value [Expression]] +] { + edge @var_decl.def -> @value.output +} + + ;;; Tuple deconstruction statements @@ -1498,11 +1843,20 @@ inherit .lexical_scope ;; For loops @stmt [Statement [ForStatement - initialization: [ForStatementInitialization - @init_stmt ([ExpressionStatement] - | [VariableDeclarationStatement] - | [TupleDeconstructionStatement]) - ] + initialization: [ForStatementInitialization @init_stmt [ExpressionStatement]] +]] { + edge @init_stmt.lexical_scope -> @stmt.lexical_scope +} + +@stmt [Statement [ForStatement + initialization: [ForStatementInitialization @init_stmt [VariableDeclarationStatement]] +]] { + edge @init_stmt.lexical_scope -> @stmt.lexical_scope + edge @stmt.init_defs -> @init_stmt.def +} + +@stmt [Statement [ForStatement + initialization: [ForStatementInitialization @init_stmt [TupleDeconstructionStatement]] ]] { edge @init_stmt.lexical_scope -> @stmt.lexical_scope edge @stmt.init_defs -> @init_stmt.defs @@ -1652,11 +2006,36 @@ inherit .lexical_scope edge @type_name.type_ref -> @state_var.lexical_scope - node typeof - attr (typeof) push_symbol = "@typeof" + node @state_var.typeof + attr (@state_var.typeof) push_symbol = "@typeof" - edge @state_var.def -> typeof - edge typeof -> @type_name.output + edge @state_var.def -> @state_var.typeof + edge @state_var.typeof -> @type_name.output +} + +@state_var [StateVariableDefinition + [StateVariableAttributes [StateVariableAttribute [PublicKeyword]]] +] { + ; Public state variables are used as functions when invoked from an external contract + node call + attr (call) pop_symbol = "()" + + ; In the general case using the getter can bind to the state variable's type + edge @state_var.def -> call + edge call -> @state_var.typeof + + ; Some complex types generate special getters (ie. arrays and mappings index + ; their contents, structs flatten most of their fields and return a tuple) + node getter + attr (getter) push_symbol = "@as_getter" + edge call -> getter + edge getter -> @state_var.typeof +} + +@state_var [StateVariableDefinition + [StateVariableDefinitionValue @value [Expression]] +] { + let @value.lexical_scope = @state_var.lexical_scope } @@ -1664,13 +2043,11 @@ inherit .lexical_scope ;;; Enum definitions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -@enum [EnumDefinition] { +@enum [EnumDefinition @name name: [Identifier]] { node @enum.lexical_scope node @enum.def node @enum.members -} -@enum [EnumDefinition @name name: [Identifier]] { attr (@enum.def) node_definition = @name attr (@enum.def) definiens_node = @enum @@ -1682,9 +2059,9 @@ inherit .lexical_scope ; Path to resolve the built-in type for enums (which is the same as for integer types) node type - attr (type) pop_symbol = "%type" + attr (type) pop_symbol = "@type" node type_enum_type - attr (type_enum_type) push_symbol = "%typeIntType" + attr (type_enum_type) push_symbol = "%IntTypeType" edge @enum.def -> type edge type -> type_enum_type edge type_enum_type -> @enum.lexical_scope @@ -1705,73 +2082,61 @@ inherit .lexical_scope ;;; Structure definitions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -@struct [StructDefinition] { +@struct [StructDefinition @name name: [Identifier]] { node @struct.lexical_scope node @struct.def node @struct.members -} - -@struct [StructDefinition @name name: [Identifier]] { - ; Since we use structs to define built-in types and some of them (ie. array) - ; have have a parametric type, we define two distinct paths to define a - ; struct: - ; 1. the normal, non parametric path, should drop scopes in the scope stack first of all - ; 2. the parametric path, that pops a scope to resolve the parametric type - ; Both of these connect to the node that pops the struct identifier symbol - - ; First the normal path - node struct_drop - attr (struct_drop) type = "drop_scopes" - edge @struct.def -> struct_drop - - ; Second path, pops the scope - node typed_params - attr (typed_params) pop_scoped_symbol = "<>" - edge @struct.def -> typed_params - - ; Connect both to the struct identifier - node def - attr (def) node_definition = @name - attr (def) definiens_node = @struct - edge struct_drop -> def - edge typed_params -> def - ; On the other end, to properly close the second path we need to jump to the popped scope - ; (this is why on the other path we drop scopes) - edge @struct.lexical_scope -> JUMP_TO_SCOPE_NODE + attr (@struct.def) node_definition = @name + attr (@struct.def) definiens_node = @struct ; Now connect normally to the struct members - node type_def - attr (type_def) pop_symbol = "@typeof" + node @struct.typeof + attr (@struct.typeof) pop_symbol = "@typeof" node member attr (member) pop_symbol = "." - edge def -> type_def - edge type_def -> member + edge @struct.def -> @struct.typeof + edge @struct.typeof -> member edge member -> @struct.members ; Bind member names when using construction with named arguments node param_names attr (param_names) pop_symbol = "@param_names" - edge def -> param_names + edge @struct.def -> param_names edge param_names -> @struct.members + + ; Used as a function call (ie. casting), should bind to itself + node call + attr (call) pop_symbol = "()" + edge @struct.def -> call + edge call -> member } @struct [StructDefinition [StructMembers @member item: [StructMember @type_name [TypeName] @name name: [Identifier]] ]] { - node def - attr (def) node_definition = @name - attr (def) definiens_node = @member + node @member.def + attr (@member.def) node_definition = @name + attr (@member.def) definiens_node = @member - edge @struct.members -> def + edge @struct.members -> @member.def edge @type_name.type_ref -> @struct.lexical_scope - node typeof - attr (typeof) push_symbol = "@typeof" + node @member.typeof + attr (@member.typeof) push_symbol = "@typeof" - edge def -> typeof - edge typeof -> @type_name.output + edge @member.def -> @member.typeof + edge @member.typeof -> @type_name.output +} + +@struct [StructDefinition [StructMembers . @first_member [StructMember]]] { + ; As a public getter result, the value returned is a tuple with all our fields flattened + ; We only care about the first member for name binding, since tuples are not real types + node getter_call + attr (getter_call) pop_symbol = "@as_getter" + edge @struct.typeof -> getter_call + edge getter_call -> @first_member.typeof } @@ -1824,6 +2189,15 @@ inherit .lexical_scope node @error.params attr (@error.params) pop_symbol = "@param_names" edge @error.def -> @error.params + + ; Bind to built-in errorType for accessing built-in member `.selector` + node typeof + attr (typeof) push_symbol = "@typeof" + node error_type + attr (error_type) push_symbol = "%ErrorType" + edge @error.def -> typeof + edge typeof -> error_type + edge error_type -> @error.lexical_scope } @error [ErrorDefinition [ErrorParametersDeclaration [ErrorParameters @@ -1867,17 +2241,59 @@ inherit .lexical_scope edge @type_name.type_ref -> @constant.lexical_scope } -@user_type [UserDefinedValueTypeDefinition] { +@user_type [UserDefinedValueTypeDefinition @name [Identifier] @value_type [ElementaryType]] { node @user_type.lexical_scope node @user_type.def -} -@user_type [UserDefinedValueTypeDefinition @name [Identifier]] { - node def - attr (def) node_definition = @name - attr (def) definiens_node = @user_type + attr (@user_type.def) node_definition = @name + attr (@user_type.def) definiens_node = @user_type - edge @user_type.def -> def + ; Provide member resolution through the built-in `%userTypeType` + ; Because the built-in is defined as a struct, we need to push an extra `@typeof` + node member_guard + attr (member_guard) pop_symbol = "." + node member + attr (member) push_symbol = "." + node typeof + attr (typeof) push_symbol = "@typeof" + node user_type_type + attr (user_type_type) push_symbol = "%UserDefinedValueType" + + edge @user_type.def -> member_guard + edge member_guard -> member + edge member -> typeof + edge typeof -> user_type_type + edge user_type_type -> @user_type.lexical_scope + + ; Hard-code built-in functions `wrap` and `unwrap` in order to be able to + ; resolve their return types + node wrap + attr (wrap) pop_symbol = "wrap" + node wrap_call + attr (wrap_call) pop_symbol = "()" + node wrap_typeof + attr (wrap_typeof) push_symbol = "@typeof" + + edge member_guard -> wrap + edge wrap -> wrap_call + edge wrap_call -> wrap_typeof + edge wrap_typeof -> @value_type.ref + edge @value_type.ref -> @user_type.lexical_scope + + node unwrap + attr (unwrap) pop_symbol = "unwrap" + node unwrap_call + attr (unwrap_call) pop_symbol = "()" + node unwrap_typeof + attr (unwrap_typeof) push_symbol = "@typeof" + node type_ref + attr (type_ref) push_symbol = (source-text @name) + + edge member_guard -> unwrap + edge unwrap -> unwrap_call + edge unwrap_call -> unwrap_typeof + edge unwrap_typeof -> type_ref + edge type_ref -> @user_type.lexical_scope } @@ -1897,9 +2313,7 @@ inherit .lexical_scope } ;; Identifier expressions -@expr [Expression @name ( - variant: [Identifier] | variant: [SuperKeyword] | variant: [ThisKeyword] -)] { +@expr [Expression @name [Identifier]] { node ref attr (ref) node_reference = @name attr (ref) parents = [@expr.enclosing_def] @@ -1908,6 +2322,14 @@ inherit .lexical_scope edge @expr.output -> ref } +@expr [Expression @keyword ([ThisKeyword] | [SuperKeyword])] { + ; This is almost equivalent to the above rule, except it doesn't generate a reference + node keyword + attr (keyword) push_symbol = (source-text @keyword) + edge keyword -> @expr.lexical_scope + edge @expr.output -> keyword +} + ;; Member access expressions @expr [Expression [MemberAccessExpression @operand operand: [Expression] @@ -1926,10 +2348,7 @@ inherit .lexical_scope edge @expr.output -> @name.ref ; Shortcut path for expressions inside contracts with using X for * directives - node star - attr (star) push_symbol = "@*" - edge member -> star - edge star -> @expr.lexical_scope + edge member -> @expr.star_extension } ;; Special case: member accesses to `super` are tagged with "super" to rank @@ -1941,21 +2360,31 @@ inherit .lexical_scope attr (@name.ref) tag = "super" } +;; Elementary types used as expressions (eg. for type casting, or for built-ins like `string.concat`) +@expr [Expression @type [ElementaryType]] { + edge @expr.output -> @type.ref + edge @type.ref -> @expr.lexical_scope + + ; Elementary types can also be used for casting; instead of defining built-in + ; struct for each available elementary type, we define a special path here + node call + attr (call) pop_symbol = "()" + node typeof + attr (typeof) push_symbol = "@typeof" + edge @expr.output -> call + edge call -> typeof + edge typeof -> @type.ref +} + ;; Index access expressions @expr [Expression [IndexAccessExpression @operand operand: [Expression] ]] { - node index_call - attr (index_call) push_symbol = "()" node index - attr (index) push_symbol = "%index" - node index_member - attr (index_member) push_symbol = "." + attr (index) push_symbol = "[]" - edge @expr.output -> index_call - edge index_call -> index - edge index -> index_member - edge index_member -> @operand.output + edge @expr.output -> index + edge index -> @operand.output } ;; Type expressions @@ -1968,7 +2397,7 @@ inherit .lexical_scope node typeof attr (typeof) push_symbol = "@typeof" node type - attr (type) push_symbol = "%typeIntType" + attr (type) push_symbol = "%IntTypeType" edge @type_expr.output -> typeof edge typeof -> type @@ -1980,7 +2409,7 @@ inherit .lexical_scope node typeof attr (typeof) push_symbol = "@typeof" node type - attr (type) push_symbol = "%type" + attr (type) push_symbol = "@type" edge @type_expr.output -> typeof edge typeof -> type @@ -2044,7 +2473,7 @@ inherit .lexical_scope attr (@options.refs) push_symbol = "@param_names" node call_options - attr (call_options) push_symbol = "%callOptions" + attr (call_options) push_symbol = "%CallOptions" edge @options.refs -> call_options edge call_options -> @expr.lexical_scope @@ -2058,6 +2487,137 @@ inherit .lexical_scope } +;;; Payable +; These work like `address`, should they should bind to `%address` +@expr [Expression [PayableKeyword]] { + node ref + attr (ref) push_symbol = "%address" + + edge ref -> @expr.lexical_scope + edge @expr.output -> ref +} + + +;;; Tuple expressions + +; Parenthesized expressions are parsed as tuples of a single value +@expr [Expression [TupleExpression [TupleValues . [TupleValue @operand [Expression]] .]]] { + edge @expr.output -> @operand.output +} + +;;; Arithmetic, bitwise & logical operators, etc + +; Bind to the left operand only: assignment expressions +@expr [Expression [_ + @left_operand left_operand: [Expression] + ( + [Equal] + | [BarEqual] + | [PlusEqual] + | [MinusEqual] + | [CaretEqual] + | [SlashEqual] + | [PercentEqual] + | [AsteriskEqual] + | [AmpersandEqual] + | [LessThanLessThanEqual] + | [GreaterThanGreaterThanEqual] + | [GreaterThanGreaterThanGreaterThanEqual] + ) +]] { + edge @expr.output -> @left_operand.output +} + +; Unary operators postfix +@expr [Expression [_ + @operand operand: [Expression] + ([PlusPlus] | [MinusMinus]) +]] { + edge @expr.output -> @operand.output +} + +; Unary operators prefix +@expr [Expression [_ + ([PlusPlus] | [MinusMinus] | [Tilde] | [Bang] | [Minus] | [Plus]) + @operand operand: [Expression] +]] { + edge @expr.output -> @operand.output +} + +; Bind to both operands: logical and/or, arithmetic, bit-wise expressions +@expr [Expression [_ + @left_operand left_operand: [Expression] + ( + [BarBar] + | [AmpersandAmpersand] + + | [Plus] + | [Minus] + | [Asterisk] + | [Slash] + | [Percent] + | [AsteriskAsterisk] + + | [Bar] + | [Caret] + | [Ampersand] + + | [LessThanLessThan] + | [GreaterThanGreaterThan] + | [GreaterThanGreaterThanGreaterThan] + ) + @right_operand right_operand: [Expression] +]] { + edge @expr.output -> @left_operand.output + edge @expr.output -> @right_operand.output +} + +; Comparison operators bind to bool type +@expr [Expression [_ + ( + [EqualEqual] + | [BangEqual] + | [LessThan] + | [GreaterThan] + | [LessThanEqual] + | [GreaterThanEqual] + ) +]] { + node typeof + attr (typeof) push_symbol = "@typeof" + node bool + attr (bool) push_symbol = "%bool" + edge @expr.output -> typeof + edge typeof -> bool + edge bool -> @expr.lexical_scope +} + +; Ternary conditional expression binds to both branches +@expr [Expression [ConditionalExpression + @true_expression true_expression: [Expression] + @false_expression false_expression: [Expression] +]] { + edge @expr.output -> @true_expression.output + edge @expr.output -> @false_expression.output +} + + +;;; Literal Address Expressions +@expr [Expression [HexNumberExpression @hex_literal [HexLiteral]]] { + scan (source-text @hex_literal) { + "0x[0-9a-fA-F]{40}" { + ; Treat it as a valid address + node typeof + attr (typeof) push_symbol = "@typeof" + node address + attr (address) push_symbol = "%address" + edge @expr.output -> typeof + edge typeof -> address + edge address -> @expr.lexical_scope + } + } +} + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Yul @@ -2167,6 +2727,38 @@ inherit .lexical_scope ;; parameters) are functions (ie. the body of the function doesn't have access ;; to any outside variables) edge @fundef.lexical_scope -> @block.function_defs + ; Exception: but outside constants *are* available, so we provide a guarded + ; access to the parent lexical scope. This guard will be popped to link to + ; available constants. + node yul_function_guard + attr (yul_function_guard) push_symbol = "@in_yul_function" + edge @fundef.lexical_scope -> yul_function_guard + edge yul_function_guard -> @block.lexical_scope +} + +;; Constants need to be available inside Yul functions. This is an exception +;; since no other external identifiers are, so the path is guarded. We create a +;; scope in the source unit, contracts and libraries, and guard it from the +;; lexical scope, so we can link constant definitions here. See the dual path in +;; the rule above. +@constant_container ([SourceUnit] | [ContractDefinition] | [LibraryDefinition]) { + node @constant_container.yul_functions_guarded_scope + attr (@constant_container.yul_functions_guarded_scope) pop_symbol = "@in_yul_function" + edge @constant_container.lexical_scope -> @constant_container.yul_functions_guarded_scope +} + +;; Make top-level constants available inside Yul functions +@source_unit [SourceUnit [SourceUnitMembers [SourceUnitMember @constant [ConstantDefinition]]]] { + edge @source_unit.yul_functions_guarded_scope -> @constant.def +} + +;; Ditto for contracts, interfaces and libraries +@contract [_ members: [_ [ContractMember + @constant [StateVariableDefinition + [StateVariableAttributes [StateVariableAttribute [ConstantKeyword]]] + ] +]]] { + edge @contract.yul_functions_guarded_scope -> @constant.def } @fundef [YulFunctionDefinition @@ -2282,11 +2874,60 @@ inherit .lexical_scope node @path.lexical_scope } -@path [YulPath @name [YulIdentifier]] { +@path [YulPath . @name [YulIdentifier]] { node ref attr (ref) node_reference = @name edge ref -> @path.lexical_scope + + if (version-matches "< 0.7.0") { + ; Before Solidity 0.7.0 storage variables' `.offset` and `.slot` were + ; accessed by suffixing the name with `_offset` and `_slot` + scan (source-text @name) { + "^(.*)_(slot|offset|length)$" { + let symbol = $0 + let without_suffix = $1 + let suffix = $2 + + ; We bind the whole symbol to the built-in field for the known cases + node pop_ref + attr (pop_ref) pop_symbol = symbol + node push_suffixless + attr (push_suffixless) push_symbol = suffix + node member_of + attr (member_of) push_symbol = "." + node typeof + attr (typeof) push_symbol = "@typeof" + node yul_external + attr (yul_external) push_symbol = "%YulExternal" + + edge ref -> pop_ref + edge pop_ref -> push_suffixless + edge push_suffixless -> member_of + edge member_of -> typeof + edge typeof -> yul_external + edge yul_external -> @path.lexical_scope + } + } + } +} + +@path [YulPath [Period] @member [YulIdentifier] .] { + ; Yul variable members only apply to external variables and hence are + ; automatically bound to a special %YulExternal built-in + node ref + attr (ref) node_reference = @member + node member_of + attr (member_of) push_symbol = "." + node typeof + attr (typeof) push_symbol = "@typeof" + node yul_external + attr (yul_external) push_symbol = "%YulExternal" + + edge ref -> member_of + edge member_of -> typeof + edge typeof -> yul_external + edge yul_external -> @path.lexical_scope } @expr [YulExpression @funcall [YulFunctionCallExpression]] { diff --git a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins.rs b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins.rs index 492dbe0f36..c72ecdea44 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins.rs +++ b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins.rs @@ -2,8 +2,9 @@ use semver::Version; +// TODO: This should be moved to the Solidity-specific 'extensions' sub-module. #[allow(unused_variables)] -pub fn get_contents(version: &Version) -> &'static str { +pub fn get_built_ins_contents(version: &Version) -> &'static str { if *version < Version::new(0, 4, 17) { include_str!("./built_ins/0.4.11.sol") } else if *version < Version::new(0, 4, 22) { @@ -26,10 +27,14 @@ pub fn get_contents(version: &Version) -> &'static str { include_str!("./built_ins/0.7.0.sol") } else if *version < Version::new(0, 8, 2) { include_str!("./built_ins/0.8.0.sol") - } else if *version < Version::new(0, 8, 7) { + } else if *version < Version::new(0, 8, 4) { include_str!("./built_ins/0.8.2.sol") - } else if *version < Version::new(0, 8, 11) { + } else if *version < Version::new(0, 8, 7) { + include_str!("./built_ins/0.8.4.sol") + } else if *version < Version::new(0, 8, 8) { include_str!("./built_ins/0.8.7.sol") + } else if *version < Version::new(0, 8, 11) { + include_str!("./built_ins/0.8.8.sol") } else if *version < Version::new(0, 8, 18) { include_str!("./built_ins/0.8.11.sol") } else if *version < Version::new(0, 8, 24) { diff --git a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.4.11.sol b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.4.11.sol index 282a1cb7e5..a012478422 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.4.11.sol +++ b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.4.11.sol @@ -18,27 +18,25 @@ contract $BuiltIns$ { function sha256(bytes memory) public returns (bytes32); function sha3(bytes memory) public returns (bytes32); function suicide(address payable recipient) public; - struct $abiType { + struct $AbiType { } struct $address { uint256 balance; function(bytes memory) returns (bool) call; function(bytes memory) returns (bool, bytes memory) callcode; function(bytes memory) returns (bool) delegatecall; - function(uint256) returns (bool) send; - function(uint256) transfer; + function(uint256 amount) returns (bool) send; + function(uint256 amount) transfer; } - struct $array { + struct $Array { uint length; - function(uint) returns ($element) $index; - function($element) returns (uint) push; + function($ValueType element) returns (uint) push; function() pop; } - struct $arrayFixed { + struct $FixedArray { uint length; - function(uint) returns ($element) $index; } - struct $blockType { + struct $BlockType { address payable coinbase; uint difficulty; uint gaslimit; @@ -47,38 +45,52 @@ contract $BuiltIns$ { function(uint) returns (bytes32) blockhash; } struct $bytes { - function($args) returns (bytes memory) concat; + uint length; + } + struct $BytesType { + function(bytes[] bytesToConcatenate) returns (bytes memory) concat; + } + struct $Function { + function(uint amount) returns (function()) gas; + function(uint amount) returns (function()) value; } - struct $functionExternal { - function(uint) returns ($function) gas; - function(uint) returns ($function) value; + struct $ExternalFunction { + function(uint amount) returns (function()) gas; + function(uint amount) returns (function()) value; } - struct $msgType { + struct $MessageType { bytes data; uint256 gas; address payable sender; bytes4 sig; uint value; } - struct $string { - function($args) returns (string memory) concat; + struct $StringType { + function(string[] stringsToConcatenate) returns (string memory) concat; } - struct $txType { + struct $TransactionType { uint gasprice; address payable origin; } - struct $typeContractType { + struct $ContractTypeType { string name; } - struct $typeInterfaceType { + struct $InterfaceTypeType { string name; } - struct $typeIntType { + struct $IntTypeType { + } + struct $YulExternal { + uint slot; + uint offset; + uint length; } - $function $placeholder; - $abiType abi; - $blockType block; - $msgType msg; + $Function $placeholder; + $AbiType abi; + $BlockType block; + $BytesType $bytes; + $MessageType msg; uint now; - $txType tx; + $StringType $string; + $TransactionType tx; } diff --git a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.4.17.sol b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.4.17.sol index 453f95ccf2..3ad1ac662a 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.4.17.sol +++ b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.4.17.sol @@ -18,27 +18,25 @@ contract $BuiltIns$ { function sha256(bytes memory) public returns (bytes32); function sha3(bytes memory) public returns (bytes32); function suicide(address payable recipient) public; - struct $abiType { + struct $AbiType { } struct $address { uint256 balance; function(bytes memory) returns (bool) call; function(bytes memory) returns (bool, bytes memory) callcode; function(bytes memory) returns (bool) delegatecall; - function(uint256) returns (bool) send; - function(uint256) transfer; + function(uint256 amount) returns (bool) send; + function(uint256 amount) transfer; } - struct $array { + struct $Array { uint length; - function(uint) returns ($element) $index; - function($element) returns (uint) push; + function($ValueType element) returns (uint) push; function() pop; } - struct $arrayFixed { + struct $FixedArray { uint length; - function(uint) returns ($element) $index; } - struct $blockType { + struct $BlockType { address payable coinbase; uint difficulty; uint gaslimit; @@ -47,39 +45,53 @@ contract $BuiltIns$ { function(uint) returns (bytes32) blockhash; } struct $bytes { - function($args) returns (bytes memory) concat; + uint length; + } + struct $BytesType { + function(bytes[] bytesToConcatenate) returns (bytes memory) concat; + } + struct $Function { + function(uint amount) returns (function()) gas; + function(uint amount) returns (function()) value; } - struct $functionExternal { - $selector selector; - function(uint) returns ($function) gas; - function(uint) returns ($function) value; + struct $ExternalFunction { + bytes4 selector; + function(uint amount) returns (function()) gas; + function(uint amount) returns (function()) value; } - struct $msgType { + struct $MessageType { bytes data; uint256 gas; address payable sender; bytes4 sig; uint value; } - struct $string { - function($args) returns (string memory) concat; + struct $StringType { + function(string[] stringsToConcatenate) returns (string memory) concat; } - struct $txType { + struct $TransactionType { uint gasprice; address payable origin; } - struct $typeContractType { + struct $ContractTypeType { string name; } - struct $typeInterfaceType { + struct $InterfaceTypeType { string name; } - struct $typeIntType { + struct $IntTypeType { + } + struct $YulExternal { + uint slot; + uint offset; + uint length; } - $function $placeholder; - $abiType abi; - $blockType block; - $msgType msg; + $Function $placeholder; + $AbiType abi; + $BlockType block; + $BytesType $bytes; + $MessageType msg; uint now; - $txType tx; + $StringType $string; + $TransactionType tx; } diff --git a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.4.22.sol b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.4.22.sol index 49d650431a..e0928e5bb4 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.4.22.sol +++ b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.4.22.sol @@ -22,31 +22,29 @@ contract $BuiltIns$ { function sha256(bytes memory) public returns (bytes32); function sha3(bytes memory) public returns (bytes32); function suicide(address payable recipient) public; - struct $abiType { - function($args) returns (bytes memory) encode; - function($args) returns (bytes memory) encodePacked; - function(bytes4 selector, $args) returns (bytes memory) encodeWithSelector; - function(string memory, $args) returns (bytes memory) encodeWithSignature; + struct $AbiType { + function($Any[] valuesToEncode) returns (bytes memory) encode; + function($Any[] valuesToEncode) returns (bytes memory) encodePacked; + function(bytes4 selector, $Any[] functionArgumentsTuple) returns (bytes memory) encodeWithSelector; + function(string memory signature, $Any[] valuesToEncode) returns (bytes memory) encodeWithSignature; } struct $address { uint256 balance; function(bytes memory) returns (bool) call; function(bytes memory) returns (bool, bytes memory) callcode; function(bytes memory) returns (bool) delegatecall; - function(uint256) returns (bool) send; - function(uint256) transfer; + function(uint256 amount) returns (bool) send; + function(uint256 amount) transfer; } - struct $array { + struct $Array { uint length; - function(uint) returns ($element) $index; - function($element) returns (uint) push; + function($ValueType element) returns (uint) push; function() pop; } - struct $arrayFixed { + struct $FixedArray { uint length; - function(uint) returns ($element) $index; } - struct $blockType { + struct $BlockType { address payable coinbase; uint difficulty; uint gaslimit; @@ -55,39 +53,53 @@ contract $BuiltIns$ { function(uint) returns (bytes32) blockhash; } struct $bytes { - function($args) returns (bytes memory) concat; + uint length; + } + struct $BytesType { + function(bytes[] bytesToConcatenate) returns (bytes memory) concat; + } + struct $Function { + function(uint amount) returns (function()) gas; + function(uint amount) returns (function()) value; } - struct $functionExternal { - $selector selector; - function(uint) returns ($function) gas; - function(uint) returns ($function) value; + struct $ExternalFunction { + bytes4 selector; + function(uint amount) returns (function()) gas; + function(uint amount) returns (function()) value; } - struct $msgType { + struct $MessageType { bytes data; uint256 gas; address payable sender; bytes4 sig; uint value; } - struct $string { - function($args) returns (string memory) concat; + struct $StringType { + function(string[] stringsToConcatenate) returns (string memory) concat; } - struct $txType { + struct $TransactionType { uint gasprice; address payable origin; } - struct $typeContractType { + struct $ContractTypeType { string name; } - struct $typeInterfaceType { + struct $InterfaceTypeType { string name; } - struct $typeIntType { + struct $IntTypeType { + } + struct $YulExternal { + uint slot; + uint offset; + uint length; } - $function $placeholder; - $abiType abi; - $blockType block; - $msgType msg; + $Function $placeholder; + $AbiType abi; + $BlockType block; + $BytesType $bytes; + $MessageType msg; uint now; - $txType tx; + $StringType $string; + $TransactionType tx; } diff --git a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.5.0.sol b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.5.0.sol index c722b7c163..18996d2bb1 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.5.0.sol +++ b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.5.0.sol @@ -20,32 +20,30 @@ contract $BuiltIns$ { function ripemd160(bytes memory) public returns (bytes20); function selfdestruct(address payable recipient) public; function sha256(bytes memory) public returns (bytes32); - struct $abiType { - function(bytes memory, $args) returns ($args) decode; - function($args) returns (bytes memory) encode; - function($args) returns (bytes memory) encodePacked; - function(bytes4 selector, $args) returns (bytes memory) encodeWithSelector; - function(string memory, $args) returns (bytes memory) encodeWithSignature; + struct $AbiType { + function(bytes memory encodedData, $Type[] encodedTypesTuple) returns ($Any[]) decode; + function($Any[] valuesToEncode) returns (bytes memory) encode; + function($Any[] valuesToEncode) returns (bytes memory) encodePacked; + function(bytes4 selector, $Any[] functionArgumentsTuple) returns (bytes memory) encodeWithSelector; + function(string memory signature, $Any[] valuesToEncode) returns (bytes memory) encodeWithSignature; } struct $address { uint256 balance; function(bytes memory) returns (bool, bytes memory) call; function(bytes memory) returns (bool, bytes memory) delegatecall; - function(uint256) returns (bool) send; + function(uint256 amount) returns (bool) send; function(bytes memory) returns (bool, bytes memory) staticcall; - function(uint256) transfer; + function(uint256 amount) transfer; } - struct $array { + struct $Array { uint length; - function(uint) returns ($element) $index; - function($element) returns (uint) push; + function($ValueType element) returns (uint) push; function() pop; } - struct $arrayFixed { + struct $FixedArray { uint length; - function(uint) returns ($element) $index; } - struct $blockType { + struct $BlockType { address payable coinbase; uint difficulty; uint gaslimit; @@ -53,38 +51,52 @@ contract $BuiltIns$ { uint timestamp; } struct $bytes { - function($args) returns (bytes memory) concat; + uint length; + } + struct $BytesType { + function(bytes[] bytesToConcatenate) returns (bytes memory) concat; + } + struct $Function { + function(uint amount) returns (function()) gas; + function(uint amount) returns (function()) value; } - struct $functionExternal { - $selector selector; - function(uint) returns ($function) gas; - function(uint) returns ($function) value; + struct $ExternalFunction { + bytes4 selector; + function(uint amount) returns (function()) gas; + function(uint amount) returns (function()) value; } - struct $msgType { + struct $MessageType { bytes data; address payable sender; bytes4 sig; uint value; } - struct $string { - function($args) returns (string memory) concat; + struct $StringType { + function(string[] stringsToConcatenate) returns (string memory) concat; } - struct $txType { + struct $TransactionType { uint gasprice; address payable origin; } - struct $typeContractType { + struct $ContractTypeType { string name; } - struct $typeInterfaceType { + struct $InterfaceTypeType { string name; } - struct $typeIntType { + struct $IntTypeType { + } + struct $YulExternal { + uint slot; + uint offset; + uint length; } - $function $placeholder; - $abiType abi; - $blockType block; - $msgType msg; + $Function $placeholder; + $AbiType abi; + $BlockType block; + $BytesType $bytes; + $MessageType msg; uint now; - $txType tx; + $StringType $string; + $TransactionType tx; } diff --git a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.5.3.sol b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.5.3.sol index 49de4c27d9..5dd4bb0750 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.5.3.sol +++ b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.5.3.sol @@ -20,32 +20,30 @@ contract $BuiltIns$ { function ripemd160(bytes memory) public returns (bytes20); function selfdestruct(address payable recipient) public; function sha256(bytes memory) public returns (bytes32); - struct $abiType { - function(bytes memory, $args) returns ($args) decode; - function($args) returns (bytes memory) encode; - function($args) returns (bytes memory) encodePacked; - function(bytes4 selector, $args) returns (bytes memory) encodeWithSelector; - function(string memory, $args) returns (bytes memory) encodeWithSignature; + struct $AbiType { + function(bytes memory encodedData, $Type[] encodedTypesTuple) returns ($Any[]) decode; + function($Any[] valuesToEncode) returns (bytes memory) encode; + function($Any[] valuesToEncode) returns (bytes memory) encodePacked; + function(bytes4 selector, $Any[] functionArgumentsTuple) returns (bytes memory) encodeWithSelector; + function(string memory signature, $Any[] valuesToEncode) returns (bytes memory) encodeWithSignature; } struct $address { uint256 balance; function(bytes memory) returns (bool, bytes memory) call; function(bytes memory) returns (bool, bytes memory) delegatecall; - function(uint256) returns (bool) send; + function(uint256 amount) returns (bool) send; function(bytes memory) returns (bool, bytes memory) staticcall; - function(uint256) transfer; + function(uint256 amount) transfer; } - struct $array { + struct $Array { uint length; - function(uint) returns ($element) $index; - function($element) returns (uint) push; + function($ValueType element) returns (uint) push; function() pop; } - struct $arrayFixed { + struct $FixedArray { uint length; - function(uint) returns ($element) $index; } - struct $blockType { + struct $BlockType { address payable coinbase; uint difficulty; uint gaslimit; @@ -53,40 +51,54 @@ contract $BuiltIns$ { uint timestamp; } struct $bytes { - function($args) returns (bytes memory) concat; + uint length; + } + struct $BytesType { + function(bytes[] bytesToConcatenate) returns (bytes memory) concat; + } + struct $Function { + function(uint amount) returns (function()) gas; + function(uint amount) returns (function()) value; } - struct $functionExternal { - $selector selector; - function(uint) returns ($function) gas; - function(uint) returns ($function) value; + struct $ExternalFunction { + bytes4 selector; + function(uint amount) returns (function()) gas; + function(uint amount) returns (function()) value; } - struct $msgType { + struct $MessageType { bytes data; address payable sender; bytes4 sig; uint value; } - struct $string { - function($args) returns (string memory) concat; + struct $StringType { + function(string[] stringsToConcatenate) returns (string memory) concat; } - struct $txType { + struct $TransactionType { uint gasprice; address payable origin; } - struct $typeContractType { + struct $ContractTypeType { string name; bytes creationCode; bytes runtimeCode; } - struct $typeInterfaceType { + struct $InterfaceTypeType { string name; } - struct $typeIntType { + struct $IntTypeType { + } + struct $YulExternal { + uint slot; + uint offset; + uint length; } - $function $placeholder; - $abiType abi; - $blockType block; - $msgType msg; + $Function $placeholder; + $AbiType abi; + $BlockType block; + $BytesType $bytes; + $MessageType msg; uint now; - $txType tx; + $StringType $string; + $TransactionType tx; } diff --git a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.6.0.sol b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.6.0.sol index 706f342a98..2fcabbc92e 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.6.0.sol +++ b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.6.0.sol @@ -20,33 +20,31 @@ contract $BuiltIns$ { function ripemd160(bytes memory) public returns (bytes20); function selfdestruct(address payable recipient) public; function sha256(bytes memory) public returns (bytes32); - struct $abiType { - function(bytes memory, $args) returns ($args) decode; - function($args) returns (bytes memory) encode; - function($args) returns (bytes memory) encodePacked; - function(bytes4 selector, $args) returns (bytes memory) encodeWithSelector; - function(string memory, $args) returns (bytes memory) encodeWithSignature; + struct $AbiType { + function(bytes memory encodedData, $Type[] encodedTypesTuple) returns ($Any[]) decode; + function($Any[] valuesToEncode) returns (bytes memory) encode; + function($Any[] valuesToEncode) returns (bytes memory) encodePacked; + function(bytes4 selector, $Any[] functionArgumentsTuple) returns (bytes memory) encodeWithSelector; + function(string memory signature, $Any[] valuesToEncode) returns (bytes memory) encodeWithSignature; } struct $address { uint256 balance; function(bytes memory) returns (bool, bytes memory) call; function(bytes memory) returns (bool, bytes memory) delegatecall; - function(uint256) returns (bool) send; + function(uint256 amount) returns (bool) send; function(bytes memory) returns (bool, bytes memory) staticcall; - function(uint256) transfer; + function(uint256 amount) transfer; } - struct $array { + struct $Array { uint length; - function(uint) returns ($element) $index; - function() returns ($element) push; - function($element) push; + function() returns ($ValueType) push; + function($ValueType element) push; function() pop; } - struct $arrayFixed { + struct $FixedArray { uint length; - function(uint) returns ($element) $index; } - struct $blockType { + struct $BlockType { address payable coinbase; uint difficulty; uint gaslimit; @@ -54,40 +52,54 @@ contract $BuiltIns$ { uint timestamp; } struct $bytes { - function($args) returns (bytes memory) concat; + uint length; + } + struct $BytesType { + function(bytes[] bytesToConcatenate) returns (bytes memory) concat; + } + struct $Function { + function(uint amount) returns (function()) gas; + function(uint amount) returns (function()) value; } - struct $functionExternal { - $selector selector; - function(uint) returns ($function) gas; - function(uint) returns ($function) value; + struct $ExternalFunction { + bytes4 selector; + function(uint amount) returns (function()) gas; + function(uint amount) returns (function()) value; } - struct $msgType { + struct $MessageType { bytes data; address payable sender; bytes4 sig; uint value; } - struct $string { - function($args) returns (string memory) concat; + struct $StringType { + function(string[] stringsToConcatenate) returns (string memory) concat; } - struct $txType { + struct $TransactionType { uint gasprice; address payable origin; } - struct $typeContractType { + struct $ContractTypeType { string name; bytes creationCode; bytes runtimeCode; } - struct $typeInterfaceType { + struct $InterfaceTypeType { string name; } - struct $typeIntType { + struct $IntTypeType { + } + struct $YulExternal { + uint slot; + uint offset; + uint length; } - $function $placeholder; - $abiType abi; - $blockType block; - $msgType msg; + $Function $placeholder; + $AbiType abi; + $BlockType block; + $BytesType $bytes; + $MessageType msg; uint now; - $txType tx; + $StringType $string; + $TransactionType tx; } diff --git a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.6.2.sol b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.6.2.sol index bbedd35ca0..dc00818947 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.6.2.sol +++ b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.6.2.sol @@ -20,33 +20,31 @@ contract $BuiltIns$ { function ripemd160(bytes memory) public returns (bytes20); function selfdestruct(address payable recipient) public; function sha256(bytes memory) public returns (bytes32); - struct $abiType { - function(bytes memory, $args) returns ($args) decode; - function($args) returns (bytes memory) encode; - function($args) returns (bytes memory) encodePacked; - function(bytes4 selector, $args) returns (bytes memory) encodeWithSelector; - function(string memory, $args) returns (bytes memory) encodeWithSignature; + struct $AbiType { + function(bytes memory encodedData, $Type[] encodedTypesTuple) returns ($Any[]) decode; + function($Any[] valuesToEncode) returns (bytes memory) encode; + function($Any[] valuesToEncode) returns (bytes memory) encodePacked; + function(bytes4 selector, $Any[] functionArgumentsTuple) returns (bytes memory) encodeWithSelector; + function(string memory signature, $Any[] valuesToEncode) returns (bytes memory) encodeWithSignature; } struct $address { uint256 balance; function(bytes memory) returns (bool, bytes memory) call; function(bytes memory) returns (bool, bytes memory) delegatecall; - function(uint256) returns (bool) send; + function(uint256 amount) returns (bool) send; function(bytes memory) returns (bool, bytes memory) staticcall; - function(uint256) transfer; + function(uint256 amount) transfer; } - struct $array { + struct $Array { uint length; - function(uint) returns ($element) $index; - function() returns ($element) push; - function($element) push; + function() returns ($ValueType) push; + function($ValueType element) push; function() pop; } - struct $arrayFixed { + struct $FixedArray { uint length; - function(uint) returns ($element) $index; } - struct $blockType { + struct $BlockType { address payable coinbase; uint difficulty; uint gaslimit; @@ -54,45 +52,59 @@ contract $BuiltIns$ { uint timestamp; } struct $bytes { - function($args) returns (bytes memory) concat; + uint length; + } + struct $BytesType { + function(bytes[] bytesToConcatenate) returns (bytes memory) concat; } - struct $callOptions { + struct $CallOptions { uint gas; uint salt; uint value; } - struct $functionExternal { - $selector selector; - function(uint) returns ($function) gas; - function(uint) returns ($function) value; + struct $Function { + function(uint amount) returns (function()) gas; + function(uint amount) returns (function()) value; + } + struct $ExternalFunction { + bytes4 selector; + function(uint amount) returns (function()) gas; + function(uint amount) returns (function()) value; } - struct $msgType { + struct $MessageType { bytes data; address payable sender; bytes4 sig; uint value; } - struct $string { - function($args) returns (string memory) concat; + struct $StringType { + function(string[] stringsToConcatenate) returns (string memory) concat; } - struct $txType { + struct $TransactionType { uint gasprice; address payable origin; } - struct $typeContractType { + struct $ContractTypeType { string name; bytes creationCode; bytes runtimeCode; } - struct $typeInterfaceType { + struct $InterfaceTypeType { string name; } - struct $typeIntType { + struct $IntTypeType { + } + struct $YulExternal { + uint slot; + uint offset; + uint length; } - $function $placeholder; - $abiType abi; - $blockType block; - $msgType msg; + $Function $placeholder; + $AbiType abi; + $BlockType block; + $BytesType $bytes; + $MessageType msg; uint now; - $txType tx; + $StringType $string; + $TransactionType tx; } diff --git a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.6.7.sol b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.6.7.sol index 1bb40d1749..4a57dfa48f 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.6.7.sol +++ b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.6.7.sol @@ -20,33 +20,31 @@ contract $BuiltIns$ { function ripemd160(bytes memory) public returns (bytes20); function selfdestruct(address payable recipient) public; function sha256(bytes memory) public returns (bytes32); - struct $abiType { - function(bytes memory, $args) returns ($args) decode; - function($args) returns (bytes memory) encode; - function($args) returns (bytes memory) encodePacked; - function(bytes4 selector, $args) returns (bytes memory) encodeWithSelector; - function(string memory, $args) returns (bytes memory) encodeWithSignature; + struct $AbiType { + function(bytes memory encodedData, $Type[] encodedTypesTuple) returns ($Any[]) decode; + function($Any[] valuesToEncode) returns (bytes memory) encode; + function($Any[] valuesToEncode) returns (bytes memory) encodePacked; + function(bytes4 selector, $Any[] functionArgumentsTuple) returns (bytes memory) encodeWithSelector; + function(string memory signature, $Any[] valuesToEncode) returns (bytes memory) encodeWithSignature; } struct $address { uint256 balance; function(bytes memory) returns (bool, bytes memory) call; function(bytes memory) returns (bool, bytes memory) delegatecall; - function(uint256) returns (bool) send; + function(uint256 amount) returns (bool) send; function(bytes memory) returns (bool, bytes memory) staticcall; - function(uint256) transfer; + function(uint256 amount) transfer; } - struct $array { + struct $Array { uint length; - function(uint) returns ($element) $index; - function() returns ($element) push; - function($element) push; + function() returns ($ValueType) push; + function($ValueType element) push; function() pop; } - struct $arrayFixed { + struct $FixedArray { uint length; - function(uint) returns ($element) $index; } - struct $blockType { + struct $BlockType { address payable coinbase; uint difficulty; uint gaslimit; @@ -54,47 +52,61 @@ contract $BuiltIns$ { uint timestamp; } struct $bytes { - function($args) returns (bytes memory) concat; + uint length; + } + struct $BytesType { + function(bytes[] bytesToConcatenate) returns (bytes memory) concat; } - struct $callOptions { + struct $CallOptions { uint gas; uint salt; uint value; } - struct $functionExternal { - $selector selector; - function(uint) returns ($function) gas; - function(uint) returns ($function) value; + struct $Function { + function(uint amount) returns (function()) gas; + function(uint amount) returns (function()) value; + } + struct $ExternalFunction { + bytes4 selector; + function(uint amount) returns (function()) gas; + function(uint amount) returns (function()) value; } - struct $msgType { + struct $MessageType { bytes data; address payable sender; bytes4 sig; uint value; } - struct $string { - function($args) returns (string memory) concat; + struct $StringType { + function(string[] stringsToConcatenate) returns (string memory) concat; } - struct $txType { + struct $TransactionType { uint gasprice; address payable origin; } - struct $typeContractType { + struct $ContractTypeType { string name; bytes creationCode; bytes runtimeCode; bytes4 interfaceId; } - struct $typeInterfaceType { + struct $InterfaceTypeType { string name; bytes4 interfaceId; } - struct $typeIntType { + struct $IntTypeType { + } + struct $YulExternal { + uint slot; + uint offset; + uint length; } - $function $placeholder; - $abiType abi; - $blockType block; - $msgType msg; + $Function $placeholder; + $AbiType abi; + $BlockType block; + $BytesType $bytes; + $MessageType msg; uint now; - $txType tx; + $StringType $string; + $TransactionType tx; } diff --git a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.6.8.sol b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.6.8.sol index 51bc2829fd..a20e478f50 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.6.8.sol +++ b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.6.8.sol @@ -20,33 +20,31 @@ contract $BuiltIns$ { function ripemd160(bytes memory) public returns (bytes20); function selfdestruct(address payable recipient) public; function sha256(bytes memory) public returns (bytes32); - struct $abiType { - function(bytes memory, $args) returns ($args) decode; - function($args) returns (bytes memory) encode; - function($args) returns (bytes memory) encodePacked; - function(bytes4 selector, $args) returns (bytes memory) encodeWithSelector; - function(string memory, $args) returns (bytes memory) encodeWithSignature; + struct $AbiType { + function(bytes memory encodedData, $Type[] encodedTypesTuple) returns ($Any[]) decode; + function($Any[] valuesToEncode) returns (bytes memory) encode; + function($Any[] valuesToEncode) returns (bytes memory) encodePacked; + function(bytes4 selector, $Any[] functionArgumentsTuple) returns (bytes memory) encodeWithSelector; + function(string memory signature, $Any[] valuesToEncode) returns (bytes memory) encodeWithSignature; } struct $address { uint256 balance; function(bytes memory) returns (bool, bytes memory) call; function(bytes memory) returns (bool, bytes memory) delegatecall; - function(uint256) returns (bool) send; + function(uint256 amount) returns (bool) send; function(bytes memory) returns (bool, bytes memory) staticcall; - function(uint256) transfer; + function(uint256 amount) transfer; } - struct $array { + struct $Array { uint length; - function(uint) returns ($element) $index; - function() returns ($element) push; - function($element) push; + function() returns ($ValueType) push; + function($ValueType element) push; function() pop; } - struct $arrayFixed { + struct $FixedArray { uint length; - function(uint) returns ($element) $index; } - struct $blockType { + struct $BlockType { address payable coinbase; uint difficulty; uint gaslimit; @@ -54,49 +52,63 @@ contract $BuiltIns$ { uint timestamp; } struct $bytes { - function($args) returns (bytes memory) concat; + uint length; + } + struct $BytesType { + function(bytes[] bytesToConcatenate) returns (bytes memory) concat; } - struct $callOptions { + struct $CallOptions { uint gas; uint salt; uint value; } - struct $functionExternal { - $selector selector; - function(uint) returns ($function) gas; - function(uint) returns ($function) value; + struct $Function { + function(uint amount) returns (function()) gas; + function(uint amount) returns (function()) value; + } + struct $ExternalFunction { + bytes4 selector; + function(uint amount) returns (function()) gas; + function(uint amount) returns (function()) value; } - struct $msgType { + struct $MessageType { bytes data; address payable sender; bytes4 sig; uint value; } - struct $string { - function($args) returns (string memory) concat; + struct $StringType { + function(string[] stringsToConcatenate) returns (string memory) concat; } - struct $txType { + struct $TransactionType { uint gasprice; address payable origin; } - struct $typeContractType { + struct $ContractTypeType { string name; bytes creationCode; bytes runtimeCode; bytes4 interfaceId; } - struct $typeInterfaceType { + struct $InterfaceTypeType { string name; bytes4 interfaceId; } - struct $typeIntType { + struct $IntTypeType { int min; int max; } - $function $placeholder; - $abiType abi; - $blockType block; - $msgType msg; + struct $YulExternal { + uint slot; + uint offset; + uint length; + } + $Function $placeholder; + $AbiType abi; + $BlockType block; + $BytesType $bytes; + $MessageType msg; uint now; - $txType tx; + $StringType $string; + $TransactionType tx; } diff --git a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.7.0.sol b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.7.0.sol index ce5c90338a..6c4e69b5d9 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.7.0.sol +++ b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.7.0.sol @@ -20,33 +20,31 @@ contract $BuiltIns$ { function ripemd160(bytes memory) public returns (bytes20); function selfdestruct(address payable recipient) public; function sha256(bytes memory) public returns (bytes32); - struct $abiType { - function(bytes memory, $args) returns ($args) decode; - function($args) returns (bytes memory) encode; - function($args) returns (bytes memory) encodePacked; - function(bytes4 selector, $args) returns (bytes memory) encodeWithSelector; - function(string memory, $args) returns (bytes memory) encodeWithSignature; + struct $AbiType { + function(bytes memory encodedData, $Type[] encodedTypesTuple) returns ($Any[]) decode; + function($Any[] valuesToEncode) returns (bytes memory) encode; + function($Any[] valuesToEncode) returns (bytes memory) encodePacked; + function(bytes4 selector, $Any[] functionArgumentsTuple) returns (bytes memory) encodeWithSelector; + function(string memory signature, $Any[] valuesToEncode) returns (bytes memory) encodeWithSignature; } struct $address { uint256 balance; function(bytes memory) returns (bool, bytes memory) call; function(bytes memory) returns (bool, bytes memory) delegatecall; - function(uint256) returns (bool) send; + function(uint256 amount) returns (bool) send; function(bytes memory) returns (bool, bytes memory) staticcall; - function(uint256) transfer; + function(uint256 amount) transfer; } - struct $array { + struct $Array { uint length; - function(uint) returns ($element) $index; - function() returns ($element) push; - function($element) push; + function() returns ($ValueType) push; + function($ValueType element) push; function() pop; } - struct $arrayFixed { + struct $FixedArray { uint length; - function(uint) returns ($element) $index; } - struct $blockType { + struct $BlockType { address payable coinbase; uint difficulty; uint gaslimit; @@ -54,46 +52,58 @@ contract $BuiltIns$ { uint timestamp; } struct $bytes { - function($args) returns (bytes memory) concat; + uint length; + } + struct $BytesType { + function(bytes[] bytesToConcatenate) returns (bytes memory) concat; } - struct $callOptions { + struct $CallOptions { uint gas; uint salt; uint value; } - struct $functionExternal { - $selector selector; + struct $Function { + } + struct $ExternalFunction { + bytes4 selector; } - struct $msgType { + struct $MessageType { bytes data; address payable sender; bytes4 sig; uint value; } - struct $string { - function($args) returns (string memory) concat; + struct $StringType { + function(string[] stringsToConcatenate) returns (string memory) concat; } - struct $txType { + struct $TransactionType { uint gasprice; address payable origin; } - struct $typeContractType { + struct $ContractTypeType { string name; bytes creationCode; bytes runtimeCode; bytes4 interfaceId; } - struct $typeInterfaceType { + struct $InterfaceTypeType { string name; bytes4 interfaceId; } - struct $typeIntType { + struct $IntTypeType { int min; int max; } - $function $placeholder; - $abiType abi; - $blockType block; - $msgType msg; - $txType tx; + struct $YulExternal { + uint slot; + uint offset; + uint length; + } + $Function $placeholder; + $AbiType abi; + $BlockType block; + $BytesType $bytes; + $MessageType msg; + $StringType $string; + $TransactionType tx; } diff --git a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.8.0.sol b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.8.0.sol index 67a4546951..4626514db5 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.8.0.sol +++ b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.8.0.sol @@ -15,12 +15,12 @@ contract $BuiltIns$ { function ripemd160(bytes memory) public returns (bytes20); function selfdestruct(address payable recipient) public; function sha256(bytes memory) public returns (bytes32); - struct $abiType { - function(bytes memory, $args) returns ($args) decode; - function($args) returns (bytes memory) encode; - function($args) returns (bytes memory) encodePacked; - function(bytes4 selector, $args) returns (bytes memory) encodeWithSelector; - function(string memory, $args) returns (bytes memory) encodeWithSignature; + struct $AbiType { + function(bytes memory encodedData, $Type[] encodedTypesTuple) returns ($Any[]) decode; + function($Any[] valuesToEncode) returns (bytes memory) encode; + function($Any[] valuesToEncode) returns (bytes memory) encodePacked; + function(bytes4 selector, $Any[] functionArgumentsTuple) returns (bytes memory) encodeWithSelector; + function(string memory signature, $Any[] valuesToEncode) returns (bytes memory) encodeWithSignature; } struct $address { uint256 balance; @@ -28,22 +28,20 @@ contract $BuiltIns$ { bytes32 codehash; function(bytes memory) returns (bool, bytes memory) call; function(bytes memory) returns (bool, bytes memory) delegatecall; - function(uint256) returns (bool) send; + function(uint256 amount) returns (bool) send; function(bytes memory) returns (bool, bytes memory) staticcall; - function(uint256) transfer; + function(uint256 amount) transfer; } - struct $array { + struct $Array { uint length; - function(uint) returns ($element) $index; - function() returns ($element) push; - function($element) push; + function() returns ($ValueType) push; + function($ValueType element) push; function() pop; } - struct $arrayFixed { + struct $FixedArray { uint length; - function(uint) returns ($element) $index; } - struct $blockType { + struct $BlockType { uint chainid; address payable coinbase; uint difficulty; @@ -52,46 +50,58 @@ contract $BuiltIns$ { uint timestamp; } struct $bytes { - function($args) returns (bytes memory) concat; + uint length; + } + struct $BytesType { + function(bytes[] bytesToConcatenate) returns (bytes memory) concat; } - struct $callOptions { + struct $CallOptions { uint gas; uint salt; uint value; } - struct $functionExternal { - $selector selector; + struct $Function { + } + struct $ExternalFunction { + bytes4 selector; } - struct $msgType { + struct $MessageType { bytes data; address sender; bytes4 sig; uint value; } - struct $string { - function($args) returns (string memory) concat; + struct $StringType { + function(string[] stringsToConcatenate) returns (string memory) concat; } - struct $txType { + struct $TransactionType { uint gasprice; address origin; } - struct $typeContractType { + struct $ContractTypeType { string name; bytes creationCode; bytes runtimeCode; bytes4 interfaceId; } - struct $typeInterfaceType { + struct $InterfaceTypeType { string name; bytes4 interfaceId; } - struct $typeIntType { + struct $IntTypeType { int min; int max; } - $function $placeholder; - $abiType abi; - $blockType block; - $msgType msg; - $txType tx; + struct $YulExternal { + uint slot; + uint offset; + uint length; + } + $Function $placeholder; + $AbiType abi; + $BlockType block; + $BytesType $bytes; + $MessageType msg; + $StringType $string; + $TransactionType tx; } diff --git a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.8.11.sol b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.8.11.sol index a5a050182f..4fd057bb07 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.8.11.sol +++ b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.8.11.sol @@ -15,13 +15,13 @@ contract $BuiltIns$ { function ripemd160(bytes memory) public returns (bytes20); function selfdestruct(address payable recipient) public; function sha256(bytes memory) public returns (bytes32); - struct $abiType { - function(bytes memory, $args) returns ($args) decode; - function($args) returns (bytes memory) encode; - function(function(), $args) returns (bytes memory) encodeCall; - function($args) returns (bytes memory) encodePacked; - function(bytes4 selector, $args) returns (bytes memory) encodeWithSelector; - function(string memory, $args) returns (bytes memory) encodeWithSignature; + struct $AbiType { + function(bytes memory encodedData, $Type[] encodedTypesTuple) returns ($Any[]) decode; + function($Any[] valuesToEncode) returns (bytes memory) encode; + function(function() functionPointer, $Any[] functionArgumentsTuple) returns (bytes memory) encodeCall; + function($Any[] valuesToEncode) returns (bytes memory) encodePacked; + function(bytes4 selector, $Any[] functionArgumentsTuple) returns (bytes memory) encodeWithSelector; + function(string memory signature, $Any[] valuesToEncode) returns (bytes memory) encodeWithSignature; } struct $address { uint256 balance; @@ -29,22 +29,20 @@ contract $BuiltIns$ { bytes32 codehash; function(bytes memory) returns (bool, bytes memory) call; function(bytes memory) returns (bool, bytes memory) delegatecall; - function(uint256) returns (bool) send; + function(uint256 amount) returns (bool) send; function(bytes memory) returns (bool, bytes memory) staticcall; - function(uint256) transfer; + function(uint256 amount) transfer; } - struct $array { + struct $Array { uint length; - function(uint) returns ($element) $index; - function() returns ($element) push; - function($element) push; + function() returns ($ValueType) push; + function($ValueType element) push; function() pop; } - struct $arrayFixed { + struct $FixedArray { uint length; - function(uint) returns ($element) $index; } - struct $blockType { + struct $BlockType { uint basefee; uint chainid; address payable coinbase; @@ -54,47 +52,66 @@ contract $BuiltIns$ { uint timestamp; } struct $bytes { - function($args) returns (bytes memory) concat; + uint length; + } + struct $BytesType { + function(bytes[] bytesToConcatenate) returns (bytes memory) concat; } - struct $callOptions { + struct $CallOptions { uint gas; uint salt; uint value; } - struct $functionExternal { - $address address; - $selector selector; + struct $ErrorType { + bytes4 selector; + } + struct $Function { + } + struct $ExternalFunction { + address address; + bytes4 selector; } - struct $msgType { + struct $MessageType { bytes data; address sender; bytes4 sig; uint value; } - struct $string { - function($args) returns (string memory) concat; + struct $StringType { + function(string[] stringsToConcatenate) returns (string memory) concat; } - struct $txType { + struct $TransactionType { uint gasprice; address origin; } - struct $typeContractType { + struct $ContractTypeType { string name; bytes creationCode; bytes runtimeCode; bytes4 interfaceId; } - struct $typeInterfaceType { + struct $InterfaceTypeType { string name; bytes4 interfaceId; } - struct $typeIntType { + struct $IntTypeType { int min; int max; } - $function $placeholder; - $abiType abi; - $blockType block; - $msgType msg; - $txType tx; + struct $UserDefinedValueType { + function($WrappedType elementaryType) returns ($UserType) wrap; + function($UserType userType) returns ($WrappedType) unwrap; + } + struct $YulExternal { + uint slot; + uint offset; + uint length; + } + $Function $placeholder; + $AbiType abi; + $BlockType block; + $BytesType $bytes; + $MessageType msg; + $StringType $string; + $TransactionType tx; } diff --git a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.8.18.sol b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.8.18.sol index 8fd9b32c01..edf82c7c7d 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.8.18.sol +++ b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.8.18.sol @@ -15,13 +15,13 @@ contract $BuiltIns$ { function ripemd160(bytes memory) public returns (bytes20); function selfdestruct(address payable recipient) public; function sha256(bytes memory) public returns (bytes32); - struct $abiType { - function(bytes memory, $args) returns ($args) decode; - function($args) returns (bytes memory) encode; - function(function(), $args) returns (bytes memory) encodeCall; - function($args) returns (bytes memory) encodePacked; - function(bytes4 selector, $args) returns (bytes memory) encodeWithSelector; - function(string memory, $args) returns (bytes memory) encodeWithSignature; + struct $AbiType { + function(bytes memory encodedData, $Type[] encodedTypesTuple) returns ($Any[]) decode; + function($Any[] valuesToEncode) returns (bytes memory) encode; + function(function() functionPointer, $Any[] functionArgumentsTuple) returns (bytes memory) encodeCall; + function($Any[] valuesToEncode) returns (bytes memory) encodePacked; + function(bytes4 selector, $Any[] functionArgumentsTuple) returns (bytes memory) encodeWithSelector; + function(string memory signature, $Any[] valuesToEncode) returns (bytes memory) encodeWithSignature; } struct $address { uint256 balance; @@ -29,22 +29,20 @@ contract $BuiltIns$ { bytes32 codehash; function(bytes memory) returns (bool, bytes memory) call; function(bytes memory) returns (bool, bytes memory) delegatecall; - function(uint256) returns (bool) send; + function(uint256 amount) returns (bool) send; function(bytes memory) returns (bool, bytes memory) staticcall; - function(uint256) transfer; + function(uint256 amount) transfer; } - struct $array { + struct $Array { uint length; - function(uint) returns ($element) $index; - function() returns ($element) push; - function($element) push; + function() returns ($ValueType) push; + function($ValueType element) push; function() pop; } - struct $arrayFixed { + struct $FixedArray { uint length; - function(uint) returns ($element) $index; } - struct $blockType { + struct $BlockType { uint basefee; uint chainid; address payable coinbase; @@ -55,47 +53,66 @@ contract $BuiltIns$ { uint timestamp; } struct $bytes { - function($args) returns (bytes memory) concat; + uint length; + } + struct $BytesType { + function(bytes[] bytesToConcatenate) returns (bytes memory) concat; } - struct $callOptions { + struct $CallOptions { uint gas; uint salt; uint value; } - struct $functionExternal { - $address address; - $selector selector; + struct $ErrorType { + bytes4 selector; + } + struct $Function { + } + struct $ExternalFunction { + address address; + bytes4 selector; } - struct $msgType { + struct $MessageType { bytes data; address sender; bytes4 sig; uint value; } - struct $string { - function($args) returns (string memory) concat; + struct $StringType { + function(string[] stringsToConcatenate) returns (string memory) concat; } - struct $txType { + struct $TransactionType { uint gasprice; address origin; } - struct $typeContractType { + struct $ContractTypeType { string name; bytes creationCode; bytes runtimeCode; bytes4 interfaceId; } - struct $typeInterfaceType { + struct $InterfaceTypeType { string name; bytes4 interfaceId; } - struct $typeIntType { + struct $IntTypeType { int min; int max; } - $function $placeholder; - $abiType abi; - $blockType block; - $msgType msg; - $txType tx; + struct $UserDefinedValueType { + function($WrappedType elementaryType) returns ($UserType) wrap; + function($UserType userType) returns ($WrappedType) unwrap; + } + struct $YulExternal { + uint slot; + uint offset; + uint length; + } + $Function $placeholder; + $AbiType abi; + $BlockType block; + $BytesType $bytes; + $MessageType msg; + $StringType $string; + $TransactionType tx; } diff --git a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.8.2.sol b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.8.2.sol index c3be365f51..be45a8cbf4 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.8.2.sol +++ b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.8.2.sol @@ -15,12 +15,12 @@ contract $BuiltIns$ { function ripemd160(bytes memory) public returns (bytes20); function selfdestruct(address payable recipient) public; function sha256(bytes memory) public returns (bytes32); - struct $abiType { - function(bytes memory, $args) returns ($args) decode; - function($args) returns (bytes memory) encode; - function($args) returns (bytes memory) encodePacked; - function(bytes4 selector, $args) returns (bytes memory) encodeWithSelector; - function(string memory, $args) returns (bytes memory) encodeWithSignature; + struct $AbiType { + function(bytes memory encodedData, $Type[] encodedTypesTuple) returns ($Any[]) decode; + function($Any[] valuesToEncode) returns (bytes memory) encode; + function($Any[] valuesToEncode) returns (bytes memory) encodePacked; + function(bytes4 selector, $Any[] functionArgumentsTuple) returns (bytes memory) encodeWithSelector; + function(string memory signature, $Any[] valuesToEncode) returns (bytes memory) encodeWithSignature; } struct $address { uint256 balance; @@ -28,22 +28,20 @@ contract $BuiltIns$ { bytes32 codehash; function(bytes memory) returns (bool, bytes memory) call; function(bytes memory) returns (bool, bytes memory) delegatecall; - function(uint256) returns (bool) send; + function(uint256 amount) returns (bool) send; function(bytes memory) returns (bool, bytes memory) staticcall; - function(uint256) transfer; + function(uint256 amount) transfer; } - struct $array { + struct $Array { uint length; - function(uint) returns ($element) $index; - function() returns ($element) push; - function($element) push; + function() returns ($ValueType) push; + function($ValueType element) push; function() pop; } - struct $arrayFixed { + struct $FixedArray { uint length; - function(uint) returns ($element) $index; } - struct $blockType { + struct $BlockType { uint chainid; address payable coinbase; uint difficulty; @@ -52,47 +50,59 @@ contract $BuiltIns$ { uint timestamp; } struct $bytes { - function($args) returns (bytes memory) concat; + uint length; + } + struct $BytesType { + function(bytes[] bytesToConcatenate) returns (bytes memory) concat; } - struct $callOptions { + struct $CallOptions { uint gas; uint salt; uint value; } - struct $functionExternal { - $address address; - $selector selector; + struct $Function { + } + struct $ExternalFunction { + address address; + bytes4 selector; } - struct $msgType { + struct $MessageType { bytes data; address sender; bytes4 sig; uint value; } - struct $string { - function($args) returns (string memory) concat; + struct $StringType { + function(string[] stringsToConcatenate) returns (string memory) concat; } - struct $txType { + struct $TransactionType { uint gasprice; address origin; } - struct $typeContractType { + struct $ContractTypeType { string name; bytes creationCode; bytes runtimeCode; bytes4 interfaceId; } - struct $typeInterfaceType { + struct $InterfaceTypeType { string name; bytes4 interfaceId; } - struct $typeIntType { + struct $IntTypeType { int min; int max; } - $function $placeholder; - $abiType abi; - $blockType block; - $msgType msg; - $txType tx; + struct $YulExternal { + uint slot; + uint offset; + uint length; + } + $Function $placeholder; + $AbiType abi; + $BlockType block; + $BytesType $bytes; + $MessageType msg; + $StringType $string; + $TransactionType tx; } diff --git a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.8.24.sol b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.8.24.sol index d461e13b67..5b537bd6f5 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.8.24.sol +++ b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.8.24.sol @@ -16,13 +16,13 @@ contract $BuiltIns$ { function ripemd160(bytes memory) public returns (bytes20); function selfdestruct(address payable recipient) public; function sha256(bytes memory) public returns (bytes32); - struct $abiType { - function(bytes memory, $args) returns ($args) decode; - function($args) returns (bytes memory) encode; - function(function(), $args) returns (bytes memory) encodeCall; - function($args) returns (bytes memory) encodePacked; - function(bytes4 selector, $args) returns (bytes memory) encodeWithSelector; - function(string memory, $args) returns (bytes memory) encodeWithSignature; + struct $AbiType { + function(bytes memory encodedData, $Type[] encodedTypesTuple) returns ($Any[]) decode; + function($Any[] valuesToEncode) returns (bytes memory) encode; + function(function() functionPointer, $Any[] functionArgumentsTuple) returns (bytes memory) encodeCall; + function($Any[] valuesToEncode) returns (bytes memory) encodePacked; + function(bytes4 selector, $Any[] functionArgumentsTuple) returns (bytes memory) encodeWithSelector; + function(string memory signature, $Any[] valuesToEncode) returns (bytes memory) encodeWithSignature; } struct $address { uint256 balance; @@ -30,22 +30,20 @@ contract $BuiltIns$ { bytes32 codehash; function(bytes memory) returns (bool, bytes memory) call; function(bytes memory) returns (bool, bytes memory) delegatecall; - function(uint256) returns (bool) send; + function(uint256 amount) returns (bool) send; function(bytes memory) returns (bool, bytes memory) staticcall; - function(uint256) transfer; + function(uint256 amount) transfer; } - struct $array { + struct $Array { uint length; - function(uint) returns ($element) $index; - function() returns ($element) push; - function($element) push; + function() returns ($ValueType) push; + function($ValueType element) push; function() pop; } - struct $arrayFixed { + struct $FixedArray { uint length; - function(uint) returns ($element) $index; } - struct $blockType { + struct $BlockType { uint basefee; uint blobbasefee; uint chainid; @@ -57,47 +55,66 @@ contract $BuiltIns$ { uint timestamp; } struct $bytes { - function($args) returns (bytes memory) concat; + uint length; + } + struct $BytesType { + function(bytes[] bytesToConcatenate) returns (bytes memory) concat; } - struct $callOptions { + struct $CallOptions { uint gas; uint salt; uint value; } - struct $functionExternal { - $address address; - $selector selector; + struct $ErrorType { + bytes4 selector; + } + struct $Function { + } + struct $ExternalFunction { + address address; + bytes4 selector; } - struct $msgType { + struct $MessageType { bytes data; address sender; bytes4 sig; uint value; } - struct $string { - function($args) returns (string memory) concat; + struct $StringType { + function(string[] stringsToConcatenate) returns (string memory) concat; } - struct $txType { + struct $TransactionType { uint gasprice; address origin; } - struct $typeContractType { + struct $ContractTypeType { string name; bytes creationCode; bytes runtimeCode; bytes4 interfaceId; } - struct $typeInterfaceType { + struct $InterfaceTypeType { string name; bytes4 interfaceId; } - struct $typeIntType { + struct $IntTypeType { int min; int max; } - $function $placeholder; - $abiType abi; - $blockType block; - $msgType msg; - $txType tx; + struct $UserDefinedValueType { + function($WrappedType elementaryType) returns ($UserType) wrap; + function($UserType userType) returns ($WrappedType) unwrap; + } + struct $YulExternal { + uint slot; + uint offset; + uint length; + } + $Function $placeholder; + $AbiType abi; + $BlockType block; + $BytesType $bytes; + $MessageType msg; + $StringType $string; + $TransactionType tx; } diff --git a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.8.26.sol b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.8.26.sol index 51b4ea13a5..b27eff44b4 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.8.26.sol +++ b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.8.26.sol @@ -17,13 +17,13 @@ contract $BuiltIns$ { function ripemd160(bytes memory) public returns (bytes20); function selfdestruct(address payable recipient) public; function sha256(bytes memory) public returns (bytes32); - struct $abiType { - function(bytes memory, $args) returns ($args) decode; - function($args) returns (bytes memory) encode; - function(function(), $args) returns (bytes memory) encodeCall; - function($args) returns (bytes memory) encodePacked; - function(bytes4 selector, $args) returns (bytes memory) encodeWithSelector; - function(string memory, $args) returns (bytes memory) encodeWithSignature; + struct $AbiType { + function(bytes memory encodedData, $Type[] encodedTypesTuple) returns ($Any[]) decode; + function($Any[] valuesToEncode) returns (bytes memory) encode; + function(function() functionPointer, $Any[] functionArgumentsTuple) returns (bytes memory) encodeCall; + function($Any[] valuesToEncode) returns (bytes memory) encodePacked; + function(bytes4 selector, $Any[] functionArgumentsTuple) returns (bytes memory) encodeWithSelector; + function(string memory signature, $Any[] valuesToEncode) returns (bytes memory) encodeWithSignature; } struct $address { uint256 balance; @@ -31,22 +31,20 @@ contract $BuiltIns$ { bytes32 codehash; function(bytes memory) returns (bool, bytes memory) call; function(bytes memory) returns (bool, bytes memory) delegatecall; - function(uint256) returns (bool) send; + function(uint256 amount) returns (bool) send; function(bytes memory) returns (bool, bytes memory) staticcall; - function(uint256) transfer; + function(uint256 amount) transfer; } - struct $array { + struct $Array { uint length; - function(uint) returns ($element) $index; - function() returns ($element) push; - function($element) push; + function() returns ($ValueType) push; + function($ValueType element) push; function() pop; } - struct $arrayFixed { + struct $FixedArray { uint length; - function(uint) returns ($element) $index; } - struct $blockType { + struct $BlockType { uint basefee; uint blobbasefee; uint chainid; @@ -58,47 +56,66 @@ contract $BuiltIns$ { uint timestamp; } struct $bytes { - function($args) returns (bytes memory) concat; + uint length; + } + struct $BytesType { + function(bytes[] bytesToConcatenate) returns (bytes memory) concat; } - struct $callOptions { + struct $CallOptions { uint gas; uint salt; uint value; } - struct $functionExternal { - $address address; - $selector selector; + struct $ErrorType { + bytes4 selector; + } + struct $Function { + } + struct $ExternalFunction { + address address; + bytes4 selector; } - struct $msgType { + struct $MessageType { bytes data; address sender; bytes4 sig; uint value; } - struct $string { - function($args) returns (string memory) concat; + struct $StringType { + function(string[] stringsToConcatenate) returns (string memory) concat; } - struct $txType { + struct $TransactionType { uint gasprice; address origin; } - struct $typeContractType { + struct $ContractTypeType { string name; bytes creationCode; bytes runtimeCode; bytes4 interfaceId; } - struct $typeInterfaceType { + struct $InterfaceTypeType { string name; bytes4 interfaceId; } - struct $typeIntType { + struct $IntTypeType { int min; int max; } - $function $placeholder; - $abiType abi; - $blockType block; - $msgType msg; - $txType tx; + struct $UserDefinedValueType { + function($WrappedType elementaryType) returns ($UserType) wrap; + function($UserType userType) returns ($WrappedType) unwrap; + } + struct $YulExternal { + uint slot; + uint offset; + uint length; + } + $Function $placeholder; + $AbiType abi; + $BlockType block; + $BytesType $bytes; + $MessageType msg; + $StringType $string; + $TransactionType tx; } diff --git a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.8.4.sol b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.8.4.sol new file mode 100644 index 0000000000..4ac08e94dd --- /dev/null +++ b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.8.4.sol @@ -0,0 +1,111 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +contract $BuiltIns$ { + function addmod(uint x, uint y, uint k) public returns (uint); + function assert(bool condition) public; + function blockhash(uint blockNumber) public returns (bytes32); + function ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) public returns (address); + function gasleft() public returns (uint256); + function keccak256(bytes memory) public returns (bytes32); + function mulmod(uint x, uint y, uint k) public returns (uint); + function require(bool condition) public; + function require(bool condition, string memory message) public; + function revert() public; + function revert(string memory reason) public; + function ripemd160(bytes memory) public returns (bytes20); + function selfdestruct(address payable recipient) public; + function sha256(bytes memory) public returns (bytes32); + struct $AbiType { + function(bytes memory encodedData, $Type[] encodedTypesTuple) returns ($Any[]) decode; + function($Any[] valuesToEncode) returns (bytes memory) encode; + function($Any[] valuesToEncode) returns (bytes memory) encodePacked; + function(bytes4 selector, $Any[] functionArgumentsTuple) returns (bytes memory) encodeWithSelector; + function(string memory signature, $Any[] valuesToEncode) returns (bytes memory) encodeWithSignature; + } + struct $address { + uint256 balance; + bytes code; + bytes32 codehash; + function(bytes memory) returns (bool, bytes memory) call; + function(bytes memory) returns (bool, bytes memory) delegatecall; + function(uint256 amount) returns (bool) send; + function(bytes memory) returns (bool, bytes memory) staticcall; + function(uint256 amount) transfer; + } + struct $Array { + uint length; + function() returns ($ValueType) push; + function($ValueType element) push; + function() pop; + } + struct $FixedArray { + uint length; + } + struct $BlockType { + uint chainid; + address payable coinbase; + uint difficulty; + uint gaslimit; + uint number; + uint timestamp; + } + struct $bytes { + uint length; + } + struct $BytesType { + function(bytes[] bytesToConcatenate) returns (bytes memory) concat; + } + struct $CallOptions { + uint gas; + uint salt; + uint value; + } + struct $ErrorType { + bytes4 selector; + } + struct $Function { + } + struct $ExternalFunction { + address address; + bytes4 selector; + } + struct $MessageType { + bytes data; + address sender; + bytes4 sig; + uint value; + } + struct $StringType { + function(string[] stringsToConcatenate) returns (string memory) concat; + } + struct $TransactionType { + uint gasprice; + address origin; + } + struct $ContractTypeType { + string name; + bytes creationCode; + bytes runtimeCode; + bytes4 interfaceId; + } + struct $InterfaceTypeType { + string name; + bytes4 interfaceId; + } + struct $IntTypeType { + int min; + int max; + } + struct $YulExternal { + uint slot; + uint offset; + uint length; + } + $Function $placeholder; + $AbiType abi; + $BlockType block; + $BytesType $bytes; + $MessageType msg; + $StringType $string; + $TransactionType tx; +} diff --git a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.8.7.sol b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.8.7.sol index 0ca8106588..503367efb7 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.8.7.sol +++ b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.8.7.sol @@ -15,12 +15,12 @@ contract $BuiltIns$ { function ripemd160(bytes memory) public returns (bytes20); function selfdestruct(address payable recipient) public; function sha256(bytes memory) public returns (bytes32); - struct $abiType { - function(bytes memory, $args) returns ($args) decode; - function($args) returns (bytes memory) encode; - function($args) returns (bytes memory) encodePacked; - function(bytes4 selector, $args) returns (bytes memory) encodeWithSelector; - function(string memory, $args) returns (bytes memory) encodeWithSignature; + struct $AbiType { + function(bytes memory encodedData, $Type[] encodedTypesTuple) returns ($Any[]) decode; + function($Any[] valuesToEncode) returns (bytes memory) encode; + function($Any[] valuesToEncode) returns (bytes memory) encodePacked; + function(bytes4 selector, $Any[] functionArgumentsTuple) returns (bytes memory) encodeWithSelector; + function(string memory signature, $Any[] valuesToEncode) returns (bytes memory) encodeWithSignature; } struct $address { uint256 balance; @@ -28,22 +28,20 @@ contract $BuiltIns$ { bytes32 codehash; function(bytes memory) returns (bool, bytes memory) call; function(bytes memory) returns (bool, bytes memory) delegatecall; - function(uint256) returns (bool) send; + function(uint256 amount) returns (bool) send; function(bytes memory) returns (bool, bytes memory) staticcall; - function(uint256) transfer; + function(uint256 amount) transfer; } - struct $array { + struct $Array { uint length; - function(uint) returns ($element) $index; - function() returns ($element) push; - function($element) push; + function() returns ($ValueType) push; + function($ValueType element) push; function() pop; } - struct $arrayFixed { + struct $FixedArray { uint length; - function(uint) returns ($element) $index; } - struct $blockType { + struct $BlockType { uint basefee; uint chainid; address payable coinbase; @@ -53,47 +51,62 @@ contract $BuiltIns$ { uint timestamp; } struct $bytes { - function($args) returns (bytes memory) concat; + uint length; + } + struct $BytesType { + function(bytes[] bytesToConcatenate) returns (bytes memory) concat; } - struct $callOptions { + struct $CallOptions { uint gas; uint salt; uint value; } - struct $functionExternal { - $address address; - $selector selector; + struct $ErrorType { + bytes4 selector; + } + struct $Function { } - struct $msgType { + struct $ExternalFunction { + address address; + bytes4 selector; + } + struct $MessageType { bytes data; address sender; bytes4 sig; uint value; } - struct $string { - function($args) returns (string memory) concat; + struct $StringType { + function(string[] stringsToConcatenate) returns (string memory) concat; } - struct $txType { + struct $TransactionType { uint gasprice; address origin; } - struct $typeContractType { + struct $ContractTypeType { string name; bytes creationCode; bytes runtimeCode; bytes4 interfaceId; } - struct $typeInterfaceType { + struct $InterfaceTypeType { string name; bytes4 interfaceId; } - struct $typeIntType { + struct $IntTypeType { int min; int max; } - $function $placeholder; - $abiType abi; - $blockType block; - $msgType msg; - $txType tx; + struct $YulExternal { + uint slot; + uint offset; + uint length; + } + $Function $placeholder; + $AbiType abi; + $BlockType block; + $BytesType $bytes; + $MessageType msg; + $StringType $string; + $TransactionType tx; } diff --git a/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.8.8.sol b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.8.8.sol new file mode 100644 index 0000000000..ec34656dbc --- /dev/null +++ b/crates/solidity/outputs/cargo/crate/src/generated/bindings/generated/built_ins/0.8.8.sol @@ -0,0 +1,116 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +contract $BuiltIns$ { + function addmod(uint x, uint y, uint k) public returns (uint); + function assert(bool condition) public; + function blockhash(uint blockNumber) public returns (bytes32); + function ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) public returns (address); + function gasleft() public returns (uint256); + function keccak256(bytes memory) public returns (bytes32); + function mulmod(uint x, uint y, uint k) public returns (uint); + function require(bool condition) public; + function require(bool condition, string memory message) public; + function revert() public; + function revert(string memory reason) public; + function ripemd160(bytes memory) public returns (bytes20); + function selfdestruct(address payable recipient) public; + function sha256(bytes memory) public returns (bytes32); + struct $AbiType { + function(bytes memory encodedData, $Type[] encodedTypesTuple) returns ($Any[]) decode; + function($Any[] valuesToEncode) returns (bytes memory) encode; + function($Any[] valuesToEncode) returns (bytes memory) encodePacked; + function(bytes4 selector, $Any[] functionArgumentsTuple) returns (bytes memory) encodeWithSelector; + function(string memory signature, $Any[] valuesToEncode) returns (bytes memory) encodeWithSignature; + } + struct $address { + uint256 balance; + bytes code; + bytes32 codehash; + function(bytes memory) returns (bool, bytes memory) call; + function(bytes memory) returns (bool, bytes memory) delegatecall; + function(uint256 amount) returns (bool) send; + function(bytes memory) returns (bool, bytes memory) staticcall; + function(uint256 amount) transfer; + } + struct $Array { + uint length; + function() returns ($ValueType) push; + function($ValueType element) push; + function() pop; + } + struct $FixedArray { + uint length; + } + struct $BlockType { + uint basefee; + uint chainid; + address payable coinbase; + uint difficulty; + uint gaslimit; + uint number; + uint timestamp; + } + struct $bytes { + uint length; + } + struct $BytesType { + function(bytes[] bytesToConcatenate) returns (bytes memory) concat; + } + struct $CallOptions { + uint gas; + uint salt; + uint value; + } + struct $ErrorType { + bytes4 selector; + } + struct $Function { + } + struct $ExternalFunction { + address address; + bytes4 selector; + } + struct $MessageType { + bytes data; + address sender; + bytes4 sig; + uint value; + } + struct $StringType { + function(string[] stringsToConcatenate) returns (string memory) concat; + } + struct $TransactionType { + uint gasprice; + address origin; + } + struct $ContractTypeType { + string name; + bytes creationCode; + bytes runtimeCode; + bytes4 interfaceId; + } + struct $InterfaceTypeType { + string name; + bytes4 interfaceId; + } + struct $IntTypeType { + int min; + int max; + } + struct $UserDefinedValueType { + function($WrappedType elementaryType) returns ($UserType) wrap; + function($UserType userType) returns ($WrappedType) unwrap; + } + struct $YulExternal { + uint slot; + uint offset; + uint length; + } + $Function $placeholder; + $AbiType abi; + $BlockType block; + $BytesType $bytes; + $MessageType msg; + $StringType $string; + $TransactionType tx; +} 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 66c8a8c4da..7803930461 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/bindings/mod.rs +++ b/crates/solidity/outputs/cargo/crate/src/generated/bindings/mod.rs @@ -4,31 +4,46 @@ mod binding_rules; #[path = "generated/built_ins.rs"] -mod built_ins; +pub mod built_ins; -use std::sync::Arc; +use std::rc::Rc; -use metaslang_bindings::{self, PathResolver}; use semver::Version; use crate::cst::KindTypes; -pub type Bindings = metaslang_bindings::Bindings; +pub type BindingGraph = metaslang_bindings::BindingGraph; pub type Definition<'a> = metaslang_bindings::Definition<'a, KindTypes>; pub type Reference<'a> = metaslang_bindings::Reference<'a, KindTypes>; +pub type BindingLocation = metaslang_bindings::BindingLocation; +pub type UserFileLocation = metaslang_bindings::UserFileLocation; + +pub use metaslang_bindings::{BuiltInLocation, PathResolver}; + +use crate::parser::ParserInitializationError; + +#[derive(thiserror::Error, Debug)] +pub enum BindingGraphInitializationError { + #[error(transparent)] + ParserInitialization(#[from] ParserInitializationError), +} pub fn create_with_resolver( version: Version, - resolver: Arc, -) -> Bindings { - Bindings::create(version, binding_rules::BINDING_RULES_SOURCE, resolver) + resolver: Rc>, +) -> Result { + let mut binding_graph = BindingGraph::create( + version.clone(), + binding_rules::BINDING_RULES_SOURCE, + resolver, + ); + + crate::extensions::bindings::add_built_ins(&mut binding_graph, version)?; + + Ok(binding_graph) } #[cfg(feature = "__private_testing_utils")] pub fn get_binding_rules() -> &'static str { binding_rules::BINDING_RULES_SOURCE } - -pub fn get_built_ins(version: &semver::Version) -> &'static str { - built_ins::get_contents(version) -} diff --git a/crates/solidity/outputs/cargo/crate/src/generated/compilation/file.rs b/crates/solidity/outputs/cargo/crate/src/generated/compilation/file.rs new file mode 100644 index 0000000000..94eee8ad56 --- /dev/null +++ b/crates/solidity/outputs/cargo/crate/src/generated/compilation/file.rs @@ -0,0 +1,47 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +use std::collections::BTreeMap; + +use metaslang_cst::text_index::TextIndex; + +use crate::cst::{Cursor, Node}; + +#[derive(Clone)] +pub struct File { + id: String, + tree: Node, + + resolved_imports: BTreeMap, +} + +impl File { + pub(super) fn new(id: String, tree: Node) -> Self { + Self { + id, + tree, + + resolved_imports: BTreeMap::new(), + } + } + + pub fn id(&self) -> &str { + &self.id + } + + pub fn tree(&self) -> &Node { + &self.tree + } + + pub fn create_tree_cursor(&self) -> Cursor { + self.tree.clone().cursor_with_offset(TextIndex::ZERO) + } + + pub(super) fn resolve_import(&mut self, import_path: &Cursor, destination_file_id: String) { + self.resolved_imports + .insert(import_path.node().id(), destination_file_id); + } + + pub(super) fn resolved_import(&self, import_path: &Cursor) -> Option<&String> { + self.resolved_imports.get(&import_path.node().id()) + } +} diff --git a/crates/solidity/outputs/cargo/crate/src/generated/compilation/internal_builder.rs b/crates/solidity/outputs/cargo/crate/src/generated/compilation/internal_builder.rs new file mode 100644 index 0000000000..0eb3cbdc2e --- /dev/null +++ b/crates/solidity/outputs/cargo/crate/src/generated/compilation/internal_builder.rs @@ -0,0 +1,95 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +use std::collections::BTreeMap; +use std::rc::Rc; + +use metaslang_cst::nodes::Node; +use semver::Version; + +use crate::compilation::{CompilationUnit, File}; +use crate::cst::Cursor; +use crate::extensions::compilation::ImportPathsExtractor; +use crate::parser::{Parser, ParserInitializationError}; + +pub struct InternalCompilationBuilder { + parser: Parser, + imports: ImportPathsExtractor, + files: BTreeMap, +} + +#[derive(thiserror::Error, Debug)] +pub enum CompilationInitializationError { + #[error(transparent)] + ParserInitialization(#[from] ParserInitializationError), +} + +impl InternalCompilationBuilder { + pub fn create(language_version: Version) -> Result { + let parser = Parser::create(language_version)?; + + Ok(Self { + parser, + imports: ImportPathsExtractor::new(), + files: BTreeMap::new(), + }) + } + + pub fn add_file(&mut self, id: String, contents: &str) -> AddFileResponse { + if self.files.contains_key(&id) { + // Already added. No need to process it again: + return AddFileResponse { + import_paths: vec![], + }; + } + + let parse_output = self.parser.parse(Parser::ROOT_KIND, contents); + + let import_paths = self.imports.extract(parse_output.create_tree_cursor()); + + let file = File::new( + id.clone(), + Node::Nonterminal(Rc::clone(parse_output.tree())), + ); + self.files.insert(id, file); + + AddFileResponse { import_paths } + } + + pub fn resolve_import( + &mut self, + source_file_id: &str, + import_path: &Cursor, + destination_file_id: String, + ) -> Result<(), ResolveImportError> { + self.files + .get_mut(source_file_id) + .ok_or_else(|| ResolveImportError::SourceFileNotFound(source_file_id.to_owned()))? + .resolve_import(import_path, destination_file_id); + + Ok(()) + } + + pub fn build(&self) -> CompilationUnit { + let language_version = self.parser.language_version().to_owned(); + + let files = self + .files + .iter() + .map(|(id, file)| (id.to_owned(), Rc::new(file.to_owned()))) + .collect(); + + CompilationUnit::new(language_version, files) + } +} + +pub struct AddFileResponse { + pub import_paths: Vec, +} + +#[derive(thiserror::Error, Debug)] +pub enum ResolveImportError { + #[error( + "Source file not found: '{0}'. Make sure to add it first, before resolving its imports." + )] + SourceFileNotFound(String), +} diff --git a/crates/solidity/outputs/cargo/crate/src/generated/compilation/mod.rs b/crates/solidity/outputs/cargo/crate/src/generated/compilation/mod.rs new file mode 100644 index 0000000000..89544c6568 --- /dev/null +++ b/crates/solidity/outputs/cargo/crate/src/generated/compilation/mod.rs @@ -0,0 +1,9 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +mod file; +mod internal_builder; +mod unit; + +pub use file::File; +pub use internal_builder::{AddFileResponse, InternalCompilationBuilder}; +pub use unit::CompilationUnit; diff --git a/crates/solidity/outputs/cargo/crate/src/generated/compilation/unit.rs b/crates/solidity/outputs/cargo/crate/src/generated/compilation/unit.rs new file mode 100644 index 0000000000..a15100e4df --- /dev/null +++ b/crates/solidity/outputs/cargo/crate/src/generated/compilation/unit.rs @@ -0,0 +1,71 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +use std::cell::OnceCell; +use std::collections::BTreeMap; +use std::rc::Rc; + +use semver::Version; + +use crate::bindings::{ + create_with_resolver, BindingGraph, BindingGraphInitializationError, PathResolver, +}; +use crate::compilation::File; +use crate::cst::{Cursor, KindTypes}; + +pub struct CompilationUnit { + language_version: Version, + files: BTreeMap>, + binding_graph: OnceCell, BindingGraphInitializationError>>, +} + +impl CompilationUnit { + pub(super) fn new(language_version: Version, files: BTreeMap>) -> Self { + Self { + language_version, + files, + binding_graph: OnceCell::new(), + } + } + + pub fn language_version(&self) -> &Version { + &self.language_version + } + + pub fn files(&self) -> Vec> { + self.files.values().cloned().collect() + } + + pub fn file(&self, id: &str) -> Option> { + self.files.get(id).cloned() + } + + pub fn binding_graph(&self) -> &Result, BindingGraphInitializationError> { + self.binding_graph.get_or_init(|| { + let resolver = Resolver { + files: self.files.clone(), + }; + + let mut binding_graph = + create_with_resolver(self.language_version.clone(), Rc::new(resolver))?; + + for (id, file) in &self.files { + binding_graph.add_user_file(id, file.create_tree_cursor()); + } + + Ok(Rc::new(binding_graph)) + }) + } +} + +struct Resolver { + files: BTreeMap>, +} + +impl PathResolver for Resolver { + fn resolve_path(&self, context_path: &str, path_to_resolve: &Cursor) -> Option { + self.files + .get(context_path)? + .resolved_import(path_to_resolve) + .cloned() + } +} diff --git a/crates/solidity/outputs/cargo/crate/src/generated/mod.rs b/crates/solidity/outputs/cargo/crate/src/generated/mod.rs index 4b9d48d9f9..3c700fafdc 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/mod.rs +++ b/crates/solidity/outputs/cargo/crate/src/generated/mod.rs @@ -2,6 +2,12 @@ #[cfg(feature = "__experimental_bindings_api")] pub mod bindings; +#[cfg(all( + feature = "__experimental_bindings_api", + feature = "__private_compilation_api" +))] +pub mod compilation; pub mod cst; pub mod diagnostic; pub mod parser; +pub mod utils; diff --git a/crates/solidity/outputs/cargo/crate/src/generated/parser/generated/parser.rs b/crates/solidity/outputs/cargo/crate/src/generated/parser/generated/parser.rs index cc1ef42937..1b2e858edf 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/parser/generated/parser.rs +++ b/crates/solidity/outputs/cargo/crate/src/generated/parser/generated/parser.rs @@ -27,6 +27,7 @@ use crate::parser::scanner_macros::{ scan_not_followed_by, scan_one_or_more, scan_optional, scan_sequence, scan_zero_or_more, }; use crate::parser::ParseOutput; +use crate::utils::LanguageFacts; #[derive(Debug)] pub struct Parser { @@ -65,7 +66,7 @@ pub struct Parser { pub(crate) version_is_at_least_0_8_24: bool, pub(crate) version_is_at_least_0_8_25: bool, pub(crate) version_is_at_least_0_8_27: bool, - pub version: Version, + language_version: Version, } #[derive(thiserror::Error, Debug)] @@ -75,142 +76,61 @@ pub enum ParserInitializationError { } impl Parser { - pub const SUPPORTED_VERSIONS: &'static [Version] = &[ - Version::new(0, 4, 11), - Version::new(0, 4, 12), - Version::new(0, 4, 13), - Version::new(0, 4, 14), - Version::new(0, 4, 15), - Version::new(0, 4, 16), - Version::new(0, 4, 17), - Version::new(0, 4, 18), - Version::new(0, 4, 19), - Version::new(0, 4, 20), - Version::new(0, 4, 21), - Version::new(0, 4, 22), - Version::new(0, 4, 23), - Version::new(0, 4, 24), - Version::new(0, 4, 25), - Version::new(0, 4, 26), - Version::new(0, 5, 0), - Version::new(0, 5, 1), - Version::new(0, 5, 2), - Version::new(0, 5, 3), - Version::new(0, 5, 4), - Version::new(0, 5, 5), - Version::new(0, 5, 6), - Version::new(0, 5, 7), - Version::new(0, 5, 8), - Version::new(0, 5, 9), - Version::new(0, 5, 10), - Version::new(0, 5, 11), - Version::new(0, 5, 12), - Version::new(0, 5, 13), - Version::new(0, 5, 14), - Version::new(0, 5, 15), - Version::new(0, 5, 16), - Version::new(0, 5, 17), - Version::new(0, 6, 0), - Version::new(0, 6, 1), - Version::new(0, 6, 2), - Version::new(0, 6, 3), - Version::new(0, 6, 4), - Version::new(0, 6, 5), - Version::new(0, 6, 6), - Version::new(0, 6, 7), - Version::new(0, 6, 8), - Version::new(0, 6, 9), - Version::new(0, 6, 10), - Version::new(0, 6, 11), - Version::new(0, 6, 12), - Version::new(0, 7, 0), - Version::new(0, 7, 1), - Version::new(0, 7, 2), - Version::new(0, 7, 3), - Version::new(0, 7, 4), - Version::new(0, 7, 5), - Version::new(0, 7, 6), - Version::new(0, 8, 0), - Version::new(0, 8, 1), - Version::new(0, 8, 2), - Version::new(0, 8, 3), - Version::new(0, 8, 4), - Version::new(0, 8, 5), - Version::new(0, 8, 6), - Version::new(0, 8, 7), - Version::new(0, 8, 8), - Version::new(0, 8, 9), - Version::new(0, 8, 10), - Version::new(0, 8, 11), - Version::new(0, 8, 12), - Version::new(0, 8, 13), - Version::new(0, 8, 14), - Version::new(0, 8, 15), - Version::new(0, 8, 16), - Version::new(0, 8, 17), - Version::new(0, 8, 18), - Version::new(0, 8, 19), - Version::new(0, 8, 20), - Version::new(0, 8, 21), - Version::new(0, 8, 22), - Version::new(0, 8, 23), - Version::new(0, 8, 24), - Version::new(0, 8, 25), - Version::new(0, 8, 26), - Version::new(0, 8, 27), - Version::new(0, 8, 28), - ]; - pub const ROOT_KIND: NonterminalKind = NonterminalKind::SourceUnit; - pub fn create(version: Version) -> std::result::Result { - if Self::SUPPORTED_VERSIONS.binary_search(&version).is_ok() { + pub fn create( + language_version: Version, + ) -> std::result::Result { + if LanguageFacts::SUPPORTED_VERSIONS + .binary_search(&language_version) + .is_ok() + { Ok(Self { - version_is_at_least_0_4_11: Version::new(0, 4, 11) <= version, - version_is_at_least_0_4_12: Version::new(0, 4, 12) <= version, - version_is_at_least_0_4_14: Version::new(0, 4, 14) <= version, - version_is_at_least_0_4_16: Version::new(0, 4, 16) <= version, - version_is_at_least_0_4_21: Version::new(0, 4, 21) <= version, - version_is_at_least_0_4_22: Version::new(0, 4, 22) <= version, - version_is_at_least_0_4_25: Version::new(0, 4, 25) <= version, - version_is_at_least_0_5_0: Version::new(0, 5, 0) <= version, - version_is_at_least_0_5_3: Version::new(0, 5, 3) <= version, - version_is_at_least_0_5_5: Version::new(0, 5, 5) <= version, - version_is_at_least_0_5_8: Version::new(0, 5, 8) <= version, - version_is_at_least_0_5_10: Version::new(0, 5, 10) <= version, - version_is_at_least_0_5_12: Version::new(0, 5, 12) <= version, - version_is_at_least_0_5_14: Version::new(0, 5, 14) <= version, - version_is_at_least_0_6_0: Version::new(0, 6, 0) <= version, - version_is_at_least_0_6_2: Version::new(0, 6, 2) <= version, - version_is_at_least_0_6_5: Version::new(0, 6, 5) <= version, - version_is_at_least_0_6_7: Version::new(0, 6, 7) <= version, - version_is_at_least_0_6_8: Version::new(0, 6, 8) <= version, - version_is_at_least_0_6_11: Version::new(0, 6, 11) <= version, - version_is_at_least_0_7_0: Version::new(0, 7, 0) <= version, - version_is_at_least_0_7_1: Version::new(0, 7, 1) <= version, - version_is_at_least_0_7_4: Version::new(0, 7, 4) <= version, - version_is_at_least_0_8_0: Version::new(0, 8, 0) <= version, - version_is_at_least_0_8_4: Version::new(0, 8, 4) <= version, - version_is_at_least_0_8_7: Version::new(0, 8, 7) <= version, - version_is_at_least_0_8_8: Version::new(0, 8, 8) <= version, - version_is_at_least_0_8_13: Version::new(0, 8, 13) <= version, - version_is_at_least_0_8_18: Version::new(0, 8, 18) <= version, - version_is_at_least_0_8_19: Version::new(0, 8, 19) <= version, - version_is_at_least_0_8_22: Version::new(0, 8, 22) <= version, - version_is_at_least_0_8_24: Version::new(0, 8, 24) <= version, - version_is_at_least_0_8_25: Version::new(0, 8, 25) <= version, - version_is_at_least_0_8_27: Version::new(0, 8, 27) <= version, - version, + version_is_at_least_0_4_11: Version::new(0, 4, 11) <= language_version, + version_is_at_least_0_4_12: Version::new(0, 4, 12) <= language_version, + version_is_at_least_0_4_14: Version::new(0, 4, 14) <= language_version, + version_is_at_least_0_4_16: Version::new(0, 4, 16) <= language_version, + version_is_at_least_0_4_21: Version::new(0, 4, 21) <= language_version, + version_is_at_least_0_4_22: Version::new(0, 4, 22) <= language_version, + version_is_at_least_0_4_25: Version::new(0, 4, 25) <= language_version, + version_is_at_least_0_5_0: Version::new(0, 5, 0) <= language_version, + version_is_at_least_0_5_3: Version::new(0, 5, 3) <= language_version, + version_is_at_least_0_5_5: Version::new(0, 5, 5) <= language_version, + version_is_at_least_0_5_8: Version::new(0, 5, 8) <= language_version, + version_is_at_least_0_5_10: Version::new(0, 5, 10) <= language_version, + version_is_at_least_0_5_12: Version::new(0, 5, 12) <= language_version, + version_is_at_least_0_5_14: Version::new(0, 5, 14) <= language_version, + version_is_at_least_0_6_0: Version::new(0, 6, 0) <= language_version, + version_is_at_least_0_6_2: Version::new(0, 6, 2) <= language_version, + version_is_at_least_0_6_5: Version::new(0, 6, 5) <= language_version, + version_is_at_least_0_6_7: Version::new(0, 6, 7) <= language_version, + version_is_at_least_0_6_8: Version::new(0, 6, 8) <= language_version, + version_is_at_least_0_6_11: Version::new(0, 6, 11) <= language_version, + version_is_at_least_0_7_0: Version::new(0, 7, 0) <= language_version, + version_is_at_least_0_7_1: Version::new(0, 7, 1) <= language_version, + version_is_at_least_0_7_4: Version::new(0, 7, 4) <= language_version, + version_is_at_least_0_8_0: Version::new(0, 8, 0) <= language_version, + version_is_at_least_0_8_4: Version::new(0, 8, 4) <= language_version, + version_is_at_least_0_8_7: Version::new(0, 8, 7) <= language_version, + version_is_at_least_0_8_8: Version::new(0, 8, 8) <= language_version, + version_is_at_least_0_8_13: Version::new(0, 8, 13) <= language_version, + version_is_at_least_0_8_18: Version::new(0, 8, 18) <= language_version, + version_is_at_least_0_8_19: Version::new(0, 8, 19) <= language_version, + version_is_at_least_0_8_22: Version::new(0, 8, 22) <= language_version, + version_is_at_least_0_8_24: Version::new(0, 8, 24) <= language_version, + version_is_at_least_0_8_25: Version::new(0, 8, 25) <= language_version, + version_is_at_least_0_8_27: Version::new(0, 8, 27) <= language_version, + language_version, }) } else { Err(ParserInitializationError::UnsupportedLanguageVersion( - version, + language_version, )) } } - pub fn version(&self) -> &Version { - &self.version + pub fn language_version(&self) -> &Version { + &self.language_version } /******************************************** * Parser Functions ********************************************/ diff --git a/crates/solidity/outputs/cargo/crate/src/generated/parser/parse_output.rs b/crates/solidity/outputs/cargo/crate/src/generated/parser/parse_output.rs index f6f06245e6..790329c22b 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/parser/parse_output.rs +++ b/crates/solidity/outputs/cargo/crate/src/generated/parser/parse_output.rs @@ -5,15 +5,15 @@ use std::rc::Rc; use crate::cst::{Cursor, NonterminalNode, TextIndex}; use crate::parser::ParseError; -#[derive(Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq)] pub struct ParseOutput { - pub(crate) parse_tree: Rc, + pub(crate) tree: Rc, pub(crate) errors: Vec, } impl ParseOutput { pub fn tree(&self) -> &Rc { - &self.parse_tree + &self.tree } pub fn errors(&self) -> &Vec { @@ -26,6 +26,6 @@ impl ParseOutput { /// Creates a cursor that starts at the root of the parse tree. pub fn create_tree_cursor(&self) -> Cursor { - Rc::clone(&self.parse_tree).cursor_with_offset(TextIndex::ZERO) + Rc::clone(&self.tree).cursor_with_offset(TextIndex::ZERO) } } diff --git a/crates/solidity/outputs/cargo/crate/src/generated/parser/parser_support/parser_function.rs b/crates/solidity/outputs/cargo/crate/src/generated/parser/parser_support/parser_function.rs index e0a2b4be62..60c1a1360c 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/parser/parser_support/parser_function.rs +++ b/crates/solidity/outputs/cargo/crate/src/generated/parser/parser_support/parser_function.rs @@ -91,7 +91,7 @@ where let node = Node::terminal(kind, input.to_string()); trivia_nodes.push(Edge::anonymous(node)); ParseOutput { - parse_tree: Rc::new(NonterminalNode::new(expected, trivia_nodes)), + tree: Rc::new(NonterminalNode::new(expected, trivia_nodes)), errors: vec![ParseError::new( start..start + input.into(), no_match.expected_terminals, @@ -155,17 +155,17 @@ where )); ParseOutput { - parse_tree: Rc::new(NonterminalNode::new(topmost_node.kind, new_children)), + tree: Rc::new(NonterminalNode::new(topmost_node.kind, new_children)), errors, } } else { - let parse_tree = topmost_node; + let tree = topmost_node; let errors = stream.into_errors(); // Sanity check: Make sure that succesful parse is equivalent to not having any invalid nodes debug_assert_eq!( errors.is_empty(), - Rc::clone(&parse_tree) + Rc::clone(&tree) .cursor_with_offset(TextIndex::ZERO) .remaining_nodes() .all(|edge| edge @@ -174,7 +174,7 @@ where .is_none()) ); - ParseOutput { parse_tree, errors } + ParseOutput { tree, errors } } } } diff --git a/crates/solidity/outputs/cargo/crate/src/generated/utils/generated/language_facts.rs b/crates/solidity/outputs/cargo/crate/src/generated/utils/generated/language_facts.rs new file mode 100644 index 0000000000..e61f6b8089 --- /dev/null +++ b/crates/solidity/outputs/cargo/crate/src/generated/utils/generated/language_facts.rs @@ -0,0 +1,95 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +use semver::Version; + +pub struct LanguageFacts; + +impl LanguageFacts { + pub const NAME: &'static str = "Solidity"; + + pub const SUPPORTED_VERSIONS: &'static [Version] = &[ + Version::new(0, 4, 11), + Version::new(0, 4, 12), + Version::new(0, 4, 13), + Version::new(0, 4, 14), + Version::new(0, 4, 15), + Version::new(0, 4, 16), + Version::new(0, 4, 17), + Version::new(0, 4, 18), + Version::new(0, 4, 19), + Version::new(0, 4, 20), + Version::new(0, 4, 21), + Version::new(0, 4, 22), + Version::new(0, 4, 23), + Version::new(0, 4, 24), + Version::new(0, 4, 25), + Version::new(0, 4, 26), + Version::new(0, 5, 0), + Version::new(0, 5, 1), + Version::new(0, 5, 2), + Version::new(0, 5, 3), + Version::new(0, 5, 4), + Version::new(0, 5, 5), + Version::new(0, 5, 6), + Version::new(0, 5, 7), + Version::new(0, 5, 8), + Version::new(0, 5, 9), + Version::new(0, 5, 10), + Version::new(0, 5, 11), + Version::new(0, 5, 12), + Version::new(0, 5, 13), + Version::new(0, 5, 14), + Version::new(0, 5, 15), + Version::new(0, 5, 16), + Version::new(0, 5, 17), + Version::new(0, 6, 0), + Version::new(0, 6, 1), + Version::new(0, 6, 2), + Version::new(0, 6, 3), + Version::new(0, 6, 4), + Version::new(0, 6, 5), + Version::new(0, 6, 6), + Version::new(0, 6, 7), + Version::new(0, 6, 8), + Version::new(0, 6, 9), + Version::new(0, 6, 10), + Version::new(0, 6, 11), + Version::new(0, 6, 12), + Version::new(0, 7, 0), + Version::new(0, 7, 1), + Version::new(0, 7, 2), + Version::new(0, 7, 3), + Version::new(0, 7, 4), + Version::new(0, 7, 5), + Version::new(0, 7, 6), + Version::new(0, 8, 0), + Version::new(0, 8, 1), + Version::new(0, 8, 2), + Version::new(0, 8, 3), + Version::new(0, 8, 4), + Version::new(0, 8, 5), + Version::new(0, 8, 6), + Version::new(0, 8, 7), + Version::new(0, 8, 8), + Version::new(0, 8, 9), + Version::new(0, 8, 10), + Version::new(0, 8, 11), + Version::new(0, 8, 12), + Version::new(0, 8, 13), + Version::new(0, 8, 14), + Version::new(0, 8, 15), + Version::new(0, 8, 16), + Version::new(0, 8, 17), + Version::new(0, 8, 18), + Version::new(0, 8, 19), + Version::new(0, 8, 20), + Version::new(0, 8, 21), + Version::new(0, 8, 22), + Version::new(0, 8, 23), + Version::new(0, 8, 24), + Version::new(0, 8, 25), + Version::new(0, 8, 26), + Version::new(0, 8, 27), + Version::new(0, 8, 28), + ]; +} diff --git a/crates/solidity/outputs/cargo/crate/src/generated/utils/mod.rs b/crates/solidity/outputs/cargo/crate/src/generated/utils/mod.rs new file mode 100644 index 0000000000..57bd4f108e --- /dev/null +++ b/crates/solidity/outputs/cargo/crate/src/generated/utils/mod.rs @@ -0,0 +1,6 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +#[path = "generated/language_facts.rs"] +mod language_facts; + +pub use language_facts::LanguageFacts; diff --git a/crates/solidity/outputs/cargo/crate/src/lib.rs b/crates/solidity/outputs/cargo/crate/src/lib.rs index 515f523f68..bd40dc9c6c 100644 --- a/crates/solidity/outputs/cargo/crate/src/lib.rs +++ b/crates/solidity/outputs/cargo/crate/src/lib.rs @@ -1,46 +1,4 @@ +mod extensions; mod generated; pub use generated::*; - -#[cfg(feature = "__experimental_bindings_api")] -pub fn transform_built_ins_node(node: &generated::cst::Node) -> generated::cst::Node { - use std::rc::Rc; - - use generated::cst::{Edge, Node, NonterminalNode, TerminalNode}; - - use crate::cst::TerminalKind; - - match node { - Node::Nonterminal(nonterminal) => { - let NonterminalNode { - kind, - text_len, - children, - } = nonterminal.as_ref(); - let children = children - .iter() - .map(|edge| Edge { - label: edge.label, - node: transform_built_ins_node(&edge.node), - }) - .collect(); - let nonterminal = Rc::new(NonterminalNode { - kind: *kind, - text_len: *text_len, - children, - }); - Node::Nonterminal(nonterminal) - } - Node::Terminal(terminal) => { - let TerminalNode { kind, text } = terminal.as_ref(); - let terminal = match terminal.as_ref().kind { - TerminalKind::Identifier => Rc::new(TerminalNode { - kind: *kind, - text: text.replace('$', "%"), - }), - _ => Rc::clone(terminal), - }; - Node::Terminal(terminal) - } - } -} diff --git a/crates/solidity/outputs/cargo/tests/src/bindings.rs b/crates/solidity/outputs/cargo/tests/src/bindings.rs index 2ddca80a49..c5a9cf60dc 100644 --- a/crates/solidity/outputs/cargo/tests/src/bindings.rs +++ b/crates/solidity/outputs/cargo/tests/src/bindings.rs @@ -1,30 +1,10 @@ -use std::rc::Rc; -use std::sync::Arc; - -use anyhow::Result; -use semver::Version; -use slang_solidity::bindings::{self, Bindings}; -use slang_solidity::cst::{Node, TextIndex}; -use slang_solidity::parser::Parser; -use slang_solidity::transform_built_ins_node; - -use crate::resolver::TestsPathResolver; - -pub fn create_bindings(version: &Version) -> Result { - let parser = Parser::create(version.clone())?; - let mut bindings = - bindings::create_with_resolver(version.clone(), Arc::new(TestsPathResolver {})); - - let built_ins_parse_output = parser.parse(Parser::ROOT_KIND, bindings::get_built_ins(version)); - assert!( - built_ins_parse_output.is_valid(), - "built-ins parse without errors" - ); - - let built_ins_cursor = - transform_built_ins_node(&Node::Nonterminal(Rc::clone(built_ins_parse_output.tree()))) - .cursor_with_offset(TextIndex::ZERO); - - bindings.add_system_file("built_ins.sol", built_ins_cursor); - Ok(bindings) +use slang_solidity::bindings::{BindingGraph, Definition}; + +pub fn lookup_definition_by_name<'a>( + binding_graph: &'a BindingGraph, + name: &str, +) -> Option> { + binding_graph + .all_definitions() + .find(|definition| definition.get_cursor().node().unparse() == name) } 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 42d533ed5d..fcc4d19547 100644 --- a/crates/solidity/outputs/cargo/tests/src/bindings_assertions/assertions.rs +++ b/crates/solidity/outputs/cargo/tests/src/bindings_assertions/assertions.rs @@ -5,7 +5,7 @@ use std::collections::HashMap; use once_cell::sync::Lazy; use regex::Regex; use semver::{Version, VersionReq}; -use slang_solidity::bindings::{Bindings, Definition}; +use slang_solidity::bindings::{BindingGraph, Definition}; use slang_solidity::cst::{Cursor, TerminalKind}; use thiserror::Error; @@ -308,21 +308,25 @@ fn search_asserted_node_backwards(mut cursor: Cursor, anchor_column: usize) -> O None } -/// Checks that the given `assertions` are fulfilled in the given `bindings` for +/// Checks that the given `assertions` are fulfilled in the given `binding_graph` for /// the indicated `version`. Only references can have version requirements, and /// the absence of a requirement means the assertion should hold for all /// language versions. /// pub fn check_assertions( - bindings: &Bindings, + binding_graph: &BindingGraph, assertions: &Assertions<'_>, version: &Version, ) -> Result { let mut failures: Vec = Vec::new(); - check_definitions(bindings, assertions.definitions.values(), &mut failures); + check_definitions( + binding_graph, + assertions.definitions.values(), + &mut failures, + ); check_references( - bindings, + binding_graph, version, assertions.references.iter(), &assertions.definitions, @@ -342,24 +346,24 @@ pub fn check_assertions( } fn check_definitions<'a>( - bindings: &Bindings, + binding_graph: &BindingGraph, definitions: impl Iterator>, failures: &mut Vec, ) { for assertion in definitions { - if let Err(failure) = find_definition(bindings, assertion) { + if let Err(failure) = find_definition(binding_graph, assertion) { failures.push(failure); } } } fn find_definition<'a>( - bindings: &'a Bindings, + binding_graph: &'a BindingGraph, assertion: &DefinitionAssertion<'_>, ) -> Result, String> { let DefinitionAssertion { cursor, .. } = assertion; - let Some(definition) = bindings.definition_at(cursor) else { + let Some(definition) = binding_graph.definition_at(cursor) else { return Err(format!("{assertion} failed: not found")); }; @@ -367,21 +371,23 @@ fn find_definition<'a>( } fn check_references<'a>( - bindings: &Bindings, + binding_graph: &BindingGraph, version: &Version, references: impl Iterator>, definitions: &HashMap>, failures: &mut Vec, ) { for assertion in references { - if let Err(failure) = check_reference_assertion(bindings, definitions, version, assertion) { + if let Err(failure) = + check_reference_assertion(binding_graph, definitions, version, assertion) + { failures.push(failure); } } } fn check_reference_assertion( - bindings: &Bindings, + binding_graph: &BindingGraph, definitions: &HashMap>, version: &Version, assertion: &ReferenceAssertion<'_>, @@ -396,7 +402,7 @@ fn check_reference_assertion( true }; - let resolution = match find_and_resolve_reference(bindings, assertion) { + let resolution = match find_and_resolve_reference(binding_graph, assertion) { Ok(resolution) => resolution, Err(err) => { if version_matches { @@ -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(bindings, 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(bindings, definitions, assertion)?; - let referenced_cursor = referenced_handle.get_cursor().unwrap(); + lookup_referenced_definition(binding_graph, definitions, assertion)?; + 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()), )); } } @@ -464,22 +471,22 @@ fn check_reference_assertion( } fn find_and_resolve_reference<'a>( - bindings: &'a Bindings, + binding_graph: &'a BindingGraph, assertion: &ReferenceAssertion<'_>, ) -> Result>, String> { let ReferenceAssertion { cursor, .. } = assertion; - let Some(reference) = bindings.reference_at(cursor) else { + let Some(reference) = binding_graph.reference_at(cursor) else { return Err(format!("{assertion} failed: not found")); }; // For the purpose of binding assertions, any failure to resolve to a single // definition will be treated as if it was unresolved - Ok(reference.jump_to_definition().ok()) + Ok(reference.resolve_definition().ok()) } fn lookup_referenced_definition<'a>( - bindings: &'a Bindings, + binding_graph: &'a BindingGraph, definitions: &HashMap>, assertion: &ReferenceAssertion<'_>, ) -> Result, String> { @@ -490,5 +497,5 @@ fn lookup_referenced_definition<'a>( let Some(definition) = definitions.get(id) else { return Err(format!("{assertion} failed: reference is undefined")); }; - find_definition(bindings, definition) + find_definition(binding_graph, definition) } diff --git a/crates/solidity/outputs/cargo/tests/src/bindings_assertions/generated/mod.rs b/crates/solidity/outputs/cargo/tests/src/bindings_assertions/generated/mod.rs index f50520d789..e61b9a8f6b 100644 --- a/crates/solidity/outputs/cargo/tests/src/bindings_assertions/generated/mod.rs +++ b/crates/solidity/outputs/cargo/tests/src/bindings_assertions/generated/mod.rs @@ -16,5 +16,6 @@ mod mappings; mod modifiers; mod scoping; mod user_types; +mod using; mod variables; mod yul; diff --git a/crates/solidity/outputs/cargo/tests/src/bindings_assertions/generated/using.rs b/crates/solidity/outputs/cargo/tests/src/bindings_assertions/generated/using.rs new file mode 100644 index 0000000000..58420ec02b --- /dev/null +++ b/crates/solidity/outputs/cargo/tests/src/bindings_assertions/generated/using.rs @@ -0,0 +1,10 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +use anyhow::Result; + +use crate::bindings_assertions::runner::run; + +#[test] +fn inherited() -> Result<()> { + run("using", "inherited") +} diff --git a/crates/solidity/outputs/cargo/tests/src/bindings_assertions/runner.rs b/crates/solidity/outputs/cargo/tests/src/bindings_assertions/runner.rs index fc009f9a68..f593e1937d 100644 --- a/crates/solidity/outputs/cargo/tests/src/bindings_assertions/runner.rs +++ b/crates/solidity/outputs/cargo/tests/src/bindings_assertions/runner.rs @@ -1,17 +1,19 @@ use std::fs; +use std::rc::Rc; use anyhow::Result; use infra_utils::cargo::CargoWorkspace; use semver::Version; -use slang_solidity::diagnostic; use slang_solidity::parser::Parser; +use slang_solidity::{bindings, diagnostic}; -use crate::bindings::create_bindings; +use crate::bindings::lookup_definition_by_name; use crate::bindings_assertions::assertions::{ check_assertions, collect_assertions_into, Assertions, }; use crate::generated::VERSION_BREAKS; use crate::multi_part_file::{split_multi_file, Part}; +use crate::resolver::TestsPathResolver; pub fn run(group_name: &str, test_name: &str) -> Result<()> { let file_name = format!("{test_name}.sol"); @@ -29,7 +31,8 @@ pub fn run(group_name: &str, test_name: &str) -> Result<()> { fn check_assertions_with_version(version: &Version, contents: &str) -> Result<()> { let parser = Parser::create(version.clone())?; - let mut bindings = create_bindings(version)?; + let mut binding_graph = + bindings::create_with_resolver(version.clone(), Rc::new(TestsPathResolver {}))?; let mut assertions = Assertions::new(); let mut skipped = 0; @@ -53,7 +56,7 @@ fn check_assertions_with_version(version: &Version, contents: &str) -> Result<() eprintln!("\nParse errors for version {version}\nFile: {file_path}\n{report}"); } - bindings.add_user_file(file_path, parse_output.create_tree_cursor()); + binding_graph.add_user_file(file_path, parse_output.create_tree_cursor()); skipped += collect_assertions_into( &mut assertions, parse_output.create_tree_cursor(), @@ -63,14 +66,13 @@ fn check_assertions_with_version(version: &Version, contents: &str) -> Result<() } if let Some(context) = multi_part.context { - let context_definition = bindings - .lookup_definition_by_name(context) + let context_definition = lookup_definition_by_name(&binding_graph, context) .expect("context definition to be found") .to_handle(); - bindings.set_context(&context_definition); + binding_graph.set_context(&context_definition); } - let result = check_assertions(&bindings, &assertions, version); + let result = check_assertions(&binding_graph, &assertions, version); match result { Ok(count) => { diff --git a/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/arrays.rs b/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/arrays.rs index 63fdbbc1cb..80d84f86d5 100644 --- a/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/arrays.rs +++ b/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/arrays.rs @@ -8,3 +8,8 @@ use crate::bindings_output::runner::run; fn indexing() -> Result<()> { run("arrays", "indexing") } + +#[test] +fn length() -> Result<()> { + run("arrays", "length") +} diff --git a/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/built_ins.rs b/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/built_ins.rs index 328c698ec2..a28a9b2670 100644 --- a/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/built_ins.rs +++ b/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/built_ins.rs @@ -19,6 +19,11 @@ fn arrays() -> Result<()> { run("built_ins", "arrays") } +#[test] +fn bytes() -> Result<()> { + run("built_ins", "bytes") +} + #[test] fn function_type() -> Result<()> { run("built_ins", "function_type") @@ -39,6 +44,16 @@ fn shadowing() -> Result<()> { run("built_ins", "shadowing") } +#[test] +fn this() -> Result<()> { + run("built_ins", "this") +} + +#[test] +fn this_as_address() -> Result<()> { + run("built_ins", "this_as_address") +} + #[test] fn type_expr() -> Result<()> { run("built_ins", "type_expr") diff --git a/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/contracts.rs b/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/contracts.rs index c89e406696..a08b136dd9 100644 --- a/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/contracts.rs +++ b/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/contracts.rs @@ -4,6 +4,11 @@ use anyhow::Result; use crate::bindings_output::runner::run; +#[test] +fn constructor_call_parent() -> Result<()> { + run("contracts", "constructor_call_parent") +} + #[test] fn constructor_invocation() -> Result<()> { run("contracts", "constructor_invocation") @@ -29,11 +34,76 @@ fn inheritance() -> Result<()> { run("contracts", "inheritance") } +#[test] +fn inherited_state_vars() -> Result<()> { + run("contracts", "inherited_state_vars") +} + +#[test] +fn internal_visibility() -> Result<()> { + run("contracts", "internal_visibility") +} + +#[test] +fn legacy_constructors() -> Result<()> { + run("contracts", "legacy_constructors") +} + +#[test] +fn legacy_function_options() -> Result<()> { + run("contracts", "legacy_function_options") +} + +#[test] +fn multi_inheritance() -> Result<()> { + run("contracts", "multi_inheritance") +} + +#[test] +fn public_array_getters() -> Result<()> { + run("contracts", "public_array_getters") +} + +#[test] +fn public_getter_members() -> Result<()> { + run("contracts", "public_getter_members") +} + #[test] fn public_getters() -> Result<()> { run("contracts", "public_getters") } +#[test] +fn public_inherited_getter() -> Result<()> { + run("contracts", "public_inherited_getter") +} + +#[test] +fn public_mapping_getters() -> Result<()> { + run("contracts", "public_mapping_getters") +} + +#[test] +fn public_struct_getter() -> Result<()> { + run("contracts", "public_struct_getter") +} + +#[test] +fn qualified_inherited() -> Result<()> { + run("contracts", "qualified_inherited") +} + +#[test] +fn qualified_parent_call() -> Result<()> { + run("contracts", "qualified_parent_call") +} + +#[test] +fn super_deep() -> Result<()> { + run("contracts", "super_deep") +} + #[test] fn super_linearisation() -> Result<()> { run("contracts", "super_linearisation") @@ -49,6 +119,11 @@ fn this_scope() -> Result<()> { run("contracts", "this_scope") } +#[test] +fn unnamed_function() -> Result<()> { + run("contracts", "unnamed_function") +} + #[test] fn virtual_lookup() -> Result<()> { run("contracts", "virtual_lookup") diff --git a/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/errors.rs b/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/errors.rs index 7725da2d61..dc6cfdeec4 100644 --- a/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/errors.rs +++ b/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/errors.rs @@ -8,3 +8,8 @@ use crate::bindings_output::runner::run; fn custom_types() -> Result<()> { run("errors", "custom_types") } + +#[test] +fn selector() -> Result<()> { + run("errors", "selector") +} diff --git a/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/expressions.rs b/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/expressions.rs index a23eba4c12..d4e1b6730d 100644 --- a/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/expressions.rs +++ b/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/expressions.rs @@ -4,11 +4,21 @@ use anyhow::Result; use crate::bindings_output::runner::run; +#[test] +fn binary_operators() -> Result<()> { + run("expressions", "binary_operators") +} + #[test] fn call_options() -> Result<()> { run("expressions", "call_options") } +#[test] +fn elementary_casting() -> Result<()> { + run("expressions", "elementary_casting") +} + #[test] fn emit_named_args() -> Result<()> { run("expressions", "emit_named_args") @@ -29,6 +39,21 @@ fn funcalls_output() -> Result<()> { run("expressions", "funcalls_output") } +#[test] +fn legacy_call_options() -> Result<()> { + run("expressions", "legacy_call_options") +} + +#[test] +fn literal_address() -> Result<()> { + run("expressions", "literal_address") +} + +#[test] +fn literal_integers() -> Result<()> { + run("expressions", "literal_integers") +} + #[test] fn new_output() -> Result<()> { run("expressions", "new_output") diff --git a/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/interfaces.rs b/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/interfaces.rs index 360bf638c1..541e9aa52b 100644 --- a/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/interfaces.rs +++ b/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/interfaces.rs @@ -9,6 +9,11 @@ fn inheritance() -> Result<()> { run("interfaces", "inheritance") } +#[test] +fn own_types_access() -> Result<()> { + run("interfaces", "own_types_access") +} + #[test] fn simple() -> Result<()> { run("interfaces", "simple") diff --git a/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/libraries.rs b/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/libraries.rs index 6e61f22c32..8a84aabbdd 100644 --- a/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/libraries.rs +++ b/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/libraries.rs @@ -4,6 +4,26 @@ use anyhow::Result; use crate::bindings_output::runner::run; +#[test] +fn constants() -> Result<()> { + run("libraries", "constants") +} + +#[test] +fn modifiers() -> Result<()> { + run("libraries", "modifiers") +} + +#[test] +fn modifiers_scope() -> Result<()> { + run("libraries", "modifiers_scope") +} + +#[test] +fn propagate_dynamic_scope() -> Result<()> { + run("libraries", "propagate_dynamic_scope") +} + #[test] fn visibility() -> Result<()> { run("libraries", "visibility") diff --git a/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/mod.rs b/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/mod.rs index ba2bdc21a4..ebe2bbe3a0 100644 --- a/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/mod.rs +++ b/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/mod.rs @@ -15,6 +15,7 @@ mod libraries; mod mappings; mod modifiers; mod structs; +mod user_types; mod using; mod variables; mod yul; diff --git a/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/structs.rs b/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/structs.rs index 407534d917..9fb31f96dc 100644 --- a/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/structs.rs +++ b/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/structs.rs @@ -9,6 +9,11 @@ fn declaration() -> Result<()> { run("structs", "declaration") } +#[test] +fn function_call() -> Result<()> { + run("structs", "function_call") +} + #[test] fn named_params_construction() -> Result<()> { run("structs", "named_params_construction") diff --git a/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/user_types.rs b/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/user_types.rs new file mode 100644 index 0000000000..889783f382 --- /dev/null +++ b/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/user_types.rs @@ -0,0 +1,10 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +use anyhow::Result; + +use crate::bindings_output::runner::run; + +#[test] +fn wrap_unwrap() -> Result<()> { + run("user_types", "wrap_unwrap") +} diff --git a/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/using.rs b/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/using.rs index 2019c4c6d1..7b8a7d7bff 100644 --- a/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/using.rs +++ b/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/using.rs @@ -4,6 +4,21 @@ use anyhow::Result; use crate::bindings_output::runner::run; +#[test] +fn address() -> Result<()> { + run("using", "address") +} + +#[test] +fn casting() -> Result<()> { + run("using", "casting") +} + +#[test] +fn chained_calls() -> Result<()> { + run("using", "chained_calls") +} + #[test] fn deconstruction() -> Result<()> { run("using", "deconstruction") @@ -39,12 +54,72 @@ fn in_library() -> Result<()> { run("using", "in_library") } +#[test] +fn inherit_extension() -> Result<()> { + run("using", "inherit_extension") +} + +#[test] +fn inherited_types() -> Result<()> { + run("using", "inherited_types") +} + +#[test] +fn mappings() -> Result<()> { + run("using", "mappings") +} + +#[test] +fn on_interfaces_inherited() -> Result<()> { + run("using", "on_interfaces_inherited") +} + +#[test] +fn on_parameters() -> Result<()> { + run("using", "on_parameters") +} + +#[test] +fn on_state_var_initialization() -> Result<()> { + run("using", "on_state_var_initialization") +} + +#[test] +fn on_super_calls() -> Result<()> { + run("using", "on_super_calls") +} + +#[test] +fn qualified_type() -> Result<()> { + run("using", "qualified_type") +} + #[test] fn star() -> Result<()> { run("using", "star") } +#[test] +fn star_in_library() -> Result<()> { + run("using", "star_in_library") +} + +#[test] +fn star_inherited() -> Result<()> { + run("using", "star_inherited") +} + #[test] fn top_level() -> Result<()> { run("using", "top_level") } + +#[test] +fn uint_alias() -> Result<()> { + run("using", "uint_alias") +} + +#[test] +fn user_types() -> Result<()> { + run("using", "user_types") +} diff --git a/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/variables.rs b/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/variables.rs index c15dc0378f..b820477fa7 100644 --- a/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/variables.rs +++ b/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/variables.rs @@ -18,3 +18,8 @@ fn params() -> Result<()> { fn state_vars() -> Result<()> { run("variables", "state_vars") } + +#[test] +fn var_declaration() -> Result<()> { + run("variables", "var_declaration") +} diff --git a/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/yul.rs b/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/yul.rs index be4e184986..f16d3cda70 100644 --- a/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/yul.rs +++ b/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/yul.rs @@ -9,16 +9,36 @@ fn conditionals() -> Result<()> { run("yul", "conditionals") } +#[test] +fn constant_access_from_functions() -> Result<()> { + run("yul", "constant_access_from_functions") +} + #[test] fn functions() -> Result<()> { run("yul", "functions") } +#[test] +fn identifiers_with_dots() -> Result<()> { + run("yul", "identifiers_with_dots") +} + #[test] fn loops() -> Result<()> { run("yul", "loops") } +#[test] +fn slot_offset_members() -> Result<()> { + run("yul", "slot_offset_members") +} + +#[test] +fn slot_suffix() -> Result<()> { + run("yul", "slot_suffix") +} + #[test] fn variables() -> Result<()> { run("yul", "variables") 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 7298d965d5..b347b541d7 100644 --- a/crates/solidity/outputs/cargo/tests/src/bindings_output/renderer.rs +++ b/crates/solidity/outputs/cargo/tests/src/bindings_output/renderer.rs @@ -4,7 +4,7 @@ use std::ops::Range; use anyhow::Result; use ariadne::{Color, Config, FnCache, Label, Report, ReportBuilder, ReportKind, Source}; use metaslang_bindings::ResolutionError; -use slang_solidity::bindings::{Bindings, Definition, Reference}; +use slang_solidity::bindings::{BindingGraph, Definition, Reference}; use slang_solidity::diagnostic; use super::runner::ParsedPart; @@ -12,13 +12,13 @@ use super::runner::ParsedPart; type ReportSpan<'a> = (&'a str, Range); pub(crate) fn render_bindings( - bindings: &Bindings, + binding_graph: &BindingGraph, parsed_parts: &[ParsedPart<'_>], ) -> Result<(String, bool)> { let mut buffer: Vec = Vec::new(); let mut all_resolved = true; - let all_definitions = collect_all_definitions(bindings); + let all_definitions = collect_all_definitions(binding_graph); for part in parsed_parts { if !part.parse_output.is_valid() { @@ -28,7 +28,7 @@ pub(crate) fn render_bindings( buffer.push(b'\n'); } - let part_references = bindings + let part_references = binding_graph .all_references() .filter(|reference| reference.get_file().is_user_path(part.path)); let (bindings_report, part_all_resolved) = @@ -52,10 +52,10 @@ pub(crate) fn render_bindings( // We collect all non built-in definitions in a vector to be able to identify // them by a numeric index -fn collect_all_definitions(bindings: &Bindings) -> Vec> { +fn collect_all_definitions(binding_graph: &BindingGraph) -> Vec> { let mut definitions: Vec> = Vec::new(); - for definition in bindings.all_definitions() { - if definition.get_file().is_user() && definition.get_cursor().is_some() { + for definition in binding_graph.all_definitions() { + 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,18 +104,14 @@ 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 }; - let definition = reference.jump_to_definition(); + let definition = reference.resolve_definition(); let message = match definition { Ok(definition) => { if definition.get_file().is_system() { diff --git a/crates/solidity/outputs/cargo/tests/src/bindings_output/runner.rs b/crates/solidity/outputs/cargo/tests/src/bindings_output/runner.rs index 4d7217163f..5daaf93288 100644 --- a/crates/solidity/outputs/cargo/tests/src/bindings_output/runner.rs +++ b/crates/solidity/outputs/cargo/tests/src/bindings_output/runner.rs @@ -1,19 +1,22 @@ use std::fs; +use std::rc::Rc; use anyhow::Result; use infra_utils::cargo::CargoWorkspace; use infra_utils::codegen::CodegenFileSystem; use infra_utils::paths::PathExtensions; use metaslang_graph_builder::graph::Graph; +use slang_solidity::bindings; use slang_solidity::cst::KindTypes; use slang_solidity::parser::{ParseOutput, Parser}; use super::graph::graphviz::render as render_graphviz_graph; use super::graph::mermaid::render as render_mermaid_graph; use super::renderer::render_bindings; -use crate::bindings::create_bindings; +use crate::bindings::lookup_definition_by_name; use crate::generated::VERSION_BREAKS; use crate::multi_part_file::{split_multi_file, Part}; +use crate::resolver::TestsPathResolver; pub(crate) struct ParsedPart<'a> { pub path: &'a str, @@ -42,7 +45,8 @@ pub fn run(group_name: &str, test_name: &str) -> Result<()> { for version in &VERSION_BREAKS { let parser = Parser::create(version.clone())?; - let mut bindings = create_bindings(version)?; + let mut binding_graph = + bindings::create_with_resolver(version.clone(), Rc::new(TestsPathResolver {}))?; let mut parsed_parts: Vec> = Vec::new(); let multi_part = split_multi_file(&contents); @@ -52,8 +56,8 @@ pub fn run(group_name: &str, test_name: &str) -> Result<()> { } in &multi_part.parts { let parse_output = parser.parse(Parser::ROOT_KIND, contents); - let graph = - bindings.add_user_file_returning_graph(path, parse_output.create_tree_cursor()); + let graph = binding_graph + .add_user_file_returning_graph(path, parse_output.create_tree_cursor()); parsed_parts.push(ParsedPart { path, contents, @@ -63,14 +67,13 @@ pub fn run(group_name: &str, test_name: &str) -> Result<()> { } if let Some(context) = multi_part.context { - let context_definition = bindings - .lookup_definition_by_name(context) + let context_definition = lookup_definition_by_name(&binding_graph, context) .expect("context definition to be found") .to_handle(); - bindings.set_context(&context_definition); + binding_graph.set_context(&context_definition); } - let (bindings_output, all_resolved) = render_bindings(&bindings, &parsed_parts)?; + let (bindings_output, all_resolved) = render_bindings(&binding_graph, &parsed_parts)?; let parse_success = parsed_parts.iter().all(|part| part.parse_output.is_valid()); let status = if parse_success && all_resolved { diff --git a/crates/solidity/outputs/cargo/tests/src/built_ins.rs b/crates/solidity/outputs/cargo/tests/src/built_ins.rs index 995602d5cb..f73340ea33 100644 --- a/crates/solidity/outputs/cargo/tests/src/built_ins.rs +++ b/crates/solidity/outputs/cargo/tests/src/built_ins.rs @@ -1,13 +1,14 @@ use anyhow::Result; +use slang_solidity::bindings::built_ins::get_built_ins_contents; +use slang_solidity::diagnostic; use slang_solidity::parser::Parser; -use slang_solidity::{bindings, diagnostic}; use crate::generated::VERSION_BREAKS; #[test] fn test_built_ins_parse_successfully() -> Result<()> { for version in &VERSION_BREAKS { - let built_ins = bindings::get_built_ins(version); + let built_ins = get_built_ins_contents(version); let parser = Parser::create(version.clone())?; let parse_output = parser.parse(Parser::ROOT_KIND, built_ins); diff --git a/crates/solidity/outputs/cargo/tests/src/resolver.rs b/crates/solidity/outputs/cargo/tests/src/resolver.rs index d428e24fb2..34c395adcd 100644 --- a/crates/solidity/outputs/cargo/tests/src/resolver.rs +++ b/crates/solidity/outputs/cargo/tests/src/resolver.rs @@ -1,16 +1,22 @@ use metaslang_bindings::PathResolver; +use slang_solidity::cst::{Cursor, KindTypes}; pub struct TestsPathResolver; -impl PathResolver for TestsPathResolver { - fn resolve_path(&self, context_path: &str, path_to_resolve: &str) -> Option { - if is_relative_path(path_to_resolve) { +impl PathResolver for TestsPathResolver { + fn resolve_path(&self, context_path: &str, path_to_resolve: &Cursor) -> Option { + let path = path_to_resolve.node().unparse(); + let path = path + .strip_prefix(|c| matches!(c, '"' | '\''))? + .strip_suffix(|c| matches!(c, '"' | '\''))?; + + if is_relative_path(path) { // Relative import: the actual path will be computed using the // context path (ie. the path of the importing source unit) - normalize_path(path_to_resolve, get_parent_path(context_path)) + normalize_path(path, get_parent_path(context_path)) } else { // Direct import: this path will be used as-is - Some(path_to_resolve.to_string()) + Some(path.to_owned()) } } } diff --git a/crates/solidity/outputs/cargo/wasm/Cargo.toml b/crates/solidity/outputs/cargo/wasm/Cargo.toml index d4a6399e87..a653d8509a 100644 --- a/crates/solidity/outputs/cargo/wasm/Cargo.toml +++ b/crates/solidity/outputs/cargo/wasm/Cargo.toml @@ -21,7 +21,10 @@ solidity_language = { workspace = true } paste = { workspace = true } semver = { workspace = true } serde_json = { workspace = true } -slang_solidity = { workspace = true } +slang_solidity = { workspace = true, features = [ + "__experimental_bindings_api", + "__private_compilation_api", +] } wit-bindgen = { workspace = true } [lints] diff --git a/crates/solidity/outputs/cargo/wasm/src/generated/generated/bindings.rs b/crates/solidity/outputs/cargo/wasm/src/generated/generated/bindgen.rs similarity index 100% rename from crates/solidity/outputs/cargo/wasm/src/generated/generated/bindings.rs rename to crates/solidity/outputs/cargo/wasm/src/generated/generated/bindgen.rs 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 395999cccb..3444eb9169 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,65 @@ { "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: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 + } + }, + "nomic-foundation:slang:compilation:compilation-unit.binding-graph()": { + "Function": { + "as_getter": true + } + }, + "nomic-foundation:slang:compilation:file.id()": { + "Function": { + "as_getter": true + } + }, + "nomic-foundation:slang:compilation:file.tree()": { + "Function": { + "as_getter": true + } + }, "nomic-foundation:slang:cst:terminal-kind": { "Enum": { "as_typescript_enum": true @@ -105,7 +165,7 @@ "as_iterator": true } }, - "nomic-foundation:slang:parser:parser.version()": { + "nomic-foundation:slang:parser:parser.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 new file mode 100644 index 0000000000..1721afc82d --- /dev/null +++ b/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/bindings.wit @@ -0,0 +1,72 @@ +// 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: borrow) -> option; + + /// If the provided cursor points at a reference `Identifier`, it will return the + /// corresponding reference. Otherwise, it will return `undefined`. + reference-at: func(cursor: borrow) -> option; + } + + /// 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. + definitions: func() -> list; + } + + /// 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/interface/generated/compilation.wit b/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/compilation.wit new file mode 100644 index 0000000000..c9db286d76 --- /dev/null +++ b/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/compilation.wit @@ -0,0 +1,68 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +interface compilation { + use bindings.{binding-graph}; + use cst.{node, cursor}; + + /// A builder for creating compilation units. + /// Allows incrementally building a transitive list of all files and their imports. + /// + /// This is an internal API, and exposed via a public `CompilationBuilder` wrapper class written in TypeScript. + /// This allows storing/invoking user supplied callbacks in TypeScript, rather than Rust, which has its limitations. + resource internal-compilation-builder { + /// Creates a new compilation builder for the specified language version. + create: static func(language-version: string) -> result; + + /// Adds a source file to the compilation unit. + add-file: func(id: string, contents: string) -> add-file-response; + + /// Resolves an import in the source file to the destination file. + resolve-import: func(source-file-id: string, import-path: borrow, destination-file-id: string) -> result<_, string>; + + /// Builds and returns the final compilation unit. + build: func() -> compilation-unit; + } + + /// Contains information about imports found in an added source file. + record add-file-response { + /// List of cursors to any import paths found in the file. + import-paths: list, + } + + /// A complete compilation unit is a complete view over all compilation inputs: + /// + /// - All source files, stored as CSTs. + /// - Name binding graph that exposes relationships between definitions and references in these files. + /// - Any relevant compilation options. + /// + /// It also exposes utilities to traverse the compilation unit and query it. + resource compilation-unit { + /// Returns the language version this compilation unit is configured for. + language-version: func() -> string; + + /// Returns a list of all files in the compilation unit. + files: func() -> list; + + /// Returns the file with the specified ID, if it exists. + file: func(id: string) -> option; + + /// Calculates name binding information for all source files within the compilation unit. + /// Returns a graph that contains all found definitions and their references. + /// + /// Note: building this graph is an expensive operation. + /// It is done lazily on the first access, and cached thereafter. + binding-graph: func() -> result; + } + + /// A single source file in the compilation unit. + resource file { + /// Returns the unique identifier of this file. + id: func() -> string; + + /// Returns the syntax tree of this file. + tree: func() -> node; + + /// Creates a cursor for traversing the syntax tree of this file. + create-tree-cursor: func() -> cursor; + } +} diff --git a/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/parser.wit b/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/parser.wit index 42b61577d4..6eca8e01ae 100644 --- a/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/parser.wit +++ b/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/parser.wit @@ -10,15 +10,11 @@ interface parser { /// This represents the starting point for parsing a complete source file. root-kind: static func() -> nonterminal-kind; - /// Returns a list of language versions supported by this parser. - /// Each version string represents a specific grammar configuration. - supported-versions: static func() -> list; - /// Creates a new parser instance for the specified language version. - create: static func(version: string) -> result; + create: static func(language-version: string) -> result; /// Returns the language version this parser instance is configured for. - version: func() -> string; + language-version: func() -> string; /// Parses the input string starting from the specified nonterminal kind. parse: func(kind: nonterminal-kind, input: string) -> parse-output; diff --git a/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/utils.wit b/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/utils.wit new file mode 100644 index 0000000000..9bb93e160f --- /dev/null +++ b/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/utils.wit @@ -0,0 +1,9 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +interface utils { + /// Provides information about the supported language versions and the grammar. + resource language-facts { + /// Returns a list of language versions supported by Slang, sorted ascendingly. + supported-versions: static func() -> list; + } +} diff --git a/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/world.wit b/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/world.wit index c5e1378860..bb9b7b10be 100644 --- a/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/world.wit +++ b/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/world.wit @@ -4,6 +4,9 @@ package nomic-foundation:slang; world slang { export ast; + export bindings; + export compilation; export cst; export parser; + export utils; } diff --git a/crates/solidity/outputs/cargo/wasm/src/generated/mod.rs b/crates/solidity/outputs/cargo/wasm/src/generated/mod.rs index c84d868d87..418be83d23 100644 --- a/crates/solidity/outputs/cargo/wasm/src/generated/mod.rs +++ b/crates/solidity/outputs/cargo/wasm/src/generated/mod.rs @@ -1,10 +1,10 @@ // This file is generated automatically by infrastructure scripts. Please don't edit by hand. -#[path = "./generated/bindings.rs"] -mod bindings; +#[path = "./generated/bindgen.rs"] +mod bindgen; mod utils; mod wrappers; struct World; -crate::wasm_crate::bindings::export!(World with_types_in crate::wasm_crate::bindings); +crate::wasm_crate::bindgen::export!(World with_types_in crate::wasm_crate::bindgen); diff --git a/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/ast/mod.rs b/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/ast/mod.rs index cf50ecacd2..2ccdcb4777 100644 --- a/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/ast/mod.rs +++ b/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/ast/mod.rs @@ -6,10 +6,10 @@ mod selectors; use crate::wasm_crate::utils::IntoFFI; mod ffi { - pub use crate::wasm_crate::bindings::exports::nomic_foundation::slang::ast::{ + pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::ast::{ Guest, GuestSelectors, }; - pub use crate::wasm_crate::bindings::exports::nomic_foundation::slang::cst::{ + pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::cst::{ Node, NonterminalNodeBorrow, }; } 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 new file mode 100644 index 0000000000..6163cf964f --- /dev/null +++ b/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/bindings/mod.rs @@ -0,0 +1,176 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +use crate::wasm_crate::utils::{define_rc_wrapper, define_wrapper, IntoFFI}; + +mod ffi { + pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::bindings::{ + BindingGraph, BindingGraphBorrow, BindingLocation, BuiltInLocation, BuiltInLocationBorrow, + CursorBorrow, Definition, DefinitionBorrow, Guest, GuestBindingGraph, GuestBuiltInLocation, + GuestDefinition, GuestReference, GuestUserFileLocation, Reference, ReferenceBorrow, + UserFileLocation, UserFileLocationBorrow, + }; + pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::cst::Cursor; +} + +mod rust { + pub use crate::rust_crate::bindings::{ + BindingGraph, BindingLocation, BuiltInLocation, UserFileLocation, + }; + + /// TODO: This is a work-around for the fact that `metaslang_bindings` internals (handles, locators, etc...) are exposed. + /// We should clean this when we finally publish `__experimental_bindings_api`. + /// That means removing the types below, and using the original types instead. + #[derive(Debug, Clone)] + pub struct Definition { + pub id: usize, + pub name_location: BindingLocation, + pub definiens_location: BindingLocation, + } + + impl From> for Definition { + fn from(definition: crate::rust_crate::bindings::Definition<'_>) -> Self { + Self { + id: definition.id(), + name_location: definition.name_location(), + definiens_location: definition.definiens_location(), + } + } + } + + /// TODO: This is a work-around for the fact that `metaslang_bindings` internals (handles, locators, etc...) are exposed. + /// We should clean this when we finally publish `__experimental_bindings_api`. + /// That means removing the types below, and using the original types instead. + #[derive(Debug, Clone)] + pub struct Reference { + pub id: usize, + pub location: BindingLocation, + pub definitions: Vec, + } + + impl From> for Reference { + fn from(reference: crate::rust_crate::bindings::Reference<'_>) -> Self { + Self { + id: reference.id(), + location: reference.location(), + definitions: reference + .definitions() + .into_iter() + .map(Into::into) + .collect(), + } + } + } +} + +impl ffi::Guest for crate::wasm_crate::World { + type BindingGraph = BindingGraphWrapper; + + type Definition = DefinitionWrapper; + type Reference = ReferenceWrapper; + + type UserFileLocation = UserFileLocationWrapper; + type BuiltInLocation = BuiltInLocationWrapper; +} + +//================================================ +// +// resource binding-graph +// +//================================================ + +define_rc_wrapper! { BindingGraph { + fn definition_at(&self, cursor: ffi::CursorBorrow<'_>) -> Option { + self._borrow_ffi() + .definition_at(&cursor._borrow_ffi()) + .map(rust::Definition::from) + .map(IntoFFI::_into_ffi) + } + + fn reference_at(&self, cursor: ffi::CursorBorrow<'_>) -> Option { + self._borrow_ffi() + .reference_at(&cursor._borrow_ffi()) + .map(rust::Reference::from) + .map(IntoFFI::_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.clone()._into_ffi() + } + + fn definiens_location(&self) -> ffi::BindingLocation { + self._borrow_ffi().definiens_location.clone()._into_ffi() + } +} } + +//================================================ +// +// resource reference +// +//================================================ + +define_wrapper! { Reference { + fn id(&self) -> u32 { + self._borrow_ffi().id.try_into().unwrap() + } + + fn location(&self) -> ffi::BindingLocation { + self._borrow_ffi().location.clone()._into_ffi() + } + + fn definitions(&self) -> Vec { + self._borrow_ffi().definitions.iter().cloned().map(IntoFFI::_into_ffi).collect() + } +} } + +//================================================ +// +// 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().to_owned()._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 new file mode 100644 index 0000000000..d168910020 --- /dev/null +++ b/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/compilation/mod.rs @@ -0,0 +1,122 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +use std::rc::Rc; + +use semver::Version; + +use crate::wasm_crate::utils::{define_rc_wrapper, define_refcell_wrapper, IntoFFI}; + +mod ffi { + pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::bindings::BindingGraph; + pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::compilation::{ + AddFileResponse, CompilationUnit, CompilationUnitBorrow, CursorBorrow, File, FileBorrow, + Guest, GuestCompilationUnit, GuestFile, GuestInternalCompilationBuilder, + InternalCompilationBuilder, InternalCompilationBuilderBorrow, + }; + pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::cst::{Cursor, Node}; +} + +mod rust { + pub use crate::rust_crate::compilation::{ + AddFileResponse, CompilationUnit, File, InternalCompilationBuilder, + }; +} + +impl ffi::Guest for crate::wasm_crate::World { + type InternalCompilationBuilder = InternalCompilationBuilderWrapper; + type CompilationUnit = CompilationUnitWrapper; + type File = FileWrapper; +} + +//================================================ +// +// resource internal-compilation-builder +// +//================================================ + +define_refcell_wrapper! { InternalCompilationBuilder { + fn create(language_version: String) -> Result { + let language_version = Version::parse(&language_version).map_err(|e| e.to_string())?; + + rust::InternalCompilationBuilder::create(language_version) + .map(IntoFFI::_into_ffi) + .map_err(|e| e.to_string()) + } + + fn add_file(&self, id: String, contents: String) -> ffi::AddFileResponse { + self._borrow_mut_ffi() + .add_file(id, &contents) + ._into_ffi() + } + + fn resolve_import(&self, source_file_id: String, import_path: ffi::CursorBorrow<'_>, destination_file_id: String) -> Result<(), String> { + self._borrow_mut_ffi() + .resolve_import(&source_file_id, &import_path._borrow_ffi(), destination_file_id) + .map_err(|e| e.to_string()) + } + + fn build(&self) -> ffi::CompilationUnit { + Rc::new(self._borrow_ffi().build())._into_ffi() + } +} } + +//================================================ +// +// record add-file-response +// +//================================================ + +impl IntoFFI for rust::AddFileResponse { + #[inline] + fn _into_ffi(self) -> ffi::AddFileResponse { + let Self { import_paths } = self; + + ffi::AddFileResponse { + import_paths: import_paths.into_iter().map(IntoFFI::_into_ffi).collect(), + } + } +} + +//================================================ +// +// resource compilation-unit +// +//================================================ + +define_rc_wrapper! { CompilationUnit { + fn language_version(&self) -> String { + self._borrow_ffi().language_version().to_string() + } + + fn files(&self) -> Vec { + self._borrow_ffi().files().into_iter().map(IntoFFI::_into_ffi).collect() + } + + fn file(&self, id: String) -> Option { + self._borrow_ffi().file(&id).map(IntoFFI::_into_ffi) + } + + fn binding_graph(&self) -> Result { + self._borrow_ffi().binding_graph().as_ref().map(Rc::clone).map(IntoFFI::_into_ffi).map_err(|e| e.to_string()) + } +} } + +//================================================ +// +// resource file +// +//================================================ + +define_rc_wrapper! { File { + fn id(&self) -> String { + self._borrow_ffi().id().to_owned() + } + + fn tree(&self) -> ffi::Node { + self._borrow_ffi().tree().to_owned()._into_ffi() + } + + fn create_tree_cursor(&self) -> ffi::Cursor { + self._borrow_ffi().create_tree_cursor()._into_ffi() + } +} } diff --git a/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/cst/mod.rs b/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/cst/mod.rs index 444cab2eab..deca6e2bb4 100644 --- a/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/cst/mod.rs +++ b/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/cst/mod.rs @@ -7,7 +7,7 @@ use crate::wasm_crate::utils::{ }; mod ffi { - pub use crate::wasm_crate::bindings::exports::nomic_foundation::slang::cst::{ + pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::cst::{ AncestorsIterator, AncestorsIteratorBorrow, Cursor, CursorBorrow, CursorIterator, CursorIteratorBorrow, Edge, EdgeLabel, Guest, GuestAncestorsIterator, GuestCursor, GuestCursorIterator, GuestNonterminalNode, GuestQuery, GuestQueryMatchIterator, diff --git a/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/mod.rs b/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/mod.rs index e05fee5635..6b289c658d 100644 --- a/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/mod.rs +++ b/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/mod.rs @@ -1,5 +1,8 @@ // This file is generated automatically by infrastructure scripts. Please don't edit by hand. mod ast; +mod bindings; +mod compilation; mod cst; mod parser; +mod utils; diff --git a/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/parser/mod.rs b/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/parser/mod.rs index d2e73f91de..01e073bb8d 100644 --- a/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/parser/mod.rs +++ b/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/parser/mod.rs @@ -5,10 +5,10 @@ use std::rc::Rc; use crate::wasm_crate::utils::{define_wrapper, FromFFI, IntoFFI}; mod ffi { - pub use crate::wasm_crate::bindings::exports::nomic_foundation::slang::cst::{ + pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::cst::{ Cursor, NonterminalNode, TextRange, }; - pub use crate::wasm_crate::bindings::exports::nomic_foundation::slang::parser::{ + pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::parser::{ Guest, GuestParseError, GuestParseOutput, GuestParser, NonterminalKind, ParseError, ParseErrorBorrow, ParseOutput, ParseOutputBorrow, Parser, ParserBorrow, }; @@ -35,22 +35,15 @@ define_wrapper! { Parser { rust::Parser::ROOT_KIND._into_ffi() } - fn supported_versions() -> Vec { - rust::Parser::SUPPORTED_VERSIONS - .iter() - .map(|v| v.to_string()) - .collect() - } - - fn create(version: String) -> Result { - semver::Version::parse(&version) - .map_err(|_| format!("Invalid semantic version: '{version}'")) + fn create(language_version: String) -> Result { + semver::Version::parse(&language_version) + .map_err(|_| format!("Invalid semantic version: '{language_version}'")) .and_then(|version| rust::Parser::create(version).map_err(|e| e.to_string())) .map(IntoFFI::_into_ffi) } - fn version(&self) -> String { - self._borrow_ffi().version.to_string() + fn language_version(&self) -> String { + self._borrow_ffi().language_version().to_string() } fn parse(&self, kind: ffi::NonterminalKind, input: String) -> ffi::ParseOutput { diff --git a/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/utils/mod.rs b/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/utils/mod.rs new file mode 100644 index 0000000000..b478ca4299 --- /dev/null +++ b/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/utils/mod.rs @@ -0,0 +1,32 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +use crate::wasm_crate::utils::define_wrapper; + +mod ffi { + pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::utils::{ + Guest, GuestLanguageFacts, LanguageFacts, LanguageFactsBorrow, + }; +} + +mod rust { + pub use crate::rust_crate::utils::LanguageFacts; +} + +impl ffi::Guest for crate::wasm_crate::World { + type LanguageFacts = LanguageFactsWrapper; +} + +//================================================ +// +// resource language-facts +// +//================================================ + +define_wrapper! { LanguageFacts { + fn supported_versions() -> Vec { + rust::LanguageFacts::SUPPORTED_VERSIONS + .iter() + .map(|v| v.to_string()) + .collect() + } +} } diff --git a/crates/solidity/outputs/npm/package/package.json b/crates/solidity/outputs/npm/package/package.json index 1f2a26bfda..c7fba2b62c 100644 --- a/crates/solidity/outputs/npm/package/package.json +++ b/crates/solidity/outputs/npm/package/package.json @@ -46,8 +46,11 @@ "exports": { ".": "./target/generated/index.mjs", "./ast": "./target/generated/ast/index.mjs", + "./bindings": "./target/generated/bindings/index.mjs", + "./compilation": "./target/generated/compilation/index.mjs", "./cst": "./target/generated/cst/index.mjs", - "./parser": "./target/generated/parser/index.mjs" + "./parser": "./target/generated/parser/index.mjs", + "./utils": "./target/generated/utils/index.mjs" }, "__dependencies_comment__": "__SLANG_NPM_PACKAGE_DEPENDENCIES__ (keep in sync)", "dependencies": { diff --git a/crates/solidity/outputs/npm/package/src/generated/bindings/index.mts b/crates/solidity/outputs/npm/package/src/generated/bindings/index.mts new file mode 100644 index 0000000000..7263f31bdc --- /dev/null +++ b/crates/solidity/outputs/npm/package/src/generated/bindings/index.mts @@ -0,0 +1,23 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +import * as generated from "../../../wasm/index.mjs"; + +export const BindingGraph = generated.bindings.BindingGraph; +export type BindingGraph = generated.bindings.BindingGraph; + +export const Definition = generated.bindings.Definition; +export type Definition = generated.bindings.Definition; + +export const Reference = generated.bindings.Reference; +export type Reference = generated.bindings.Reference; + +export type BindingLocation = generated.bindings.BindingLocation; + +export const BindingLocationType = generated.bindings.BindingLocationType; +export type BindingLocationType = generated.bindings.BindingLocationType; + +export const UserFileLocation = generated.bindings.UserFileLocation; +export type UserFileLocation = generated.bindings.UserFileLocation; + +export const BuiltInLocation = generated.bindings.BuiltInLocation; +export type BuiltInLocation = generated.bindings.BuiltInLocation; diff --git a/crates/solidity/outputs/npm/package/src/generated/compilation/builder.mts b/crates/solidity/outputs/npm/package/src/generated/compilation/builder.mts new file mode 100644 index 0000000000..4649389f8b --- /dev/null +++ b/crates/solidity/outputs/npm/package/src/generated/compilation/builder.mts @@ -0,0 +1,114 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +import { Cursor } from "../cst/index.mjs"; +import { CompilationUnit } from "./index.mjs"; + +import * as generated from "../../../wasm/index.mjs"; + +const InternalCompilationBuilder = generated.compilation.InternalCompilationBuilder; +type InternalCompilationBuilder = generated.compilation.InternalCompilationBuilder; + +/** + * User-provided options and callbacks necessary for the `CompilationBuilder` class to perform its job. + */ +export interface CompilationBuilderConfig { + /** + * The language version to parse files with. + */ + languageVersion: string; + + /** + * Callback used by this builder to load the contents of a file. + * + * The user is responsible for fetching the file from the filesystem. + * If the file is not found, the callback should return undefined. + * Any errors thrown by the callback will be propagated to the caller. + */ + readFile: (fileId: string) => Promise; + + /** + * Callback used by this builder to resolve an import path. + * For example, if a source file contains the following statement: + * + * ```solidity + * import {Foo} from "foo.sol"; + * ``` + * + * Then the API will invoke the callback with a cursor pointing to the `"foo.sol"` string literal. + * + * The user is responsible for resolving it to a file in the compilation, and return its ID. + * If the callback returns `undefined`, the import will stay unresolved. + * Any errors thrown by the callback will be propagated to the caller. + */ + resolveImport: (sourceFileId: string, importPath: Cursor) => Promise; +} + +/** + * A builder for creating compilation units. + * Allows incrementally building a list of all files and their imports. + */ +export class CompilationBuilder { + private readonly seenFiles: Set = new Set(); + + private constructor( + private readonly internalBuilder: InternalCompilationBuilder, + + /** + * The user-supplied configuration. + */ + public readonly config: CompilationBuilderConfig, + ) {} + + /** + * Creates a new compilation builder for the specified language version. + */ + public static create(config: CompilationBuilderConfig): CompilationBuilder { + const internalBuilder = InternalCompilationBuilder.create(config.languageVersion); + return new CompilationBuilder(internalBuilder, config); + } + + /** + * Adds a source file to the compilation unit. + * Typically, users only need to add the "root" file, which contains the main contract they are trying to analyze. + * Any files that are imported by the root file will be discovered and loaded automatically by the config callbacks. + * + * Adding multiple files (roots) is supported. For example, an IDE can choose to add all NPM dependencies, + * regardless of whether they are imported or not, to be able to query the definitions there. + * + * Adding a file that has already been added is a no-op. + */ + public async addFile(id: string): Promise { + if (this.seenFiles.has(id)) { + return; + } else { + this.seenFiles.add(id); + } + + const contents = await this.config.readFile(id); + if (contents === undefined) { + return; + } + + const { importPaths } = this.internalBuilder.addFile(id, contents); + + await Promise.all( + importPaths.map(async (importPath) => { + const destinationFileId = await this.config.resolveImport(id, importPath); + if (destinationFileId === undefined) { + return; + } + + this.internalBuilder.resolveImport(id, importPath, destinationFileId); + + await this.addFile(destinationFileId); + }), + ); + } + + /** + * Builds and returns the final compilation unit. + */ + public build(): CompilationUnit { + return this.internalBuilder.build(); + } +} diff --git a/crates/solidity/outputs/npm/package/src/generated/compilation/index.mts b/crates/solidity/outputs/npm/package/src/generated/compilation/index.mts new file mode 100644 index 0000000000..832fe073b8 --- /dev/null +++ b/crates/solidity/outputs/npm/package/src/generated/compilation/index.mts @@ -0,0 +1,16 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +import * as generated from "../../../wasm/index.mjs"; +import * as builder from "./builder.mjs"; + +// This is a wrapper around 'generated.compilation.InternalCompilationBuilder': +export const CompilationBuilder = builder.CompilationBuilder; +export type CompilationBuilder = builder.CompilationBuilder; + +export type CompilationBuilderConfig = builder.CompilationBuilderConfig; + +export const CompilationUnit = generated.compilation.CompilationUnit; +export type CompilationUnit = generated.compilation.CompilationUnit; + +export const File = generated.compilation.File; +export type File = generated.compilation.File; diff --git a/crates/solidity/outputs/npm/package/src/generated/cst/index.mts b/crates/solidity/outputs/npm/package/src/generated/cst/index.mts index 9ceb7c6f40..2bb806862e 100644 --- a/crates/solidity/outputs/npm/package/src/generated/cst/index.mts +++ b/crates/solidity/outputs/npm/package/src/generated/cst/index.mts @@ -50,10 +50,9 @@ export type TextIndex = generated.cst.TextIndex; export type TextRange = generated.cst.TextRange; -/* - * Helpers: +/** + * Asserts that this node is a `NonterminalNode` with the provided kind and text. */ - export function assertIsNonterminalNode( node: unknown, kind?: NonterminalKind, @@ -72,6 +71,9 @@ export function assertIsNonterminalNode( } } +/** + * Asserts that this node is a `TerminalKind` with the provided kind and text. + */ export function assertIsTerminalNode(node: unknown, kind?: TerminalKind, text?: string): asserts node is TerminalNode { if (!(node instanceof TerminalNode)) { throw new Error("Node provided is not a TerminalNode."); diff --git a/crates/solidity/outputs/npm/package/src/generated/index.mts b/crates/solidity/outputs/npm/package/src/generated/index.mts index 847cd1d82b..9aa39203ba 100644 --- a/crates/solidity/outputs/npm/package/src/generated/index.mts +++ b/crates/solidity/outputs/npm/package/src/generated/index.mts @@ -1,5 +1,8 @@ // This file is generated automatically by infrastructure scripts. Please don't edit by hand. export * as ast from "./ast/index.mjs"; +export * as bindings from "./bindings/index.mjs"; +export * as compilation from "./compilation/index.mjs"; export * as cst from "./cst/index.mjs"; export * as parser from "./parser/index.mjs"; +export * as utils from "./utils/index.mjs"; diff --git a/crates/solidity/outputs/npm/package/src/generated/utils/index.mts b/crates/solidity/outputs/npm/package/src/generated/utils/index.mts new file mode 100644 index 0000000000..f1b7780fcb --- /dev/null +++ b/crates/solidity/outputs/npm/package/src/generated/utils/index.mts @@ -0,0 +1,6 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +import * as generated from "../../../wasm/index.mjs"; + +export const LanguageFacts = generated.utils.LanguageFacts; +export type LanguageFacts = generated.utils.LanguageFacts; diff --git a/crates/solidity/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-bindings.d.ts b/crates/solidity/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-bindings.d.ts new file mode 100644 index 0000000000..b2b0d4dc94 --- /dev/null +++ b/crates/solidity/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-bindings.d.ts @@ -0,0 +1,153 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +export namespace NomicFoundationSlangBindings { + export { BindingGraph }; + export { Definition }; + export { Reference }; + export { UserFileLocation }; + export { BuiltInLocation }; + export { BindingLocation }; + export { BindingLocationType }; +} +import type { Cursor } from "./nomic-foundation-slang-cst.js"; +export { Cursor }; +/** + * 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. + */ +export type BindingLocation = UserFileLocation | BuiltInLocation; +export enum BindingLocationType { + UserFileLocation = "UserFileLocation", + BuiltInLocation = "BuiltInLocation", +} + +/** + * 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. + */ +export class BindingGraph { + /** + * If the provided cursor points at a definition `Identifier`, it will return the + * corresponding definition. Otherwise, it will return `undefined`. + */ + definitionAt(cursor: Cursor): Definition | undefined; + /** + * If the provided cursor points at a reference `Identifier`, it will return the + * corresponding reference. Otherwise, it will return `undefined`. + */ + referenceAt(cursor: Cursor): Reference | undefined; +} + +/** + * Represents a location of a built-in symbol in the language. + */ +export class BuiltInLocation { + /** + * The variant of `BindingLocationType` that corresponds to this class. + */ + readonly type = BindingLocationType.BuiltInLocation; + + /** + * Coerce this variant to a `BuiltInLocation`, or `undefined` if this is not the correct type. + */ + asBuiltInLocation(): this; + + /** + * Return `true` if this object is an instance of `BuiltInLocation`. + */ + isBuiltInLocation(): this is BuiltInLocation; + + /** + * Coerce this variant to a `UserFileLocation`, or `undefined` if this is not the correct type. + */ + asUserFileLocation(): undefined; + + /** + * Return `true` if this object is an instance of `UserFileLocation`. + */ + isUserFileLocation(): false; +} + +/** + * Represents a definition in the binding graph. + */ +export class 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. + */ + get id(): number; + /** + * Returns the location of the definition's name. + * For `contract X {}`, that is the location of the `X` `Identifier` node. + */ + get nameLocation(): BindingLocation; + /** + * Returns the location of the definition's definiens. + * For `contract X {}`, that is the location of the parent `ContractDefinition` node. + */ + get definiensLocation(): BindingLocation; +} + +/** + * Represents a reference in the binding graph. + */ +export class 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. + */ + get id(): number; + /** + * Returns the location of the reference. + * For `new X()`, that is the location of the `X` `Identifier` node. + */ + get location(): BindingLocation; + /** + * 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. + */ + definitions(): Definition[]; +} + +/** + * Represents a location of a user-defined symbol in a user file. + */ +export class UserFileLocation { + /** + * The variant of `BindingLocationType` that corresponds to this class. + */ + readonly type = BindingLocationType.UserFileLocation; + + /** + * Coerce this variant to a `UserFileLocation`, or `undefined` if this is not the correct type. + */ + asUserFileLocation(): this; + + /** + * Return `true` if this object is an instance of `UserFileLocation`. + */ + isUserFileLocation(): this is UserFileLocation; + + /** + * Coerce this variant to a `BuiltInLocation`, or `undefined` if this is not the correct type. + */ + asBuiltInLocation(): undefined; + + /** + * Return `true` if this object is an instance of `BuiltInLocation`. + */ + isBuiltInLocation(): false; + + /** + * Returns the ID of the file that contains the symbol. + */ + get fileId(): string; + /** + * Returns a cursor to the CST node that contains the symbol. + */ + get cursor(): Cursor; +} diff --git a/crates/solidity/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-compilation.d.ts b/crates/solidity/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-compilation.d.ts new file mode 100644 index 0000000000..3c1a6831c1 --- /dev/null +++ b/crates/solidity/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-compilation.d.ts @@ -0,0 +1,98 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +export namespace NomicFoundationSlangCompilation { + export { InternalCompilationBuilder }; + export { CompilationUnit }; + export { File }; +} +import type { BindingGraph } from "./nomic-foundation-slang-bindings.js"; +export { BindingGraph }; +import type { Node } from "./nomic-foundation-slang-cst.js"; +export { Node }; +import type { Cursor } from "./nomic-foundation-slang-cst.js"; +export { Cursor }; +/** + * Contains information about imports found in an added source file. + */ +export interface AddFileResponse { + /** + * List of cursors to any import paths found in the file. + */ + importPaths: Cursor[]; +} + +/** + * A complete compilation unit is a complete view over all compilation inputs: + * + * - All source files, stored as CSTs. + * - Name binding graph that exposes relationships between definitions and references in these files. + * - Any relevant compilation options. + * + * It also exposes utilities to traverse the compilation unit and query it. + */ +export class CompilationUnit { + /** + * Returns the language version this compilation unit is configured for. + */ + get languageVersion(): string; + /** + * Returns a list of all files in the compilation unit. + */ + files(): File[]; + /** + * Returns the file with the specified ID, if it exists. + */ + file(id: string): File | undefined; + /** + * Calculates name binding information for all source files within the compilation unit. + * Returns a graph that contains all found definitions and their references. + * + * Note: building this graph is an expensive operation. + * It is done lazily on the first access, and cached thereafter. + */ + get bindingGraph(): BindingGraph; +} + +/** + * A single source file in the compilation unit. + */ +export class File { + /** + * Returns the unique identifier of this file. + */ + get id(): string; + /** + * Returns the syntax tree of this file. + */ + get tree(): Node; + /** + * Creates a cursor for traversing the syntax tree of this file. + */ + createTreeCursor(): Cursor; +} + +/** + * A builder for creating compilation units. + * Allows incrementally building a transitive list of all files and their imports. + * + * This is an internal API, and exposed via a public `CompilationBuilder` wrapper class written in TypeScript. + * This allows storing/invoking user supplied callbacks in TypeScript, rather than Rust, which has its limitations. + */ +export class InternalCompilationBuilder { + /** + * Creates a new compilation builder for the specified language version. + */ + static create(languageVersion: string): InternalCompilationBuilder; + /** + * Adds a source file to the compilation unit. + */ + addFile(id: string, contents: string): AddFileResponse; + /** + * Resolves an import in the source file to the destination file. + */ + resolveImport(sourceFileId: string, importPath: Cursor, destinationFileId: string): void; + /** + * Builds and returns the final compilation unit. + */ + build(): CompilationUnit; +} diff --git a/crates/solidity/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-parser.d.ts b/crates/solidity/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-parser.d.ts index ba8ffd64a0..07fe4156a6 100644 --- a/crates/solidity/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-parser.d.ts +++ b/crates/solidity/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-parser.d.ts @@ -65,19 +65,14 @@ export class Parser { * This represents the starting point for parsing a complete source file. */ static rootKind(): NonterminalKind; - /** - * Returns a list of language versions supported by this parser. - * Each version string represents a specific grammar configuration. - */ - static supportedVersions(): string[]; /** * Creates a new parser instance for the specified language version. */ - static create(version: string): Parser; + static create(languageVersion: string): Parser; /** * Returns the language version this parser instance is configured for. */ - get version(): string; + get languageVersion(): string; /** * Parses the input string starting from the specified nonterminal kind. */ diff --git a/crates/solidity/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-utils.d.ts b/crates/solidity/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-utils.d.ts new file mode 100644 index 0000000000..0a3e19de1c --- /dev/null +++ b/crates/solidity/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-utils.d.ts @@ -0,0 +1,15 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +export namespace NomicFoundationSlangUtils { + export { LanguageFacts }; +} + +/** + * Provides information about the supported language versions and the grammar. + */ +export class LanguageFacts { + /** + * Returns a list of language versions supported by Slang, sorted ascendingly. + */ + static supportedVersions(): string[]; +} diff --git a/crates/solidity/outputs/npm/package/wasm/generated/solidity_cargo_wasm.component.d.ts b/crates/solidity/outputs/npm/package/wasm/generated/solidity_cargo_wasm.component.d.ts index c7614866dd..959f0ad174 100644 --- a/crates/solidity/outputs/npm/package/wasm/generated/solidity_cargo_wasm.component.d.ts +++ b/crates/solidity/outputs/npm/package/wasm/generated/solidity_cargo_wasm.component.d.ts @@ -2,7 +2,13 @@ import { NomicFoundationSlangCst } from "./interfaces/nomic-foundation-slang-cst.js"; import { NomicFoundationSlangAst } from "./interfaces/nomic-foundation-slang-ast.js"; +import { NomicFoundationSlangBindings } from "./interfaces/nomic-foundation-slang-bindings.js"; +import { NomicFoundationSlangCompilation } from "./interfaces/nomic-foundation-slang-compilation.js"; import { NomicFoundationSlangParser } from "./interfaces/nomic-foundation-slang-parser.js"; +import { NomicFoundationSlangUtils } from "./interfaces/nomic-foundation-slang-utils.js"; export * as cst from "./interfaces/nomic-foundation-slang-cst.js"; export * as ast from "./interfaces/nomic-foundation-slang-ast.js"; +export * as bindings from "./interfaces/nomic-foundation-slang-bindings.js"; +export * as compilation from "./interfaces/nomic-foundation-slang-compilation.js"; export * as parser from "./interfaces/nomic-foundation-slang-parser.js"; +export * as utils from "./interfaces/nomic-foundation-slang-utils.js"; diff --git a/crates/solidity/outputs/npm/tests/src/compilation/binding-graph.test.mts b/crates/solidity/outputs/npm/tests/src/compilation/binding-graph.test.mts new file mode 100644 index 0000000000..085833e71a --- /dev/null +++ b/crates/solidity/outputs/npm/tests/src/compilation/binding-graph.test.mts @@ -0,0 +1,123 @@ +import assert from "node:assert"; +import { NonterminalKind, TerminalKind } from "@nomicfoundation/slang/cst"; +import { createBuilder } from "./common.mjs"; +import { BindingLocation } from "@nomicfoundation/slang/bindings"; + +test("binding graph", async () => { + const builder = await createBuilder(); + await builder.addFile("child.sol"); + + const unit = builder.build(); + const cursor = unit.file("child.sol")!.createTreeCursor(); + + // import { Parent } from "./parent.sol"; + // ^^^^^^ + assert(cursor.goToNextTerminalWithKind(TerminalKind.Identifier)); + assert.equal(cursor.node.unparse(), "Parent"); + + { + const definition = unit.bindingGraph.definitionAt(cursor)!; + assertUserFileLocation(definition.nameLocation, "child.sol", TerminalKind.Identifier, 3); + assertUserFileLocation(definition.definiensLocation, "child.sol", NonterminalKind.ImportDeconstructionSymbol, 3); + } + + { + const reference = unit.bindingGraph.referenceAt(cursor)!; + assertUserFileLocation(reference.location, "child.sol", TerminalKind.Identifier, 3); + + const defs = reference.definitions(); + assert.equal(defs.length, 1); + + assertUserFileLocation(defs[0]!.nameLocation, "parent.sol", TerminalKind.Identifier, 3); + assertUserFileLocation(defs[0]!.definiensLocation, "parent.sol", NonterminalKind.ContractDefinition, 2); + } + + // contract Child is Parent { + // ^^^^^ + assert(cursor.goToNextTerminalWithKind(TerminalKind.Identifier)); + assert.equal(cursor.node.unparse(), "Child"); + + { + const definition = unit.bindingGraph.definitionAt(cursor)!; + assertUserFileLocation(definition.nameLocation, "child.sol", TerminalKind.Identifier, 5); + assertUserFileLocation(definition.definiensLocation, "child.sol", NonterminalKind.ContractDefinition, 4); + } + + { + assert.equal(unit.bindingGraph.referenceAt(cursor), undefined); + } + + // contract Child is Parent { + // ^^^^^^ + assert(cursor.goToNextTerminalWithKind(TerminalKind.Identifier)); + assert.equal(cursor.node.unparse(), "Parent"); + + { + assert.equal(unit.bindingGraph.definitionAt(cursor), undefined); + } + + { + const reference = unit.bindingGraph.referenceAt(cursor)!; + assertUserFileLocation(reference.location, "child.sol", TerminalKind.Identifier, 5); + + const defs = reference.definitions(); + assert.equal(defs.length, 2); + + assertUserFileLocation(defs[0]!.nameLocation, "child.sol", TerminalKind.Identifier, 3); + assertUserFileLocation(defs[0]!.definiensLocation, "child.sol", NonterminalKind.ImportDeconstructionSymbol, 3); + + assertUserFileLocation(defs[1]!.nameLocation, "parent.sol", TerminalKind.Identifier, 3); + assertUserFileLocation(defs[1]!.definiensLocation, "parent.sol", NonterminalKind.ContractDefinition, 2); + } + + // function foo() public pure { + // ^^^ + assert(cursor.goToNextTerminalWithKind(TerminalKind.Identifier)); + assert.equal(cursor.node.unparse(), "foo"); + + { + const definition = unit.bindingGraph.definitionAt(cursor)!; + assertUserFileLocation(definition.nameLocation, "child.sol", TerminalKind.Identifier, 6); + assertUserFileLocation(definition.definiensLocation, "child.sol", NonterminalKind.FunctionDefinition, 6); + } + + { + assert.equal(unit.bindingGraph.referenceAt(cursor), undefined); + } + + // assert(true); + // ^^^^^^ + assert(cursor.goToNextTerminalWithKind(TerminalKind.Identifier)); + assert.equal(cursor.node.unparse(), "assert"); + + { + assert.equal(unit.bindingGraph.definitionAt(cursor), undefined); + } + + { + const reference = unit.bindingGraph.referenceAt(cursor)!; + assertUserFileLocation(reference.location, "child.sol", TerminalKind.Identifier, 7); + + const defs = reference.definitions(); + assert.equal(defs.length, 1); + + assert(defs[0]!.nameLocation.isBuiltInLocation()); + assert(defs[0]!.definiensLocation.isBuiltInLocation()); + } + + // Done! No more identifiers in the file. + assert(!cursor.goToNextTerminalWithKind(TerminalKind.Identifier)); +}); + +function assertUserFileLocation( + location: BindingLocation, + fileId: string, + kind: TerminalKind | NonterminalKind, + line: number, +) { + assert(location.isUserFileLocation()); + + assert.equal(location.fileId, fileId); + assert.equal(location.cursor.node.kind, kind); + assert.equal(location.cursor.textRange.start.line, line); +} diff --git a/crates/solidity/outputs/npm/tests/src/compilation/builder.test.mts b/crates/solidity/outputs/npm/tests/src/compilation/builder.test.mts new file mode 100644 index 0000000000..1fde3e41f0 --- /dev/null +++ b/crates/solidity/outputs/npm/tests/src/compilation/builder.test.mts @@ -0,0 +1,44 @@ +import assert from "node:assert"; +import { CompilationBuilder } from "@nomicfoundation/slang/compilation"; +import { NonterminalKind } from "@nomicfoundation/slang/cst"; +import { createBuilder } from "./common.mjs"; + +test("empty builder", async () => { + const builder = await createBuilder(); + + assertFiles(builder, []); +}); + +test("parent file without imports", async () => { + const builder = await createBuilder(); + + await builder.addFile("parent.sol"); + + assertFiles(builder, ["parent.sol"]); +}); + +test("child file with one import", async () => { + const builder = await createBuilder(); + + await builder.addFile("child.sol"); + + assertFiles(builder, ["parent.sol", "child.sol"]); +}); + +function assertFiles(builder: CompilationBuilder, expected: string[]) { + const unit = builder.build(); + + const actual = unit.files().map((file) => { + assert.strictEqual(file.tree.kind, NonterminalKind.SourceUnit); + assert.strictEqual(file.tree.id, file.createTreeCursor().node.id); + + return file.id; + }); + + for (const id of actual) { + const file = unit.file(id)!; + assert.strictEqual(file.id, id); + } + + assert.deepEqual(actual.sort(), expected.sort()); +} diff --git a/crates/solidity/outputs/npm/tests/src/compilation/common.mts b/crates/solidity/outputs/npm/tests/src/compilation/common.mts new file mode 100644 index 0000000000..ea7805da0b --- /dev/null +++ b/crates/solidity/outputs/npm/tests/src/compilation/common.mts @@ -0,0 +1,25 @@ +import path from "node:path"; +import assert from "node:assert"; +import { CompilationBuilder } from "@nomicfoundation/slang/compilation"; +import { readRepoFile } from "../utils/files.mjs"; + +export async function createBuilder(): Promise { + const builder = CompilationBuilder.create({ + languageVersion: "0.8.0", + + readFile: async (fileId) => { + return readRepoFile("crates/solidity/outputs/npm/tests/src/compilation/inputs", fileId); + }, + + resolveImport: async (sourceFileId, importPath) => { + const importLiteral = importPath.node.unparse(); + assert(importLiteral.startsWith('"')); + assert(importLiteral.endsWith('"')); + + const importString = importLiteral.slice(1, -1); + return path.join(sourceFileId, "..", importString); + }, + }); + + return builder; +} diff --git a/crates/solidity/outputs/npm/tests/src/compilation/inputs/child.sol b/crates/solidity/outputs/npm/tests/src/compilation/inputs/child.sol new file mode 100644 index 0000000000..074be93fbd --- /dev/null +++ b/crates/solidity/outputs/npm/tests/src/compilation/inputs/child.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity x.x.x; + +import { Parent } from "./parent.sol"; + +contract Child is Parent { + function foo() public pure { + assert(true); + } +} diff --git a/crates/solidity/outputs/npm/tests/src/compilation/inputs/parent.sol b/crates/solidity/outputs/npm/tests/src/compilation/inputs/parent.sol new file mode 100644 index 0000000000..9e6b2447c1 --- /dev/null +++ b/crates/solidity/outputs/npm/tests/src/compilation/inputs/parent.sol @@ -0,0 +1,4 @@ +// SPDX-License-Identifier: MIT +pragma solidity x.x.x; + +contract Parent {} diff --git a/crates/solidity/testing/perf/benches/iai/main.rs b/crates/solidity/testing/perf/benches/iai/main.rs index 1957df012e..e9216a4f29 100644 --- a/crates/solidity/testing/perf/benches/iai/main.rs +++ b/crates/solidity/testing/perf/benches/iai/main.rs @@ -7,8 +7,7 @@ use iai_callgrind::{ library_benchmark, library_benchmark_group, main, Direction, FlamegraphConfig, LibraryBenchmarkConfig, Tool, ValgrindTool, }; -use slang_solidity::bindings::Bindings; -use slang_solidity::parser::ParseOutput; +use slang_solidity::bindings::BindingGraph; use solidity_testing_perf::dataset::SourceFile; use solidity_testing_perf::tests::definitions::Dependencies; use solidity_testing_perf::tests::parser::ParsedFile; @@ -18,6 +17,14 @@ mod __dependencies_used_in_lib__ { } macro_rules! define_benchmark { + ($name:ident) => { + #[library_benchmark] + fn $name() { + black_box(solidity_testing_perf::tests::$name::run()); + } + }; +} +macro_rules! define_payload_benchmark { ($name:ident, $payload:ty) => { #[library_benchmark(setup = solidity_testing_perf::tests::$name::setup)] fn $name(payload: $payload) { @@ -33,12 +40,12 @@ macro_rules! define_benchmark { * * __SLANG_INFRA_BENCHMARKS_LIST__ (keep in sync) */ -define_benchmark!(parser, Vec); -define_benchmark!(cursor, Vec); -define_benchmark!(query, Vec); -define_benchmark!(init_bindings, ParseOutput); -define_benchmark!(definitions, Dependencies); -define_benchmark!(references, Bindings); +define_payload_benchmark!(parser, Vec); +define_payload_benchmark!(cursor, Vec); +define_payload_benchmark!(query, Vec); +define_benchmark!(init_bindings); +define_payload_benchmark!(definitions, Dependencies); +define_payload_benchmark!(references, BindingGraph); library_benchmark_group!( name = benchmarks; diff --git a/crates/solidity/testing/perf/src/lib.rs b/crates/solidity/testing/perf/src/lib.rs index 7819ab9ea0..0b25500b67 100644 --- a/crates/solidity/testing/perf/src/lib.rs +++ b/crates/solidity/testing/perf/src/lib.rs @@ -12,6 +12,14 @@ mod __dependencies_used_in_benches__ { #[cfg(test)] mod unit_tests { macro_rules! define_test { + ($name:ident) => { + #[test] + fn $name() { + crate::tests::$name::run(); + } + }; + } + macro_rules! define_payload_test { ($name:ident) => { #[test] fn $name() { @@ -24,10 +32,10 @@ mod unit_tests { /* * __SLANG_INFRA_BENCHMARKS_LIST__ (keep in sync) */ - define_test!(parser); - define_test!(cursor); - define_test!(query); + define_payload_test!(parser); + define_payload_test!(cursor); + define_payload_test!(query); define_test!(init_bindings); - define_test!(definitions); - define_test!(references); + define_payload_test!(definitions); + define_payload_test!(references); } diff --git a/crates/solidity/testing/perf/src/tests/definitions.rs b/crates/solidity/testing/perf/src/tests/definitions.rs index 047651d0f6..a41134c328 100644 --- a/crates/solidity/testing/perf/src/tests/definitions.rs +++ b/crates/solidity/testing/perf/src/tests/definitions.rs @@ -1,23 +1,26 @@ -use slang_solidity::bindings::Bindings; +use slang_solidity::bindings::BindingGraph; use crate::tests::parser::ParsedFile; pub struct Dependencies { - pub bindings: Bindings, + pub binding_graph: BindingGraph, pub files: Vec, } pub fn setup() -> Dependencies { - let bindings = super::init_bindings::run(super::init_bindings::setup()); + let binding_graph = super::init_bindings::run(); let files = super::parser::run(super::parser::setup()); - Dependencies { bindings, files } + Dependencies { + binding_graph, + files, + } } -pub fn run(dependencies: Dependencies) -> Bindings { +pub fn run(dependencies: Dependencies) -> BindingGraph { let mut definition_count = 0_usize; let Dependencies { - mut bindings, + mut binding_graph, files, } = dependencies; @@ -27,11 +30,14 @@ pub fn run(dependencies: Dependencies) -> Bindings { parse_output, } in &files { - bindings.add_user_file(path.to_str().unwrap(), parse_output.create_tree_cursor()); - definition_count += bindings.all_definitions().count(); + binding_graph.add_user_file(path.to_str().unwrap(), parse_output.create_tree_cursor()); + definition_count += binding_graph + .all_definitions() + .filter(|definition| definition.get_file().is_user()) + .count(); } - assert_eq!(definition_count, 2832, "Failed to fetch all definitions"); + assert_eq!(definition_count, 2322, "Failed to fetch all definitions"); - bindings + binding_graph } diff --git a/crates/solidity/testing/perf/src/tests/init_bindings.rs b/crates/solidity/testing/perf/src/tests/init_bindings.rs index 78119d2533..f46ffa186c 100644 --- a/crates/solidity/testing/perf/src/tests/init_bindings.rs +++ b/crates/solidity/testing/perf/src/tests/init_bindings.rs @@ -1,33 +1,24 @@ -use std::sync::Arc; +use std::rc::Rc; use metaslang_bindings::PathResolver; -use slang_solidity::bindings::{create_with_resolver, get_built_ins, Bindings}; -use slang_solidity::parser::{ParseOutput, Parser}; +use slang_solidity::bindings::{create_with_resolver, BindingGraph}; +use slang_solidity::cst::{Cursor, KindTypes}; use crate::dataset::SOLC_VERSION; -pub fn setup() -> ParseOutput { - let parser = Parser::create(SOLC_VERSION).unwrap(); - - let built_ins = parser.parse(Parser::ROOT_KIND, get_built_ins(&SOLC_VERSION)); - - assert!(built_ins.is_valid(), "built-ins parse without errors"); - - built_ins -} - -pub fn run(built_ins: ParseOutput) -> Bindings { - let mut bindings = create_with_resolver(SOLC_VERSION, Arc::new(NoOpResolver {})); - - bindings.add_system_file("built_ins.sol", built_ins.create_tree_cursor()); - - bindings +pub fn run() -> BindingGraph { + create_with_resolver(SOLC_VERSION, Rc::new(NoOpResolver {})).unwrap() } struct NoOpResolver; -impl PathResolver for NoOpResolver { - fn resolve_path(&self, _context_path: &str, path_to_resolve: &str) -> Option { - Some(path_to_resolve.to_string()) +impl PathResolver for NoOpResolver { + fn resolve_path(&self, _context_path: &str, path_to_resolve: &Cursor) -> Option { + let path = path_to_resolve.node().unparse(); + let path = path + .strip_prefix(|c| matches!(c, '"' | '\''))? + .strip_suffix(|c| matches!(c, '"' | '\''))?; + + Some(path.to_owned()) } } diff --git a/crates/solidity/testing/perf/src/tests/references.rs b/crates/solidity/testing/perf/src/tests/references.rs index 5e237e2d69..c039149a6d 100644 --- a/crates/solidity/testing/perf/src/tests/references.rs +++ b/crates/solidity/testing/perf/src/tests/references.rs @@ -1,28 +1,32 @@ -use slang_solidity::bindings::Bindings; +use slang_solidity::bindings::BindingGraph; -pub fn setup() -> Bindings { +pub fn setup() -> BindingGraph { let dependencies = super::definitions::setup(); super::definitions::run(dependencies) } -pub fn run(bindings: Bindings) { +pub fn run(binding_graph: BindingGraph) { let mut reference_count = 0_usize; let mut resolved_references = 0_usize; - for reference in bindings.all_references() { + for reference in binding_graph.all_references() { + if reference.get_file().is_system() { + // skip built-ins + continue; + } reference_count += 1; - let resolution = reference.jump_to_definition(); + let resolution = reference.resolve_definition(); if resolution.is_ok() { resolved_references += 1; } } - assert_eq!(reference_count, 1686, "Failed to fetch all references"); + assert_eq!(reference_count, 1652, "Failed to fetch all references"); assert_eq!( - resolved_references, 1353, + resolved_references, 1409, "Failed to resolve all references" ); } diff --git a/crates/solidity/testing/sanctuary/src/events.rs b/crates/solidity/testing/sanctuary/src/events.rs index d74bb8445c..2b40f9e418 100644 --- a/crates/solidity/testing/sanctuary/src/events.rs +++ b/crates/solidity/testing/sanctuary/src/events.rs @@ -5,6 +5,7 @@ use indicatif::ProgressBar; use infra_utils::github::GitHub; use crate::reporting::Reporter; +use crate::results::ShardResults; const MAX_PRINTED_FAILURES: u64 = 1000; @@ -133,4 +134,15 @@ impl Events { pub fn trace(&self, message: impl AsRef) { self.reporter.println(message); } + + pub fn to_results(&self) -> ShardResults { + ShardResults { + source_files: self.source_files.position(), + passed: self.passed.position(), + failed: self.failed.position(), + incompatible: self.incompatible.position(), + not_found: self.not_found.position(), + elapsed: self.all_directories.elapsed(), + } + } } diff --git a/crates/solidity/testing/sanctuary/src/main.rs b/crates/solidity/testing/sanctuary/src/main.rs index 80f39766d6..19054d91b9 100644 --- a/crates/solidity/testing/sanctuary/src/main.rs +++ b/crates/solidity/testing/sanctuary/src/main.rs @@ -2,13 +2,18 @@ mod chains; mod datasets; mod events; mod reporting; +mod results; mod tests; +use std::path::PathBuf; + use anyhow::Result; -use clap::Parser; +use clap::{Parser, Subcommand}; +use infra_utils::github::GitHub; use infra_utils::paths::PathExtensions; use infra_utils::terminal::{NumbersDefaultDisplay, Terminal}; use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; +use results::{display_all_results, AllResults}; use crate::chains::Chain; use crate::datasets::{DataSet, SourceFile}; @@ -17,6 +22,18 @@ use crate::tests::{run_test, select_tests, TestSelection}; #[derive(Debug, Parser)] struct Cli { + #[command(subcommand)] + command: Commands, +} + +#[derive(Subcommand, Debug)] +enum Commands { + Test(TestCommand), + ShowCombinedResults(ShowCombinedResultsCommand), +} + +#[derive(Debug, Parser)] +struct TestCommand { /// Chain and sub-network to run against. #[command(subcommand)] chain: Chain, @@ -44,13 +61,29 @@ struct ShardingOptions { shard_index: Option, } +#[derive(Debug, Parser)] +struct ShowCombinedResultsCommand { + results_file: PathBuf, +} + fn main() -> Result<()> { - let Cli { + let Cli { command } = Cli::parse(); + + match command { + Commands::Test(test_command) => run_test_command(test_command), + Commands::ShowCombinedResults(show_command) => { + run_show_combined_results_command(show_command) + } + } +} + +fn run_test_command(command: TestCommand) -> Result<()> { + let TestCommand { chain, sharding_options, trace, check_bindings, - } = Cli::parse(); + } = command; Terminal::step(format!( "initialize {chain}/{network}", @@ -93,6 +126,16 @@ fn main() -> Result<()> { events.finish_directory(); } + if GitHub::is_running_in_ci() { + let output_path = PathBuf::from("target").join("__SLANG_SANCTUARY_SHARD_RESULTS__.json"); + let results = events.to_results(); + let value = serde_json::to_string(&results)?; + + std::fs::create_dir_all(output_path.parent().unwrap())?; + output_path.write_string(value)?; + println!("Wrote results to {output_path:?}"); + } + let failure_count = events.failure_count(); if failure_count > 0 { println!(); @@ -131,6 +174,15 @@ fn run_in_parallel(files: &Vec, events: &Events, check_bindings: boo .try_for_each(|file| run_test(file, events, check_bindings)) } +fn run_show_combined_results_command(command: ShowCombinedResultsCommand) -> Result<()> { + let ShowCombinedResultsCommand { results_file } = command; + + let contents = results_file.read_to_string()?; + let all_results: AllResults = serde_json::from_str(&contents)?; + display_all_results(&all_results); + Ok(()) +} + #[test] fn verify_clap_cli() { // Catches problems earlier in the development cycle: diff --git a/crates/solidity/testing/sanctuary/src/results.rs b/crates/solidity/testing/sanctuary/src/results.rs new file mode 100644 index 0000000000..98fadb3b3d --- /dev/null +++ b/crates/solidity/testing/sanctuary/src/results.rs @@ -0,0 +1,115 @@ +use std::collections::BTreeMap; +use std::time::Duration; + +use indicatif::{FormattedDuration, HumanCount}; +use serde::de::{Error, Visitor}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Default, Serialize, Deserialize)] +pub struct ShardResults { + pub source_files: u64, + pub passed: u64, + pub failed: u64, + pub incompatible: u64, + pub not_found: u64, + pub elapsed: Duration, +} + +#[derive(Debug)] +pub struct AllResults { + pub shards: BTreeMap, +} + +impl<'de> Deserialize<'de> for AllResults { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + deserializer.deserialize_map(AllResultsVisitor {}) + } +} + +struct AllResultsVisitor {} + +impl<'de> Visitor<'de> for AllResultsVisitor { + type Value = AllResults; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("a results map") + } + + fn visit_map(self, mut access: M) -> std::result::Result + where + M: serde::de::MapAccess<'de>, + { + use serde::de::Unexpected; + + let mut shards: BTreeMap = BTreeMap::new(); + while let Some((key, value)) = access.next_entry::()? { + let shard_index = key + .strip_prefix("__SLANG_SANCTUARY_SHARD_RESULTS__") + .ok_or(Error::invalid_value( + Unexpected::Str(&key), + &"a string prefixed with __SLANG_SANCTUARY_SHARD_RESULTS__", + ))? + .parse() + .map_err(|_| { + Error::invalid_value(Unexpected::Str(&key), &"a positive shard index") + })?; + let shard_results = serde_json::from_str(&value).map_err(|_| { + Error::invalid_value( + Unexpected::Str(&value), + &"a JSON string with the shard results", + ) + })?; + shards.insert(shard_index, shard_results); + } + + Ok(AllResults { shards }) + } +} + +pub fn display_all_results(all_results: &AllResults) { + let mut totals = ShardResults::default(); + println!("Shard ID | Source files | Passed | Failed | Incompatible | Not found | Elapsed"); + println!("------------------------------------------------------------------------------------------------"); + for (shard_index, shard_results) in &all_results.shards { + println!( + "{shard_index:<8} | \ + {source_files:>12} | \ + {passed:>12} | \ + {failed:>12} | \ + {incompatible:>12} | \ + {not_found:>12} | \ + {elapsed}", + source_files = format!("{}", HumanCount(shard_results.source_files)), + passed = format!("{}", HumanCount(shard_results.passed)), + failed = format!("{}", HumanCount(shard_results.failed)), + incompatible = format!("{}", HumanCount(shard_results.incompatible)), + not_found = format!("{}", HumanCount(shard_results.not_found)), + elapsed = FormattedDuration(shard_results.elapsed), + ); + totals.source_files += shard_results.source_files; + totals.passed += shard_results.passed; + totals.failed += shard_results.failed; + totals.incompatible += shard_results.incompatible; + totals.not_found += shard_results.not_found; + totals.elapsed += shard_results.elapsed; + } + println!("------------------------------------------------------------------------------------------------"); + println!( + "TOTALS | \ + {source_files:>12} | \ + {passed:>12} | \ + {failed:>12} | \ + {incompatible:>12} | \ + {not_found:>12} | \ + {elapsed}", + source_files = format!("{}", HumanCount(totals.source_files)), + passed = format!("{}", HumanCount(totals.passed)), + failed = format!("{}", HumanCount(totals.failed)), + incompatible = format!("{}", HumanCount(totals.incompatible)), + not_found = format!("{}", HumanCount(totals.not_found)), + elapsed = FormattedDuration(totals.elapsed), + ); +} diff --git a/crates/solidity/testing/sanctuary/src/tests.rs b/crates/solidity/testing/sanctuary/src/tests.rs index 5a6c421f39..948184697f 100644 --- a/crates/solidity/testing/sanctuary/src/tests.rs +++ b/crates/solidity/testing/sanctuary/src/tests.rs @@ -1,18 +1,18 @@ use std::cmp::min; use std::path::Path; use std::rc::Rc; -use std::sync::Arc; use anyhow::Result; use infra_utils::paths::PathExtensions; use itertools::Itertools; use metaslang_bindings::PathResolver; use semver::Version; -use slang_solidity::bindings::Bindings; -use slang_solidity::cst::{Cursor, Node, NonterminalKind, TextIndex, TextRange}; +use slang_solidity::bindings; +use slang_solidity::bindings::BindingGraph; +use slang_solidity::cst::{Cursor, KindTypes, NonterminalKind, TextRange}; use slang_solidity::diagnostic::{Diagnostic, Severity}; use slang_solidity::parser::{ParseOutput, Parser}; -use slang_solidity::{bindings, transform_built_ins_node}; +use slang_solidity::utils::LanguageFacts; use crate::datasets::{DataSet, SourceFile}; use crate::events::{Events, TestOutcome}; @@ -153,7 +153,7 @@ fn extract_compiler_version(compiler: &str) -> Option { panic!("Unrecognized compiler/version: '{compiler}'"); }; - if &version < Parser::SUPPORTED_VERSIONS.first().unwrap() { + if &version < LanguageFacts::SUPPORTED_VERSIONS.first().unwrap() { // Version is too early: return None; } @@ -187,9 +187,9 @@ fn run_bindings_check( output: &ParseOutput, ) -> Result> { let mut unresolved = Vec::new(); - let bindings = create_bindings(version, source_id, output)?; + let binding_graph = create_bindings(version, source_id, output)?; - for reference in bindings.all_references() { + for reference in binding_graph.all_references() { if reference.get_file().is_system() { // skip built-ins continue; @@ -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 }); } } @@ -205,36 +205,32 @@ fn run_bindings_check( Ok(unresolved) } -fn create_bindings(version: &Version, source_id: &str, output: &ParseOutput) -> Result { - let mut bindings = bindings::create_with_resolver( +fn create_bindings( + version: &Version, + source_id: &str, + output: &ParseOutput, +) -> Result { + let mut binding_graph = bindings::create_with_resolver( version.clone(), - Arc::new(SingleFileResolver { + Rc::new(SingleFileResolver { source_id: source_id.into(), }), - ); - let parser = Parser::create(version.clone())?; - let built_ins_output = parser.parse( - NonterminalKind::SourceUnit, - bindings::get_built_ins(version), - ); - let built_ins_tree = built_ins_output.tree(); - let built_ins_cursor = transform_built_ins_node(&Node::Nonterminal(Rc::clone(built_ins_tree))) - .cursor_with_offset(TextIndex::ZERO); - - bindings.add_system_file("built_ins.sol", built_ins_cursor); - bindings.add_user_file(source_id, output.create_tree_cursor()); - Ok(bindings) + )?; + + binding_graph.add_user_file(source_id, output.create_tree_cursor()); + + Ok(binding_graph) } -/// Bindings `PathResolver` that always resolves to the given `source_id`. +/// The `PathResolver` that always resolves to the given `source_id`. /// This is useful for Sanctuary since all dependencies are concatenated in the /// same file, but the import directives are retained. struct SingleFileResolver { source_id: String, } -impl PathResolver for SingleFileResolver { - fn resolve_path(&self, _context_path: &str, _path_to_resolve: &str) -> Option { +impl PathResolver for SingleFileResolver { + fn resolve_path(&self, _context_path: &str, _path_to_resolve: &Cursor) -> Option { Some(self.source_id.clone()) } } diff --git a/crates/solidity/testing/snapshots/bindings_assertions/using/inherited.sol b/crates/solidity/testing/snapshots/bindings_assertions/using/inherited.sol new file mode 100644 index 0000000000..6bcd410801 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_assertions/using/inherited.sol @@ -0,0 +1,16 @@ +library Lib { + function squared(int x) public returns (int) { return x * x; } + // ^def:1 +} + +contract Base { + using Lib for int; +} + +contract Test is Base { + function test(int x) public returns (int) { + return x.squared(); + // ^ref:1 (< 0.7.0) + // ^ref:! (>= 0.7.0) + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/arrays/length/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/arrays/length/generated/0.4.11-success.txt new file mode 100644 index 0000000000..2e3248e35d --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/arrays/length/generated/0.4.11-success.txt @@ -0,0 +1,33 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ library Lib { + │ ─┬─ + │ ╰─── def: 1 + 2 │ function nop(uint x) internal {} + │ ─┬─ ┬ + │ ╰────────── def: 2 + │ │ + │ ╰── def: 3 + │ + 4 │ contract Test { + │ ──┬─ + │ ╰─── def: 4 + 5 │ using Lib for uint; + │ ─┬─ + │ ╰─── ref: 1 + 6 │ function test(uint256[] memory data) public { + │ ──┬─ ──┬─ + │ ╰───────────────────────── def: 5 + │ │ + │ ╰─── def: 6 + 7 │ data.length.nop(); + │ ──┬─ ───┬── ─┬─ + │ ╰────────────── ref: 6 + │ │ │ + │ ╰──────── ref: built-in + │ │ + │ ╰─── ref: 2 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/arrays/length/input.sol b/crates/solidity/testing/snapshots/bindings_output/arrays/length/input.sol new file mode 100644 index 0000000000..10925efe89 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/arrays/length/input.sol @@ -0,0 +1,9 @@ +library Lib { + function nop(uint x) internal {} +} +contract Test { + using Lib for uint; + function test(uint256[] memory data) public { + data.length.nop(); + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/built_ins/address/generated/0.4.11-failure.txt b/crates/solidity/testing/snapshots/bindings_output/built_ins/address/generated/0.4.11-failure.txt index 1f202ff321..9ff8c9567f 100644 --- a/crates/solidity/testing/snapshots/bindings_output/built_ins/address/generated/0.4.11-failure.txt +++ b/crates/solidity/testing/snapshots/bindings_output/built_ins/address/generated/0.4.11-failure.txt @@ -59,4 +59,9 @@ References and definitions: │ ╰─────────── ref: 3 │ │ │ ╰─── ref: built-in + 9 │ uint256 v10 = address(this).balance; + │ ─┬─ ───┬─── + │ ╰─────────────────────────── def: 12 + │ │ + │ ╰───── ref: built-in ───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/built_ins/address/generated/0.5.0-success.txt b/crates/solidity/testing/snapshots/bindings_output/built_ins/address/generated/0.5.0-success.txt index c51e30477e..d5f0a1db53 100644 --- a/crates/solidity/testing/snapshots/bindings_output/built_ins/address/generated/0.5.0-success.txt +++ b/crates/solidity/testing/snapshots/bindings_output/built_ins/address/generated/0.5.0-success.txt @@ -59,4 +59,9 @@ References and definitions: │ ╰─────────── ref: 3 │ │ │ ╰─── ref: built-in + 9 │ uint256 v10 = address(this).balance; + │ ─┬─ ───┬─── + │ ╰─────────────────────────── def: 12 + │ │ + │ ╰───── ref: built-in ───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/built_ins/address/input.sol b/crates/solidity/testing/snapshots/bindings_output/built_ins/address/input.sol index 7c97254b4d..769a5d8cc4 100644 --- a/crates/solidity/testing/snapshots/bindings_output/built_ins/address/input.sol +++ b/crates/solidity/testing/snapshots/bindings_output/built_ins/address/input.sol @@ -6,5 +6,6 @@ contract Test { (bool v7, bytes memory v8) = recipient.staticcall(x1); recipient.transfer(1); bool v9 = recipient.send(1); + uint256 v10 = address(this).balance; } } diff --git a/crates/solidity/testing/snapshots/bindings_output/built_ins/arrays/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/built_ins/arrays/generated/0.4.11-success.txt index 4f2a748f2f..7d6647ad22 100644 --- a/crates/solidity/testing/snapshots/bindings_output/built_ins/arrays/generated/0.4.11-success.txt +++ b/crates/solidity/testing/snapshots/bindings_output/built_ins/arrays/generated/0.4.11-success.txt @@ -1,76 +1,41 @@ # This file is generated automatically by infrastructure scripts. Please don't edit by hand. References and definitions: - ╭─[input.sol:1:1] - │ - 1 │ contract Test { - │ ──┬─ - │ ╰─── def: 1 - 2 │ uint[] a; - │ ┬ - │ ╰── def: 2 - 3 │ function testArray() public { - │ ────┬──── - │ ╰────── def: 3 - 4 │ uint[] storage b = new uint[](5); - │ ┬ - │ ╰── def: 4 - 5 │ assert(b.length == 5); - │ ───┬── ┬ ───┬── - │ ╰───────────── ref: built-in - │ │ │ - │ ╰───────── ref: 4 - │ │ - │ ╰──── ref: built-in - │ - 7 │ a.push(); - │ ┬ ──┬─ - │ ╰─────── ref: 2 - │ │ - │ ╰─── ref: built-in - 8 │ a.push(1); - │ ┬ ──┬─ - │ ╰─────── ref: 2 - │ │ - │ ╰─── ref: built-in - 9 │ a.pop(); - │ ┬ ─┬─ - │ ╰────── ref: 2 - │ │ - │ ╰─── ref: built-in - │ - 12 │ function testConcat() public { - │ ─────┬──── - │ ╰────── def: 5 - 13 │ bytes memory b1; - │ ─┬ - │ ╰── def: 6 - 14 │ bytes memory b2; - │ ─┬ - │ ╰── def: 7 - 15 │ bytes memory b3 = b1.concat(b2); - │ ─┬ ─┬ ───┬── ─┬ - │ ╰───────────────── def: 8 - │ │ │ │ - │ ╰──────────── ref: 6 - │ │ │ - │ ╰─────── ref: built-in - │ │ - │ ╰── ref: 7 - │ - 17 │ string memory s1; - │ ─┬ - │ ╰── def: 9 - 18 │ string memory s2; - │ ─┬ - │ ╰── def: 10 - 19 │ string memory s3 = s1.concat(s2); - │ ─┬ ─┬ ───┬── ─┬ - │ ╰───────────────── def: 11 - │ │ │ │ - │ ╰──────────── ref: 9 - │ │ │ - │ ╰─────── ref: built-in - │ │ - │ ╰── ref: 10 -────╯ + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ uint[] a; + │ ┬ + │ ╰── def: 2 + 3 │ function testArray() public { + │ ────┬──── + │ ╰────── def: 3 + 4 │ uint[] storage b = new uint[](5); + │ ┬ + │ ╰── def: 4 + 5 │ assert(b.length == 5); + │ ───┬── ┬ ───┬── + │ ╰───────────── ref: built-in + │ │ │ + │ ╰───────── ref: 4 + │ │ + │ ╰──── ref: built-in + │ + 7 │ a.push(); + │ ┬ ──┬─ + │ ╰─────── ref: 2 + │ │ + │ ╰─── ref: built-in + 8 │ a.push(1); + │ ┬ ──┬─ + │ ╰─────── ref: 2 + │ │ + │ ╰─── ref: built-in + 9 │ a.pop(); + │ ┬ ─┬─ + │ ╰────── ref: 2 + │ │ + │ ╰─── ref: built-in +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/built_ins/arrays/generated/0.6.0-success.txt b/crates/solidity/testing/snapshots/bindings_output/built_ins/arrays/generated/0.6.0-success.txt index 1253ccf796..c8f4c1481f 100644 --- a/crates/solidity/testing/snapshots/bindings_output/built_ins/arrays/generated/0.6.0-success.txt +++ b/crates/solidity/testing/snapshots/bindings_output/built_ins/arrays/generated/0.6.0-success.txt @@ -1,76 +1,41 @@ # This file is generated automatically by infrastructure scripts. Please don't edit by hand. References and definitions: - ╭─[input.sol:1:1] - │ - 1 │ contract Test { - │ ──┬─ - │ ╰─── def: 1 - 2 │ uint[] a; - │ ┬ - │ ╰── def: 2 - 3 │ function testArray() public { - │ ────┬──── - │ ╰────── def: 3 - 4 │ uint[] storage b = new uint[](5); - │ ┬ - │ ╰── def: 4 - 5 │ assert(b.length == 5); - │ ───┬── ┬ ───┬── - │ ╰───────────── ref: built-in - │ │ │ - │ ╰───────── ref: 4 - │ │ - │ ╰──── ref: built-in - │ - 7 │ a.push(); - │ ┬ ──┬─ - │ ╰─────── ref: 2 - │ │ - │ ╰─── refs: built-in, built-in - 8 │ a.push(1); - │ ┬ ──┬─ - │ ╰─────── ref: 2 - │ │ - │ ╰─── refs: built-in, built-in - 9 │ a.pop(); - │ ┬ ─┬─ - │ ╰────── ref: 2 - │ │ - │ ╰─── ref: built-in - │ - 12 │ function testConcat() public { - │ ─────┬──── - │ ╰────── def: 5 - 13 │ bytes memory b1; - │ ─┬ - │ ╰── def: 6 - 14 │ bytes memory b2; - │ ─┬ - │ ╰── def: 7 - 15 │ bytes memory b3 = b1.concat(b2); - │ ─┬ ─┬ ───┬── ─┬ - │ ╰───────────────── def: 8 - │ │ │ │ - │ ╰──────────── ref: 6 - │ │ │ - │ ╰─────── ref: built-in - │ │ - │ ╰── ref: 7 - │ - 17 │ string memory s1; - │ ─┬ - │ ╰── def: 9 - 18 │ string memory s2; - │ ─┬ - │ ╰── def: 10 - 19 │ string memory s3 = s1.concat(s2); - │ ─┬ ─┬ ───┬── ─┬ - │ ╰───────────────── def: 11 - │ │ │ │ - │ ╰──────────── ref: 9 - │ │ │ - │ ╰─────── ref: built-in - │ │ - │ ╰── ref: 10 -────╯ + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ uint[] a; + │ ┬ + │ ╰── def: 2 + 3 │ function testArray() public { + │ ────┬──── + │ ╰────── def: 3 + 4 │ uint[] storage b = new uint[](5); + │ ┬ + │ ╰── def: 4 + 5 │ assert(b.length == 5); + │ ───┬── ┬ ───┬── + │ ╰───────────── ref: built-in + │ │ │ + │ ╰───────── ref: 4 + │ │ + │ ╰──── ref: built-in + │ + 7 │ a.push(); + │ ┬ ──┬─ + │ ╰─────── ref: 2 + │ │ + │ ╰─── refs: built-in, built-in + 8 │ a.push(1); + │ ┬ ──┬─ + │ ╰─────── ref: 2 + │ │ + │ ╰─── refs: built-in, built-in + 9 │ a.pop(); + │ ┬ ─┬─ + │ ╰────── ref: 2 + │ │ + │ ╰─── ref: built-in +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/built_ins/arrays/input.sol b/crates/solidity/testing/snapshots/bindings_output/built_ins/arrays/input.sol index 619d86dbb8..1646154c42 100644 --- a/crates/solidity/testing/snapshots/bindings_output/built_ins/arrays/input.sol +++ b/crates/solidity/testing/snapshots/bindings_output/built_ins/arrays/input.sol @@ -8,14 +8,4 @@ contract Test { a.push(1); a.pop(); } - - function testConcat() public { - bytes memory b1; - bytes memory b2; - bytes memory b3 = b1.concat(b2); - - string memory s1; - string memory s2; - string memory s3 = s1.concat(s2); - } } diff --git a/crates/solidity/testing/snapshots/bindings_output/built_ins/bytes/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/built_ins/bytes/generated/0.4.11-success.txt new file mode 100644 index 0000000000..01319e37d0 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/built_ins/bytes/generated/0.4.11-success.txt @@ -0,0 +1,51 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ function testBytes() public { + │ ────┬──── + │ ╰────── def: 2 + 3 │ bytes memory b1; + │ ─┬ + │ ╰── def: 3 + 4 │ bytes memory b2; + │ ─┬ + │ ╰── def: 4 + 5 │ bytes memory b3 = bytes.concat(b1, b2); + │ ─┬ ───┬── ─┬ ─┬ + │ ╰──────────────────────── def: 5 + │ │ │ │ + │ ╰─────────── ref: built-in + │ │ │ + │ ╰────── ref: 3 + │ │ + │ ╰── ref: 4 + 6 │ b1.length; + │ ─┬ ───┬── + │ ╰───────── ref: 3 + │ │ + │ ╰──── ref: built-in + │ + 9 │ function testString() public { + │ ─────┬──── + │ ╰────── def: 6 + 10 │ string memory s1; + │ ─┬ + │ ╰── def: 7 + 11 │ string memory s2; + │ ─┬ + │ ╰── def: 8 + 12 │ string memory s3 = string.concat(s1, s2); + │ ─┬ ───┬── ─┬ ─┬ + │ ╰───────────────────────── def: 9 + │ │ │ │ + │ ╰─────────── ref: built-in + │ │ │ + │ ╰────── ref: 7 + │ │ + │ ╰── ref: 8 +────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/built_ins/bytes/input.sol b/crates/solidity/testing/snapshots/bindings_output/built_ins/bytes/input.sol new file mode 100644 index 0000000000..d6da9002a3 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/built_ins/bytes/input.sol @@ -0,0 +1,14 @@ +contract Test { + function testBytes() public { + bytes memory b1; + bytes memory b2; + bytes memory b3 = bytes.concat(b1, b2); + b1.length; + } + + function testString() public { + string memory s1; + string memory s2; + string memory s3 = string.concat(s1, s2); + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/built_ins/function_type/generated/0.4.11-failure.txt b/crates/solidity/testing/snapshots/bindings_output/built_ins/function_type/generated/0.4.11-failure.txt index b90ecb72e9..8164d93dfd 100644 --- a/crates/solidity/testing/snapshots/bindings_output/built_ins/function_type/generated/0.4.11-failure.txt +++ b/crates/solidity/testing/snapshots/bindings_output/built_ins/function_type/generated/0.4.11-failure.txt @@ -10,19 +10,15 @@ References and definitions: │ ──┬─ │ ╰─── def: 2 3 │ bytes4 v1 = this.test.selector; - │ ─┬ ──┬─ ──┬─ ────┬─── + │ ─┬ ──┬─ ────┬─── │ ╰─────────────────────── def: 3 - │ │ │ │ - │ ╰───────────────── ref: 1 │ │ │ │ ╰──────────── ref: 2 │ │ │ ╰───── unresolved 4 │ address v2 = this.test.address; - │ ─┬ ──┬─ ──┬─ ───┬─── + │ ─┬ ──┬─ ───┬─── │ ╰────────────────────── def: 4 - │ │ │ │ - │ ╰──────────────── ref: 1 │ │ │ │ ╰─────────── ref: 2 │ │ diff --git a/crates/solidity/testing/snapshots/bindings_output/built_ins/function_type/generated/0.4.21-failure.txt b/crates/solidity/testing/snapshots/bindings_output/built_ins/function_type/generated/0.4.21-failure.txt index 0d92e4506b..ec1fe46b15 100644 --- a/crates/solidity/testing/snapshots/bindings_output/built_ins/function_type/generated/0.4.21-failure.txt +++ b/crates/solidity/testing/snapshots/bindings_output/built_ins/function_type/generated/0.4.21-failure.txt @@ -10,19 +10,15 @@ References and definitions: │ ──┬─ │ ╰─── def: 2 3 │ bytes4 v1 = this.test.selector; - │ ─┬ ──┬─ ──┬─ ────┬─── + │ ─┬ ──┬─ ────┬─── │ ╰─────────────────────── def: 3 - │ │ │ │ - │ ╰───────────────── ref: 1 │ │ │ │ ╰──────────── ref: 2 │ │ │ ╰───── ref: built-in 4 │ address v2 = this.test.address; - │ ─┬ ──┬─ ──┬─ ───┬─── + │ ─┬ ──┬─ ───┬─── │ ╰────────────────────── def: 4 - │ │ │ │ - │ ╰──────────────── ref: 1 │ │ │ │ ╰─────────── ref: 2 │ │ diff --git a/crates/solidity/testing/snapshots/bindings_output/built_ins/function_type/generated/0.8.4-success.txt b/crates/solidity/testing/snapshots/bindings_output/built_ins/function_type/generated/0.8.4-success.txt index 4e5d5be407..1b10c554b8 100644 --- a/crates/solidity/testing/snapshots/bindings_output/built_ins/function_type/generated/0.8.4-success.txt +++ b/crates/solidity/testing/snapshots/bindings_output/built_ins/function_type/generated/0.8.4-success.txt @@ -10,19 +10,15 @@ References and definitions: │ ──┬─ │ ╰─── def: 2 3 │ bytes4 v1 = this.test.selector; - │ ─┬ ──┬─ ──┬─ ────┬─── + │ ─┬ ──┬─ ────┬─── │ ╰─────────────────────── def: 3 - │ │ │ │ - │ ╰───────────────── ref: 1 │ │ │ │ ╰──────────── ref: 2 │ │ │ ╰───── ref: built-in 4 │ address v2 = this.test.address; - │ ─┬ ──┬─ ──┬─ ───┬─── + │ ─┬ ──┬─ ───┬─── │ ╰────────────────────── def: 4 - │ │ │ │ - │ ╰──────────────── ref: 1 │ │ │ │ ╰─────────── ref: 2 │ │ diff --git a/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.4.11-failure.txt b/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.4.11-failure.txt index 012ad3172e..1968dc3495 100644 --- a/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.4.11-failure.txt +++ b/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.4.11-failure.txt @@ -124,14 +124,12 @@ References and definitions: │ │ │ ╰── ref: 19 36 │ bytes memory v3 = abi.encodeCall(this.testMath, (1, 2, 3)); - │ ─┬ ─┬─ ─────┬──── ──┬─ ────┬─── + │ ─┬ ─┬─ ─────┬──── ────┬─── │ ╰───────────────────────────────── def: 21 - │ │ │ │ │ + │ │ │ │ │ ╰──────────────────────────── ref: built-in - │ │ │ │ + │ │ │ │ ╰──────────────────── unresolved - │ │ │ - │ ╰──────────── ref: 1 │ │ │ ╰───── ref: 5 37 │ bytes memory v4 = abi.encodePacked(10, 20); @@ -142,14 +140,12 @@ References and definitions: │ │ │ ╰─────── unresolved 38 │ bytes memory v5 = abi.encodeWithSelector(this.testMath.selector, (1, 2, 3)); - │ ─┬ ─┬─ ─────────┬──────── ──┬─ ────┬─── ────┬─── + │ ─┬ ─┬─ ─────────┬──────── ────┬─── ────┬─── │ ╰────────────────────────────────────────────────── def: 23 - │ │ │ │ │ │ + │ │ │ │ │ │ ╰───────────────────────────────────────────── ref: built-in - │ │ │ │ │ + │ │ │ │ │ ╰───────────────────────────────── unresolved - │ │ │ │ - │ ╰───────────────────── ref: 1 │ │ │ │ ╰────────────── ref: 5 │ │ diff --git a/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.4.21-failure.txt b/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.4.21-failure.txt index 4ff6d6c42c..54e971d730 100644 --- a/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.4.21-failure.txt +++ b/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.4.21-failure.txt @@ -124,14 +124,12 @@ References and definitions: │ │ │ ╰── ref: 19 36 │ bytes memory v3 = abi.encodeCall(this.testMath, (1, 2, 3)); - │ ─┬ ─┬─ ─────┬──── ──┬─ ────┬─── + │ ─┬ ─┬─ ─────┬──── ────┬─── │ ╰───────────────────────────────── def: 21 - │ │ │ │ │ + │ │ │ │ │ ╰──────────────────────────── ref: built-in - │ │ │ │ + │ │ │ │ ╰──────────────────── unresolved - │ │ │ - │ ╰──────────── ref: 1 │ │ │ ╰───── ref: 5 37 │ bytes memory v4 = abi.encodePacked(10, 20); @@ -142,14 +140,12 @@ References and definitions: │ │ │ ╰─────── unresolved 38 │ bytes memory v5 = abi.encodeWithSelector(this.testMath.selector, (1, 2, 3)); - │ ─┬ ─┬─ ─────────┬──────── ──┬─ ────┬─── ────┬─── + │ ─┬ ─┬─ ─────────┬──────── ────┬─── ────┬─── │ ╰────────────────────────────────────────────────── def: 23 - │ │ │ │ │ │ + │ │ │ │ │ │ ╰───────────────────────────────────────────── ref: built-in - │ │ │ │ │ + │ │ │ │ │ ╰───────────────────────────────── unresolved - │ │ │ │ - │ ╰───────────────────── ref: 1 │ │ │ │ ╰────────────── ref: 5 │ │ diff --git a/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.4.22-failure.txt b/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.4.22-failure.txt index 1282f7841d..fc3aaa04ce 100644 --- a/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.4.22-failure.txt +++ b/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.4.22-failure.txt @@ -124,14 +124,12 @@ References and definitions: │ │ │ ╰── ref: 19 36 │ bytes memory v3 = abi.encodeCall(this.testMath, (1, 2, 3)); - │ ─┬ ─┬─ ─────┬──── ──┬─ ────┬─── + │ ─┬ ─┬─ ─────┬──── ────┬─── │ ╰───────────────────────────────── def: 21 - │ │ │ │ │ + │ │ │ │ │ ╰──────────────────────────── ref: built-in - │ │ │ │ + │ │ │ │ ╰──────────────────── unresolved - │ │ │ - │ ╰──────────── ref: 1 │ │ │ ╰───── ref: 5 37 │ bytes memory v4 = abi.encodePacked(10, 20); @@ -142,14 +140,12 @@ References and definitions: │ │ │ ╰─────── ref: built-in 38 │ bytes memory v5 = abi.encodeWithSelector(this.testMath.selector, (1, 2, 3)); - │ ─┬ ─┬─ ─────────┬──────── ──┬─ ────┬─── ────┬─── + │ ─┬ ─┬─ ─────────┬──────── ────┬─── ────┬─── │ ╰────────────────────────────────────────────────── def: 23 - │ │ │ │ │ │ + │ │ │ │ │ │ ╰───────────────────────────────────────────── ref: built-in - │ │ │ │ │ + │ │ │ │ │ ╰───────────────────────────────── ref: built-in - │ │ │ │ - │ ╰───────────────────── ref: 1 │ │ │ │ ╰────────────── ref: 5 │ │ diff --git a/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.5.0-failure.txt b/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.5.0-failure.txt index f901dcb995..3a79b59191 100644 --- a/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.5.0-failure.txt +++ b/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.5.0-failure.txt @@ -124,14 +124,12 @@ References and definitions: │ │ │ ╰── ref: 19 36 │ bytes memory v3 = abi.encodeCall(this.testMath, (1, 2, 3)); - │ ─┬ ─┬─ ─────┬──── ──┬─ ────┬─── + │ ─┬ ─┬─ ─────┬──── ────┬─── │ ╰───────────────────────────────── def: 21 - │ │ │ │ │ + │ │ │ │ │ ╰──────────────────────────── ref: built-in - │ │ │ │ + │ │ │ │ ╰──────────────────── unresolved - │ │ │ - │ ╰──────────── ref: 1 │ │ │ ╰───── ref: 5 37 │ bytes memory v4 = abi.encodePacked(10, 20); @@ -142,14 +140,12 @@ References and definitions: │ │ │ ╰─────── ref: built-in 38 │ bytes memory v5 = abi.encodeWithSelector(this.testMath.selector, (1, 2, 3)); - │ ─┬ ─┬─ ─────────┬──────── ──┬─ ────┬─── ────┬─── + │ ─┬ ─┬─ ─────────┬──────── ────┬─── ────┬─── │ ╰────────────────────────────────────────────────── def: 23 - │ │ │ │ │ │ + │ │ │ │ │ │ ╰───────────────────────────────────────────── ref: built-in - │ │ │ │ │ + │ │ │ │ │ ╰───────────────────────────────── ref: built-in - │ │ │ │ - │ ╰───────────────────── ref: 1 │ │ │ │ ╰────────────── ref: 5 │ │ diff --git a/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.8.13-failure.txt b/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.8.13-failure.txt index 690910c0a7..43b3aa3a88 100644 --- a/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.8.13-failure.txt +++ b/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.8.13-failure.txt @@ -121,14 +121,12 @@ References and definitions: │ │ │ ╰── ref: 19 36 │ bytes memory v3 = abi.encodeCall(this.testMath, (1, 2, 3)); - │ ─┬ ─┬─ ─────┬──── ──┬─ ────┬─── + │ ─┬ ─┬─ ─────┬──── ────┬─── │ ╰───────────────────────────────── def: 21 - │ │ │ │ │ + │ │ │ │ │ ╰──────────────────────────── ref: built-in - │ │ │ │ + │ │ │ │ ╰──────────────────── ref: built-in - │ │ │ - │ ╰──────────── ref: 1 │ │ │ ╰───── ref: 5 37 │ bytes memory v4 = abi.encodePacked(10, 20); @@ -139,14 +137,12 @@ References and definitions: │ │ │ ╰─────── ref: built-in 38 │ bytes memory v5 = abi.encodeWithSelector(this.testMath.selector, (1, 2, 3)); - │ ─┬ ─┬─ ─────────┬──────── ──┬─ ────┬─── ────┬─── + │ ─┬ ─┬─ ─────────┬──────── ────┬─── ────┬─── │ ╰────────────────────────────────────────────────── def: 23 - │ │ │ │ │ │ + │ │ │ │ │ │ ╰───────────────────────────────────────────── ref: built-in - │ │ │ │ │ + │ │ │ │ │ ╰───────────────────────────────── ref: built-in - │ │ │ │ - │ ╰───────────────────── ref: 1 │ │ │ │ ╰────────────── ref: 5 │ │ diff --git a/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.8.24-success.txt b/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.8.24-success.txt index cda93f689d..4134c68526 100644 --- a/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.8.24-success.txt +++ b/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.8.24-success.txt @@ -121,14 +121,12 @@ References and definitions: │ │ │ ╰── ref: 19 36 │ bytes memory v3 = abi.encodeCall(this.testMath, (1, 2, 3)); - │ ─┬ ─┬─ ─────┬──── ──┬─ ────┬─── + │ ─┬ ─┬─ ─────┬──── ────┬─── │ ╰───────────────────────────────── def: 21 - │ │ │ │ │ + │ │ │ │ │ ╰──────────────────────────── ref: built-in - │ │ │ │ + │ │ │ │ ╰──────────────────── ref: built-in - │ │ │ - │ ╰──────────── ref: 1 │ │ │ ╰───── ref: 5 37 │ bytes memory v4 = abi.encodePacked(10, 20); @@ -139,14 +137,12 @@ References and definitions: │ │ │ ╰─────── ref: built-in 38 │ bytes memory v5 = abi.encodeWithSelector(this.testMath.selector, (1, 2, 3)); - │ ─┬ ─┬─ ─────────┬──────── ──┬─ ────┬─── ────┬─── + │ ─┬ ─┬─ ─────────┬──────── ────┬─── ────┬─── │ ╰────────────────────────────────────────────────── def: 23 - │ │ │ │ │ │ + │ │ │ │ │ │ ╰───────────────────────────────────────────── ref: built-in - │ │ │ │ │ + │ │ │ │ │ ╰───────────────────────────────── ref: built-in - │ │ │ │ - │ ╰───────────────────── ref: 1 │ │ │ │ ╰────────────── ref: 5 │ │ diff --git a/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.8.27-success.txt b/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.8.27-success.txt index 5b04719552..1d9544857a 100644 --- a/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.8.27-success.txt +++ b/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.8.27-success.txt @@ -121,14 +121,12 @@ References and definitions: │ │ │ ╰── ref: 19 36 │ bytes memory v3 = abi.encodeCall(this.testMath, (1, 2, 3)); - │ ─┬ ─┬─ ─────┬──── ──┬─ ────┬─── + │ ─┬ ─┬─ ─────┬──── ────┬─── │ ╰───────────────────────────────── def: 21 - │ │ │ │ │ + │ │ │ │ │ ╰──────────────────────────── ref: built-in - │ │ │ │ + │ │ │ │ ╰──────────────────── ref: built-in - │ │ │ - │ ╰──────────── ref: 1 │ │ │ ╰───── ref: 5 37 │ bytes memory v4 = abi.encodePacked(10, 20); @@ -139,14 +137,12 @@ References and definitions: │ │ │ ╰─────── ref: built-in 38 │ bytes memory v5 = abi.encodeWithSelector(this.testMath.selector, (1, 2, 3)); - │ ─┬ ─┬─ ─────────┬──────── ──┬─ ────┬─── ────┬─── + │ ─┬ ─┬─ ─────────┬──────── ────┬─── ────┬─── │ ╰────────────────────────────────────────────────── def: 23 - │ │ │ │ │ │ + │ │ │ │ │ │ ╰───────────────────────────────────────────── ref: built-in - │ │ │ │ │ + │ │ │ │ │ ╰───────────────────────────────── ref: built-in - │ │ │ │ - │ ╰───────────────────── ref: 1 │ │ │ │ ╰────────────── ref: 5 │ │ diff --git a/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.8.4-failure.txt b/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.8.4-failure.txt index 835dcf5dcc..3c898c3511 100644 --- a/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.8.4-failure.txt +++ b/crates/solidity/testing/snapshots/bindings_output/built_ins/functions/generated/0.8.4-failure.txt @@ -121,14 +121,12 @@ References and definitions: │ │ │ ╰── ref: 19 36 │ bytes memory v3 = abi.encodeCall(this.testMath, (1, 2, 3)); - │ ─┬ ─┬─ ─────┬──── ──┬─ ────┬─── + │ ─┬ ─┬─ ─────┬──── ────┬─── │ ╰───────────────────────────────── def: 21 - │ │ │ │ │ + │ │ │ │ │ ╰──────────────────────────── ref: built-in - │ │ │ │ + │ │ │ │ ╰──────────────────── unresolved - │ │ │ - │ ╰──────────── ref: 1 │ │ │ ╰───── ref: 5 37 │ bytes memory v4 = abi.encodePacked(10, 20); @@ -139,14 +137,12 @@ References and definitions: │ │ │ ╰─────── ref: built-in 38 │ bytes memory v5 = abi.encodeWithSelector(this.testMath.selector, (1, 2, 3)); - │ ─┬ ─┬─ ─────────┬──────── ──┬─ ────┬─── ────┬─── + │ ─┬ ─┬─ ─────────┬──────── ────┬─── ────┬─── │ ╰────────────────────────────────────────────────── def: 23 - │ │ │ │ │ │ + │ │ │ │ │ │ ╰───────────────────────────────────────────── ref: built-in - │ │ │ │ │ + │ │ │ │ │ ╰───────────────────────────────── ref: built-in - │ │ │ │ - │ ╰───────────────────── ref: 1 │ │ │ │ ╰────────────── ref: 5 │ │ diff --git a/crates/solidity/testing/snapshots/bindings_output/built_ins/this/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/built_ins/this/generated/0.4.11-success.txt new file mode 100644 index 0000000000..c86bc2430b --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/built_ins/this/generated/0.4.11-success.txt @@ -0,0 +1,15 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ library Lib { + │ ─┬─ + │ ╰─── def: 1 + 2 │ function test() internal returns (uint) { + │ ──┬─ + │ ╰─── def: 2 + 3 │ return address(this).balance; + │ ───┬─── + │ ╰───── ref: built-in +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/built_ins/this/input.sol b/crates/solidity/testing/snapshots/bindings_output/built_ins/this/input.sol new file mode 100644 index 0000000000..ac4a90eeb0 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/built_ins/this/input.sol @@ -0,0 +1,5 @@ +library Lib { + function test() internal returns (uint) { + return address(this).balance; + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/built_ins/this_as_address/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/built_ins/this_as_address/generated/0.4.11-success.txt new file mode 100644 index 0000000000..e5572f9274 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/built_ins/this_as_address/generated/0.4.11-success.txt @@ -0,0 +1,16 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ function test() public { + │ ──┬─ + │ ╰─── def: 2 + │ + 4 │ this.balance; + │ ───┬─── + │ ╰───── ref: built-in +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/built_ins/this_as_address/generated/0.5.0-failure.txt b/crates/solidity/testing/snapshots/bindings_output/built_ins/this_as_address/generated/0.5.0-failure.txt new file mode 100644 index 0000000000..8d1ee729e4 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/built_ins/this_as_address/generated/0.5.0-failure.txt @@ -0,0 +1,16 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ function test() public { + │ ──┬─ + │ ╰─── def: 2 + │ + 4 │ this.balance; + │ ───┬─── + │ ╰───── unresolved +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/built_ins/this_as_address/input.sol b/crates/solidity/testing/snapshots/bindings_output/built_ins/this_as_address/input.sol new file mode 100644 index 0000000000..06d15f15bd --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/built_ins/this_as_address/input.sol @@ -0,0 +1,6 @@ +contract Test { + function test() public { + // This was valid before 0.5.0 + this.balance; + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/constructor_call_parent/generated/0.4.11-failure.txt b/crates/solidity/testing/snapshots/bindings_output/contracts/constructor_call_parent/generated/0.4.11-failure.txt new file mode 100644 index 0000000000..fa35b69352 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/constructor_call_parent/generated/0.4.11-failure.txt @@ -0,0 +1,27 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected ConstantKeyword or Identifier or InternalKeyword or PrivateKeyword or PublicKeyword. + ╭─[input.sol:4:16] + │ + 4 │ ╭─▶ constructor() Base() { + 5 │ ├─▶ } + │ │ + │ ╰─────────── Error occurred here. +───╯ +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Base {} + │ ──┬─ + │ ╰─── def: 1 + │ + 3 │ contract Test is Base { + │ ──┬─ ──┬─ + │ ╰─────────── def: 2 + │ │ + │ ╰─── ref: 1 + 4 │ constructor() Base() { + │ ─────┬───── + │ ╰─────── unresolved +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/constructor_call_parent/generated/0.4.22-success.txt b/crates/solidity/testing/snapshots/bindings_output/contracts/constructor_call_parent/generated/0.4.22-success.txt new file mode 100644 index 0000000000..84795b192d --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/constructor_call_parent/generated/0.4.22-success.txt @@ -0,0 +1,18 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Base {} + │ ──┬─ + │ ╰─── def: 1 + │ + 3 │ contract Test is Base { + │ ──┬─ ──┬─ + │ ╰─────────── def: 2 + │ │ + │ ╰─── ref: 1 + 4 │ constructor() Base() { + │ ──┬─ + │ ╰─── ref: 1 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/constructor_call_parent/input.sol b/crates/solidity/testing/snapshots/bindings_output/contracts/constructor_call_parent/input.sol new file mode 100644 index 0000000000..98fa43a3ea --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/constructor_call_parent/input.sol @@ -0,0 +1,6 @@ +contract Base {} + +contract Test is Base { + constructor() Base() { + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/inherited_state_vars/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/contracts/inherited_state_vars/generated/0.4.11-success.txt new file mode 100644 index 0000000000..64c83c5658 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/inherited_state_vars/generated/0.4.11-success.txt @@ -0,0 +1,36 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Base { + │ ──┬─ + │ ╰─── def: 1 + 2 │ int in_base; + │ ───┬─── + │ ╰───── def: 2 + │ + 4 │ contract Middle is Base { + │ ───┬── ──┬─ + │ ╰──────────── def: 3 + │ │ + │ ╰─── ref: 1 + 5 │ int in_middle; + │ ────┬──── + │ ╰────── def: 4 + │ + 7 │ contract Test is Middle { + │ ──┬─ ───┬── + │ ╰───────────── def: 5 + │ │ + │ ╰──── ref: 3 + 8 │ function test() public { + │ ──┬─ + │ ╰─── def: 6 + 9 │ in_base; + │ ───┬─── + │ ╰───── ref: 2 + 10 │ in_middle; + │ ────┬──── + │ ╰────── ref: 4 +────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/inherited_state_vars/input.sol b/crates/solidity/testing/snapshots/bindings_output/contracts/inherited_state_vars/input.sol new file mode 100644 index 0000000000..593a55a1c5 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/inherited_state_vars/input.sol @@ -0,0 +1,12 @@ +contract Base { + int in_base; +} +contract Middle is Base { + int in_middle; +} +contract Test is Middle { + function test() public { + in_base; + in_middle; + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/internal_visibility/generated/0.4.11-failure.txt b/crates/solidity/testing/snapshots/bindings_output/contracts/internal_visibility/generated/0.4.11-failure.txt new file mode 100644 index 0000000000..507119f26e --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/internal_visibility/generated/0.4.11-failure.txt @@ -0,0 +1,13 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected ContractKeyword or ImportKeyword or InterfaceKeyword or LibraryKeyword or PragmaKeyword. + ╭─[input.sol:1:1] + │ + 1 │ ╭─▶ abstract contract Ownable { + ┆ ┆ + 13 │ ├─▶ } + │ │ + │ ╰─────── Error occurred here. +────╯ +References and definitions: diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/internal_visibility/generated/0.6.0-success.txt b/crates/solidity/testing/snapshots/bindings_output/contracts/internal_visibility/generated/0.6.0-success.txt new file mode 100644 index 0000000000..acd63c8cb7 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/internal_visibility/generated/0.6.0-success.txt @@ -0,0 +1,41 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ abstract contract Ownable { + │ ───┬─── + │ ╰───── def: 1 + 2 │ address internal owner; + │ ──┬── + │ ╰──── def: 2 + 3 │ address default_visibility; + │ ─────────┬──────── + │ ╰────────── def: 3 + 4 │ function _internal_only() internal {} + │ ───────┬────── + │ ╰──────── def: 4 + │ + 6 │ contract Test is Ownable { + │ ──┬─ ───┬─── + │ ╰────────────── def: 5 + │ │ + │ ╰───── ref: 1 + 7 │ function test() public { + │ ──┬─ + │ ╰─── def: 6 + 8 │ owner; + │ ──┬── + │ ╰──── ref: 2 + 9 │ default_visibility; + │ ─────────┬──────── + │ ╰────────── ref: 3 + 10 │ _internal_only(); + │ ───────┬────── + │ ╰──────── ref: 4 + 11 │ Ownable._internal_only(); + │ ───┬─── ───────┬────── + │ ╰──────────────────── ref: 1 + │ │ + │ ╰──────── ref: 4 +────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/internal_visibility/input.sol b/crates/solidity/testing/snapshots/bindings_output/contracts/internal_visibility/input.sol new file mode 100644 index 0000000000..48bd9c2fda --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/internal_visibility/input.sol @@ -0,0 +1,13 @@ +abstract contract Ownable { + address internal owner; + address default_visibility; + function _internal_only() internal {} +} +contract Test is Ownable { + function test() public { + owner; + default_visibility; + _internal_only(); + Ownable._internal_only(); + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/legacy_constructors/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/contracts/legacy_constructors/generated/0.4.11-success.txt new file mode 100644 index 0000000000..33d044032f --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/legacy_constructors/generated/0.4.11-success.txt @@ -0,0 +1,20 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Base { + │ ──┬─ + │ ╰─── def: 1 + │ + 3 │ contract Test is Base { + │ ──┬─ ──┬─ + │ ╰─────────── def: 2 + │ │ + │ ╰─── ref: 1 + 4 │ function Test() public Base() {} + │ ──┬─ ──┬─ + │ ╰───────────────── def: 3 + │ │ + │ ╰─── ref: 1 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/legacy_constructors/generated/0.5.0-failure.txt b/crates/solidity/testing/snapshots/bindings_output/contracts/legacy_constructors/generated/0.5.0-failure.txt new file mode 100644 index 0000000000..24988498b8 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/legacy_constructors/generated/0.5.0-failure.txt @@ -0,0 +1,20 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Base { + │ ──┬─ + │ ╰─── def: 1 + │ + 3 │ contract Test is Base { + │ ──┬─ ──┬─ + │ ╰─────────── def: 2 + │ │ + │ ╰─── ref: 1 + 4 │ function Test() public Base() {} + │ ──┬─ ──┬─ + │ ╰───────────────── def: 3 + │ │ + │ ╰─── unresolved +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/legacy_constructors/input.sol b/crates/solidity/testing/snapshots/bindings_output/contracts/legacy_constructors/input.sol new file mode 100644 index 0000000000..eba69e5203 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/legacy_constructors/input.sol @@ -0,0 +1,5 @@ +contract Base { +} +contract Test is Base { + function Test() public Base() {} +} diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/legacy_function_options/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/contracts/legacy_function_options/generated/0.4.11-success.txt new file mode 100644 index 0000000000..e7f54749fd --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/legacy_function_options/generated/0.4.11-success.txt @@ -0,0 +1,35 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract RefundVault { + │ ─────┬───── + │ ╰─────── def: 1 + 2 │ function deposit() public payable {} + │ ───┬─── + │ ╰───── def: 2 + │ + 4 │ contract Test { + │ ──┬─ + │ ╰─── def: 3 + 5 │ RefundVault public vault; + │ ─────┬───── ──┬── + │ ╰──────────────────── ref: 1 + │ │ + │ ╰──── def: 4 + 6 │ function test() internal { + │ ──┬─ + │ ╰─── def: 5 + 7 │ vault.deposit.value(msg.value)(); + │ ──┬── ───┬─── ──┬── ─┬─ ──┬── + │ ╰──────────────────────────── ref: 4 + │ │ │ │ │ + │ ╰───────────────────── ref: 2 + │ │ │ │ + │ ╰────────────── ref: built-in + │ │ │ + │ ╰───────── ref: built-in + │ │ + │ ╰──── ref: built-in +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/legacy_function_options/generated/0.7.0-failure.txt b/crates/solidity/testing/snapshots/bindings_output/contracts/legacy_function_options/generated/0.7.0-failure.txt new file mode 100644 index 0000000000..065ccbdfad --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/legacy_function_options/generated/0.7.0-failure.txt @@ -0,0 +1,35 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract RefundVault { + │ ─────┬───── + │ ╰─────── def: 1 + 2 │ function deposit() public payable {} + │ ───┬─── + │ ╰───── def: 2 + │ + 4 │ contract Test { + │ ──┬─ + │ ╰─── def: 3 + 5 │ RefundVault public vault; + │ ─────┬───── ──┬── + │ ╰──────────────────── ref: 1 + │ │ + │ ╰──── def: 4 + 6 │ function test() internal { + │ ──┬─ + │ ╰─── def: 5 + 7 │ vault.deposit.value(msg.value)(); + │ ──┬── ───┬─── ──┬── ─┬─ ──┬── + │ ╰──────────────────────────── ref: 4 + │ │ │ │ │ + │ ╰───────────────────── ref: 2 + │ │ │ │ + │ ╰────────────── unresolved + │ │ │ + │ ╰───────── ref: built-in + │ │ + │ ╰──── ref: built-in +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/legacy_function_options/input.sol b/crates/solidity/testing/snapshots/bindings_output/contracts/legacy_function_options/input.sol new file mode 100644 index 0000000000..d5fd938d05 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/legacy_function_options/input.sol @@ -0,0 +1,9 @@ +contract RefundVault { + function deposit() public payable {} +} +contract Test { + RefundVault public vault; + function test() internal { + vault.deposit.value(msg.value)(); + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/multi_inheritance/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/contracts/multi_inheritance/generated/0.4.11-success.txt new file mode 100644 index 0000000000..280b52987b --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/multi_inheritance/generated/0.4.11-success.txt @@ -0,0 +1,38 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Base1 { + │ ──┬── + │ ╰──── def: 1 + 2 │ function base1() returns (int) { return 1; } + │ ──┬── + │ ╰──── def: 2 + │ + 5 │ contract Base2 { + │ ──┬── + │ ╰──── def: 3 + 6 │ function base2() returns (int) { return 2; } + │ ──┬── + │ ╰──── def: 4 + │ + 9 │ contract Derived is + │ ───┬─── + │ ╰───── def: 5 + 10 │ Base1, + │ ──┬── + │ ╰──── ref: 1 + 11 │ Base2 + │ ──┬── + │ ╰──── ref: 3 + │ + 13 │ function test() returns (int) { + │ ──┬─ + │ ╰─── def: 6 + 14 │ return base1() + base2(); + │ ──┬── ──┬── + │ ╰────────────── ref: 2 + │ │ + │ ╰──── ref: 4 +────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/multi_inheritance/input.sol b/crates/solidity/testing/snapshots/bindings_output/contracts/multi_inheritance/input.sol new file mode 100644 index 0000000000..604fcfa794 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/multi_inheritance/input.sol @@ -0,0 +1,16 @@ +contract Base1 { + function base1() returns (int) { return 1; } +} + +contract Base2 { + function base2() returns (int) { return 2; } +} + +contract Derived is + Base1, + Base2 +{ + function test() returns (int) { + return base1() + base2(); + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/public_array_getters/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/contracts/public_array_getters/generated/0.4.11-success.txt new file mode 100644 index 0000000000..3c4e526ae4 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/public_array_getters/generated/0.4.11-success.txt @@ -0,0 +1,30 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ function test(TokenState tokenState) public { + │ ──┬─ ─────┬──── ─────┬──── + │ ╰───────────────────────── def: 2 + │ │ │ + │ ╰───────────────── ref: 4 + │ │ + │ ╰────── def: 3 + 3 │ tokenState.owners(1).balance; + │ ─────┬──── ───┬── ───┬─── + │ ╰──────────────────────── ref: 3 + │ │ │ + │ ╰─────────────── ref: 5 + │ │ + │ ╰───── ref: built-in + │ + 6 │ contract TokenState { + │ ─────┬──── + │ ╰────── def: 4 + 7 │ address[] public owners; + │ ───┬── + │ ╰──── def: 5 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/public_array_getters/input.sol b/crates/solidity/testing/snapshots/bindings_output/contracts/public_array_getters/input.sol new file mode 100644 index 0000000000..1fd95e6a5e --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/public_array_getters/input.sol @@ -0,0 +1,8 @@ +contract Test { + function test(TokenState tokenState) public { + tokenState.owners(1).balance; + } +} +contract TokenState { + address[] public owners; +} diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/public_getter_members/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/contracts/public_getter_members/generated/0.4.11-success.txt new file mode 100644 index 0000000000..503776d84b --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/public_getter_members/generated/0.4.11-success.txt @@ -0,0 +1,30 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Base { + │ ──┬─ + │ ╰─── def: 1 + 2 │ address public owner; + │ ──┬── + │ ╰──── def: 2 + │ + 4 │ contract Test { + │ ──┬─ + │ ╰─── def: 3 + 5 │ function test(Base base) public { + │ ──┬─ ──┬─ ──┬─ + │ ╰───────────── def: 4 + │ │ │ + │ ╰──────── ref: 1 + │ │ + │ ╰─── def: 5 + 6 │ base.owner().balance; + │ ──┬─ ──┬── ───┬─── + │ ╰─────────────────── ref: 5 + │ │ │ + │ ╰────────────── ref: 2 + │ │ + │ ╰───── ref: built-in +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/public_getter_members/input.sol b/crates/solidity/testing/snapshots/bindings_output/contracts/public_getter_members/input.sol new file mode 100644 index 0000000000..eca1760059 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/public_getter_members/input.sol @@ -0,0 +1,8 @@ +contract Base { + address public owner; +} +contract Test { + function test(Base base) public { + base.owner().balance; + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/public_getters/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/contracts/public_getters/generated/0.4.11-success.txt index beb90fd893..7afdf26c48 100644 --- a/crates/solidity/testing/snapshots/bindings_output/contracts/public_getters/generated/0.4.11-success.txt +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/public_getters/generated/0.4.11-success.txt @@ -26,10 +26,8 @@ References and definitions: │ ──┬─ │ ╰─── def: 6 10 │ return y + this.y() + f.x(); - │ ┬ ──┬─ ┬ ┬ ┬ + │ ┬ ┬ ┬ ┬ │ ╰─────────────────── ref: 4 - │ │ │ │ │ - │ ╰───────────── ref: 3 │ │ │ │ │ ╰────────── ref: 4 │ │ │ diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/public_inherited_getter/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/contracts/public_inherited_getter/generated/0.4.11-success.txt new file mode 100644 index 0000000000..fab1b7434b --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/public_inherited_getter/generated/0.4.11-success.txt @@ -0,0 +1,35 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract RegistrarAccess { + │ ───────┬─────── + │ ╰───────── def: 1 + 2 │ Root root; + │ ──┬─ ──┬─ + │ ╰──────── ref: 4 + │ │ + │ ╰─── def: 2 + 3 │ function test() public { + │ ──┬─ + │ ╰─── def: 3 + 4 │ root.controllers; + │ ──┬─ ─────┬───── + │ ╰─────────────── ref: 2 + │ │ + │ ╰─────── ref: 6 + │ + 8 │ contract Root is Controllable {} + │ ──┬─ ──────┬───── + │ ╰─────────────────── def: 4 + │ │ + │ ╰─────── ref: 5 + │ + 10 │ contract Controllable { + │ ──────┬───── + │ ╰─────── def: 5 + 11 │ mapping (address => bool) public controllers; + │ ─────┬───── + │ ╰─────── def: 6 +────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/public_inherited_getter/input.sol b/crates/solidity/testing/snapshots/bindings_output/contracts/public_inherited_getter/input.sol new file mode 100644 index 0000000000..5388a5d254 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/public_inherited_getter/input.sol @@ -0,0 +1,12 @@ +contract RegistrarAccess { + Root root; + function test() public { + root.controllers; + } +} + +contract Root is Controllable {} + +contract Controllable { + mapping (address => bool) public controllers; +} diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/public_mapping_getters/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/contracts/public_mapping_getters/generated/0.4.11-success.txt new file mode 100644 index 0000000000..84dff71c3f --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/public_mapping_getters/generated/0.4.11-success.txt @@ -0,0 +1,30 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ function test(TokenState tokenState) public { + │ ──┬─ ─────┬──── ─────┬──── + │ ╰───────────────────────── def: 2 + │ │ │ + │ ╰───────────────── ref: 4 + │ │ + │ ╰────── def: 3 + 3 │ tokenState.owners(1).balance; + │ ─────┬──── ───┬── ───┬─── + │ ╰──────────────────────── ref: 3 + │ │ │ + │ ╰─────────────── ref: 5 + │ │ + │ ╰───── ref: built-in + │ + 6 │ contract TokenState { + │ ─────┬──── + │ ╰────── def: 4 + 7 │ mapping(uint => address) public owners; + │ ───┬── + │ ╰──── def: 5 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/public_mapping_getters/input.sol b/crates/solidity/testing/snapshots/bindings_output/contracts/public_mapping_getters/input.sol new file mode 100644 index 0000000000..69efebff11 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/public_mapping_getters/input.sol @@ -0,0 +1,8 @@ +contract Test { + function test(TokenState tokenState) public { + tokenState.owners(1).balance; + } +} +contract TokenState { + mapping(uint => address) public owners; +} diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/public_struct_getter/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/contracts/public_struct_getter/generated/0.4.11-success.txt new file mode 100644 index 0000000000..28722902e6 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/public_struct_getter/generated/0.4.11-success.txt @@ -0,0 +1,37 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Base { + │ ──┬─ + │ ╰─── def: 1 + 2 │ struct Owner { address owner; } + │ ──┬── ──┬── + │ ╰──────────────────── def: 2 + │ │ + │ ╰──── def: 3 + 3 │ Owner public owner; + │ ──┬── ──┬── + │ ╰───────────────── ref: 2 + │ │ + │ ╰──── def: 4 + │ + 5 │ contract Test { + │ ──┬─ + │ ╰─── def: 5 + 6 │ function test(Base base) public { + │ ──┬─ ──┬─ ──┬─ + │ ╰───────────── def: 6 + │ │ │ + │ ╰──────── ref: 1 + │ │ + │ ╰─── def: 7 + 7 │ base.owner().balance; + │ ──┬─ ──┬── ───┬─── + │ ╰─────────────────── ref: 7 + │ │ │ + │ ╰────────────── ref: 4 + │ │ + │ ╰───── ref: built-in +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/public_struct_getter/input.sol b/crates/solidity/testing/snapshots/bindings_output/contracts/public_struct_getter/input.sol new file mode 100644 index 0000000000..3c85bc3911 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/public_struct_getter/input.sol @@ -0,0 +1,9 @@ +contract Base { + struct Owner { address owner; } + Owner public owner; +} +contract Test { + function test(Base base) public { + base.owner().balance; + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/qualified_inherited/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/contracts/qualified_inherited/generated/0.4.11-success.txt new file mode 100644 index 0000000000..da81507f48 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/qualified_inherited/generated/0.4.11-success.txt @@ -0,0 +1,26 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Base { + │ ──┬─ + │ ╰─── def: 1 + 2 │ bool renounced; + │ ────┬──── + │ ╰────── def: 2 + │ + 4 │ contract Test is Base { + │ ──┬─ ──┬─ + │ ╰─────────── def: 3 + │ │ + │ ╰─── ref: 1 + 5 │ function test() public { + │ ──┬─ + │ ╰─── def: 4 + 6 │ Base.renounced = true; + │ ──┬─ ────┬──── + │ ╰───────────── ref: 1 + │ │ + │ ╰────── ref: 2 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/qualified_inherited/input.sol b/crates/solidity/testing/snapshots/bindings_output/contracts/qualified_inherited/input.sol new file mode 100644 index 0000000000..bc9b730d79 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/qualified_inherited/input.sol @@ -0,0 +1,8 @@ +contract Base { + bool renounced; +} +contract Test is Base { + function test() public { + Base.renounced = true; + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/qualified_parent_call/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/contracts/qualified_parent_call/generated/0.4.11-success.txt new file mode 100644 index 0000000000..e0763a81c8 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/qualified_parent_call/generated/0.4.11-success.txt @@ -0,0 +1,31 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Base { + │ ──┬─ + │ ╰─── def: 1 + 2 │ function in_base() internal {} + │ ───┬─── + │ ╰───── def: 2 + │ + 4 │ contract Middle is Base {} + │ ───┬── ──┬─ + │ ╰──────────── def: 3 + │ │ + │ ╰─── ref: 1 + 5 │ contract Test is Middle { + │ ──┬─ ───┬── + │ ╰───────────── def: 4 + │ │ + │ ╰──── ref: 3 + 6 │ function test() public { + │ ──┬─ + │ ╰─── def: 5 + 7 │ Base.in_base(); + │ ──┬─ ───┬─── + │ ╰─────────── ref: 1 + │ │ + │ ╰───── ref: 2 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/qualified_parent_call/input.sol b/crates/solidity/testing/snapshots/bindings_output/contracts/qualified_parent_call/input.sol new file mode 100644 index 0000000000..3e23b1b8b9 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/qualified_parent_call/input.sol @@ -0,0 +1,9 @@ +contract Base { + function in_base() internal {} +} +contract Middle is Base {} +contract Test is Middle { + function test() public { + Base.in_base(); + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/super_deep/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/contracts/super_deep/generated/0.4.11-success.txt new file mode 100644 index 0000000000..66779a28d1 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/super_deep/generated/0.4.11-success.txt @@ -0,0 +1,29 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Base { + │ ──┬─ + │ ╰─── def: 1 + 2 │ function in_base() {} + │ ───┬─── + │ ╰───── def: 2 + │ + 4 │ contract Middle is Base {} + │ ───┬── ──┬─ + │ ╰──────────── def: 3 + │ │ + │ ╰─── ref: 1 + 5 │ contract Test is Middle { + │ ──┬─ ───┬── + │ ╰───────────── def: 4 + │ │ + │ ╰──── ref: 3 + 6 │ function in_base() { + │ ───┬─── + │ ╰───── def: 5 + 7 │ super.in_base(); + │ ───┬─── + │ ╰───── ref: 2 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/super_deep/input.sol b/crates/solidity/testing/snapshots/bindings_output/contracts/super_deep/input.sol new file mode 100644 index 0000000000..0a933e7431 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/super_deep/input.sol @@ -0,0 +1,9 @@ +contract Base { + function in_base() {} +} +contract Middle is Base {} +contract Test is Middle { + function in_base() { + super.in_base(); + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/super_linearisation/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/contracts/super_linearisation/generated/0.4.11-success.txt index e5d4bc6d71..5819b34073 100644 --- a/crates/solidity/testing/snapshots/bindings_output/contracts/super_linearisation/generated/0.4.11-success.txt +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/super_linearisation/generated/0.4.11-success.txt @@ -19,9 +19,7 @@ References and definitions: │ ─┬─ │ ╰─── def: 4 6 │ super.foo(); - │ ──┬── ─┬─ - │ ╰──────── ref: 1 - │ │ + │ ─┬─ │ ╰─── ref: 2 │ 9 │ contract C is A { @@ -33,9 +31,7 @@ References and definitions: │ ─┬─ │ ╰─── def: 6 11 │ super.foo(); - │ ──┬── ─┬─ - │ ╰──────── ref: 1 - │ │ + │ ─┬─ │ ╰─── ref: 4 │ 14 │ contract D is B, C { @@ -49,8 +45,6 @@ References and definitions: │ ─┬─ │ ╰─── def: 8 16 │ super.foo(); - │ ──┬── ─┬─ - │ ╰──────── refs: 3, 5 - │ │ + │ ─┬─ │ ╰─── ref: 6 ────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/super_scope/generated/0.4.16-failure.txt b/crates/solidity/testing/snapshots/bindings_output/contracts/super_scope/generated/0.4.16-failure.txt index 1e7b1003b1..1e0d62fb2d 100644 --- a/crates/solidity/testing/snapshots/bindings_output/contracts/super_scope/generated/0.4.16-failure.txt +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/super_scope/generated/0.4.16-failure.txt @@ -28,8 +28,6 @@ References and definitions: │ │ │ ╰── ref: 1 13 │ return super.foo(); - │ ──┬── ─┬─ - │ ╰──────── ref: 1 - │ │ + │ ─┬─ │ ╰─── ref: 2 ────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/super_scope/generated/0.6.0-success.txt b/crates/solidity/testing/snapshots/bindings_output/contracts/super_scope/generated/0.6.0-success.txt index c3f150295d..7feb70120a 100644 --- a/crates/solidity/testing/snapshots/bindings_output/contracts/super_scope/generated/0.6.0-success.txt +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/super_scope/generated/0.6.0-success.txt @@ -22,8 +22,6 @@ References and definitions: │ │ │ ╰── ref: 1 13 │ return super.foo(); - │ ──┬── ─┬─ - │ ╰──────── ref: 1 - │ │ + │ ─┬─ │ ╰─── ref: 2 ────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/this_scope/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/contracts/this_scope/generated/0.4.11-success.txt index 2f9f1eb37e..ac355a829c 100644 --- a/crates/solidity/testing/snapshots/bindings_output/contracts/this_scope/generated/0.4.11-success.txt +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/this_scope/generated/0.4.11-success.txt @@ -14,8 +14,6 @@ References and definitions: │ ─┬─ │ ╰─── def: 3 5 │ this.foo(); - │ ──┬─ ─┬─ - │ ╰─────── ref: 1 - │ │ + │ ─┬─ │ ╰─── ref: 2 ───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/unnamed_function/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/contracts/unnamed_function/generated/0.4.11-success.txt new file mode 100644 index 0000000000..24a80f6855 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/unnamed_function/generated/0.4.11-success.txt @@ -0,0 +1,13 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + │ + 3 │ revert(); + │ ───┬── + │ ╰──── ref: built-in +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/unnamed_function/generated/0.4.22-success.txt b/crates/solidity/testing/snapshots/bindings_output/contracts/unnamed_function/generated/0.4.22-success.txt new file mode 100644 index 0000000000..165fe5e41d --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/unnamed_function/generated/0.4.22-success.txt @@ -0,0 +1,13 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + │ + 3 │ revert(); + │ ───┬── + │ ╰──── refs: built-in, built-in +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/unnamed_function/generated/0.6.0-failure.txt b/crates/solidity/testing/snapshots/bindings_output/contracts/unnamed_function/generated/0.6.0-failure.txt new file mode 100644 index 0000000000..17e5d6e85e --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/unnamed_function/generated/0.6.0-failure.txt @@ -0,0 +1,19 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected ConstantKeyword or Identifier or InternalKeyword or OverrideKeyword or PrivateKeyword or PublicKeyword. + ╭─[input.sol:2:25] + │ + 2 │ ╭─▶ function () payable { + ┆ ┆ + 4 │ ├─▶ } + │ │ + │ ╰─────────── Error occurred here. +───╯ +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/unnamed_function/generated/0.6.5-failure.txt b/crates/solidity/testing/snapshots/bindings_output/contracts/unnamed_function/generated/0.6.5-failure.txt new file mode 100644 index 0000000000..1dda92db7e --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/unnamed_function/generated/0.6.5-failure.txt @@ -0,0 +1,19 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected ConstantKeyword or Identifier or ImmutableKeyword or InternalKeyword or OverrideKeyword or PrivateKeyword or PublicKeyword. + ╭─[input.sol:2:25] + │ + 2 │ ╭─▶ function () payable { + ┆ ┆ + 4 │ ├─▶ } + │ │ + │ ╰─────────── Error occurred here. +───╯ +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/unnamed_function/generated/0.8.27-failure.txt b/crates/solidity/testing/snapshots/bindings_output/contracts/unnamed_function/generated/0.8.27-failure.txt new file mode 100644 index 0000000000..61ee40e68c --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/unnamed_function/generated/0.8.27-failure.txt @@ -0,0 +1,19 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected ConstantKeyword or Identifier or ImmutableKeyword or InternalKeyword or OverrideKeyword or PrivateKeyword or PublicKeyword or TransientKeyword. + ╭─[input.sol:2:25] + │ + 2 │ ╭─▶ function () payable { + ┆ ┆ + 4 │ ├─▶ } + │ │ + │ ╰─────────── Error occurred here. +───╯ +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/unnamed_function/input.sol b/crates/solidity/testing/snapshots/bindings_output/contracts/unnamed_function/input.sol new file mode 100644 index 0000000000..e69d46f688 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/unnamed_function/input.sol @@ -0,0 +1,5 @@ +contract Test { + function () payable { + revert(); + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/virtual_methods/generated/0.4.16-failure.txt b/crates/solidity/testing/snapshots/bindings_output/contracts/virtual_methods/generated/0.4.16-failure.txt index 99eacf7c99..1a4864098f 100644 --- a/crates/solidity/testing/snapshots/bindings_output/contracts/virtual_methods/generated/0.4.16-failure.txt +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/virtual_methods/generated/0.4.16-failure.txt @@ -58,8 +58,6 @@ References and definitions: │ │ │ ╰── ref: 5 25 │ return super.foo(); - │ ──┬── ─┬─ - │ ╰──────── refs: 3, 5 - │ │ + │ ─┬─ │ ╰─── ref: 6 ────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/contracts/virtual_methods/generated/0.6.0-success.txt b/crates/solidity/testing/snapshots/bindings_output/contracts/virtual_methods/generated/0.6.0-success.txt index 78ee0e6e94..c5f1386460 100644 --- a/crates/solidity/testing/snapshots/bindings_output/contracts/virtual_methods/generated/0.6.0-success.txt +++ b/crates/solidity/testing/snapshots/bindings_output/contracts/virtual_methods/generated/0.6.0-success.txt @@ -46,8 +46,6 @@ References and definitions: │ │ │ ╰── ref: 5 25 │ return super.foo(); - │ ──┬── ─┬─ - │ ╰──────── refs: 3, 5 - │ │ + │ ─┬─ │ ╰─── ref: 6 ────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/errors/selector/generated/0.4.11-failure.txt b/crates/solidity/testing/snapshots/bindings_output/errors/selector/generated/0.4.11-failure.txt new file mode 100644 index 0000000000..5bc593e595 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/errors/selector/generated/0.4.11-failure.txt @@ -0,0 +1,31 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected Equal or Semicolon. + ╭─[input.sol:2:20] + │ + 2 │ error TestError(); + │ ─┬ + │ ╰── Error occurred here. +───╯ +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ error TestError(); + │ ──┬── ────┬──── + │ ╰────────────── unresolved + │ │ + │ ╰────── def: 2 + │ + 4 │ function test() public { + │ ──┬─ + │ ╰─── def: 3 + 5 │ TestError.selector; + │ ────┬──── ────┬─── + │ ╰─────────────── ref: 2 + │ │ + │ ╰───── unresolved +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/errors/selector/generated/0.8.4-success.txt b/crates/solidity/testing/snapshots/bindings_output/errors/selector/generated/0.8.4-success.txt new file mode 100644 index 0000000000..41e568485d --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/errors/selector/generated/0.8.4-success.txt @@ -0,0 +1,21 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ error TestError(); + │ ────┬──── + │ ╰────── def: 2 + │ + 4 │ function test() public { + │ ──┬─ + │ ╰─── def: 3 + 5 │ TestError.selector; + │ ────┬──── ────┬─── + │ ╰─────────────── ref: 2 + │ │ + │ ╰───── ref: built-in +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/errors/selector/input.sol b/crates/solidity/testing/snapshots/bindings_output/errors/selector/input.sol new file mode 100644 index 0000000000..1c9d61ed82 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/errors/selector/input.sol @@ -0,0 +1,7 @@ +contract Test { + error TestError(); + + function test() public { + TestError.selector; + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/expressions/binary_operators/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/expressions/binary_operators/generated/0.4.11-success.txt new file mode 100644 index 0000000000..69f5695dea --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/expressions/binary_operators/generated/0.4.11-success.txt @@ -0,0 +1,100 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ library Lib { + │ ─┬─ + │ ╰─── def: 1 + 2 │ function nop_uint(uint x) public returns (uint) {} + │ ────┬─── ┬ + │ ╰──────────── def: 2 + │ │ + │ ╰── def: 3 + 3 │ function nop_bool(bool x) public returns (bool) {} + │ ────┬─── ┬ + │ ╰──────────── def: 4 + │ │ + │ ╰── def: 5 + │ + 6 │ contract Test { + │ ──┬─ + │ ╰─── def: 6 + 7 │ using Lib for uint; + │ ─┬─ + │ ╰─── ref: 1 + 8 │ using Lib for bool; + │ ─┬─ + │ ╰─── ref: 1 + 9 │ function test(uint a, uint b) public { + │ ──┬─ ┬ ┬ + │ ╰────────────────── def: 7 + │ │ │ + │ ╰────────── def: 8 + │ │ + │ ╰── def: 9 + 10 │ (a += b).nop_uint(); + │ ┬ ┬ ────┬─── + │ ╰───────────────── ref: 8 + │ │ │ + │ ╰──────────── ref: 9 + │ │ + │ ╰───── ref: 2 + 11 │ (true ? a : b).nop_uint(); + │ ┬ ┬ ────┬─── + │ ╰──────────────── ref: 8 + │ │ │ + │ ╰──────────── ref: 9 + │ │ + │ ╰───── ref: 2 + 12 │ (a == b).nop_bool(); + │ ┬ ┬ ────┬─── + │ ╰───────────────── ref: 8 + │ │ │ + │ ╰──────────── ref: 9 + │ │ + │ ╰───── ref: 4 + 13 │ (a > b).nop_bool(); + │ ┬ ┬ ────┬─── + │ ╰──────────────── ref: 8 + │ │ │ + │ ╰──────────── ref: 9 + │ │ + │ ╰───── ref: 4 + 14 │ (a | b).nop_uint(); + │ ┬ ┬ ────┬─── + │ ╰──────────────── ref: 8 + │ │ │ + │ ╰──────────── ref: 9 + │ │ + │ ╰───── ref: 2 + 15 │ (a << 1).nop_uint(); + │ ┬ ────┬─── + │ ╰───────────────── ref: 8 + │ │ + │ ╰───── ref: 2 + 16 │ (a + b).nop_uint(); + │ ┬ ┬ ────┬─── + │ ╰──────────────── ref: 8 + │ │ │ + │ ╰──────────── ref: 9 + │ │ + │ ╰───── ref: 2 + 17 │ (a * b).nop_uint(); + │ ┬ ┬ ────┬─── + │ ╰──────────────── ref: 8 + │ │ │ + │ ╰──────────── ref: 9 + │ │ + │ ╰───── ref: 2 + 18 │ (a++).nop_uint(); + │ ┬ ────┬─── + │ ╰────────────── ref: 8 + │ │ + │ ╰───── ref: 2 + 19 │ (++a).nop_uint(); + │ ┬ ────┬─── + │ ╰──────────── ref: 8 + │ │ + │ ╰───── ref: 2 +────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/expressions/binary_operators/input.sol b/crates/solidity/testing/snapshots/bindings_output/expressions/binary_operators/input.sol new file mode 100644 index 0000000000..90d76c2564 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/expressions/binary_operators/input.sol @@ -0,0 +1,21 @@ +library Lib { + function nop_uint(uint x) public returns (uint) {} + function nop_bool(bool x) public returns (bool) {} +} + +contract Test { + using Lib for uint; + using Lib for bool; + function test(uint a, uint b) public { + (a += b).nop_uint(); + (true ? a : b).nop_uint(); + (a == b).nop_bool(); + (a > b).nop_bool(); + (a | b).nop_uint(); + (a << 1).nop_uint(); + (a + b).nop_uint(); + (a * b).nop_uint(); + (a++).nop_uint(); + (++a).nop_uint(); + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/expressions/elementary_casting/generated/0.4.11-failure.txt b/crates/solidity/testing/snapshots/bindings_output/expressions/elementary_casting/generated/0.4.11-failure.txt new file mode 100644 index 0000000000..f25c1ffe3c --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/expressions/elementary_casting/generated/0.4.11-failure.txt @@ -0,0 +1,40 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected AddressKeyword or AssemblyKeyword or BoolKeyword or BreakKeyword or ByteKeyword or BytesKeyword or CloseBrace or ContinueKeyword or DecimalLiteral or DoKeyword or DoubleQuotedHexStringLiteral or DoubleQuotedStringLiteral or FalseKeyword or FixedKeyword or ForKeyword or FunctionKeyword or HexLiteral or Identifier or IfKeyword or IntKeyword or MappingKeyword or NewKeyword or OpenBrace or OpenBracket or OpenParen or ReturnKeyword or SingleQuotedHexStringLiteral or SingleQuotedStringLiteral or StringKeyword or SuperKeyword or ThisKeyword or ThrowKeyword or TrueKeyword or UfixedKeyword or UintKeyword or VarKeyword or WhileKeyword. + ╭─[input.sol:6:9] + │ + 6 │ ╭─▶ payable(a).call(""); + ┆ ┆ + 8 │ ├─▶ } + │ │ + │ ╰─────────── Error occurred here. +───╯ +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ using Lib for uint; + │ ─┬─ + │ ╰─── ref: 4 + │ + 4 │ function test(address a) public { + │ ──┬─ ┬ + │ ╰───────────── def: 2 + │ │ + │ ╰── def: 3 + 5 │ address(this).balance; + │ ───┬─── + │ ╰───── ref: built-in + │ + 11 │ library Lib { + │ ─┬─ + │ ╰─── def: 4 + 12 │ function noop(uint x) public returns (uint) {} + │ ──┬─ ┬ + │ ╰────────── def: 5 + │ │ + │ ╰── def: 6 +────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/expressions/elementary_casting/generated/0.4.21-failure.txt b/crates/solidity/testing/snapshots/bindings_output/expressions/elementary_casting/generated/0.4.21-failure.txt new file mode 100644 index 0000000000..bdf6d7ee03 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/expressions/elementary_casting/generated/0.4.21-failure.txt @@ -0,0 +1,40 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected AddressKeyword or AssemblyKeyword or BoolKeyword or BreakKeyword or ByteKeyword or BytesKeyword or CloseBrace or ContinueKeyword or DecimalLiteral or DoKeyword or DoubleQuotedHexStringLiteral or DoubleQuotedStringLiteral or EmitKeyword or FalseKeyword or FixedKeyword or ForKeyword or FunctionKeyword or HexLiteral or Identifier or IfKeyword or IntKeyword or MappingKeyword or NewKeyword or OpenBrace or OpenBracket or OpenParen or ReturnKeyword or SingleQuotedHexStringLiteral or SingleQuotedStringLiteral or StringKeyword or SuperKeyword or ThisKeyword or ThrowKeyword or TrueKeyword or UfixedKeyword or UintKeyword or VarKeyword or WhileKeyword. + ╭─[input.sol:6:9] + │ + 6 │ ╭─▶ payable(a).call(""); + ┆ ┆ + 8 │ ├─▶ } + │ │ + │ ╰─────────── Error occurred here. +───╯ +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ using Lib for uint; + │ ─┬─ + │ ╰─── ref: 4 + │ + 4 │ function test(address a) public { + │ ──┬─ ┬ + │ ╰───────────── def: 2 + │ │ + │ ╰── def: 3 + 5 │ address(this).balance; + │ ───┬─── + │ ╰───── ref: built-in + │ + 11 │ library Lib { + │ ─┬─ + │ ╰─── def: 4 + 12 │ function noop(uint x) public returns (uint) {} + │ ──┬─ ┬ + │ ╰────────── def: 5 + │ │ + │ ╰── def: 6 +────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/expressions/elementary_casting/generated/0.5.0-failure.txt b/crates/solidity/testing/snapshots/bindings_output/expressions/elementary_casting/generated/0.5.0-failure.txt new file mode 100644 index 0000000000..8ee42cb4f3 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/expressions/elementary_casting/generated/0.5.0-failure.txt @@ -0,0 +1,40 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected AddressKeyword or AssemblyKeyword or BoolKeyword or BreakKeyword or ByteKeyword or BytesKeyword or CloseBrace or ContinueKeyword or DecimalLiteral or DoKeyword or DoubleQuotedHexStringLiteral or DoubleQuotedStringLiteral or EmitKeyword or FalseKeyword or FixedKeyword or ForKeyword or FunctionKeyword or HexLiteral or Identifier or IfKeyword or IntKeyword or MappingKeyword or NewKeyword or OpenBrace or OpenBracket or OpenParen or ReturnKeyword or SingleQuotedHexStringLiteral or SingleQuotedStringLiteral or StringKeyword or SuperKeyword or ThisKeyword or TrueKeyword or UfixedKeyword or UintKeyword or WhileKeyword. + ╭─[input.sol:6:9] + │ + 6 │ ╭─▶ payable(a).call(""); + ┆ ┆ + 8 │ ├─▶ } + │ │ + │ ╰─────────── Error occurred here. +───╯ +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ using Lib for uint; + │ ─┬─ + │ ╰─── ref: 4 + │ + 4 │ function test(address a) public { + │ ──┬─ ┬ + │ ╰───────────── def: 2 + │ │ + │ ╰── def: 3 + 5 │ address(this).balance; + │ ───┬─── + │ ╰───── ref: built-in + │ + 11 │ library Lib { + │ ─┬─ + │ ╰─── def: 4 + 12 │ function noop(uint x) public returns (uint) {} + │ ──┬─ ┬ + │ ╰────────── def: 5 + │ │ + │ ╰── def: 6 +────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/expressions/elementary_casting/generated/0.5.3-failure.txt b/crates/solidity/testing/snapshots/bindings_output/expressions/elementary_casting/generated/0.5.3-failure.txt new file mode 100644 index 0000000000..0563005915 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/expressions/elementary_casting/generated/0.5.3-failure.txt @@ -0,0 +1,40 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected AddressKeyword or AssemblyKeyword or BoolKeyword or BreakKeyword or ByteKeyword or BytesKeyword or CloseBrace or ContinueKeyword or DecimalLiteral or DoKeyword or DoubleQuotedHexStringLiteral or DoubleQuotedStringLiteral or EmitKeyword or FalseKeyword or FixedKeyword or ForKeyword or FunctionKeyword or HexLiteral or Identifier or IfKeyword or IntKeyword or MappingKeyword or NewKeyword or OpenBrace or OpenBracket or OpenParen or ReturnKeyword or SingleQuotedHexStringLiteral or SingleQuotedStringLiteral or StringKeyword or SuperKeyword or ThisKeyword or TrueKeyword or TypeKeyword or UfixedKeyword or UintKeyword or WhileKeyword. + ╭─[input.sol:6:9] + │ + 6 │ ╭─▶ payable(a).call(""); + ┆ ┆ + 8 │ ├─▶ } + │ │ + │ ╰─────────── Error occurred here. +───╯ +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ using Lib for uint; + │ ─┬─ + │ ╰─── ref: 4 + │ + 4 │ function test(address a) public { + │ ──┬─ ┬ + │ ╰───────────── def: 2 + │ │ + │ ╰── def: 3 + 5 │ address(this).balance; + │ ───┬─── + │ ╰───── ref: built-in + │ + 11 │ library Lib { + │ ─┬─ + │ ╰─── def: 4 + 12 │ function noop(uint x) public returns (uint) {} + │ ──┬─ ┬ + │ ╰────────── def: 5 + │ │ + │ ╰── def: 6 +────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/expressions/elementary_casting/generated/0.6.0-success.txt b/crates/solidity/testing/snapshots/bindings_output/expressions/elementary_casting/generated/0.6.0-success.txt new file mode 100644 index 0000000000..55ec33f7cd --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/expressions/elementary_casting/generated/0.6.0-success.txt @@ -0,0 +1,38 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ using Lib for uint; + │ ─┬─ + │ ╰─── ref: 4 + │ + 4 │ function test(address a) public { + │ ──┬─ ┬ + │ ╰───────────── def: 2 + │ │ + │ ╰── def: 3 + 5 │ address(this).balance; + │ ───┬─── + │ ╰───── ref: built-in + 6 │ payable(a).call(""); + │ ┬ ──┬─ + │ ╰──────── ref: 3 + │ │ + │ ╰─── ref: built-in + 7 │ uint(10).noop(); + │ ──┬─ + │ ╰─── ref: 5 + │ + 11 │ library Lib { + │ ─┬─ + │ ╰─── def: 4 + 12 │ function noop(uint x) public returns (uint) {} + │ ──┬─ ┬ + │ ╰────────── def: 5 + │ │ + │ ╰── def: 6 +────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/expressions/elementary_casting/input.sol b/crates/solidity/testing/snapshots/bindings_output/expressions/elementary_casting/input.sol new file mode 100644 index 0000000000..db44f7978e --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/expressions/elementary_casting/input.sol @@ -0,0 +1,13 @@ +contract Test { + using Lib for uint; + + function test(address a) public { + address(this).balance; + payable(a).call(""); + uint(10).noop(); + } +} + +library Lib { + function noop(uint x) public returns (uint) {} +} diff --git a/crates/solidity/testing/snapshots/bindings_output/expressions/legacy_call_options/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/expressions/legacy_call_options/generated/0.4.11-success.txt new file mode 100644 index 0000000000..4f39167043 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/expressions/legacy_call_options/generated/0.4.11-success.txt @@ -0,0 +1,35 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ function test(address rcpt, bytes memory data) public { + │ ──┬─ ──┬─ ──┬─ + │ ╰─────────────────────────────────── def: 2 + │ │ │ + │ ╰────────────────────── def: 3 + │ │ + │ ╰─── def: 4 + │ + 4 │ rcpt.call.value(1)(data); + │ ──┬─ ──┬─ ──┬── ──┬─ + │ ╰────────────────────── ref: 3 + │ │ │ │ + │ ╰───────────────── ref: built-in + │ │ │ + │ ╰──────────── ref: built-in + │ │ + │ ╰─── ref: 4 + 5 │ rcpt.call.gas(1)(data); + │ ──┬─ ──┬─ ─┬─ ──┬─ + │ ╰──────────────────── ref: 3 + │ │ │ │ + │ ╰─────────────── ref: built-in + │ │ │ + │ ╰─────────── ref: built-in + │ │ + │ ╰─── ref: 4 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/expressions/legacy_call_options/generated/0.7.0-failure.txt b/crates/solidity/testing/snapshots/bindings_output/expressions/legacy_call_options/generated/0.7.0-failure.txt new file mode 100644 index 0000000000..b15ce9308a --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/expressions/legacy_call_options/generated/0.7.0-failure.txt @@ -0,0 +1,35 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ function test(address rcpt, bytes memory data) public { + │ ──┬─ ──┬─ ──┬─ + │ ╰─────────────────────────────────── def: 2 + │ │ │ + │ ╰────────────────────── def: 3 + │ │ + │ ╰─── def: 4 + │ + 4 │ rcpt.call.value(1)(data); + │ ──┬─ ──┬─ ──┬── ──┬─ + │ ╰────────────────────── ref: 3 + │ │ │ │ + │ ╰───────────────── ref: built-in + │ │ │ + │ ╰──────────── unresolved + │ │ + │ ╰─── ref: 4 + 5 │ rcpt.call.gas(1)(data); + │ ──┬─ ──┬─ ─┬─ ──┬─ + │ ╰──────────────────── ref: 3 + │ │ │ │ + │ ╰─────────────── ref: built-in + │ │ │ + │ ╰─────────── unresolved + │ │ + │ ╰─── ref: 4 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/expressions/legacy_call_options/input.sol b/crates/solidity/testing/snapshots/bindings_output/expressions/legacy_call_options/input.sol new file mode 100644 index 0000000000..cc5d1f69ce --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/expressions/legacy_call_options/input.sol @@ -0,0 +1,7 @@ +contract Test { + function test(address rcpt, bytes memory data) public { + // this is valid on Solidity < 0.7.0 + rcpt.call.value(1)(data); + rcpt.call.gas(1)(data); + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/expressions/literal_address/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/expressions/literal_address/generated/0.4.11-success.txt new file mode 100644 index 0000000000..31773815f8 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/expressions/literal_address/generated/0.4.11-success.txt @@ -0,0 +1,19 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ function test(bytes memory data) public { + │ ──┬─ ──┬─ + │ ╰───────────────────── def: 2 + │ │ + │ ╰─── def: 3 + 3 │ 0x2d3fC875de7Fe7Da43AD0afa0E7023c9B91D06b1.delegatecall(data); + │ ──────┬───── ──┬─ + │ ╰──────────── ref: built-in + │ │ + │ ╰─── ref: 3 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/expressions/literal_address/input.sol b/crates/solidity/testing/snapshots/bindings_output/expressions/literal_address/input.sol new file mode 100644 index 0000000000..2f58b86413 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/expressions/literal_address/input.sol @@ -0,0 +1,5 @@ +contract Test { + function test(bytes memory data) public { + 0x2d3fC875de7Fe7Da43AD0afa0E7023c9B91D06b1.delegatecall(data); + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/expressions/literal_integers/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/expressions/literal_integers/generated/0.4.11-success.txt new file mode 100644 index 0000000000..e00ce09b33 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/expressions/literal_integers/generated/0.4.11-success.txt @@ -0,0 +1,27 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ library Lib { + │ ─┬─ + │ ╰─── def: 1 + 2 │ function nop(uint256 x) internal {} + │ ─┬─ ┬ + │ ╰───────────── def: 2 + │ │ + │ ╰── def: 3 + │ + 4 │ contract Test { + │ ──┬─ + │ ╰─── def: 4 + 5 │ using Lib for uint256; + │ ─┬─ + │ ╰─── ref: 1 + 6 │ function test() public { + │ ──┬─ + │ ╰─── def: 5 + 7 │ (50 * 10**uint(4)).nop(); + │ ─┬─ + │ ╰─── ref: 2 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/expressions/literal_integers/input.sol b/crates/solidity/testing/snapshots/bindings_output/expressions/literal_integers/input.sol new file mode 100644 index 0000000000..3ffcec21df --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/expressions/literal_integers/input.sol @@ -0,0 +1,9 @@ +library Lib { + function nop(uint256 x) internal {} +} +contract Test { + using Lib for uint256; + function test() public { + (50 * 10**uint(4)).nop(); + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/interfaces/own_types_access/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/interfaces/own_types_access/generated/0.4.11-success.txt new file mode 100644 index 0000000000..bfc96cf8da --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/interfaces/own_types_access/generated/0.4.11-success.txt @@ -0,0 +1,23 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ interface IFoo { + │ ──┬─ + │ ╰─── def: 1 + 2 │ struct Bar { + │ ─┬─ + │ ╰─── def: 2 + 3 │ int value; + │ ──┬── + │ ╰──── def: 3 + │ + 5 │ function test(Bar memory bar); + │ ──┬─ ─┬─ ─┬─ + │ ╰────────────────── def: 4 + │ │ │ + │ ╰────────────── ref: 2 + │ │ + │ ╰─── def: 5 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/interfaces/own_types_access/input.sol b/crates/solidity/testing/snapshots/bindings_output/interfaces/own_types_access/input.sol new file mode 100644 index 0000000000..23d18a2bd3 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/interfaces/own_types_access/input.sol @@ -0,0 +1,6 @@ +interface IFoo { + struct Bar { + int value; + } + function test(Bar memory bar); +} diff --git a/crates/solidity/testing/snapshots/bindings_output/libraries/constants/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/libraries/constants/generated/0.4.11-success.txt new file mode 100644 index 0000000000..d83d224dfa --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/libraries/constants/generated/0.4.11-success.txt @@ -0,0 +1,34 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ library Lib { + │ ─┬─ + │ ╰─── def: 1 + 2 │ uint private constant X = 1; + │ ┬ + │ ╰── def: 2 + 3 │ uint public constant Y = 2; + │ ┬ + │ ╰── def: 3 + │ + 5 │ function test() public returns (uint) { + │ ──┬─ + │ ╰─── def: 4 + 6 │ return X; + │ ┬ + │ ╰── ref: 2 + │ + 10 │ contract Test { + │ ──┬─ + │ ╰─── def: 5 + 11 │ function test() public { + │ ──┬─ + │ ╰─── def: 6 + 12 │ Lib.Y; + │ ─┬─ ┬ + │ ╰───── ref: 1 + │ │ + │ ╰── ref: 3 +────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/libraries/constants/input.sol b/crates/solidity/testing/snapshots/bindings_output/libraries/constants/input.sol new file mode 100644 index 0000000000..6990c22be9 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/libraries/constants/input.sol @@ -0,0 +1,14 @@ +library Lib { + uint private constant X = 1; + uint public constant Y = 2; + + function test() public returns (uint) { + return X; + } +} + +contract Test { + function test() public { + Lib.Y; + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/libraries/modifiers/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/libraries/modifiers/generated/0.4.11-success.txt new file mode 100644 index 0000000000..3fa6594466 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/libraries/modifiers/generated/0.4.11-success.txt @@ -0,0 +1,21 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ library Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ modifier withinRange() { + │ ─────┬───── + │ ╰─────── def: 2 + 3 │ _; + │ ┬ + │ ╰── ref: built-in + │ + 5 │ function test() internal withinRange() {} + │ ──┬─ ─────┬───── + │ ╰────────────────────────── def: 3 + │ │ + │ ╰─────── ref: 2 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/libraries/modifiers/input.sol b/crates/solidity/testing/snapshots/bindings_output/libraries/modifiers/input.sol new file mode 100644 index 0000000000..72cebbcaf9 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/libraries/modifiers/input.sol @@ -0,0 +1,6 @@ +library Test { + modifier withinRange() { + _; + } + function test() internal withinRange() {} +} diff --git a/crates/solidity/testing/snapshots/bindings_output/libraries/modifiers_scope/generated/0.4.11-failure.txt b/crates/solidity/testing/snapshots/bindings_output/libraries/modifiers_scope/generated/0.4.11-failure.txt new file mode 100644 index 0000000000..6e61f4eb45 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/libraries/modifiers_scope/generated/0.4.11-failure.txt @@ -0,0 +1,38 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected Equal or Semicolon. + ╭─[input.sol:2:25] + │ + 2 │ error IndexOutOfBounds(); + │ ─┬ + │ ╰── Error occurred here. +───╯ +Error: Expected Equal or Semicolon. + ╭─[input.sol:5:28] + │ + 5 │ revert IndexOutOfBounds(); + │ ─┬ + │ ╰── Error occurred here. +───╯ +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ library Lib { + │ ─┬─ + │ ╰─── def: 1 + 2 │ error IndexOutOfBounds(); + │ ──┬── ────────┬─────── + │ ╰───────────────────── unresolved + │ │ + │ ╰───────── def: 2 + │ + 4 │ modifier test() { + │ ──┬─ + │ ╰─── def: 3 + 5 │ revert IndexOutOfBounds(); + │ ───┬── ────────┬─────── + │ ╰───────────────────── ref: built-in + │ │ + │ ╰───────── def: 4 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/libraries/modifiers_scope/generated/0.4.22-failure.txt b/crates/solidity/testing/snapshots/bindings_output/libraries/modifiers_scope/generated/0.4.22-failure.txt new file mode 100644 index 0000000000..622f19db63 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/libraries/modifiers_scope/generated/0.4.22-failure.txt @@ -0,0 +1,38 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected Equal or Semicolon. + ╭─[input.sol:2:25] + │ + 2 │ error IndexOutOfBounds(); + │ ─┬ + │ ╰── Error occurred here. +───╯ +Error: Expected Equal or Semicolon. + ╭─[input.sol:5:28] + │ + 5 │ revert IndexOutOfBounds(); + │ ─┬ + │ ╰── Error occurred here. +───╯ +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ library Lib { + │ ─┬─ + │ ╰─── def: 1 + 2 │ error IndexOutOfBounds(); + │ ──┬── ────────┬─────── + │ ╰───────────────────── unresolved + │ │ + │ ╰───────── def: 2 + │ + 4 │ modifier test() { + │ ──┬─ + │ ╰─── def: 3 + 5 │ revert IndexOutOfBounds(); + │ ───┬── ────────┬─────── + │ ╰───────────────────── refs: built-in, built-in + │ │ + │ ╰───────── def: 4 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/libraries/modifiers_scope/generated/0.8.4-success.txt b/crates/solidity/testing/snapshots/bindings_output/libraries/modifiers_scope/generated/0.8.4-success.txt new file mode 100644 index 0000000000..ef7dba6b93 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/libraries/modifiers_scope/generated/0.8.4-success.txt @@ -0,0 +1,19 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ library Lib { + │ ─┬─ + │ ╰─── def: 1 + 2 │ error IndexOutOfBounds(); + │ ────────┬─────── + │ ╰───────── def: 2 + │ + 4 │ modifier test() { + │ ──┬─ + │ ╰─── def: 3 + 5 │ revert IndexOutOfBounds(); + │ ────────┬─────── + │ ╰───────── ref: 2 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/libraries/modifiers_scope/input.sol b/crates/solidity/testing/snapshots/bindings_output/libraries/modifiers_scope/input.sol new file mode 100644 index 0000000000..066b231b3f --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/libraries/modifiers_scope/input.sol @@ -0,0 +1,7 @@ +library Lib { + error IndexOutOfBounds(); + + modifier test() { + revert IndexOutOfBounds(); + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/libraries/propagate_dynamic_scope/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/libraries/propagate_dynamic_scope/generated/0.4.11-success.txt new file mode 100644 index 0000000000..ce220baf55 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/libraries/propagate_dynamic_scope/generated/0.4.11-success.txt @@ -0,0 +1,49 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ interface IERC20Upgradable { + │ ────────┬─────── + │ ╰───────── def: 1 + 2 │ function allowance(address owner) external returns (uint256); + │ ────┬──── ──┬── + │ ╰──────────────────── def: 2 + │ │ + │ ╰──── def: 3 + │ + 4 │ library Math { + │ ──┬─ + │ ╰─── def: 4 + 5 │ function nop(uint256 x) public {} + │ ─┬─ ┬ + │ ╰───────────── def: 5 + │ │ + │ ╰── def: 6 + │ + 7 │ library Test { + │ ──┬─ + │ ╰─── def: 7 + 8 │ using Math for uint256; + │ ──┬─ + │ ╰─── ref: 4 + │ + 10 │ function test(IERC20Upgradable token) internal { + │ ──┬─ ────────┬─────── ──┬── + │ ╰────────────────────────── def: 8 + │ │ │ + │ ╰─────────────── ref: 1 + │ │ + │ ╰──── def: 9 + 11 │ token.allowance(msg.sender).nop(); + │ ──┬── ────┬──── ─┬─ ───┬── ─┬─ + │ ╰────────────────────────────── ref: 9 + │ │ │ │ │ + │ ╰────────────────────── ref: 2 + │ │ │ │ + │ ╰─────────────── ref: built-in + │ │ │ + │ ╰───────── ref: built-in + │ │ + │ ╰─── ref: 5 +────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/libraries/propagate_dynamic_scope/input.sol b/crates/solidity/testing/snapshots/bindings_output/libraries/propagate_dynamic_scope/input.sol new file mode 100644 index 0000000000..2c12057eb3 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/libraries/propagate_dynamic_scope/input.sol @@ -0,0 +1,13 @@ +interface IERC20Upgradable { + function allowance(address owner) external returns (uint256); +} +library Math { + function nop(uint256 x) public {} +} +library Test { + using Math for uint256; + + function test(IERC20Upgradable token) internal { + token.allowance(msg.sender).nop(); + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/structs/function_call/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/structs/function_call/generated/0.4.11-success.txt new file mode 100644 index 0000000000..5e81f906d2 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/structs/function_call/generated/0.4.11-success.txt @@ -0,0 +1,31 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ struct Value { + │ ──┬── + │ ╰──── def: 2 + 3 │ int x; + │ ┬ + │ ╰── def: 3 + │ + 5 │ function test() public { + │ ──┬─ + │ ╰─── def: 4 + 6 │ Value(10).x; + │ ──┬── ┬ + │ ╰────────── ref: 2 + │ │ + │ ╰── ref: 3 + 7 │ Value({x: 10}).x; + │ ──┬── ┬ ┬ + │ ╰─────────────── ref: 2 + │ │ │ + │ ╰────────── ref: 3 + │ │ + │ ╰── ref: 3 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/structs/function_call/input.sol b/crates/solidity/testing/snapshots/bindings_output/structs/function_call/input.sol new file mode 100644 index 0000000000..48f1b04eb8 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/structs/function_call/input.sol @@ -0,0 +1,9 @@ +contract Test { + struct Value { + int x; + } + function test() public { + Value(10).x; + Value({x: 10}).x; + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/user_types/wrap_unwrap/generated/0.4.11-failure.txt b/crates/solidity/testing/snapshots/bindings_output/user_types/wrap_unwrap/generated/0.4.11-failure.txt new file mode 100644 index 0000000000..b87a09cf85 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/user_types/wrap_unwrap/generated/0.4.11-failure.txt @@ -0,0 +1,13 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected ContractKeyword or ImportKeyword or InterfaceKeyword or LibraryKeyword or PragmaKeyword. + ╭─[input.sol:1:1] + │ + 1 │ ╭─▶ type ShortString is bytes32; + ┆ ┆ + 8 │ ├─▶ } + │ │ + │ ╰─────── Error occurred here. +───╯ +References and definitions: diff --git a/crates/solidity/testing/snapshots/bindings_output/user_types/wrap_unwrap/generated/0.6.0-failure.txt b/crates/solidity/testing/snapshots/bindings_output/user_types/wrap_unwrap/generated/0.6.0-failure.txt new file mode 100644 index 0000000000..cea0619d12 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/user_types/wrap_unwrap/generated/0.6.0-failure.txt @@ -0,0 +1,13 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected ContractKeyword or EnumKeyword or ImportKeyword or InterfaceKeyword or LibraryKeyword or PragmaKeyword or StructKeyword. + ╭─[input.sol:1:1] + │ + 1 │ ╭─▶ type ShortString is bytes32; + ┆ ┆ + 8 │ ├─▶ } + │ │ + │ ╰─────── Error occurred here. +───╯ +References and definitions: diff --git a/crates/solidity/testing/snapshots/bindings_output/user_types/wrap_unwrap/generated/0.7.1-failure.txt b/crates/solidity/testing/snapshots/bindings_output/user_types/wrap_unwrap/generated/0.7.1-failure.txt new file mode 100644 index 0000000000..3505cedb20 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/user_types/wrap_unwrap/generated/0.7.1-failure.txt @@ -0,0 +1,13 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected ContractKeyword or EnumKeyword or FunctionKeyword or ImportKeyword or InterfaceKeyword or LibraryKeyword or PragmaKeyword or StructKeyword. + ╭─[input.sol:1:1] + │ + 1 │ ╭─▶ type ShortString is bytes32; + ┆ ┆ + 8 │ ├─▶ } + │ │ + │ ╰─────── Error occurred here. +───╯ +References and definitions: diff --git a/crates/solidity/testing/snapshots/bindings_output/user_types/wrap_unwrap/generated/0.7.4-failure.txt b/crates/solidity/testing/snapshots/bindings_output/user_types/wrap_unwrap/generated/0.7.4-failure.txt new file mode 100644 index 0000000000..bd4b20a86b --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/user_types/wrap_unwrap/generated/0.7.4-failure.txt @@ -0,0 +1,13 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected AddressKeyword or BoolKeyword or ByteKeyword or BytesKeyword or ContractKeyword or EnumKeyword or FixedKeyword or FunctionKeyword or Identifier or ImportKeyword or IntKeyword or InterfaceKeyword or LibraryKeyword or MappingKeyword or PragmaKeyword or StringKeyword or StructKeyword or UfixedKeyword or UintKeyword. + ╭─[input.sol:1:1] + │ + 1 │ ╭─▶ type ShortString is bytes32; + ┆ ┆ + 8 │ ├─▶ } + │ │ + │ ╰─────── Error occurred here. +───╯ +References and definitions: diff --git a/crates/solidity/testing/snapshots/bindings_output/user_types/wrap_unwrap/generated/0.8.0-failure.txt b/crates/solidity/testing/snapshots/bindings_output/user_types/wrap_unwrap/generated/0.8.0-failure.txt new file mode 100644 index 0000000000..619151156f --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/user_types/wrap_unwrap/generated/0.8.0-failure.txt @@ -0,0 +1,13 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected AddressKeyword or BoolKeyword or BytesKeyword or ContractKeyword or EnumKeyword or FixedKeyword or FunctionKeyword or Identifier or ImportKeyword or IntKeyword or InterfaceKeyword or LibraryKeyword or MappingKeyword or PragmaKeyword or StringKeyword or StructKeyword or UfixedKeyword or UintKeyword. + ╭─[input.sol:1:1] + │ + 1 │ ╭─▶ type ShortString is bytes32; + ┆ ┆ + 8 │ ├─▶ } + │ │ + │ ╰─────── Error occurred here. +───╯ +References and definitions: diff --git a/crates/solidity/testing/snapshots/bindings_output/user_types/wrap_unwrap/generated/0.8.4-failure.txt b/crates/solidity/testing/snapshots/bindings_output/user_types/wrap_unwrap/generated/0.8.4-failure.txt new file mode 100644 index 0000000000..f56435985e --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/user_types/wrap_unwrap/generated/0.8.4-failure.txt @@ -0,0 +1,13 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected AddressKeyword or BoolKeyword or BytesKeyword or ContractKeyword or EnumKeyword or ErrorKeyword or FixedKeyword or FunctionKeyword or Identifier or ImportKeyword or IntKeyword or InterfaceKeyword or LibraryKeyword or MappingKeyword or PragmaKeyword or StringKeyword or StructKeyword or UfixedKeyword or UintKeyword. + ╭─[input.sol:1:1] + │ + 1 │ ╭─▶ type ShortString is bytes32; + ┆ ┆ + 8 │ ├─▶ } + │ │ + │ ╰─────── Error occurred here. +───╯ +References and definitions: diff --git a/crates/solidity/testing/snapshots/bindings_output/user_types/wrap_unwrap/generated/0.8.8-success.txt b/crates/solidity/testing/snapshots/bindings_output/user_types/wrap_unwrap/generated/0.8.8-success.txt new file mode 100644 index 0000000000..0563a6f694 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/user_types/wrap_unwrap/generated/0.8.8-success.txt @@ -0,0 +1,36 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ type ShortString is bytes32; + │ ─────┬───── + │ ╰─────── def: 1 + │ + 3 │ contract Test { + │ ──┬─ + │ ╰─── def: 2 + 4 │ function test(bytes32 data) public { + │ ──┬─ ──┬─ + │ ╰──────────────── def: 3 + │ │ + │ ╰─── def: 4 + 5 │ ShortString s = ShortString.wrap(data); + │ ─────┬───── ┬ ─────┬───── ──┬─ ──┬─ + │ ╰───────────────────────────────── ref: 1 + │ │ │ │ │ + │ ╰────────────────────────── def: 5 + │ │ │ │ + │ ╰───────────────── ref: 1 + │ │ │ + │ ╰──────── ref: built-in + │ │ + │ ╰─── ref: 4 + 6 │ ShortString.unwrap(s); + │ ─────┬───── ───┬── ┬ + │ ╰──────────────── ref: 1 + │ │ │ + │ ╰────── ref: built-in + │ │ + │ ╰── ref: 5 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/user_types/wrap_unwrap/input.sol b/crates/solidity/testing/snapshots/bindings_output/user_types/wrap_unwrap/input.sol new file mode 100644 index 0000000000..f6bc7b63b9 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/user_types/wrap_unwrap/input.sol @@ -0,0 +1,8 @@ +type ShortString is bytes32; + +contract Test { + function test(bytes32 data) public { + ShortString s = ShortString.wrap(data); + ShortString.unwrap(s); + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/using/address/generated/0.4.11-failure.txt b/crates/solidity/testing/snapshots/bindings_output/using/address/generated/0.4.11-failure.txt new file mode 100644 index 0000000000..97aeb1b768 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/address/generated/0.4.11-failure.txt @@ -0,0 +1,35 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected AddressKeyword or AssemblyKeyword or BoolKeyword or BreakKeyword or ByteKeyword or BytesKeyword or CloseBrace or ContinueKeyword or DecimalLiteral or DoKeyword or DoubleQuotedHexStringLiteral or DoubleQuotedStringLiteral or FalseKeyword or FixedKeyword or ForKeyword or FunctionKeyword or HexLiteral or Identifier or IfKeyword or IntKeyword or MappingKeyword or NewKeyword or OpenBrace or OpenBracket or OpenParen or ReturnKeyword or SingleQuotedHexStringLiteral or SingleQuotedStringLiteral or StringKeyword or SuperKeyword or ThisKeyword or ThrowKeyword or TrueKeyword or UfixedKeyword or UintKeyword or VarKeyword or WhileKeyword. + ╭─[input.sol:7:9] + │ + 7 │ ╭─▶ payable(_rcpt).sendValue(); + 8 │ ├─▶ } + │ │ + │ ╰─────────── Error occurred here. +───╯ +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ library Address { + │ ───┬─── + │ ╰───── def: 1 + 2 │ function sendValue(address payable recipient) internal {} + │ ────┬──── ────┬──── + │ ╰──────────────────────────────── def: 2 + │ │ + │ ╰────── def: 3 + │ + 4 │ contract Test { + │ ──┬─ + │ ╰─── def: 4 + 5 │ using Address for address payable; + │ ───┬─── + │ ╰───── ref: 1 + 6 │ function test(address _rcpt) public { + │ ──┬─ ──┬── + │ ╰───────────────── def: 5 + │ │ + │ ╰──── def: 6 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/using/address/generated/0.4.21-failure.txt b/crates/solidity/testing/snapshots/bindings_output/using/address/generated/0.4.21-failure.txt new file mode 100644 index 0000000000..d4bb34a55a --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/address/generated/0.4.21-failure.txt @@ -0,0 +1,35 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected AddressKeyword or AssemblyKeyword or BoolKeyword or BreakKeyword or ByteKeyword or BytesKeyword or CloseBrace or ContinueKeyword or DecimalLiteral or DoKeyword or DoubleQuotedHexStringLiteral or DoubleQuotedStringLiteral or EmitKeyword or FalseKeyword or FixedKeyword or ForKeyword or FunctionKeyword or HexLiteral or Identifier or IfKeyword or IntKeyword or MappingKeyword or NewKeyword or OpenBrace or OpenBracket or OpenParen or ReturnKeyword or SingleQuotedHexStringLiteral or SingleQuotedStringLiteral or StringKeyword or SuperKeyword or ThisKeyword or ThrowKeyword or TrueKeyword or UfixedKeyword or UintKeyword or VarKeyword or WhileKeyword. + ╭─[input.sol:7:9] + │ + 7 │ ╭─▶ payable(_rcpt).sendValue(); + 8 │ ├─▶ } + │ │ + │ ╰─────────── Error occurred here. +───╯ +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ library Address { + │ ───┬─── + │ ╰───── def: 1 + 2 │ function sendValue(address payable recipient) internal {} + │ ────┬──── ────┬──── + │ ╰──────────────────────────────── def: 2 + │ │ + │ ╰────── def: 3 + │ + 4 │ contract Test { + │ ──┬─ + │ ╰─── def: 4 + 5 │ using Address for address payable; + │ ───┬─── + │ ╰───── ref: 1 + 6 │ function test(address _rcpt) public { + │ ──┬─ ──┬── + │ ╰───────────────── def: 5 + │ │ + │ ╰──── def: 6 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/using/address/generated/0.5.0-failure.txt b/crates/solidity/testing/snapshots/bindings_output/using/address/generated/0.5.0-failure.txt new file mode 100644 index 0000000000..d1ae8bf8e8 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/address/generated/0.5.0-failure.txt @@ -0,0 +1,35 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected AddressKeyword or AssemblyKeyword or BoolKeyword or BreakKeyword or ByteKeyword or BytesKeyword or CloseBrace or ContinueKeyword or DecimalLiteral or DoKeyword or DoubleQuotedHexStringLiteral or DoubleQuotedStringLiteral or EmitKeyword or FalseKeyword or FixedKeyword or ForKeyword or FunctionKeyword or HexLiteral or Identifier or IfKeyword or IntKeyword or MappingKeyword or NewKeyword or OpenBrace or OpenBracket or OpenParen or ReturnKeyword or SingleQuotedHexStringLiteral or SingleQuotedStringLiteral or StringKeyword or SuperKeyword or ThisKeyword or TrueKeyword or UfixedKeyword or UintKeyword or WhileKeyword. + ╭─[input.sol:7:9] + │ + 7 │ ╭─▶ payable(_rcpt).sendValue(); + 8 │ ├─▶ } + │ │ + │ ╰─────────── Error occurred here. +───╯ +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ library Address { + │ ───┬─── + │ ╰───── def: 1 + 2 │ function sendValue(address payable recipient) internal {} + │ ────┬──── ────┬──── + │ ╰──────────────────────────────── def: 2 + │ │ + │ ╰────── def: 3 + │ + 4 │ contract Test { + │ ──┬─ + │ ╰─── def: 4 + 5 │ using Address for address payable; + │ ───┬─── + │ ╰───── ref: 1 + 6 │ function test(address _rcpt) public { + │ ──┬─ ──┬── + │ ╰───────────────── def: 5 + │ │ + │ ╰──── def: 6 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/using/address/generated/0.5.3-failure.txt b/crates/solidity/testing/snapshots/bindings_output/using/address/generated/0.5.3-failure.txt new file mode 100644 index 0000000000..05a55cb7be --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/address/generated/0.5.3-failure.txt @@ -0,0 +1,35 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected AddressKeyword or AssemblyKeyword or BoolKeyword or BreakKeyword or ByteKeyword or BytesKeyword or CloseBrace or ContinueKeyword or DecimalLiteral or DoKeyword or DoubleQuotedHexStringLiteral or DoubleQuotedStringLiteral or EmitKeyword or FalseKeyword or FixedKeyword or ForKeyword or FunctionKeyword or HexLiteral or Identifier or IfKeyword or IntKeyword or MappingKeyword or NewKeyword or OpenBrace or OpenBracket or OpenParen or ReturnKeyword or SingleQuotedHexStringLiteral or SingleQuotedStringLiteral or StringKeyword or SuperKeyword or ThisKeyword or TrueKeyword or TypeKeyword or UfixedKeyword or UintKeyword or WhileKeyword. + ╭─[input.sol:7:9] + │ + 7 │ ╭─▶ payable(_rcpt).sendValue(); + 8 │ ├─▶ } + │ │ + │ ╰─────────── Error occurred here. +───╯ +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ library Address { + │ ───┬─── + │ ╰───── def: 1 + 2 │ function sendValue(address payable recipient) internal {} + │ ────┬──── ────┬──── + │ ╰──────────────────────────────── def: 2 + │ │ + │ ╰────── def: 3 + │ + 4 │ contract Test { + │ ──┬─ + │ ╰─── def: 4 + 5 │ using Address for address payable; + │ ───┬─── + │ ╰───── ref: 1 + 6 │ function test(address _rcpt) public { + │ ──┬─ ──┬── + │ ╰───────────────── def: 5 + │ │ + │ ╰──── def: 6 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/using/address/generated/0.6.0-success.txt b/crates/solidity/testing/snapshots/bindings_output/using/address/generated/0.6.0-success.txt new file mode 100644 index 0000000000..48d9b99f62 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/address/generated/0.6.0-success.txt @@ -0,0 +1,31 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ library Address { + │ ───┬─── + │ ╰───── def: 1 + 2 │ function sendValue(address payable recipient) internal {} + │ ────┬──── ────┬──── + │ ╰──────────────────────────────── def: 2 + │ │ + │ ╰────── def: 3 + │ + 4 │ contract Test { + │ ──┬─ + │ ╰─── def: 4 + 5 │ using Address for address payable; + │ ───┬─── + │ ╰───── ref: 1 + 6 │ function test(address _rcpt) public { + │ ──┬─ ──┬── + │ ╰───────────────── def: 5 + │ │ + │ ╰──── def: 6 + 7 │ payable(_rcpt).sendValue(); + │ ──┬── ────┬──── + │ ╰─────────────── ref: 6 + │ │ + │ ╰────── ref: 2 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/using/address/input.sol b/crates/solidity/testing/snapshots/bindings_output/using/address/input.sol new file mode 100644 index 0000000000..06dcc8494d --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/address/input.sol @@ -0,0 +1,9 @@ +library Address { + function sendValue(address payable recipient) internal {} +} +contract Test { + using Address for address payable; + function test(address _rcpt) public { + payable(_rcpt).sendValue(); + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/using/casting/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/using/casting/generated/0.4.11-success.txt new file mode 100644 index 0000000000..7c63d30e2f --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/casting/generated/0.4.11-success.txt @@ -0,0 +1,41 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ interface IERC20 { + │ ───┬── + │ ╰──── def: 1 + │ + 3 │ library SafeERC20 { + │ ────┬──── + │ ╰────── def: 2 + 4 │ function safeApprove(IERC20 token) internal {} + │ ─────┬───── ───┬── ──┬── + │ ╰──────────────────── def: 3 + │ │ │ + │ ╰────────── ref: 1 + │ │ + │ ╰──── def: 4 + │ + 6 │ contract Test { + │ ──┬─ + │ ╰─── def: 5 + 7 │ using SafeERC20 for IERC20; + │ ────┬──── ───┬── + │ ╰───────────────── ref: 2 + │ │ + │ ╰──── ref: 1 + 8 │ function test(address token) public { + │ ──┬─ ──┬── + │ ╰───────────────── def: 6 + │ │ + │ ╰──── def: 7 + 9 │ IERC20(token).safeApprove(); + │ ───┬── ──┬── ─────┬───── + │ ╰─────────────────────── ref: 1 + │ │ │ + │ ╰───────────────── ref: 7 + │ │ + │ ╰─────── ref: 3 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/using/casting/input.sol b/crates/solidity/testing/snapshots/bindings_output/using/casting/input.sol new file mode 100644 index 0000000000..2f6cf1f80c --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/casting/input.sol @@ -0,0 +1,11 @@ +interface IERC20 { +} +library SafeERC20 { + function safeApprove(IERC20 token) internal {} +} +contract Test { + using SafeERC20 for IERC20; + function test(address token) public { + IERC20(token).safeApprove(); + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/using/chained_calls/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/using/chained_calls/generated/0.4.11-success.txt new file mode 100644 index 0000000000..180ec2bfde --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/chained_calls/generated/0.4.11-success.txt @@ -0,0 +1,78 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ library Foo { + │ ─┬─ + │ ╰─── def: 1 + 2 │ struct Bar { + │ ─┬─ + │ ╰─── def: 2 + 3 │ uint value; + │ ──┬── + │ ╰──── def: 3 + │ + 5 │ function noop(uint x) public returns (uint) {} + │ ──┬─ ┬ + │ ╰────────── def: 4 + │ │ + │ ╰── def: 5 + 6 │ function bar(uint x) public returns (Bar) {} + │ ─┬─ ┬ ─┬─ + │ ╰─────────────────────────────── def: 6 + │ │ │ + │ ╰─────────────────────── def: 7 + │ │ + │ ╰─── ref: 2 + │ + 9 │ contract Test { + │ ──┬─ + │ ╰─── def: 8 + 10 │ using Foo for uint; + │ ─┬─ + │ ╰─── ref: 1 + 11 │ function test(uint a, Foo.Bar memory b) public { + │ ──┬─ ┬ ─┬─ ─┬─ ┬ + │ ╰──────────────────────────── def: 9 + │ │ │ │ │ + │ ╰──────────────────── def: 10 + │ │ │ │ + │ ╰──────────────── ref: 1 + │ │ │ + │ ╰──────────── ref: 2 + │ │ + │ ╰── def: 11 + 12 │ uint[] memory xs; + │ ─┬ + │ ╰── def: 12 + 13 │ a.noop().noop().noop(); + │ ┬ ──┬─ ──┬─ ──┬─ + │ ╰───────────────────── ref: 10 + │ │ │ │ + │ ╰───────────────── ref: 4 + │ │ │ + │ ╰────────── ref: 4 + │ │ + │ ╰─── ref: 4 + 14 │ b.value.noop().bar().value.noop(); + │ ┬ ──┬── ──┬─ ─┬─ ──┬── ──┬─ + │ ╰──────────────────────────────── ref: 11 + │ │ │ │ │ │ + │ ╰──────────────────────────── ref: 3 + │ │ │ │ │ + │ ╰────────────────────── ref: 4 + │ │ │ │ + │ ╰──────────────── ref: 6 + │ │ │ + │ ╰───────── ref: 3 + │ │ + │ ╰─── ref: 4 + 15 │ xs[5].noop().noop(); + │ ─┬ ──┬─ ──┬─ + │ ╰───────────────── ref: 12 + │ │ │ + │ ╰────────── ref: 4 + │ │ + │ ╰─── ref: 4 +────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/using/chained_calls/input.sol b/crates/solidity/testing/snapshots/bindings_output/using/chained_calls/input.sol new file mode 100644 index 0000000000..0a0143ee1c --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/chained_calls/input.sol @@ -0,0 +1,17 @@ +library Foo { + struct Bar { + uint value; + } + function noop(uint x) public returns (uint) {} + function bar(uint x) public returns (Bar) {} +} + +contract Test { + using Foo for uint; + function test(uint a, Foo.Bar memory b) public { + uint[] memory xs; + a.noop().noop().noop(); + b.value.noop().bar().value.noop(); + xs[5].noop().noop(); + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/using/inherit_extension/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/using/inherit_extension/generated/0.4.11-success.txt new file mode 100644 index 0000000000..d8aec265bc --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/inherit_extension/generated/0.4.11-success.txt @@ -0,0 +1,44 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 2 │ library Lib { + │ ─┬─ + │ ╰─── def: 1 + 3 │ function nop(uint256 x) {} + │ ─┬─ ┬ + │ ╰───────────── def: 2 + │ │ + │ ╰── def: 3 + │ + 5 │ contract Base { + │ ──┬─ + │ ╰─── def: 4 + 6 │ uint256 totalSupply; + │ ─────┬───── + │ ╰─────── def: 5 + │ + 8 │ contract Middle is Base { + │ ───┬── ──┬─ + │ ╰──────────── def: 6 + │ │ + │ ╰─── ref: 4 + 9 │ using Lib for uint256; + │ ─┬─ + │ ╰─── ref: 1 + │ + 11 │ contract Test is Middle { + │ ──┬─ ───┬── + │ ╰───────────── def: 7 + │ │ + │ ╰──── ref: 6 + 12 │ function test() public { + │ ──┬─ + │ ╰─── def: 8 + 13 │ totalSupply.nop(); + │ ─────┬───── ─┬─ + │ ╰─────────── ref: 5 + │ │ + │ ╰─── ref: 2 +────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/using/inherit_extension/generated/0.7.0-failure.txt b/crates/solidity/testing/snapshots/bindings_output/using/inherit_extension/generated/0.7.0-failure.txt new file mode 100644 index 0000000000..3aa3f58fd1 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/inherit_extension/generated/0.7.0-failure.txt @@ -0,0 +1,44 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 2 │ library Lib { + │ ─┬─ + │ ╰─── def: 1 + 3 │ function nop(uint256 x) {} + │ ─┬─ ┬ + │ ╰───────────── def: 2 + │ │ + │ ╰── def: 3 + │ + 5 │ contract Base { + │ ──┬─ + │ ╰─── def: 4 + 6 │ uint256 totalSupply; + │ ─────┬───── + │ ╰─────── def: 5 + │ + 8 │ contract Middle is Base { + │ ───┬── ──┬─ + │ ╰──────────── def: 6 + │ │ + │ ╰─── ref: 4 + 9 │ using Lib for uint256; + │ ─┬─ + │ ╰─── ref: 1 + │ + 11 │ contract Test is Middle { + │ ──┬─ ───┬── + │ ╰───────────── def: 7 + │ │ + │ ╰──── ref: 6 + 12 │ function test() public { + │ ──┬─ + │ ╰─── def: 8 + 13 │ totalSupply.nop(); + │ ─────┬───── ─┬─ + │ ╰─────────── ref: 5 + │ │ + │ ╰─── unresolved +────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/using/inherit_extension/input.sol b/crates/solidity/testing/snapshots/bindings_output/using/inherit_extension/input.sol new file mode 100644 index 0000000000..6e5e05addb --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/inherit_extension/input.sol @@ -0,0 +1,15 @@ +// In Solidity < 0.7.0 using directives are inherited in sub contracts +library Lib { + function nop(uint256 x) {} +} +contract Base { + uint256 totalSupply; +} +contract Middle is Base { + using Lib for uint256; +} +contract Test is Middle { + function test() public { + totalSupply.nop(); + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/using/inherited_types/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/using/inherited_types/generated/0.4.11-success.txt new file mode 100644 index 0000000000..e4adbece8d --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/inherited_types/generated/0.4.11-success.txt @@ -0,0 +1,52 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ interface IPool { + │ ──┬── + │ ╰──── def: 1 + 2 │ struct Info { + │ ──┬─ + │ ╰─── def: 2 + 3 │ uint256 amount; + │ ───┬── + │ ╰──── def: 3 + │ + 6 │ library Math { + │ ──┬─ + │ ╰─── def: 4 + 7 │ function nop(uint256 x) public {} + │ ─┬─ ┬ + │ ╰───────────── def: 5 + │ │ + │ ╰── def: 6 + │ + 9 │ contract Test is IPool { + │ ──┬─ ──┬── + │ ╰──────────── def: 7 + │ │ + │ ╰──── ref: 1 + 10 │ mapping(uint256 => Info) infos; + │ ──┬─ ──┬── + │ ╰────────── ref: 2 + │ │ + │ ╰──── def: 8 + 11 │ using Math for uint256; + │ ──┬─ + │ ╰─── ref: 4 + 12 │ function test(uint256 x) public { + │ ──┬─ ┬ + │ ╰───────────── def: 9 + │ │ + │ ╰── def: 10 + 13 │ infos[x].amount.nop(); + │ ──┬── ┬ ───┬── ─┬─ + │ ╰────────────────── ref: 8 + │ │ │ │ + │ ╰────────────── ref: 10 + │ │ │ + │ ╰──────── ref: 3 + │ │ + │ ╰─── ref: 5 +────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/using/inherited_types/input.sol b/crates/solidity/testing/snapshots/bindings_output/using/inherited_types/input.sol new file mode 100644 index 0000000000..d136d3833a --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/inherited_types/input.sol @@ -0,0 +1,15 @@ +interface IPool { + struct Info { + uint256 amount; + } +} +library Math { + function nop(uint256 x) public {} +} +contract Test is IPool { + mapping(uint256 => Info) infos; + using Math for uint256; + function test(uint256 x) public { + infos[x].amount.nop(); + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/using/mappings/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/using/mappings/generated/0.4.11-success.txt new file mode 100644 index 0000000000..6094b2e72e --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/mappings/generated/0.4.11-success.txt @@ -0,0 +1,32 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ using Lib for mapping(address => uint); + │ ─┬─ + │ ╰─── ref: 4 + 3 │ mapping(address => uint) balances; + │ ────┬─── + │ ╰───── def: 2 + 4 │ function test() public { + │ ──┬─ + │ ╰─── def: 3 + 5 │ balances.nop(); + │ ────┬─── ─┬─ + │ ╰───────── ref: 2 + │ │ + │ ╰─── ref: 5 + │ + 8 │ library Lib { + │ ─┬─ + │ ╰─── def: 4 + 9 │ function nop(mapping(address => uint) storage m) internal {} + │ ─┬─ ┬ + │ ╰────────────────────────────────────── def: 5 + │ │ + │ ╰── def: 6 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/using/mappings/input.sol b/crates/solidity/testing/snapshots/bindings_output/using/mappings/input.sol new file mode 100644 index 0000000000..07c9130933 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/mappings/input.sol @@ -0,0 +1,10 @@ +contract Test { + using Lib for mapping(address => uint); + mapping(address => uint) balances; + function test() public { + balances.nop(); + } +} +library Lib { + function nop(mapping(address => uint) storage m) internal {} +} diff --git a/crates/solidity/testing/snapshots/bindings_output/using/on_interfaces_inherited/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/using/on_interfaces_inherited/generated/0.4.11-success.txt new file mode 100644 index 0000000000..f11a068098 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/on_interfaces_inherited/generated/0.4.11-success.txt @@ -0,0 +1,48 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ library LibFoo { + │ ───┬── + │ ╰──── def: 1 + 2 │ function use_foo(IFoo x) public returns (int) {} + │ ───┬─── ──┬─ ┬ + │ ╰──────────── def: 2 + │ │ │ + │ ╰───── ref: 4 + │ │ + │ ╰── def: 3 + │ + 4 │ interface IFoo { + │ ──┬─ + │ ╰─── def: 4 + │ + 6 │ contract Base { + │ ──┬─ + │ ╰─── def: 5 + 7 │ using LibFoo for IFoo; + │ ───┬── ──┬─ + │ ╰───────────── ref: 1 + │ │ + │ ╰─── ref: 4 + │ + 9 │ contract Test is Base { + │ ──┬─ ──┬─ + │ ╰─────────── def: 6 + │ │ + │ ╰─── ref: 5 + 10 │ function test(address x) public { + │ ──┬─ ┬ + │ ╰───────────── def: 7 + │ │ + │ ╰── def: 8 + │ + 12 │ IFoo(x).use_foo(); + │ ──┬─ ┬ ───┬─── + │ ╰────────────── ref: 4 + │ │ │ + │ ╰─────────── ref: 8 + │ │ + │ ╰───── ref: 2 +────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/using/on_interfaces_inherited/generated/0.7.0-failure.txt b/crates/solidity/testing/snapshots/bindings_output/using/on_interfaces_inherited/generated/0.7.0-failure.txt new file mode 100644 index 0000000000..5afd65e4af --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/on_interfaces_inherited/generated/0.7.0-failure.txt @@ -0,0 +1,48 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ library LibFoo { + │ ───┬── + │ ╰──── def: 1 + 2 │ function use_foo(IFoo x) public returns (int) {} + │ ───┬─── ──┬─ ┬ + │ ╰──────────── def: 2 + │ │ │ + │ ╰───── ref: 4 + │ │ + │ ╰── def: 3 + │ + 4 │ interface IFoo { + │ ──┬─ + │ ╰─── def: 4 + │ + 6 │ contract Base { + │ ──┬─ + │ ╰─── def: 5 + 7 │ using LibFoo for IFoo; + │ ───┬── ──┬─ + │ ╰───────────── ref: 1 + │ │ + │ ╰─── ref: 4 + │ + 9 │ contract Test is Base { + │ ──┬─ ──┬─ + │ ╰─────────── def: 6 + │ │ + │ ╰─── ref: 5 + 10 │ function test(address x) public { + │ ──┬─ ┬ + │ ╰───────────── def: 7 + │ │ + │ ╰── def: 8 + │ + 12 │ IFoo(x).use_foo(); + │ ──┬─ ┬ ───┬─── + │ ╰────────────── ref: 4 + │ │ │ + │ ╰─────────── ref: 8 + │ │ + │ ╰───── unresolved +────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/using/on_interfaces_inherited/input.sol b/crates/solidity/testing/snapshots/bindings_output/using/on_interfaces_inherited/input.sol new file mode 100644 index 0000000000..c894206b75 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/on_interfaces_inherited/input.sol @@ -0,0 +1,14 @@ +library LibFoo { + function use_foo(IFoo x) public returns (int) {} +} +interface IFoo { +} +contract Base { + using LibFoo for IFoo; +} +contract Test is Base { + function test(address x) public { + // should work for Solidity < 0.7.0 + IFoo(x).use_foo(); + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/using/on_parameters/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/using/on_parameters/generated/0.4.11-success.txt new file mode 100644 index 0000000000..4753580729 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/on_parameters/generated/0.4.11-success.txt @@ -0,0 +1,38 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ library Lib { + │ ─┬─ + │ ╰─── def: 1 + 2 │ function nop(uint256 x) internal {} + │ ─┬─ ┬ + │ ╰───────────── def: 2 + │ │ + │ ╰── def: 3 + │ + 4 │ contract Test { + │ ──┬─ + │ ╰─── def: 4 + 5 │ using Lib for uint256; + │ ─┬─ + │ ╰─── ref: 1 + 6 │ function test(uint256 x) public returns (uint256 y) { + │ ──┬─ ┬ ┬ + │ ╰──────────────────────────────────────── def: 5 + │ │ │ + │ ╰───────────────────────────── def: 6 + │ │ + │ ╰── def: 7 + 7 │ x.nop(); + │ ┬ ─┬─ + │ ╰────── ref: 6 + │ │ + │ ╰─── ref: 2 + 8 │ y.nop(); + │ ┬ ─┬─ + │ ╰────── ref: 7 + │ │ + │ ╰─── ref: 2 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/using/on_parameters/input.sol b/crates/solidity/testing/snapshots/bindings_output/using/on_parameters/input.sol new file mode 100644 index 0000000000..135ab2423e --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/on_parameters/input.sol @@ -0,0 +1,10 @@ +library Lib { + function nop(uint256 x) internal {} +} +contract Test { + using Lib for uint256; + function test(uint256 x) public returns (uint256 y) { + x.nop(); + y.nop(); + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/using/on_state_var_initialization/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/using/on_state_var_initialization/generated/0.4.11-success.txt new file mode 100644 index 0000000000..0dacde723a --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/on_state_var_initialization/generated/0.4.11-success.txt @@ -0,0 +1,33 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ library Lib { + │ ─┬─ + │ ╰─── def: 1 + 2 │ function nop(uint256 x) returns (uint256) { return x; } + │ ─┬─ ┬ ┬ + │ ╰─────────────────────────────────────────── def: 2 + │ │ │ + │ ╰──────────────────────────────── def: 3 + │ │ + │ ╰── ref: 3 + │ + 4 │ contract Test { + │ ──┬─ + │ ╰─── def: 4 + 5 │ using Lib for uint256; + │ ─┬─ + │ ╰─── ref: 1 + 6 │ uint256 private v1 = 1; + │ ─┬ + │ ╰── def: 5 + 7 │ uint256 private v2 = v1.nop(); + │ ─┬ ─┬ ─┬─ + │ ╰─────────── def: 6 + │ │ │ + │ ╰────── ref: 5 + │ │ + │ ╰─── ref: 2 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/using/on_state_var_initialization/input.sol b/crates/solidity/testing/snapshots/bindings_output/using/on_state_var_initialization/input.sol new file mode 100644 index 0000000000..ff41b32b6e --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/on_state_var_initialization/input.sol @@ -0,0 +1,8 @@ +library Lib { + function nop(uint256 x) returns (uint256) { return x; } +} +contract Test { + using Lib for uint256; + uint256 private v1 = 1; + uint256 private v2 = v1.nop(); +} diff --git a/crates/solidity/testing/snapshots/bindings_output/using/on_super_calls/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/using/on_super_calls/generated/0.4.11-success.txt new file mode 100644 index 0000000000..99cdf03840 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/on_super_calls/generated/0.4.11-success.txt @@ -0,0 +1,38 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract A { + │ ┬ + │ ╰── def: 1 + 2 │ function total() public returns (uint256) {} + │ ──┬── + │ ╰──── def: 2 + │ + 4 │ contract B is A { + │ ┬ ┬ + │ ╰─────── def: 3 + │ │ + │ ╰── ref: 1 + 5 │ using Lib for uint256; + │ ─┬─ + │ ╰─── ref: 5 + 6 │ function total() public returns (uint256) { + │ ──┬── + │ ╰──── def: 4 + 7 │ return super.total().nop(); + │ ──┬── ─┬─ + │ ╰────────── ref: 2 + │ │ + │ ╰─── ref: 6 + │ + 10 │ library Lib { + │ ─┬─ + │ ╰─── def: 5 + 11 │ function nop(uint256 x) internal returns (uint256) {} + │ ─┬─ ┬ + │ ╰───────────── def: 6 + │ │ + │ ╰── def: 7 +────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/using/on_super_calls/input.sol b/crates/solidity/testing/snapshots/bindings_output/using/on_super_calls/input.sol new file mode 100644 index 0000000000..5fde21f3a5 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/on_super_calls/input.sol @@ -0,0 +1,12 @@ +contract A { + function total() public returns (uint256) {} +} +contract B is A { + using Lib for uint256; + function total() public returns (uint256) { + return super.total().nop(); + } +} +library Lib { + function nop(uint256 x) internal returns (uint256) {} +} diff --git a/crates/solidity/testing/snapshots/bindings_output/using/qualified_type/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/using/qualified_type/generated/0.4.11-success.txt new file mode 100644 index 0000000000..d2c34aa894 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/qualified_type/generated/0.4.11-success.txt @@ -0,0 +1,49 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ library Lib { + │ ─┬─ + │ ╰─── def: 1 + 2 │ struct Value { + │ ──┬── + │ ╰──── def: 2 + 3 │ int x; + │ ┬ + │ ╰── def: 3 + │ + 5 │ function getValue() external returns (Value memory) {} + │ ────┬─── ──┬── + │ ╰─────────────────────────────── def: 4 + │ │ + │ ╰──── ref: 2 + 6 │ function use(Value memory x) external {} + │ ─┬─ ──┬── ┬ + │ ╰────────────────── def: 5 + │ │ │ + │ ╰───────────── ref: 2 + │ │ + │ ╰── def: 6 + │ + 8 │ contract Test { + │ ──┬─ + │ ╰─── def: 7 + 9 │ using Lib for Lib.Value; + │ ─┬─ ─┬─ ──┬── + │ ╰───────────────── ref: 1 + │ │ │ + │ ╰───────── ref: 1 + │ │ + │ ╰──── ref: 2 + 10 │ function test() internal { + │ ──┬─ + │ ╰─── def: 8 + 11 │ Lib.getValue().use(); + │ ─┬─ ────┬─── ─┬─ + │ ╰────────────────── ref: 1 + │ │ │ + │ ╰─────────── ref: 4 + │ │ + │ ╰─── ref: 5 +────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/using/qualified_type/input.sol b/crates/solidity/testing/snapshots/bindings_output/using/qualified_type/input.sol new file mode 100644 index 0000000000..b63cc756e5 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/qualified_type/input.sol @@ -0,0 +1,13 @@ +library Lib { + struct Value { + int x; + } + function getValue() external returns (Value memory) {} + function use(Value memory x) external {} +} +contract Test { + using Lib for Lib.Value; + function test() internal { + Lib.getValue().use(); + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/using/star/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/using/star/generated/0.4.11-success.txt index 63dd244363..f3c3ede787 100644 --- a/crates/solidity/testing/snapshots/bindings_output/using/star/generated/0.4.11-success.txt +++ b/crates/solidity/testing/snapshots/bindings_output/using/star/generated/0.4.11-success.txt @@ -1,45 +1,32 @@ # This file is generated automatically by infrastructure scripts. Please don't edit by hand. References and definitions: - ╭─[input.sol:1:1] - │ - 1 │ library Lib { - │ ─┬─ - │ ╰─── def: 1 - 2 │ struct Counter { - │ ───┬─── - │ ╰───── def: 2 - 3 │ uint value; - │ ──┬── - │ ╰──── def: 3 - │ - 6 │ function increment(Counter memory _counter) public {} - │ ────┬──── ───┬─── ────┬─── - │ ╰────────────────────────────── def: 4 - │ │ │ - │ ╰───────────────────── ref: 2 - │ │ - │ ╰───── def: 5 - │ - 9 │ contract Test { - │ ──┬─ - │ ╰─── def: 6 - 10 │ using Lib for *; - │ ─┬─ - │ ╰─── ref: 1 - │ - 12 │ function test(Lib.Counter memory c) public { - │ ──┬─ ─┬─ ───┬─── ┬ - │ ╰──────────────────────── def: 7 - │ │ │ │ - │ ╰──────────────────── ref: 1 - │ │ │ - │ ╰────────────── ref: 2 - │ │ - │ ╰── def: 8 - 13 │ c.increment(); - │ ┬ ────┬──── - │ ╰──────────── ref: 8 - │ │ - │ ╰────── ref: 4 -────╯ + ╭─[input.sol:1:1] + │ + 1 │ library Lib { + │ ─┬─ + │ ╰─── def: 1 + 2 │ function increment(uint x) public {} + │ ────┬──── ┬ + │ ╰───────────── def: 2 + │ │ + │ ╰── def: 3 + │ + 5 │ contract Test { + │ ──┬─ + │ ╰─── def: 4 + 6 │ using Lib for *; + │ ─┬─ + │ ╰─── ref: 1 + │ + 8 │ function test(uint x) public { + │ ──┬─ ┬ + │ ╰────────── def: 5 + │ │ + │ ╰── def: 6 + 9 │ x.increment(); + │ ┬ ────┬──── + │ ╰──────────── ref: 6 + │ │ + │ ╰────── ref: 2 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/using/star/input.sol b/crates/solidity/testing/snapshots/bindings_output/using/star/input.sol index 90669136e3..af70c03cd9 100644 --- a/crates/solidity/testing/snapshots/bindings_output/using/star/input.sol +++ b/crates/solidity/testing/snapshots/bindings_output/using/star/input.sol @@ -1,15 +1,11 @@ library Lib { - struct Counter { - uint value; - } - - function increment(Counter memory _counter) public {} + function increment(uint x) public {} } contract Test { using Lib for *; - function test(Lib.Counter memory c) public { - c.increment(); + function test(uint x) public { + x.increment(); } } diff --git a/crates/solidity/testing/snapshots/bindings_output/using/star_in_library/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/using/star_in_library/generated/0.4.11-success.txt new file mode 100644 index 0000000000..dfe2b1d565 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/star_in_library/generated/0.4.11-success.txt @@ -0,0 +1,33 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ library Lib { + │ ─┬─ + │ ╰─── def: 1 + 2 │ using Math for *; + │ ──┬─ + │ ╰─── ref: 4 + 3 │ function test(uint x) internal { + │ ──┬─ ┬ + │ ╰────────── def: 2 + │ │ + │ ╰── def: 3 + 4 │ x.add(1); + │ ┬ ─┬─ + │ ╰────── ref: 3 + │ │ + │ ╰─── ref: 5 + │ + 7 │ library Math { + │ ──┬─ + │ ╰─── def: 4 + 8 │ function add(uint x, uint y) internal {} + │ ─┬─ ┬ ┬ + │ ╰────────────────── def: 5 + │ │ │ + │ ╰────────── def: 6 + │ │ + │ ╰── def: 7 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/using/star_in_library/input.sol b/crates/solidity/testing/snapshots/bindings_output/using/star_in_library/input.sol new file mode 100644 index 0000000000..91fcfeaceb --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/star_in_library/input.sol @@ -0,0 +1,9 @@ +library Lib { + using Math for *; + function test(uint x) internal { + x.add(1); + } +} +library Math { + function add(uint x, uint y) internal {} +} diff --git a/crates/solidity/testing/snapshots/bindings_output/using/star_inherited/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/using/star_inherited/generated/0.4.11-success.txt new file mode 100644 index 0000000000..0c749da6a4 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/star_inherited/generated/0.4.11-success.txt @@ -0,0 +1,38 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ library Lib { + │ ─┬─ + │ ╰─── def: 1 + 2 │ function increment(uint x) public {} + │ ────┬──── ┬ + │ ╰───────────── def: 2 + │ │ + │ ╰── def: 3 + │ + 5 │ contract Base { + │ ──┬─ + │ ╰─── def: 4 + 6 │ using Lib for *; + │ ─┬─ + │ ╰─── ref: 1 + │ + 9 │ contract Test is Base { + │ ──┬─ ──┬─ + │ ╰─────────── def: 5 + │ │ + │ ╰─── ref: 4 + 10 │ function test(uint x) public { + │ ──┬─ ┬ + │ ╰────────── def: 6 + │ │ + │ ╰── def: 7 + │ + 12 │ x.increment(); + │ ┬ ────┬──── + │ ╰──────────── ref: 7 + │ │ + │ ╰────── ref: 2 +────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/using/star_inherited/generated/0.7.0-failure.txt b/crates/solidity/testing/snapshots/bindings_output/using/star_inherited/generated/0.7.0-failure.txt new file mode 100644 index 0000000000..d743ce1067 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/star_inherited/generated/0.7.0-failure.txt @@ -0,0 +1,38 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ library Lib { + │ ─┬─ + │ ╰─── def: 1 + 2 │ function increment(uint x) public {} + │ ────┬──── ┬ + │ ╰───────────── def: 2 + │ │ + │ ╰── def: 3 + │ + 5 │ contract Base { + │ ──┬─ + │ ╰─── def: 4 + 6 │ using Lib for *; + │ ─┬─ + │ ╰─── ref: 1 + │ + 9 │ contract Test is Base { + │ ──┬─ ──┬─ + │ ╰─────────── def: 5 + │ │ + │ ╰─── ref: 4 + 10 │ function test(uint x) public { + │ ──┬─ ┬ + │ ╰────────── def: 6 + │ │ + │ ╰── def: 7 + │ + 12 │ x.increment(); + │ ┬ ────┬──── + │ ╰──────────── ref: 7 + │ │ + │ ╰────── unresolved +────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/using/star_inherited/input.sol b/crates/solidity/testing/snapshots/bindings_output/using/star_inherited/input.sol new file mode 100644 index 0000000000..1d77492bcd --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/star_inherited/input.sol @@ -0,0 +1,14 @@ +library Lib { + function increment(uint x) public {} +} + +contract Base { + using Lib for *; +} + +contract Test is Base { + function test(uint x) public { + // should resolve for Solidity < 0.7.0 + x.increment(); + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/using/uint_alias/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/using/uint_alias/generated/0.4.11-success.txt new file mode 100644 index 0000000000..d04e0ece4e --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/uint_alias/generated/0.4.11-success.txt @@ -0,0 +1,32 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ using Lib for uint256; + │ ─┬─ + │ ╰─── ref: 4 + 3 │ function test() public { + │ ──┬─ + │ ╰─── def: 2 + 4 │ uint x; + │ ┬ + │ ╰── def: 3 + 5 │ x.nop(); + │ ┬ ─┬─ + │ ╰────── ref: 3 + │ │ + │ ╰─── ref: 5 + │ + 8 │ library Lib { + │ ─┬─ + │ ╰─── def: 4 + 9 │ function nop(uint256 x) external {} + │ ─┬─ ┬ + │ ╰───────────── def: 5 + │ │ + │ ╰── def: 6 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/using/uint_alias/input.sol b/crates/solidity/testing/snapshots/bindings_output/using/uint_alias/input.sol new file mode 100644 index 0000000000..6785caf83f --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/uint_alias/input.sol @@ -0,0 +1,10 @@ +contract Test { + using Lib for uint256; + function test() public { + uint x; + x.nop(); + } +} +library Lib { + function nop(uint256 x) external {} +} diff --git a/crates/solidity/testing/snapshots/bindings_output/using/user_types/generated/0.4.11-failure.txt b/crates/solidity/testing/snapshots/bindings_output/using/user_types/generated/0.4.11-failure.txt new file mode 100644 index 0000000000..5b3351888a --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/user_types/generated/0.4.11-failure.txt @@ -0,0 +1,13 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected ContractKeyword or ImportKeyword or InterfaceKeyword or LibraryKeyword or PragmaKeyword. + ╭─[input.sol:1:1] + │ + 1 │ ╭─▶ type ShortString is bytes32; + ┆ ┆ + 18 │ ├─▶ } + │ │ + │ ╰─────── Error occurred here. +────╯ +References and definitions: diff --git a/crates/solidity/testing/snapshots/bindings_output/using/user_types/generated/0.6.0-failure.txt b/crates/solidity/testing/snapshots/bindings_output/using/user_types/generated/0.6.0-failure.txt new file mode 100644 index 0000000000..59217924c2 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/user_types/generated/0.6.0-failure.txt @@ -0,0 +1,13 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected ContractKeyword or EnumKeyword or ImportKeyword or InterfaceKeyword or LibraryKeyword or PragmaKeyword or StructKeyword. + ╭─[input.sol:1:1] + │ + 1 │ ╭─▶ type ShortString is bytes32; + ┆ ┆ + 18 │ ├─▶ } + │ │ + │ ╰─────── Error occurred here. +────╯ +References and definitions: diff --git a/crates/solidity/testing/snapshots/bindings_output/using/user_types/generated/0.7.1-failure.txt b/crates/solidity/testing/snapshots/bindings_output/using/user_types/generated/0.7.1-failure.txt new file mode 100644 index 0000000000..d19bf6dfe0 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/user_types/generated/0.7.1-failure.txt @@ -0,0 +1,13 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected ContractKeyword or EnumKeyword or FunctionKeyword or ImportKeyword or InterfaceKeyword or LibraryKeyword or PragmaKeyword or StructKeyword. + ╭─[input.sol:1:1] + │ + 1 │ ╭─▶ type ShortString is bytes32; + ┆ ┆ + 18 │ ├─▶ } + │ │ + │ ╰─────── Error occurred here. +────╯ +References and definitions: diff --git a/crates/solidity/testing/snapshots/bindings_output/using/user_types/generated/0.7.4-failure.txt b/crates/solidity/testing/snapshots/bindings_output/using/user_types/generated/0.7.4-failure.txt new file mode 100644 index 0000000000..50dc41f2ab --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/user_types/generated/0.7.4-failure.txt @@ -0,0 +1,13 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected AddressKeyword or BoolKeyword or ByteKeyword or BytesKeyword or ContractKeyword or EnumKeyword or FixedKeyword or FunctionKeyword or Identifier or ImportKeyword or IntKeyword or InterfaceKeyword or LibraryKeyword or MappingKeyword or PragmaKeyword or StringKeyword or StructKeyword or UfixedKeyword or UintKeyword. + ╭─[input.sol:1:1] + │ + 1 │ ╭─▶ type ShortString is bytes32; + ┆ ┆ + 18 │ ├─▶ } + │ │ + │ ╰─────── Error occurred here. +────╯ +References and definitions: diff --git a/crates/solidity/testing/snapshots/bindings_output/using/user_types/generated/0.8.0-failure.txt b/crates/solidity/testing/snapshots/bindings_output/using/user_types/generated/0.8.0-failure.txt new file mode 100644 index 0000000000..205226995e --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/user_types/generated/0.8.0-failure.txt @@ -0,0 +1,13 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected AddressKeyword or BoolKeyword or BytesKeyword or ContractKeyword or EnumKeyword or FixedKeyword or FunctionKeyword or Identifier or ImportKeyword or IntKeyword or InterfaceKeyword or LibraryKeyword or MappingKeyword or PragmaKeyword or StringKeyword or StructKeyword or UfixedKeyword or UintKeyword. + ╭─[input.sol:1:1] + │ + 1 │ ╭─▶ type ShortString is bytes32; + ┆ ┆ + 18 │ ├─▶ } + │ │ + │ ╰─────── Error occurred here. +────╯ +References and definitions: diff --git a/crates/solidity/testing/snapshots/bindings_output/using/user_types/generated/0.8.4-failure.txt b/crates/solidity/testing/snapshots/bindings_output/using/user_types/generated/0.8.4-failure.txt new file mode 100644 index 0000000000..c709a0526b --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/user_types/generated/0.8.4-failure.txt @@ -0,0 +1,13 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected AddressKeyword or BoolKeyword or BytesKeyword or ContractKeyword or EnumKeyword or ErrorKeyword or FixedKeyword or FunctionKeyword or Identifier or ImportKeyword or IntKeyword or InterfaceKeyword or LibraryKeyword or MappingKeyword or PragmaKeyword or StringKeyword or StructKeyword or UfixedKeyword or UintKeyword. + ╭─[input.sol:1:1] + │ + 1 │ ╭─▶ type ShortString is bytes32; + ┆ ┆ + 18 │ ├─▶ } + │ │ + │ ╰─────── Error occurred here. +────╯ +References and definitions: diff --git a/crates/solidity/testing/snapshots/bindings_output/using/user_types/generated/0.8.8-success.txt b/crates/solidity/testing/snapshots/bindings_output/using/user_types/generated/0.8.8-success.txt new file mode 100644 index 0000000000..2ec0bb8683 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/user_types/generated/0.8.8-success.txt @@ -0,0 +1,67 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ type ShortString is bytes32; + │ ─────┬───── + │ ╰─────── def: 1 + │ + 3 │ contract Test { + │ ──┬─ + │ ╰─── def: 2 + 4 │ using Lib for ShortString; + │ ─┬─ ─────┬───── + │ ╰─────────────────── ref: 6 + │ │ + │ ╰─────── ref: 1 + 5 │ using Lib for bytes32; + │ ─┬─ + │ ╰─── ref: 6 + │ + 7 │ function test(bytes32 data) public { + │ ──┬─ ──┬─ + │ ╰──────────────── def: 3 + │ │ + │ ╰─── def: 4 + 8 │ ShortString s; + │ ─────┬───── ┬ + │ ╰───────── ref: 1 + │ │ + │ ╰── def: 5 + │ + 10 │ ShortString.wrap(data).nop(); + │ ─────┬───── ──┬─ ──┬─ ─┬─ + │ ╰────────────────────── ref: 1 + │ │ │ │ + │ ╰───────────── ref: built-in + │ │ │ + │ ╰──────── ref: 4 + │ │ + │ ╰─── ref: 7 + 11 │ ShortString.unwrap(s).pon(); + │ ─────┬───── ───┬── ┬ ─┬─ + │ ╰───────────────────── ref: 1 + │ │ │ │ + │ ╰─────────── ref: built-in + │ │ │ + │ ╰─────── ref: 5 + │ │ + │ ╰─── ref: 9 + │ + 15 │ library Lib { + │ ─┬─ + │ ╰─── def: 6 + 16 │ function nop(ShortString x) internal {} + │ ─┬─ ─────┬───── ┬ + │ ╰───────────────── def: 7 + │ │ │ + │ ╰───────── ref: 1 + │ │ + │ ╰── def: 8 + 17 │ function pon(bytes32 x) internal {} + │ ─┬─ ┬ + │ ╰───────────── def: 9 + │ │ + │ ╰── def: 10 +────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/using/user_types/input.sol b/crates/solidity/testing/snapshots/bindings_output/using/user_types/input.sol new file mode 100644 index 0000000000..2cd5524ea3 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/using/user_types/input.sol @@ -0,0 +1,18 @@ +type ShortString is bytes32; + +contract Test { + using Lib for ShortString; + using Lib for bytes32; + + function test(bytes32 data) public { + ShortString s; + + ShortString.wrap(data).nop(); + ShortString.unwrap(s).pon(); + } +} + +library Lib { + function nop(ShortString x) internal {} + function pon(bytes32 x) internal {} +} diff --git a/crates/solidity/testing/snapshots/bindings_output/variables/var_declaration/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/variables/var_declaration/generated/0.4.11-success.txt new file mode 100644 index 0000000000..49bae9ee2c --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/variables/var_declaration/generated/0.4.11-success.txt @@ -0,0 +1,31 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ struct Value { int x; } + │ ──┬── ┬ + │ ╰──────────── def: 2 + │ │ + │ ╰── def: 3 + 3 │ function test(Value memory value) public { + │ ──┬─ ──┬── ──┬── + │ ╰────────────────────── def: 4 + │ │ │ + │ ╰───────────────── ref: 2 + │ │ + │ ╰──── def: 5 + 4 │ var v = value; + │ ┬ ──┬── + │ ╰────────── def: 6 + │ │ + │ ╰──── ref: 5 + 5 │ v.x; + │ ┬ ┬ + │ ╰──── refs: 6, 5 + │ │ + │ ╰── ref: 3 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/variables/var_declaration/generated/0.5.0-failure.txt b/crates/solidity/testing/snapshots/bindings_output/variables/var_declaration/generated/0.5.0-failure.txt new file mode 100644 index 0000000000..b1aab5f30b --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/variables/var_declaration/generated/0.5.0-failure.txt @@ -0,0 +1,31 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected AddressKeyword or AssemblyKeyword or BoolKeyword or BreakKeyword or ByteKeyword or BytesKeyword or CloseBrace or ContinueKeyword or DecimalLiteral or DoKeyword or DoubleQuotedHexStringLiteral or DoubleQuotedStringLiteral or EmitKeyword or FalseKeyword or FixedKeyword or ForKeyword or FunctionKeyword or HexLiteral or Identifier or IfKeyword or IntKeyword or MappingKeyword or NewKeyword or OpenBrace or OpenBracket or OpenParen or ReturnKeyword or SingleQuotedHexStringLiteral or SingleQuotedStringLiteral or StringKeyword or SuperKeyword or ThisKeyword or TrueKeyword or UfixedKeyword or UintKeyword or WhileKeyword. + ╭─[input.sol:4:9] + │ + 4 │ ╭─▶ var v = value; + ┆ ┆ + 6 │ ├─▶ } + │ │ + │ ╰─────────── Error occurred here. +───╯ +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ struct Value { int x; } + │ ──┬── ┬ + │ ╰──────────── def: 2 + │ │ + │ ╰── def: 3 + 3 │ function test(Value memory value) public { + │ ──┬─ ──┬── ──┬── + │ ╰────────────────────── def: 4 + │ │ │ + │ ╰───────────────── ref: 2 + │ │ + │ ╰──── def: 5 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/variables/var_declaration/generated/0.5.3-failure.txt b/crates/solidity/testing/snapshots/bindings_output/variables/var_declaration/generated/0.5.3-failure.txt new file mode 100644 index 0000000000..916fc51d48 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/variables/var_declaration/generated/0.5.3-failure.txt @@ -0,0 +1,31 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected AddressKeyword or AssemblyKeyword or BoolKeyword or BreakKeyword or ByteKeyword or BytesKeyword or CloseBrace or ContinueKeyword or DecimalLiteral or DoKeyword or DoubleQuotedHexStringLiteral or DoubleQuotedStringLiteral or EmitKeyword or FalseKeyword or FixedKeyword or ForKeyword or FunctionKeyword or HexLiteral or Identifier or IfKeyword or IntKeyword or MappingKeyword or NewKeyword or OpenBrace or OpenBracket or OpenParen or ReturnKeyword or SingleQuotedHexStringLiteral or SingleQuotedStringLiteral or StringKeyword or SuperKeyword or ThisKeyword or TrueKeyword or TypeKeyword or UfixedKeyword or UintKeyword or WhileKeyword. + ╭─[input.sol:4:9] + │ + 4 │ ╭─▶ var v = value; + ┆ ┆ + 6 │ ├─▶ } + │ │ + │ ╰─────────── Error occurred here. +───╯ +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ struct Value { int x; } + │ ──┬── ┬ + │ ╰──────────── def: 2 + │ │ + │ ╰── def: 3 + 3 │ function test(Value memory value) public { + │ ──┬─ ──┬── ──┬── + │ ╰────────────────────── def: 4 + │ │ │ + │ ╰───────────────── ref: 2 + │ │ + │ ╰──── def: 5 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/variables/var_declaration/generated/0.6.0-failure.txt b/crates/solidity/testing/snapshots/bindings_output/variables/var_declaration/generated/0.6.0-failure.txt new file mode 100644 index 0000000000..baeb9846cc --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/variables/var_declaration/generated/0.6.0-failure.txt @@ -0,0 +1,31 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected AddressKeyword or AssemblyKeyword or BoolKeyword or BreakKeyword or ByteKeyword or BytesKeyword or CloseBrace or ContinueKeyword or DecimalLiteral or DoKeyword or DoubleQuotedHexStringLiteral or DoubleQuotedStringLiteral or EmitKeyword or FalseKeyword or FixedKeyword or ForKeyword or FunctionKeyword or HexLiteral or Identifier or IfKeyword or IntKeyword or MappingKeyword or NewKeyword or OpenBrace or OpenBracket or OpenParen or PayableKeyword or ReturnKeyword or SingleQuotedHexStringLiteral or SingleQuotedStringLiteral or StringKeyword or SuperKeyword or ThisKeyword or TrueKeyword or TryKeyword or TypeKeyword or UfixedKeyword or UintKeyword or WhileKeyword. + ╭─[input.sol:4:9] + │ + 4 │ ╭─▶ var v = value; + ┆ ┆ + 6 │ ├─▶ } + │ │ + │ ╰─────────── Error occurred here. +───╯ +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ struct Value { int x; } + │ ──┬── ┬ + │ ╰──────────── def: 2 + │ │ + │ ╰── def: 3 + 3 │ function test(Value memory value) public { + │ ──┬─ ──┬── ──┬── + │ ╰────────────────────── def: 4 + │ │ │ + │ ╰───────────────── ref: 2 + │ │ + │ ╰──── def: 5 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/variables/var_declaration/generated/0.7.0-failure.txt b/crates/solidity/testing/snapshots/bindings_output/variables/var_declaration/generated/0.7.0-failure.txt new file mode 100644 index 0000000000..d9a26d93af --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/variables/var_declaration/generated/0.7.0-failure.txt @@ -0,0 +1,31 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected AddressKeyword or AssemblyKeyword or BoolKeyword or BreakKeyword or ByteKeyword or BytesKeyword or CloseBrace or ContinueKeyword or DecimalLiteral or DoKeyword or DoubleQuotedHexStringLiteral or DoubleQuotedStringLiteral or DoubleQuotedUnicodeStringLiteral or EmitKeyword or FalseKeyword or FixedKeyword or ForKeyword or FunctionKeyword or HexLiteral or Identifier or IfKeyword or IntKeyword or MappingKeyword or NewKeyword or OpenBrace or OpenBracket or OpenParen or PayableKeyword or ReturnKeyword or SingleQuotedHexStringLiteral or SingleQuotedStringLiteral or SingleQuotedUnicodeStringLiteral or StringKeyword or SuperKeyword or ThisKeyword or TrueKeyword or TryKeyword or TypeKeyword or UfixedKeyword or UintKeyword or WhileKeyword. + ╭─[input.sol:4:9] + │ + 4 │ ╭─▶ var v = value; + ┆ ┆ + 6 │ ├─▶ } + │ │ + │ ╰─────────── Error occurred here. +───╯ +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ struct Value { int x; } + │ ──┬── ┬ + │ ╰──────────── def: 2 + │ │ + │ ╰── def: 3 + 3 │ function test(Value memory value) public { + │ ──┬─ ──┬── ──┬── + │ ╰────────────────────── def: 4 + │ │ │ + │ ╰───────────────── ref: 2 + │ │ + │ ╰──── def: 5 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/variables/var_declaration/generated/0.8.0-failure.txt b/crates/solidity/testing/snapshots/bindings_output/variables/var_declaration/generated/0.8.0-failure.txt new file mode 100644 index 0000000000..4ab42efd3b --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/variables/var_declaration/generated/0.8.0-failure.txt @@ -0,0 +1,31 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected AddressKeyword or AssemblyKeyword or BoolKeyword or BreakKeyword or BytesKeyword or CloseBrace or ContinueKeyword or DecimalLiteral or DoKeyword or DoubleQuotedHexStringLiteral or DoubleQuotedStringLiteral or DoubleQuotedUnicodeStringLiteral or EmitKeyword or FalseKeyword or FixedKeyword or ForKeyword or FunctionKeyword or HexLiteral or Identifier or IfKeyword or IntKeyword or MappingKeyword or NewKeyword or OpenBrace or OpenBracket or OpenParen or PayableKeyword or ReturnKeyword or SingleQuotedHexStringLiteral or SingleQuotedStringLiteral or SingleQuotedUnicodeStringLiteral or StringKeyword or SuperKeyword or ThisKeyword or TrueKeyword or TryKeyword or TypeKeyword or UfixedKeyword or UintKeyword or UncheckedKeyword or WhileKeyword. + ╭─[input.sol:4:9] + │ + 4 │ ╭─▶ var v = value; + ┆ ┆ + 6 │ ├─▶ } + │ │ + │ ╰─────────── Error occurred here. +───╯ +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ struct Value { int x; } + │ ──┬── ┬ + │ ╰──────────── def: 2 + │ │ + │ ╰── def: 3 + 3 │ function test(Value memory value) public { + │ ──┬─ ──┬── ──┬── + │ ╰────────────────────── def: 4 + │ │ │ + │ ╰───────────────── ref: 2 + │ │ + │ ╰──── def: 5 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/variables/var_declaration/generated/0.8.4-failure.txt b/crates/solidity/testing/snapshots/bindings_output/variables/var_declaration/generated/0.8.4-failure.txt new file mode 100644 index 0000000000..bef3f48735 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/variables/var_declaration/generated/0.8.4-failure.txt @@ -0,0 +1,31 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected AddressKeyword or AssemblyKeyword or BoolKeyword or BreakKeyword or BytesKeyword or CloseBrace or ContinueKeyword or DecimalLiteral or DoKeyword or DoubleQuotedHexStringLiteral or DoubleQuotedStringLiteral or DoubleQuotedUnicodeStringLiteral or EmitKeyword or FalseKeyword or FixedKeyword or ForKeyword or FunctionKeyword or HexLiteral or Identifier or IfKeyword or IntKeyword or MappingKeyword or NewKeyword or OpenBrace or OpenBracket or OpenParen or PayableKeyword or ReturnKeyword or RevertKeyword or SingleQuotedHexStringLiteral or SingleQuotedStringLiteral or SingleQuotedUnicodeStringLiteral or StringKeyword or SuperKeyword or ThisKeyword or TrueKeyword or TryKeyword or TypeKeyword or UfixedKeyword or UintKeyword or UncheckedKeyword or WhileKeyword. + ╭─[input.sol:4:9] + │ + 4 │ ╭─▶ var v = value; + ┆ ┆ + 6 │ ├─▶ } + │ │ + │ ╰─────────── Error occurred here. +───╯ +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ struct Value { int x; } + │ ──┬── ┬ + │ ╰──────────── def: 2 + │ │ + │ ╰── def: 3 + 3 │ function test(Value memory value) public { + │ ──┬─ ──┬── ──┬── + │ ╰────────────────────── def: 4 + │ │ │ + │ ╰───────────────── ref: 2 + │ │ + │ ╰──── def: 5 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/variables/var_declaration/input.sol b/crates/solidity/testing/snapshots/bindings_output/variables/var_declaration/input.sol new file mode 100644 index 0000000000..2a03158592 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/variables/var_declaration/input.sol @@ -0,0 +1,7 @@ +contract Test { + struct Value { int x; } + function test(Value memory value) public { + var v = value; + v.x; + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/yul/constant_access_from_functions/generated/0.4.11-failure.txt b/crates/solidity/testing/snapshots/bindings_output/yul/constant_access_from_functions/generated/0.4.11-failure.txt new file mode 100644 index 0000000000..568d7b9b08 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/yul/constant_access_from_functions/generated/0.4.11-failure.txt @@ -0,0 +1,67 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected ContractKeyword or ImportKeyword or InterfaceKeyword or LibraryKeyword or PragmaKeyword. + ╭─[input.sol:27:1] + │ + 27 │ uint256 constant TOP_LEVEL_CONST = 0; + │ ───────────────────┬────────────────── + │ ╰──────────────────── Error occurred here. +────╯ +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract InContracts { + │ ─────┬───── + │ ╰─────── def: 1 + 2 │ uint256 private constant CONTRACT_CONST = 1; + │ ───────┬────── + │ ╰──────── def: 2 + │ + 4 │ function test() public { + │ ──┬─ + │ ╰─── def: 3 + │ + 6 │ function swap(emptyPtr) { + │ ──┬─ ────┬─── + │ ╰──────────── def: 4 + │ │ + │ ╰───── def: 5 + 7 │ mstore(emptyPtr, CONTRACT_CONST) + │ ────┬─── ───────┬────── + │ ╰───────────────────── ref: 5 + │ │ + │ ╰──────── ref: 2 + 8 │ mstore(emptyPtr, TOP_LEVEL_CONST) + │ ────┬─── ───────┬─────── + │ ╰────────────────────── ref: 5 + │ │ + │ ╰───────── unresolved + │ + 14 │ library InLibraries { + │ ─────┬───── + │ ╰─────── def: 6 + 15 │ uint256 private constant LIB_CONST = 2; + │ ────┬──── + │ ╰────── def: 7 + │ + 17 │ function test() public { + │ ──┬─ + │ ╰─── def: 8 + │ + 19 │ function swap(emptyPtr) { + │ ──┬─ ────┬─── + │ ╰──────────── def: 9 + │ │ + │ ╰───── def: 10 + 20 │ mstore(emptyPtr, LIB_CONST) + │ ────┬─── ────┬──── + │ ╰──────────────── ref: 10 + │ │ + │ ╰────── ref: 7 + 21 │ mstore(emptyPtr, TOP_LEVEL_CONST) + │ ────┬─── ───────┬─────── + │ ╰────────────────────── ref: 10 + │ │ + │ ╰───────── unresolved +────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/yul/constant_access_from_functions/generated/0.6.0-failure.txt b/crates/solidity/testing/snapshots/bindings_output/yul/constant_access_from_functions/generated/0.6.0-failure.txt new file mode 100644 index 0000000000..19b7c69fae --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/yul/constant_access_from_functions/generated/0.6.0-failure.txt @@ -0,0 +1,67 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected ContractKeyword or EnumKeyword or ImportKeyword or InterfaceKeyword or LibraryKeyword or PragmaKeyword or StructKeyword. + ╭─[input.sol:27:1] + │ + 27 │ uint256 constant TOP_LEVEL_CONST = 0; + │ ───────────────────┬────────────────── + │ ╰──────────────────── Error occurred here. +────╯ +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract InContracts { + │ ─────┬───── + │ ╰─────── def: 1 + 2 │ uint256 private constant CONTRACT_CONST = 1; + │ ───────┬────── + │ ╰──────── def: 2 + │ + 4 │ function test() public { + │ ──┬─ + │ ╰─── def: 3 + │ + 6 │ function swap(emptyPtr) { + │ ──┬─ ────┬─── + │ ╰──────────── def: 4 + │ │ + │ ╰───── def: 5 + 7 │ mstore(emptyPtr, CONTRACT_CONST) + │ ────┬─── ───────┬────── + │ ╰───────────────────── ref: 5 + │ │ + │ ╰──────── ref: 2 + 8 │ mstore(emptyPtr, TOP_LEVEL_CONST) + │ ────┬─── ───────┬─────── + │ ╰────────────────────── ref: 5 + │ │ + │ ╰───────── unresolved + │ + 14 │ library InLibraries { + │ ─────┬───── + │ ╰─────── def: 6 + 15 │ uint256 private constant LIB_CONST = 2; + │ ────┬──── + │ ╰────── def: 7 + │ + 17 │ function test() public { + │ ──┬─ + │ ╰─── def: 8 + │ + 19 │ function swap(emptyPtr) { + │ ──┬─ ────┬─── + │ ╰──────────── def: 9 + │ │ + │ ╰───── def: 10 + 20 │ mstore(emptyPtr, LIB_CONST) + │ ────┬─── ────┬──── + │ ╰──────────────── ref: 10 + │ │ + │ ╰────── ref: 7 + 21 │ mstore(emptyPtr, TOP_LEVEL_CONST) + │ ────┬─── ───────┬─────── + │ ╰────────────────────── ref: 10 + │ │ + │ ╰───────── unresolved +────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/yul/constant_access_from_functions/generated/0.7.1-failure.txt b/crates/solidity/testing/snapshots/bindings_output/yul/constant_access_from_functions/generated/0.7.1-failure.txt new file mode 100644 index 0000000000..19d15d5248 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/yul/constant_access_from_functions/generated/0.7.1-failure.txt @@ -0,0 +1,67 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected ContractKeyword or EnumKeyword or FunctionKeyword or ImportKeyword or InterfaceKeyword or LibraryKeyword or PragmaKeyword or StructKeyword. + ╭─[input.sol:27:1] + │ + 27 │ uint256 constant TOP_LEVEL_CONST = 0; + │ ───────────────────┬────────────────── + │ ╰──────────────────── Error occurred here. +────╯ +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract InContracts { + │ ─────┬───── + │ ╰─────── def: 1 + 2 │ uint256 private constant CONTRACT_CONST = 1; + │ ───────┬────── + │ ╰──────── def: 2 + │ + 4 │ function test() public { + │ ──┬─ + │ ╰─── def: 3 + │ + 6 │ function swap(emptyPtr) { + │ ──┬─ ────┬─── + │ ╰──────────── def: 4 + │ │ + │ ╰───── def: 5 + 7 │ mstore(emptyPtr, CONTRACT_CONST) + │ ────┬─── ───────┬────── + │ ╰───────────────────── ref: 5 + │ │ + │ ╰──────── ref: 2 + 8 │ mstore(emptyPtr, TOP_LEVEL_CONST) + │ ────┬─── ───────┬─────── + │ ╰────────────────────── ref: 5 + │ │ + │ ╰───────── unresolved + │ + 14 │ library InLibraries { + │ ─────┬───── + │ ╰─────── def: 6 + 15 │ uint256 private constant LIB_CONST = 2; + │ ────┬──── + │ ╰────── def: 7 + │ + 17 │ function test() public { + │ ──┬─ + │ ╰─── def: 8 + │ + 19 │ function swap(emptyPtr) { + │ ──┬─ ────┬─── + │ ╰──────────── def: 9 + │ │ + │ ╰───── def: 10 + 20 │ mstore(emptyPtr, LIB_CONST) + │ ────┬─── ────┬──── + │ ╰──────────────── ref: 10 + │ │ + │ ╰────── ref: 7 + 21 │ mstore(emptyPtr, TOP_LEVEL_CONST) + │ ────┬─── ───────┬─────── + │ ╰────────────────────── ref: 10 + │ │ + │ ╰───────── unresolved +────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/yul/constant_access_from_functions/generated/0.7.4-success.txt b/crates/solidity/testing/snapshots/bindings_output/yul/constant_access_from_functions/generated/0.7.4-success.txt new file mode 100644 index 0000000000..38815261bc --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/yul/constant_access_from_functions/generated/0.7.4-success.txt @@ -0,0 +1,63 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract InContracts { + │ ─────┬───── + │ ╰─────── def: 1 + 2 │ uint256 private constant CONTRACT_CONST = 1; + │ ───────┬────── + │ ╰──────── def: 2 + │ + 4 │ function test() public { + │ ──┬─ + │ ╰─── def: 3 + │ + 6 │ function swap(emptyPtr) { + │ ──┬─ ────┬─── + │ ╰──────────── def: 4 + │ │ + │ ╰───── def: 5 + 7 │ mstore(emptyPtr, CONTRACT_CONST) + │ ────┬─── ───────┬────── + │ ╰───────────────────── ref: 5 + │ │ + │ ╰──────── ref: 2 + 8 │ mstore(emptyPtr, TOP_LEVEL_CONST) + │ ────┬─── ───────┬─────── + │ ╰────────────────────── ref: 5 + │ │ + │ ╰───────── ref: 11 + │ + 14 │ library InLibraries { + │ ─────┬───── + │ ╰─────── def: 6 + 15 │ uint256 private constant LIB_CONST = 2; + │ ────┬──── + │ ╰────── def: 7 + │ + 17 │ function test() public { + │ ──┬─ + │ ╰─── def: 8 + │ + 19 │ function swap(emptyPtr) { + │ ──┬─ ────┬─── + │ ╰──────────── def: 9 + │ │ + │ ╰───── def: 10 + 20 │ mstore(emptyPtr, LIB_CONST) + │ ────┬─── ────┬──── + │ ╰──────────────── ref: 10 + │ │ + │ ╰────── ref: 7 + 21 │ mstore(emptyPtr, TOP_LEVEL_CONST) + │ ────┬─── ───────┬─────── + │ ╰────────────────────── ref: 10 + │ │ + │ ╰───────── ref: 11 + │ + 27 │ uint256 constant TOP_LEVEL_CONST = 0; + │ ───────┬─────── + │ ╰───────── def: 11 +────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/yul/constant_access_from_functions/input.sol b/crates/solidity/testing/snapshots/bindings_output/yul/constant_access_from_functions/input.sol new file mode 100644 index 0000000000..2dcf1ca5ad --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/yul/constant_access_from_functions/input.sol @@ -0,0 +1,27 @@ +contract InContracts { + uint256 private constant CONTRACT_CONST = 1; + + function test() public { + assembly { + function swap(emptyPtr) { + mstore(emptyPtr, CONTRACT_CONST) + mstore(emptyPtr, TOP_LEVEL_CONST) + } + } + } +} + +library InLibraries { + uint256 private constant LIB_CONST = 2; + + function test() public { + assembly { + function swap(emptyPtr) { + mstore(emptyPtr, LIB_CONST) + mstore(emptyPtr, TOP_LEVEL_CONST) + } + } + } +} + +uint256 constant TOP_LEVEL_CONST = 0; diff --git a/crates/solidity/testing/snapshots/bindings_output/yul/identifiers_with_dots/generated/0.4.11-failure.txt b/crates/solidity/testing/snapshots/bindings_output/yul/identifiers_with_dots/generated/0.4.11-failure.txt new file mode 100644 index 0000000000..d14a31e3bf --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/yul/identifiers_with_dots/generated/0.4.11-failure.txt @@ -0,0 +1,26 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected CloseBrace or DoubleQuotedHexStringLiteral or DoubleQuotedStringLiteral or Equal or EqualColon or OpenBrace or SingleQuotedHexStringLiteral or SingleQuotedStringLiteral or YulAddKeyword or YulAddModKeyword or YulAddressKeyword or YulAndKeyword or YulBalanceKeyword or YulBlockHashKeyword or YulBreakKeyword or YulByteKeyword or YulCallCodeKeyword or YulCallDataCopyKeyword or YulCallDataLoadKeyword or YulCallDataSizeKeyword or YulCallKeyword or YulCallValueKeyword or YulCallerKeyword or YulChainIdKeyword or YulCoinBaseKeyword or YulContinueKeyword or YulCreateKeyword or YulDecimalLiteral or YulDelegateCallKeyword or YulDifficultyKeyword or YulDivKeyword or YulEqKeyword or YulExpKeyword or YulExtCodeCopyKeyword or YulExtCodeSizeKeyword or YulFalseKeyword or YulForKeyword or YulFunctionKeyword or YulGasKeyword or YulGasLimitKeyword or YulGasPriceKeyword or YulGtKeyword or YulHexLiteral or YulIdentifier or YulIfKeyword or YulInvalidKeyword or YulIsZeroKeyword or YulJumpKeyword or YulJumpiKeyword or YulLetKeyword or YulLog0Keyword or YulLog1Keyword or YulLog2Keyword or YulLog3Keyword or YulLog4Keyword or YulLtKeyword or YulMLoadKeyword or YulMSizeKeyword or YulMStore8Keyword or YulMStoreKeyword or YulModKeyword or YulMulKeyword or YulMulModKeyword or YulNotKeyword or YulNumberKeyword or YulOrKeyword or YulOriginKeyword or YulPopKeyword or YulReturnKeyword or YulRevertKeyword or YulSDivKeyword or YulSLoadKeyword or YulSModKeyword or YulSStoreKeyword or YulSarKeyword or YulSelfBalanceKeyword or YulSelfDestructKeyword or YulSgtKeyword or YulSha3Keyword or YulShlKeyword or YulShrKeyword or YulSignExtendKeyword or YulSltKeyword or YulStopKeyword or YulSubKeyword or YulSuicideKeyword or YulSwitchKeyword or YulTimestampKeyword or YulTrueKeyword or YulXorKeyword. + ╭─[input.sol:4:18] + │ + 4 │ ╭─▶ let x.y.z := 0 + ┆ ┆ + 6 │ ├─▶ } + │ │ + │ ╰─────────────── Error occurred here. +───╯ +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ function test() public { + │ ──┬─ + │ ╰─── def: 2 + │ + 4 │ let x.y.z := 0 + │ ┬ + │ ╰── def: 3 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/yul/identifiers_with_dots/generated/0.4.12-failure.txt b/crates/solidity/testing/snapshots/bindings_output/yul/identifiers_with_dots/generated/0.4.12-failure.txt new file mode 100644 index 0000000000..d64f0a606b --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/yul/identifiers_with_dots/generated/0.4.12-failure.txt @@ -0,0 +1,26 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected CloseBrace or DoubleQuotedHexStringLiteral or DoubleQuotedStringLiteral or Equal or EqualColon or OpenBrace or SingleQuotedHexStringLiteral or SingleQuotedStringLiteral or YulAddKeyword or YulAddModKeyword or YulAddressKeyword or YulAndKeyword or YulBalanceKeyword or YulBlockHashKeyword or YulBreakKeyword or YulByteKeyword or YulCallCodeKeyword or YulCallDataCopyKeyword or YulCallDataLoadKeyword or YulCallDataSizeKeyword or YulCallKeyword or YulCallValueKeyword or YulCallerKeyword or YulChainIdKeyword or YulCoinBaseKeyword or YulContinueKeyword or YulCreate2Keyword or YulCreateKeyword or YulDecimalLiteral or YulDelegateCallKeyword or YulDifficultyKeyword or YulDivKeyword or YulEqKeyword or YulExpKeyword or YulExtCodeCopyKeyword or YulExtCodeSizeKeyword or YulFalseKeyword or YulForKeyword or YulFunctionKeyword or YulGasKeyword or YulGasLimitKeyword or YulGasPriceKeyword or YulGtKeyword or YulHexLiteral or YulIdentifier or YulIfKeyword or YulInvalidKeyword or YulIsZeroKeyword or YulJumpKeyword or YulJumpiKeyword or YulKeccak256Keyword or YulLetKeyword or YulLog0Keyword or YulLog1Keyword or YulLog2Keyword or YulLog3Keyword or YulLog4Keyword or YulLtKeyword or YulMLoadKeyword or YulMSizeKeyword or YulMStore8Keyword or YulMStoreKeyword or YulModKeyword or YulMulKeyword or YulMulModKeyword or YulNotKeyword or YulNumberKeyword or YulOrKeyword or YulOriginKeyword or YulPopKeyword or YulReturnDataCopyKeyword or YulReturnDataSizeKeyword or YulReturnKeyword or YulRevertKeyword or YulSDivKeyword or YulSLoadKeyword or YulSModKeyword or YulSStoreKeyword or YulSarKeyword or YulSelfBalanceKeyword or YulSelfDestructKeyword or YulSgtKeyword or YulSha3Keyword or YulShlKeyword or YulShrKeyword or YulSignExtendKeyword or YulSltKeyword or YulStaticCallKeyword or YulStopKeyword or YulSubKeyword or YulSuicideKeyword or YulSwitchKeyword or YulTimestampKeyword or YulTrueKeyword or YulXorKeyword. + ╭─[input.sol:4:18] + │ + 4 │ ╭─▶ let x.y.z := 0 + ┆ ┆ + 6 │ ├─▶ } + │ │ + │ ╰─────────────── Error occurred here. +───╯ +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ function test() public { + │ ──┬─ + │ ╰─── def: 2 + │ + 4 │ let x.y.z := 0 + │ ┬ + │ ╰── def: 3 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/yul/identifiers_with_dots/generated/0.5.0-failure.txt b/crates/solidity/testing/snapshots/bindings_output/yul/identifiers_with_dots/generated/0.5.0-failure.txt new file mode 100644 index 0000000000..a85be30fd2 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/yul/identifiers_with_dots/generated/0.5.0-failure.txt @@ -0,0 +1,26 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected CloseBrace or DoubleQuotedHexStringLiteral or DoubleQuotedStringLiteral or OpenBrace or SingleQuotedHexStringLiteral or SingleQuotedStringLiteral or YulAddKeyword or YulAddModKeyword or YulAddressKeyword or YulAndKeyword or YulBalanceKeyword or YulBlockHashKeyword or YulBreakKeyword or YulByteKeyword or YulCallCodeKeyword or YulCallDataCopyKeyword or YulCallDataLoadKeyword or YulCallDataSizeKeyword or YulCallKeyword or YulCallValueKeyword or YulCallerKeyword or YulChainIdKeyword or YulCoinBaseKeyword or YulContinueKeyword or YulCreate2Keyword or YulCreateKeyword or YulDecimalLiteral or YulDelegateCallKeyword or YulDifficultyKeyword or YulDivKeyword or YulEqKeyword or YulExpKeyword or YulExtCodeCopyKeyword or YulExtCodeHashKeyword or YulExtCodeSizeKeyword or YulFalseKeyword or YulForKeyword or YulFunctionKeyword or YulGasKeyword or YulGasLimitKeyword or YulGasPriceKeyword or YulGtKeyword or YulHexLiteral or YulIdentifier or YulIfKeyword or YulInvalidKeyword or YulIsZeroKeyword or YulKeccak256Keyword or YulLetKeyword or YulLog0Keyword or YulLog1Keyword or YulLog2Keyword or YulLog3Keyword or YulLog4Keyword or YulLtKeyword or YulMLoadKeyword or YulMSizeKeyword or YulMStore8Keyword or YulMStoreKeyword or YulModKeyword or YulMulKeyword or YulMulModKeyword or YulNotKeyword or YulNumberKeyword or YulOrKeyword or YulOriginKeyword or YulPopKeyword or YulReturnDataCopyKeyword or YulReturnDataSizeKeyword or YulReturnKeyword or YulRevertKeyword or YulSDivKeyword or YulSLoadKeyword or YulSModKeyword or YulSStoreKeyword or YulSarKeyword or YulSelfBalanceKeyword or YulSelfDestructKeyword or YulSgtKeyword or YulShlKeyword or YulShrKeyword or YulSignExtendKeyword or YulSltKeyword or YulStaticCallKeyword or YulStopKeyword or YulSubKeyword or YulSwitchKeyword or YulTimestampKeyword or YulTrueKeyword or YulXorKeyword. + ╭─[input.sol:4:18] + │ + 4 │ ╭─▶ let x.y.z := 0 + ┆ ┆ + 6 │ ├─▶ } + │ │ + │ ╰─────────────── Error occurred here. +───╯ +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ function test() public { + │ ──┬─ + │ ╰─── def: 2 + │ + 4 │ let x.y.z := 0 + │ ┬ + │ ╰── def: 3 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/yul/identifiers_with_dots/generated/0.5.8-success.txt b/crates/solidity/testing/snapshots/bindings_output/yul/identifiers_with_dots/generated/0.5.8-success.txt new file mode 100644 index 0000000000..a50ffd562b --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/yul/identifiers_with_dots/generated/0.5.8-success.txt @@ -0,0 +1,21 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ function test() public { + │ ──┬─ + │ ╰─── def: 2 + │ + 4 │ let x.y.z := 0 + │ ──┬── + │ ╰──── def: 3 + 5 │ let r := add(x.y.z, 20) + │ ┬ ──┬── + │ ╰─────────────── def: 4 + │ │ + │ ╰──── ref: 3 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/yul/identifiers_with_dots/generated/0.7.0-failure.txt b/crates/solidity/testing/snapshots/bindings_output/yul/identifiers_with_dots/generated/0.7.0-failure.txt new file mode 100644 index 0000000000..13ec567204 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/yul/identifiers_with_dots/generated/0.7.0-failure.txt @@ -0,0 +1,26 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected CloseBrace or DoubleQuotedHexStringLiteral or DoubleQuotedStringLiteral or OpenBrace or SingleQuotedHexStringLiteral or SingleQuotedStringLiteral or YulAddKeyword or YulAddModKeyword or YulAddressKeyword or YulAndKeyword or YulBalanceKeyword or YulBlockHashKeyword or YulBreakKeyword or YulByteKeyword or YulCallCodeKeyword or YulCallDataCopyKeyword or YulCallDataLoadKeyword or YulCallDataSizeKeyword or YulCallKeyword or YulCallValueKeyword or YulCallerKeyword or YulChainIdKeyword or YulCoinBaseKeyword or YulContinueKeyword or YulCreate2Keyword or YulCreateKeyword or YulDecimalLiteral or YulDelegateCallKeyword or YulDifficultyKeyword or YulDivKeyword or YulEqKeyword or YulExpKeyword or YulExtCodeCopyKeyword or YulExtCodeHashKeyword or YulExtCodeSizeKeyword or YulFalseKeyword or YulForKeyword or YulFunctionKeyword or YulGasKeyword or YulGasLimitKeyword or YulGasPriceKeyword or YulGtKeyword or YulHexLiteral or YulIdentifier or YulIfKeyword or YulInvalidKeyword or YulIsZeroKeyword or YulKeccak256Keyword or YulLeaveKeyword or YulLetKeyword or YulLog0Keyword or YulLog1Keyword or YulLog2Keyword or YulLog3Keyword or YulLog4Keyword or YulLtKeyword or YulMLoadKeyword or YulMSizeKeyword or YulMStore8Keyword or YulMStoreKeyword or YulModKeyword or YulMulKeyword or YulMulModKeyword or YulNotKeyword or YulNumberKeyword or YulOrKeyword or YulOriginKeyword or YulPopKeyword or YulReturnDataCopyKeyword or YulReturnDataSizeKeyword or YulReturnKeyword or YulRevertKeyword or YulSDivKeyword or YulSLoadKeyword or YulSModKeyword or YulSStoreKeyword or YulSarKeyword or YulSelfBalanceKeyword or YulSelfDestructKeyword or YulSgtKeyword or YulShlKeyword or YulShrKeyword or YulSignExtendKeyword or YulSltKeyword or YulStaticCallKeyword or YulStopKeyword or YulSubKeyword or YulSwitchKeyword or YulTimestampKeyword or YulTrueKeyword or YulXorKeyword. + ╭─[input.sol:4:18] + │ + 4 │ ╭─▶ let x.y.z := 0 + ┆ ┆ + 6 │ ├─▶ } + │ │ + │ ╰─────────────── Error occurred here. +───╯ +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ function test() public { + │ ──┬─ + │ ╰─── def: 2 + │ + 4 │ let x.y.z := 0 + │ ┬ + │ ╰── def: 3 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/yul/identifiers_with_dots/generated/0.8.18-failure.txt b/crates/solidity/testing/snapshots/bindings_output/yul/identifiers_with_dots/generated/0.8.18-failure.txt new file mode 100644 index 0000000000..ba89cdf44b --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/yul/identifiers_with_dots/generated/0.8.18-failure.txt @@ -0,0 +1,26 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected CloseBrace or DoubleQuotedHexStringLiteral or DoubleQuotedStringLiteral or OpenBrace or SingleQuotedHexStringLiteral or SingleQuotedStringLiteral or YulAddKeyword or YulAddModKeyword or YulAddressKeyword or YulAndKeyword or YulBalanceKeyword or YulBaseFeeKeyword or YulBlockHashKeyword or YulBreakKeyword or YulByteKeyword or YulCallCodeKeyword or YulCallDataCopyKeyword or YulCallDataLoadKeyword or YulCallDataSizeKeyword or YulCallKeyword or YulCallValueKeyword or YulCallerKeyword or YulChainIdKeyword or YulCoinBaseKeyword or YulContinueKeyword or YulCreate2Keyword or YulCreateKeyword or YulDecimalLiteral or YulDelegateCallKeyword or YulDivKeyword or YulEqKeyword or YulExpKeyword or YulExtCodeCopyKeyword or YulExtCodeHashKeyword or YulExtCodeSizeKeyword or YulFalseKeyword or YulForKeyword or YulFunctionKeyword or YulGasKeyword or YulGasLimitKeyword or YulGasPriceKeyword or YulGtKeyword or YulHexLiteral or YulIdentifier or YulIfKeyword or YulInvalidKeyword or YulIsZeroKeyword or YulKeccak256Keyword or YulLeaveKeyword or YulLetKeyword or YulLog0Keyword or YulLog1Keyword or YulLog2Keyword or YulLog3Keyword or YulLog4Keyword or YulLtKeyword or YulMLoadKeyword or YulMSizeKeyword or YulMStore8Keyword or YulMStoreKeyword or YulModKeyword or YulMulKeyword or YulMulModKeyword or YulNotKeyword or YulNumberKeyword or YulOrKeyword or YulOriginKeyword or YulPopKeyword or YulPrevRandaoKeyword or YulReturnDataCopyKeyword or YulReturnDataSizeKeyword or YulReturnKeyword or YulRevertKeyword or YulSDivKeyword or YulSLoadKeyword or YulSModKeyword or YulSStoreKeyword or YulSarKeyword or YulSelfBalanceKeyword or YulSelfDestructKeyword or YulSgtKeyword or YulShlKeyword or YulShrKeyword or YulSignExtendKeyword or YulSltKeyword or YulStaticCallKeyword or YulStopKeyword or YulSubKeyword or YulSwitchKeyword or YulTimestampKeyword or YulTrueKeyword or YulXorKeyword. + ╭─[input.sol:4:18] + │ + 4 │ ╭─▶ let x.y.z := 0 + ┆ ┆ + 6 │ ├─▶ } + │ │ + │ ╰─────────────── Error occurred here. +───╯ +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ function test() public { + │ ──┬─ + │ ╰─── def: 2 + │ + 4 │ let x.y.z := 0 + │ ┬ + │ ╰── def: 3 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/yul/identifiers_with_dots/generated/0.8.24-failure.txt b/crates/solidity/testing/snapshots/bindings_output/yul/identifiers_with_dots/generated/0.8.24-failure.txt new file mode 100644 index 0000000000..1a4a9715b3 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/yul/identifiers_with_dots/generated/0.8.24-failure.txt @@ -0,0 +1,26 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected CloseBrace or DoubleQuotedHexStringLiteral or DoubleQuotedStringLiteral or OpenBrace or SingleQuotedHexStringLiteral or SingleQuotedStringLiteral or YulAddKeyword or YulAddModKeyword or YulAddressKeyword or YulAndKeyword or YulBalanceKeyword or YulBaseFeeKeyword or YulBlobBaseFeeKeyword or YulBlobHashKeyword or YulBlockHashKeyword or YulBreakKeyword or YulByteKeyword or YulCallCodeKeyword or YulCallDataCopyKeyword or YulCallDataLoadKeyword or YulCallDataSizeKeyword or YulCallKeyword or YulCallValueKeyword or YulCallerKeyword or YulChainIdKeyword or YulCoinBaseKeyword or YulContinueKeyword or YulCreate2Keyword or YulCreateKeyword or YulDecimalLiteral or YulDelegateCallKeyword or YulDivKeyword or YulEqKeyword or YulExpKeyword or YulExtCodeCopyKeyword or YulExtCodeHashKeyword or YulExtCodeSizeKeyword or YulFalseKeyword or YulForKeyword or YulFunctionKeyword or YulGasKeyword or YulGasLimitKeyword or YulGasPriceKeyword or YulGtKeyword or YulHexLiteral or YulIdentifier or YulIfKeyword or YulInvalidKeyword or YulIsZeroKeyword or YulKeccak256Keyword or YulLeaveKeyword or YulLetKeyword or YulLog0Keyword or YulLog1Keyword or YulLog2Keyword or YulLog3Keyword or YulLog4Keyword or YulLtKeyword or YulMCopyKeyword or YulMLoadKeyword or YulMSizeKeyword or YulMStore8Keyword or YulMStoreKeyword or YulModKeyword or YulMulKeyword or YulMulModKeyword or YulNotKeyword or YulNumberKeyword or YulOrKeyword or YulOriginKeyword or YulPopKeyword or YulPrevRandaoKeyword or YulReturnDataCopyKeyword or YulReturnDataSizeKeyword or YulReturnKeyword or YulRevertKeyword or YulSDivKeyword or YulSLoadKeyword or YulSModKeyword or YulSStoreKeyword or YulSarKeyword or YulSelfBalanceKeyword or YulSelfDestructKeyword or YulSgtKeyword or YulShlKeyword or YulShrKeyword or YulSignExtendKeyword or YulSltKeyword or YulStaticCallKeyword or YulStopKeyword or YulSubKeyword or YulSwitchKeyword or YulTLoadKeyword or YulTStoreKeyword or YulTimestampKeyword or YulTrueKeyword or YulXorKeyword. + ╭─[input.sol:4:18] + │ + 4 │ ╭─▶ let x.y.z := 0 + ┆ ┆ + 6 │ ├─▶ } + │ │ + │ ╰─────────────── Error occurred here. +───╯ +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ function test() public { + │ ──┬─ + │ ╰─── def: 2 + │ + 4 │ let x.y.z := 0 + │ ┬ + │ ╰── def: 3 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/yul/identifiers_with_dots/generated/0.8.7-failure.txt b/crates/solidity/testing/snapshots/bindings_output/yul/identifiers_with_dots/generated/0.8.7-failure.txt new file mode 100644 index 0000000000..7572b37c42 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/yul/identifiers_with_dots/generated/0.8.7-failure.txt @@ -0,0 +1,26 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected CloseBrace or DoubleQuotedHexStringLiteral or DoubleQuotedStringLiteral or OpenBrace or SingleQuotedHexStringLiteral or SingleQuotedStringLiteral or YulAddKeyword or YulAddModKeyword or YulAddressKeyword or YulAndKeyword or YulBalanceKeyword or YulBaseFeeKeyword or YulBlockHashKeyword or YulBreakKeyword or YulByteKeyword or YulCallCodeKeyword or YulCallDataCopyKeyword or YulCallDataLoadKeyword or YulCallDataSizeKeyword or YulCallKeyword or YulCallValueKeyword or YulCallerKeyword or YulChainIdKeyword or YulCoinBaseKeyword or YulContinueKeyword or YulCreate2Keyword or YulCreateKeyword or YulDecimalLiteral or YulDelegateCallKeyword or YulDifficultyKeyword or YulDivKeyword or YulEqKeyword or YulExpKeyword or YulExtCodeCopyKeyword or YulExtCodeHashKeyword or YulExtCodeSizeKeyword or YulFalseKeyword or YulForKeyword or YulFunctionKeyword or YulGasKeyword or YulGasLimitKeyword or YulGasPriceKeyword or YulGtKeyword or YulHexLiteral or YulIdentifier or YulIfKeyword or YulInvalidKeyword or YulIsZeroKeyword or YulKeccak256Keyword or YulLeaveKeyword or YulLetKeyword or YulLog0Keyword or YulLog1Keyword or YulLog2Keyword or YulLog3Keyword or YulLog4Keyword or YulLtKeyword or YulMLoadKeyword or YulMSizeKeyword or YulMStore8Keyword or YulMStoreKeyword or YulModKeyword or YulMulKeyword or YulMulModKeyword or YulNotKeyword or YulNumberKeyword or YulOrKeyword or YulOriginKeyword or YulPopKeyword or YulReturnDataCopyKeyword or YulReturnDataSizeKeyword or YulReturnKeyword or YulRevertKeyword or YulSDivKeyword or YulSLoadKeyword or YulSModKeyword or YulSStoreKeyword or YulSarKeyword or YulSelfBalanceKeyword or YulSelfDestructKeyword or YulSgtKeyword or YulShlKeyword or YulShrKeyword or YulSignExtendKeyword or YulSltKeyword or YulStaticCallKeyword or YulStopKeyword or YulSubKeyword or YulSwitchKeyword or YulTimestampKeyword or YulTrueKeyword or YulXorKeyword. + ╭─[input.sol:4:18] + │ + 4 │ ╭─▶ let x.y.z := 0 + ┆ ┆ + 6 │ ├─▶ } + │ │ + │ ╰─────────────── Error occurred here. +───╯ +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ function test() public { + │ ──┬─ + │ ╰─── def: 2 + │ + 4 │ let x.y.z := 0 + │ ┬ + │ ╰── def: 3 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/yul/identifiers_with_dots/input.sol b/crates/solidity/testing/snapshots/bindings_output/yul/identifiers_with_dots/input.sol new file mode 100644 index 0000000000..84beae31ee --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/yul/identifiers_with_dots/input.sol @@ -0,0 +1,8 @@ +contract Test { + function test() public { + assembly { + let x.y.z := 0 + let r := add(x.y.z, 20) + } + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/yul/slot_offset_members/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/yul/slot_offset_members/generated/0.4.11-success.txt new file mode 100644 index 0000000000..6e244c0dcf --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/yul/slot_offset_members/generated/0.4.11-success.txt @@ -0,0 +1,30 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ bytes data; + │ ──┬─ + │ ╰─── def: 2 + 3 │ function test() public { + │ ──┬─ + │ ╰─── def: 3 + │ + 5 │ let s := sload(data.slot) + │ ┬ ──┬─ ──┬─ + │ ╰───────────────────── def: 4 + │ │ │ + │ ╰──────── ref: 2 + │ │ + │ ╰─── ref: built-in + 6 │ let o := sload(data.offset) + │ ┬ ──┬─ ───┬── + │ ╰─────────────────────── def: 5 + │ │ │ + │ ╰────────── ref: 2 + │ │ + │ ╰──── ref: built-in +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/yul/slot_offset_members/generated/0.5.8-failure.txt b/crates/solidity/testing/snapshots/bindings_output/yul/slot_offset_members/generated/0.5.8-failure.txt new file mode 100644 index 0000000000..6ec15facf8 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/yul/slot_offset_members/generated/0.5.8-failure.txt @@ -0,0 +1,26 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ bytes data; + │ ──┬─ + │ ╰─── def: 2 + 3 │ function test() public { + │ ──┬─ + │ ╰─── def: 3 + │ + 5 │ let s := sload(data.slot) + │ ┬ ────┬──── + │ ╰───────────────────── def: 4 + │ │ + │ ╰────── unresolved + 6 │ let o := sload(data.offset) + │ ┬ ─────┬───── + │ ╰─────────────────────── def: 5 + │ │ + │ ╰─────── unresolved +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/yul/slot_offset_members/generated/0.7.0-success.txt b/crates/solidity/testing/snapshots/bindings_output/yul/slot_offset_members/generated/0.7.0-success.txt new file mode 100644 index 0000000000..6e244c0dcf --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/yul/slot_offset_members/generated/0.7.0-success.txt @@ -0,0 +1,30 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ bytes data; + │ ──┬─ + │ ╰─── def: 2 + 3 │ function test() public { + │ ──┬─ + │ ╰─── def: 3 + │ + 5 │ let s := sload(data.slot) + │ ┬ ──┬─ ──┬─ + │ ╰───────────────────── def: 4 + │ │ │ + │ ╰──────── ref: 2 + │ │ + │ ╰─── ref: built-in + 6 │ let o := sload(data.offset) + │ ┬ ──┬─ ───┬── + │ ╰─────────────────────── def: 5 + │ │ │ + │ ╰────────── ref: 2 + │ │ + │ ╰──── ref: built-in +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/yul/slot_offset_members/input.sol b/crates/solidity/testing/snapshots/bindings_output/yul/slot_offset_members/input.sol new file mode 100644 index 0000000000..e35896c309 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/yul/slot_offset_members/input.sol @@ -0,0 +1,9 @@ +contract Test { + bytes data; + function test() public { + assembly { + let s := sload(data.slot) + let o := sload(data.offset) + } + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/yul/slot_suffix/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/yul/slot_suffix/generated/0.4.11-success.txt new file mode 100644 index 0000000000..bb7557764a --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/yul/slot_suffix/generated/0.4.11-success.txt @@ -0,0 +1,26 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ bytes data; + │ ──┬─ + │ ╰─── def: 2 + 3 │ function test() public { + │ ──┬─ + │ ╰─── def: 3 + │ + 5 │ let s := sload(data_slot) + │ ┬ ────┬──── + │ ╰───────────────────── def: 4 + │ │ + │ ╰────── ref: built-in + 6 │ let o := sload(data_offset) + │ ┬ ─────┬───── + │ ╰─────────────────────── def: 5 + │ │ + │ ╰─────── ref: built-in +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/yul/slot_suffix/generated/0.7.0-failure.txt b/crates/solidity/testing/snapshots/bindings_output/yul/slot_suffix/generated/0.7.0-failure.txt new file mode 100644 index 0000000000..8745d145dd --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/yul/slot_suffix/generated/0.7.0-failure.txt @@ -0,0 +1,26 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Test { + │ ──┬─ + │ ╰─── def: 1 + 2 │ bytes data; + │ ──┬─ + │ ╰─── def: 2 + 3 │ function test() public { + │ ──┬─ + │ ╰─── def: 3 + │ + 5 │ let s := sload(data_slot) + │ ┬ ────┬──── + │ ╰───────────────────── def: 4 + │ │ + │ ╰────── unresolved + 6 │ let o := sload(data_offset) + │ ┬ ─────┬───── + │ ╰─────────────────────── def: 5 + │ │ + │ ╰─────── unresolved +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/yul/slot_suffix/input.sol b/crates/solidity/testing/snapshots/bindings_output/yul/slot_suffix/input.sol new file mode 100644 index 0000000000..67caad33a2 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/yul/slot_suffix/input.sol @@ -0,0 +1,9 @@ +contract Test { + bytes data; + function test() public { + assembly { + let s := sload(data_slot) + let o := sload(data_offset) + } + } +} diff --git a/crates/testlang/outputs/cargo/crate/Cargo.toml b/crates/testlang/outputs/cargo/crate/Cargo.toml index eeb4213383..45a8685cba 100644 --- a/crates/testlang/outputs/cargo/crate/Cargo.toml +++ b/crates/testlang/outputs/cargo/crate/Cargo.toml @@ -11,6 +11,7 @@ name = "slang_testlang" default = [] __experimental_bindings_api = ["dep:metaslang_bindings"] __private_ariadne_errors = ["dep:ariadne"] +__private_compilation_api = [] __private_testing_utils = [] [build-dependencies] diff --git a/crates/testlang/outputs/cargo/crate/src/extensions/bindings/mod.rs b/crates/testlang/outputs/cargo/crate/src/extensions/bindings/mod.rs new file mode 100644 index 0000000000..eee8b7880f --- /dev/null +++ b/crates/testlang/outputs/cargo/crate/src/extensions/bindings/mod.rs @@ -0,0 +1,12 @@ +use semver::Version; + +use crate::bindings::BindingGraph; +use crate::parser::ParserInitializationError; + +#[allow(clippy::needless_pass_by_value)] +pub fn add_built_ins( + _binding_graph: &mut BindingGraph, + _version: Version, +) -> Result<(), ParserInitializationError> { + unreachable!("Built-ins are Solidity-specific") +} diff --git a/crates/testlang/outputs/cargo/crate/src/extensions/compilation/mod.rs b/crates/testlang/outputs/cargo/crate/src/extensions/compilation/mod.rs new file mode 100644 index 0000000000..ddbb6d5a87 --- /dev/null +++ b/crates/testlang/outputs/cargo/crate/src/extensions/compilation/mod.rs @@ -0,0 +1,15 @@ +use crate::cst::Cursor; + +pub struct ImportPathsExtractor; + +impl ImportPathsExtractor { + pub fn new() -> Self { + Self + } + + #[allow(clippy::unused_self)] + #[allow(clippy::needless_pass_by_value)] + pub fn extract(&self, _: Cursor) -> Vec { + unreachable!("Import paths are Solidity-specific") + } +} diff --git a/crates/testlang/outputs/cargo/crate/src/extensions/mod.rs b/crates/testlang/outputs/cargo/crate/src/extensions/mod.rs new file mode 100644 index 0000000000..78402f8764 --- /dev/null +++ b/crates/testlang/outputs/cargo/crate/src/extensions/mod.rs @@ -0,0 +1,8 @@ +#[cfg(all( + feature = "__experimental_bindings_api", + feature = "__private_compilation_api" +))] +pub mod compilation; + +#[cfg(feature = "__experimental_bindings_api")] +pub mod bindings; diff --git a/crates/testlang/outputs/cargo/crate/src/generated/bindings/generated/built_ins.rs b/crates/testlang/outputs/cargo/crate/src/generated/bindings/generated/built_ins.rs index 0c4a214fc9..b9d12d31f8 100644 --- a/crates/testlang/outputs/cargo/crate/src/generated/bindings/generated/built_ins.rs +++ b/crates/testlang/outputs/cargo/crate/src/generated/bindings/generated/built_ins.rs @@ -2,7 +2,8 @@ use semver::Version; +// TODO: This should be moved to the Solidity-specific 'extensions' sub-module. #[allow(unused_variables)] -pub fn get_contents(version: &Version) -> &'static str { +pub fn get_built_ins_contents(version: &Version) -> &'static str { "" } 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 66c8a8c4da..7803930461 100644 --- a/crates/testlang/outputs/cargo/crate/src/generated/bindings/mod.rs +++ b/crates/testlang/outputs/cargo/crate/src/generated/bindings/mod.rs @@ -4,31 +4,46 @@ mod binding_rules; #[path = "generated/built_ins.rs"] -mod built_ins; +pub mod built_ins; -use std::sync::Arc; +use std::rc::Rc; -use metaslang_bindings::{self, PathResolver}; use semver::Version; use crate::cst::KindTypes; -pub type Bindings = metaslang_bindings::Bindings; +pub type BindingGraph = metaslang_bindings::BindingGraph; pub type Definition<'a> = metaslang_bindings::Definition<'a, KindTypes>; pub type Reference<'a> = metaslang_bindings::Reference<'a, KindTypes>; +pub type BindingLocation = metaslang_bindings::BindingLocation; +pub type UserFileLocation = metaslang_bindings::UserFileLocation; + +pub use metaslang_bindings::{BuiltInLocation, PathResolver}; + +use crate::parser::ParserInitializationError; + +#[derive(thiserror::Error, Debug)] +pub enum BindingGraphInitializationError { + #[error(transparent)] + ParserInitialization(#[from] ParserInitializationError), +} pub fn create_with_resolver( version: Version, - resolver: Arc, -) -> Bindings { - Bindings::create(version, binding_rules::BINDING_RULES_SOURCE, resolver) + resolver: Rc>, +) -> Result { + let mut binding_graph = BindingGraph::create( + version.clone(), + binding_rules::BINDING_RULES_SOURCE, + resolver, + ); + + crate::extensions::bindings::add_built_ins(&mut binding_graph, version)?; + + Ok(binding_graph) } #[cfg(feature = "__private_testing_utils")] pub fn get_binding_rules() -> &'static str { binding_rules::BINDING_RULES_SOURCE } - -pub fn get_built_ins(version: &semver::Version) -> &'static str { - built_ins::get_contents(version) -} diff --git a/crates/testlang/outputs/cargo/crate/src/generated/compilation/file.rs b/crates/testlang/outputs/cargo/crate/src/generated/compilation/file.rs new file mode 100644 index 0000000000..94eee8ad56 --- /dev/null +++ b/crates/testlang/outputs/cargo/crate/src/generated/compilation/file.rs @@ -0,0 +1,47 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +use std::collections::BTreeMap; + +use metaslang_cst::text_index::TextIndex; + +use crate::cst::{Cursor, Node}; + +#[derive(Clone)] +pub struct File { + id: String, + tree: Node, + + resolved_imports: BTreeMap, +} + +impl File { + pub(super) fn new(id: String, tree: Node) -> Self { + Self { + id, + tree, + + resolved_imports: BTreeMap::new(), + } + } + + pub fn id(&self) -> &str { + &self.id + } + + pub fn tree(&self) -> &Node { + &self.tree + } + + pub fn create_tree_cursor(&self) -> Cursor { + self.tree.clone().cursor_with_offset(TextIndex::ZERO) + } + + pub(super) fn resolve_import(&mut self, import_path: &Cursor, destination_file_id: String) { + self.resolved_imports + .insert(import_path.node().id(), destination_file_id); + } + + pub(super) fn resolved_import(&self, import_path: &Cursor) -> Option<&String> { + self.resolved_imports.get(&import_path.node().id()) + } +} diff --git a/crates/testlang/outputs/cargo/crate/src/generated/compilation/internal_builder.rs b/crates/testlang/outputs/cargo/crate/src/generated/compilation/internal_builder.rs new file mode 100644 index 0000000000..0eb3cbdc2e --- /dev/null +++ b/crates/testlang/outputs/cargo/crate/src/generated/compilation/internal_builder.rs @@ -0,0 +1,95 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +use std::collections::BTreeMap; +use std::rc::Rc; + +use metaslang_cst::nodes::Node; +use semver::Version; + +use crate::compilation::{CompilationUnit, File}; +use crate::cst::Cursor; +use crate::extensions::compilation::ImportPathsExtractor; +use crate::parser::{Parser, ParserInitializationError}; + +pub struct InternalCompilationBuilder { + parser: Parser, + imports: ImportPathsExtractor, + files: BTreeMap, +} + +#[derive(thiserror::Error, Debug)] +pub enum CompilationInitializationError { + #[error(transparent)] + ParserInitialization(#[from] ParserInitializationError), +} + +impl InternalCompilationBuilder { + pub fn create(language_version: Version) -> Result { + let parser = Parser::create(language_version)?; + + Ok(Self { + parser, + imports: ImportPathsExtractor::new(), + files: BTreeMap::new(), + }) + } + + pub fn add_file(&mut self, id: String, contents: &str) -> AddFileResponse { + if self.files.contains_key(&id) { + // Already added. No need to process it again: + return AddFileResponse { + import_paths: vec![], + }; + } + + let parse_output = self.parser.parse(Parser::ROOT_KIND, contents); + + let import_paths = self.imports.extract(parse_output.create_tree_cursor()); + + let file = File::new( + id.clone(), + Node::Nonterminal(Rc::clone(parse_output.tree())), + ); + self.files.insert(id, file); + + AddFileResponse { import_paths } + } + + pub fn resolve_import( + &mut self, + source_file_id: &str, + import_path: &Cursor, + destination_file_id: String, + ) -> Result<(), ResolveImportError> { + self.files + .get_mut(source_file_id) + .ok_or_else(|| ResolveImportError::SourceFileNotFound(source_file_id.to_owned()))? + .resolve_import(import_path, destination_file_id); + + Ok(()) + } + + pub fn build(&self) -> CompilationUnit { + let language_version = self.parser.language_version().to_owned(); + + let files = self + .files + .iter() + .map(|(id, file)| (id.to_owned(), Rc::new(file.to_owned()))) + .collect(); + + CompilationUnit::new(language_version, files) + } +} + +pub struct AddFileResponse { + pub import_paths: Vec, +} + +#[derive(thiserror::Error, Debug)] +pub enum ResolveImportError { + #[error( + "Source file not found: '{0}'. Make sure to add it first, before resolving its imports." + )] + SourceFileNotFound(String), +} diff --git a/crates/testlang/outputs/cargo/crate/src/generated/compilation/mod.rs b/crates/testlang/outputs/cargo/crate/src/generated/compilation/mod.rs new file mode 100644 index 0000000000..89544c6568 --- /dev/null +++ b/crates/testlang/outputs/cargo/crate/src/generated/compilation/mod.rs @@ -0,0 +1,9 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +mod file; +mod internal_builder; +mod unit; + +pub use file::File; +pub use internal_builder::{AddFileResponse, InternalCompilationBuilder}; +pub use unit::CompilationUnit; diff --git a/crates/testlang/outputs/cargo/crate/src/generated/compilation/unit.rs b/crates/testlang/outputs/cargo/crate/src/generated/compilation/unit.rs new file mode 100644 index 0000000000..a15100e4df --- /dev/null +++ b/crates/testlang/outputs/cargo/crate/src/generated/compilation/unit.rs @@ -0,0 +1,71 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +use std::cell::OnceCell; +use std::collections::BTreeMap; +use std::rc::Rc; + +use semver::Version; + +use crate::bindings::{ + create_with_resolver, BindingGraph, BindingGraphInitializationError, PathResolver, +}; +use crate::compilation::File; +use crate::cst::{Cursor, KindTypes}; + +pub struct CompilationUnit { + language_version: Version, + files: BTreeMap>, + binding_graph: OnceCell, BindingGraphInitializationError>>, +} + +impl CompilationUnit { + pub(super) fn new(language_version: Version, files: BTreeMap>) -> Self { + Self { + language_version, + files, + binding_graph: OnceCell::new(), + } + } + + pub fn language_version(&self) -> &Version { + &self.language_version + } + + pub fn files(&self) -> Vec> { + self.files.values().cloned().collect() + } + + pub fn file(&self, id: &str) -> Option> { + self.files.get(id).cloned() + } + + pub fn binding_graph(&self) -> &Result, BindingGraphInitializationError> { + self.binding_graph.get_or_init(|| { + let resolver = Resolver { + files: self.files.clone(), + }; + + let mut binding_graph = + create_with_resolver(self.language_version.clone(), Rc::new(resolver))?; + + for (id, file) in &self.files { + binding_graph.add_user_file(id, file.create_tree_cursor()); + } + + Ok(Rc::new(binding_graph)) + }) + } +} + +struct Resolver { + files: BTreeMap>, +} + +impl PathResolver for Resolver { + fn resolve_path(&self, context_path: &str, path_to_resolve: &Cursor) -> Option { + self.files + .get(context_path)? + .resolved_import(path_to_resolve) + .cloned() + } +} diff --git a/crates/testlang/outputs/cargo/crate/src/generated/mod.rs b/crates/testlang/outputs/cargo/crate/src/generated/mod.rs index 4b9d48d9f9..3c700fafdc 100644 --- a/crates/testlang/outputs/cargo/crate/src/generated/mod.rs +++ b/crates/testlang/outputs/cargo/crate/src/generated/mod.rs @@ -2,6 +2,12 @@ #[cfg(feature = "__experimental_bindings_api")] pub mod bindings; +#[cfg(all( + feature = "__experimental_bindings_api", + feature = "__private_compilation_api" +))] +pub mod compilation; pub mod cst; pub mod diagnostic; pub mod parser; +pub mod utils; diff --git a/crates/testlang/outputs/cargo/crate/src/generated/parser/generated/parser.rs b/crates/testlang/outputs/cargo/crate/src/generated/parser/generated/parser.rs index a3f6c34bc2..a7fcd186f0 100644 --- a/crates/testlang/outputs/cargo/crate/src/generated/parser/generated/parser.rs +++ b/crates/testlang/outputs/cargo/crate/src/generated/parser/generated/parser.rs @@ -27,12 +27,13 @@ use crate::parser::scanner_macros::{ scan_not_followed_by, scan_one_or_more, scan_optional, scan_sequence, scan_zero_or_more, }; use crate::parser::ParseOutput; +use crate::utils::LanguageFacts; #[derive(Debug)] pub struct Parser { #[allow(dead_code)] pub(crate) version_is_at_least_1_0_0: bool, - pub version: Version, + language_version: Version, } #[derive(thiserror::Error, Debug)] @@ -42,30 +43,28 @@ pub enum ParserInitializationError { } impl Parser { - pub const SUPPORTED_VERSIONS: &'static [Version] = &[ - Version::new(1, 0, 0), - Version::new(1, 0, 1), - Version::new(1, 1, 0), - Version::new(1, 1, 1), - ]; - pub const ROOT_KIND: NonterminalKind = NonterminalKind::SourceUnit; - pub fn create(version: Version) -> std::result::Result { - if Self::SUPPORTED_VERSIONS.binary_search(&version).is_ok() { + pub fn create( + language_version: Version, + ) -> std::result::Result { + if LanguageFacts::SUPPORTED_VERSIONS + .binary_search(&language_version) + .is_ok() + { Ok(Self { - version_is_at_least_1_0_0: Version::new(1, 0, 0) <= version, - version, + version_is_at_least_1_0_0: Version::new(1, 0, 0) <= language_version, + language_version, }) } else { Err(ParserInitializationError::UnsupportedLanguageVersion( - version, + language_version, )) } } - pub fn version(&self) -> &Version { - &self.version + pub fn language_version(&self) -> &Version { + &self.language_version } /******************************************** * Parser Functions ********************************************/ diff --git a/crates/testlang/outputs/cargo/crate/src/generated/parser/parse_output.rs b/crates/testlang/outputs/cargo/crate/src/generated/parser/parse_output.rs index f6f06245e6..790329c22b 100644 --- a/crates/testlang/outputs/cargo/crate/src/generated/parser/parse_output.rs +++ b/crates/testlang/outputs/cargo/crate/src/generated/parser/parse_output.rs @@ -5,15 +5,15 @@ use std::rc::Rc; use crate::cst::{Cursor, NonterminalNode, TextIndex}; use crate::parser::ParseError; -#[derive(Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq)] pub struct ParseOutput { - pub(crate) parse_tree: Rc, + pub(crate) tree: Rc, pub(crate) errors: Vec, } impl ParseOutput { pub fn tree(&self) -> &Rc { - &self.parse_tree + &self.tree } pub fn errors(&self) -> &Vec { @@ -26,6 +26,6 @@ impl ParseOutput { /// Creates a cursor that starts at the root of the parse tree. pub fn create_tree_cursor(&self) -> Cursor { - Rc::clone(&self.parse_tree).cursor_with_offset(TextIndex::ZERO) + Rc::clone(&self.tree).cursor_with_offset(TextIndex::ZERO) } } diff --git a/crates/testlang/outputs/cargo/crate/src/generated/parser/parser_support/parser_function.rs b/crates/testlang/outputs/cargo/crate/src/generated/parser/parser_support/parser_function.rs index e0a2b4be62..60c1a1360c 100644 --- a/crates/testlang/outputs/cargo/crate/src/generated/parser/parser_support/parser_function.rs +++ b/crates/testlang/outputs/cargo/crate/src/generated/parser/parser_support/parser_function.rs @@ -91,7 +91,7 @@ where let node = Node::terminal(kind, input.to_string()); trivia_nodes.push(Edge::anonymous(node)); ParseOutput { - parse_tree: Rc::new(NonterminalNode::new(expected, trivia_nodes)), + tree: Rc::new(NonterminalNode::new(expected, trivia_nodes)), errors: vec![ParseError::new( start..start + input.into(), no_match.expected_terminals, @@ -155,17 +155,17 @@ where )); ParseOutput { - parse_tree: Rc::new(NonterminalNode::new(topmost_node.kind, new_children)), + tree: Rc::new(NonterminalNode::new(topmost_node.kind, new_children)), errors, } } else { - let parse_tree = topmost_node; + let tree = topmost_node; let errors = stream.into_errors(); // Sanity check: Make sure that succesful parse is equivalent to not having any invalid nodes debug_assert_eq!( errors.is_empty(), - Rc::clone(&parse_tree) + Rc::clone(&tree) .cursor_with_offset(TextIndex::ZERO) .remaining_nodes() .all(|edge| edge @@ -174,7 +174,7 @@ where .is_none()) ); - ParseOutput { parse_tree, errors } + ParseOutput { tree, errors } } } } diff --git a/crates/testlang/outputs/cargo/crate/src/generated/utils/generated/language_facts.rs b/crates/testlang/outputs/cargo/crate/src/generated/utils/generated/language_facts.rs new file mode 100644 index 0000000000..9dea6c75c1 --- /dev/null +++ b/crates/testlang/outputs/cargo/crate/src/generated/utils/generated/language_facts.rs @@ -0,0 +1,16 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +use semver::Version; + +pub struct LanguageFacts; + +impl LanguageFacts { + pub const NAME: &'static str = "Testlang"; + + pub const SUPPORTED_VERSIONS: &'static [Version] = &[ + Version::new(1, 0, 0), + Version::new(1, 0, 1), + Version::new(1, 1, 0), + Version::new(1, 1, 1), + ]; +} diff --git a/crates/testlang/outputs/cargo/crate/src/generated/utils/mod.rs b/crates/testlang/outputs/cargo/crate/src/generated/utils/mod.rs new file mode 100644 index 0000000000..57bd4f108e --- /dev/null +++ b/crates/testlang/outputs/cargo/crate/src/generated/utils/mod.rs @@ -0,0 +1,6 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +#[path = "generated/language_facts.rs"] +mod language_facts; + +pub use language_facts::LanguageFacts; diff --git a/crates/testlang/outputs/cargo/crate/src/lib.rs b/crates/testlang/outputs/cargo/crate/src/lib.rs index 086cd6d549..bd40dc9c6c 100644 --- a/crates/testlang/outputs/cargo/crate/src/lib.rs +++ b/crates/testlang/outputs/cargo/crate/src/lib.rs @@ -1,3 +1,4 @@ +mod extensions; mod generated; pub use generated::*; diff --git a/crates/testlang/outputs/cargo/tests/src/versions/mod.rs b/crates/testlang/outputs/cargo/tests/src/versions/mod.rs index 079d19dfb4..b5eb2c1ec8 100644 --- a/crates/testlang/outputs/cargo/tests/src/versions/mod.rs +++ b/crates/testlang/outputs/cargo/tests/src/versions/mod.rs @@ -1,9 +1,9 @@ use semver::Version; -use slang_testlang::parser::Parser; +use slang_testlang::utils::LanguageFacts; #[test] fn list_supported_versions() { - let versions = Parser::SUPPORTED_VERSIONS; + let versions = LanguageFacts::SUPPORTED_VERSIONS; assert!(!versions.is_empty()); assert!(!versions.contains(&Version::new(0, 0, 0))); diff --git a/crates/testlang/outputs/cargo/wasm/Cargo.toml b/crates/testlang/outputs/cargo/wasm/Cargo.toml index cb5dc8e8e9..6a96dc2211 100644 --- a/crates/testlang/outputs/cargo/wasm/Cargo.toml +++ b/crates/testlang/outputs/cargo/wasm/Cargo.toml @@ -21,7 +21,10 @@ testlang_language = { workspace = true } paste = { workspace = true } semver = { workspace = true } serde_json = { workspace = true } -slang_testlang = { workspace = true } +slang_testlang = { workspace = true, features = [ + "__experimental_bindings_api", + "__private_compilation_api", +] } wit-bindgen = { workspace = true } [lints] diff --git a/crates/testlang/outputs/cargo/wasm/src/generated/generated/bindings.rs b/crates/testlang/outputs/cargo/wasm/src/generated/generated/bindgen.rs similarity index 100% rename from crates/testlang/outputs/cargo/wasm/src/generated/generated/bindings.rs rename to crates/testlang/outputs/cargo/wasm/src/generated/generated/bindgen.rs 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 395999cccb..3444eb9169 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,65 @@ { "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: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 + } + }, + "nomic-foundation:slang:compilation:compilation-unit.binding-graph()": { + "Function": { + "as_getter": true + } + }, + "nomic-foundation:slang:compilation:file.id()": { + "Function": { + "as_getter": true + } + }, + "nomic-foundation:slang:compilation:file.tree()": { + "Function": { + "as_getter": true + } + }, "nomic-foundation:slang:cst:terminal-kind": { "Enum": { "as_typescript_enum": true @@ -105,7 +165,7 @@ "as_iterator": true } }, - "nomic-foundation:slang:parser:parser.version()": { + "nomic-foundation:slang:parser:parser.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 new file mode 100644 index 0000000000..1721afc82d --- /dev/null +++ b/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/bindings.wit @@ -0,0 +1,72 @@ +// 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: borrow) -> option; + + /// If the provided cursor points at a reference `Identifier`, it will return the + /// corresponding reference. Otherwise, it will return `undefined`. + reference-at: func(cursor: borrow) -> option; + } + + /// 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. + definitions: func() -> list; + } + + /// 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/interface/generated/compilation.wit b/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/compilation.wit new file mode 100644 index 0000000000..c9db286d76 --- /dev/null +++ b/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/compilation.wit @@ -0,0 +1,68 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +interface compilation { + use bindings.{binding-graph}; + use cst.{node, cursor}; + + /// A builder for creating compilation units. + /// Allows incrementally building a transitive list of all files and their imports. + /// + /// This is an internal API, and exposed via a public `CompilationBuilder` wrapper class written in TypeScript. + /// This allows storing/invoking user supplied callbacks in TypeScript, rather than Rust, which has its limitations. + resource internal-compilation-builder { + /// Creates a new compilation builder for the specified language version. + create: static func(language-version: string) -> result; + + /// Adds a source file to the compilation unit. + add-file: func(id: string, contents: string) -> add-file-response; + + /// Resolves an import in the source file to the destination file. + resolve-import: func(source-file-id: string, import-path: borrow, destination-file-id: string) -> result<_, string>; + + /// Builds and returns the final compilation unit. + build: func() -> compilation-unit; + } + + /// Contains information about imports found in an added source file. + record add-file-response { + /// List of cursors to any import paths found in the file. + import-paths: list, + } + + /// A complete compilation unit is a complete view over all compilation inputs: + /// + /// - All source files, stored as CSTs. + /// - Name binding graph that exposes relationships between definitions and references in these files. + /// - Any relevant compilation options. + /// + /// It also exposes utilities to traverse the compilation unit and query it. + resource compilation-unit { + /// Returns the language version this compilation unit is configured for. + language-version: func() -> string; + + /// Returns a list of all files in the compilation unit. + files: func() -> list; + + /// Returns the file with the specified ID, if it exists. + file: func(id: string) -> option; + + /// Calculates name binding information for all source files within the compilation unit. + /// Returns a graph that contains all found definitions and their references. + /// + /// Note: building this graph is an expensive operation. + /// It is done lazily on the first access, and cached thereafter. + binding-graph: func() -> result; + } + + /// A single source file in the compilation unit. + resource file { + /// Returns the unique identifier of this file. + id: func() -> string; + + /// Returns the syntax tree of this file. + tree: func() -> node; + + /// Creates a cursor for traversing the syntax tree of this file. + create-tree-cursor: func() -> cursor; + } +} diff --git a/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/parser.wit b/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/parser.wit index 42b61577d4..6eca8e01ae 100644 --- a/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/parser.wit +++ b/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/parser.wit @@ -10,15 +10,11 @@ interface parser { /// This represents the starting point for parsing a complete source file. root-kind: static func() -> nonterminal-kind; - /// Returns a list of language versions supported by this parser. - /// Each version string represents a specific grammar configuration. - supported-versions: static func() -> list; - /// Creates a new parser instance for the specified language version. - create: static func(version: string) -> result; + create: static func(language-version: string) -> result; /// Returns the language version this parser instance is configured for. - version: func() -> string; + language-version: func() -> string; /// Parses the input string starting from the specified nonterminal kind. parse: func(kind: nonterminal-kind, input: string) -> parse-output; diff --git a/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/utils.wit b/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/utils.wit new file mode 100644 index 0000000000..9bb93e160f --- /dev/null +++ b/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/utils.wit @@ -0,0 +1,9 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +interface utils { + /// Provides information about the supported language versions and the grammar. + resource language-facts { + /// Returns a list of language versions supported by Slang, sorted ascendingly. + supported-versions: static func() -> list; + } +} diff --git a/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/world.wit b/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/world.wit index c5e1378860..bb9b7b10be 100644 --- a/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/world.wit +++ b/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/world.wit @@ -4,6 +4,9 @@ package nomic-foundation:slang; world slang { export ast; + export bindings; + export compilation; export cst; export parser; + export utils; } diff --git a/crates/testlang/outputs/cargo/wasm/src/generated/mod.rs b/crates/testlang/outputs/cargo/wasm/src/generated/mod.rs index c84d868d87..418be83d23 100644 --- a/crates/testlang/outputs/cargo/wasm/src/generated/mod.rs +++ b/crates/testlang/outputs/cargo/wasm/src/generated/mod.rs @@ -1,10 +1,10 @@ // This file is generated automatically by infrastructure scripts. Please don't edit by hand. -#[path = "./generated/bindings.rs"] -mod bindings; +#[path = "./generated/bindgen.rs"] +mod bindgen; mod utils; mod wrappers; struct World; -crate::wasm_crate::bindings::export!(World with_types_in crate::wasm_crate::bindings); +crate::wasm_crate::bindgen::export!(World with_types_in crate::wasm_crate::bindgen); diff --git a/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/ast/mod.rs b/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/ast/mod.rs index cf50ecacd2..2ccdcb4777 100644 --- a/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/ast/mod.rs +++ b/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/ast/mod.rs @@ -6,10 +6,10 @@ mod selectors; use crate::wasm_crate::utils::IntoFFI; mod ffi { - pub use crate::wasm_crate::bindings::exports::nomic_foundation::slang::ast::{ + pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::ast::{ Guest, GuestSelectors, }; - pub use crate::wasm_crate::bindings::exports::nomic_foundation::slang::cst::{ + pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::cst::{ Node, NonterminalNodeBorrow, }; } 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 new file mode 100644 index 0000000000..6163cf964f --- /dev/null +++ b/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/bindings/mod.rs @@ -0,0 +1,176 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +use crate::wasm_crate::utils::{define_rc_wrapper, define_wrapper, IntoFFI}; + +mod ffi { + pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::bindings::{ + BindingGraph, BindingGraphBorrow, BindingLocation, BuiltInLocation, BuiltInLocationBorrow, + CursorBorrow, Definition, DefinitionBorrow, Guest, GuestBindingGraph, GuestBuiltInLocation, + GuestDefinition, GuestReference, GuestUserFileLocation, Reference, ReferenceBorrow, + UserFileLocation, UserFileLocationBorrow, + }; + pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::cst::Cursor; +} + +mod rust { + pub use crate::rust_crate::bindings::{ + BindingGraph, BindingLocation, BuiltInLocation, UserFileLocation, + }; + + /// TODO: This is a work-around for the fact that `metaslang_bindings` internals (handles, locators, etc...) are exposed. + /// We should clean this when we finally publish `__experimental_bindings_api`. + /// That means removing the types below, and using the original types instead. + #[derive(Debug, Clone)] + pub struct Definition { + pub id: usize, + pub name_location: BindingLocation, + pub definiens_location: BindingLocation, + } + + impl From> for Definition { + fn from(definition: crate::rust_crate::bindings::Definition<'_>) -> Self { + Self { + id: definition.id(), + name_location: definition.name_location(), + definiens_location: definition.definiens_location(), + } + } + } + + /// TODO: This is a work-around for the fact that `metaslang_bindings` internals (handles, locators, etc...) are exposed. + /// We should clean this when we finally publish `__experimental_bindings_api`. + /// That means removing the types below, and using the original types instead. + #[derive(Debug, Clone)] + pub struct Reference { + pub id: usize, + pub location: BindingLocation, + pub definitions: Vec, + } + + impl From> for Reference { + fn from(reference: crate::rust_crate::bindings::Reference<'_>) -> Self { + Self { + id: reference.id(), + location: reference.location(), + definitions: reference + .definitions() + .into_iter() + .map(Into::into) + .collect(), + } + } + } +} + +impl ffi::Guest for crate::wasm_crate::World { + type BindingGraph = BindingGraphWrapper; + + type Definition = DefinitionWrapper; + type Reference = ReferenceWrapper; + + type UserFileLocation = UserFileLocationWrapper; + type BuiltInLocation = BuiltInLocationWrapper; +} + +//================================================ +// +// resource binding-graph +// +//================================================ + +define_rc_wrapper! { BindingGraph { + fn definition_at(&self, cursor: ffi::CursorBorrow<'_>) -> Option { + self._borrow_ffi() + .definition_at(&cursor._borrow_ffi()) + .map(rust::Definition::from) + .map(IntoFFI::_into_ffi) + } + + fn reference_at(&self, cursor: ffi::CursorBorrow<'_>) -> Option { + self._borrow_ffi() + .reference_at(&cursor._borrow_ffi()) + .map(rust::Reference::from) + .map(IntoFFI::_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.clone()._into_ffi() + } + + fn definiens_location(&self) -> ffi::BindingLocation { + self._borrow_ffi().definiens_location.clone()._into_ffi() + } +} } + +//================================================ +// +// resource reference +// +//================================================ + +define_wrapper! { Reference { + fn id(&self) -> u32 { + self._borrow_ffi().id.try_into().unwrap() + } + + fn location(&self) -> ffi::BindingLocation { + self._borrow_ffi().location.clone()._into_ffi() + } + + fn definitions(&self) -> Vec { + self._borrow_ffi().definitions.iter().cloned().map(IntoFFI::_into_ffi).collect() + } +} } + +//================================================ +// +// 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().to_owned()._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 new file mode 100644 index 0000000000..d168910020 --- /dev/null +++ b/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/compilation/mod.rs @@ -0,0 +1,122 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +use std::rc::Rc; + +use semver::Version; + +use crate::wasm_crate::utils::{define_rc_wrapper, define_refcell_wrapper, IntoFFI}; + +mod ffi { + pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::bindings::BindingGraph; + pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::compilation::{ + AddFileResponse, CompilationUnit, CompilationUnitBorrow, CursorBorrow, File, FileBorrow, + Guest, GuestCompilationUnit, GuestFile, GuestInternalCompilationBuilder, + InternalCompilationBuilder, InternalCompilationBuilderBorrow, + }; + pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::cst::{Cursor, Node}; +} + +mod rust { + pub use crate::rust_crate::compilation::{ + AddFileResponse, CompilationUnit, File, InternalCompilationBuilder, + }; +} + +impl ffi::Guest for crate::wasm_crate::World { + type InternalCompilationBuilder = InternalCompilationBuilderWrapper; + type CompilationUnit = CompilationUnitWrapper; + type File = FileWrapper; +} + +//================================================ +// +// resource internal-compilation-builder +// +//================================================ + +define_refcell_wrapper! { InternalCompilationBuilder { + fn create(language_version: String) -> Result { + let language_version = Version::parse(&language_version).map_err(|e| e.to_string())?; + + rust::InternalCompilationBuilder::create(language_version) + .map(IntoFFI::_into_ffi) + .map_err(|e| e.to_string()) + } + + fn add_file(&self, id: String, contents: String) -> ffi::AddFileResponse { + self._borrow_mut_ffi() + .add_file(id, &contents) + ._into_ffi() + } + + fn resolve_import(&self, source_file_id: String, import_path: ffi::CursorBorrow<'_>, destination_file_id: String) -> Result<(), String> { + self._borrow_mut_ffi() + .resolve_import(&source_file_id, &import_path._borrow_ffi(), destination_file_id) + .map_err(|e| e.to_string()) + } + + fn build(&self) -> ffi::CompilationUnit { + Rc::new(self._borrow_ffi().build())._into_ffi() + } +} } + +//================================================ +// +// record add-file-response +// +//================================================ + +impl IntoFFI for rust::AddFileResponse { + #[inline] + fn _into_ffi(self) -> ffi::AddFileResponse { + let Self { import_paths } = self; + + ffi::AddFileResponse { + import_paths: import_paths.into_iter().map(IntoFFI::_into_ffi).collect(), + } + } +} + +//================================================ +// +// resource compilation-unit +// +//================================================ + +define_rc_wrapper! { CompilationUnit { + fn language_version(&self) -> String { + self._borrow_ffi().language_version().to_string() + } + + fn files(&self) -> Vec { + self._borrow_ffi().files().into_iter().map(IntoFFI::_into_ffi).collect() + } + + fn file(&self, id: String) -> Option { + self._borrow_ffi().file(&id).map(IntoFFI::_into_ffi) + } + + fn binding_graph(&self) -> Result { + self._borrow_ffi().binding_graph().as_ref().map(Rc::clone).map(IntoFFI::_into_ffi).map_err(|e| e.to_string()) + } +} } + +//================================================ +// +// resource file +// +//================================================ + +define_rc_wrapper! { File { + fn id(&self) -> String { + self._borrow_ffi().id().to_owned() + } + + fn tree(&self) -> ffi::Node { + self._borrow_ffi().tree().to_owned()._into_ffi() + } + + fn create_tree_cursor(&self) -> ffi::Cursor { + self._borrow_ffi().create_tree_cursor()._into_ffi() + } +} } diff --git a/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/cst/mod.rs b/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/cst/mod.rs index 444cab2eab..deca6e2bb4 100644 --- a/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/cst/mod.rs +++ b/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/cst/mod.rs @@ -7,7 +7,7 @@ use crate::wasm_crate::utils::{ }; mod ffi { - pub use crate::wasm_crate::bindings::exports::nomic_foundation::slang::cst::{ + pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::cst::{ AncestorsIterator, AncestorsIteratorBorrow, Cursor, CursorBorrow, CursorIterator, CursorIteratorBorrow, Edge, EdgeLabel, Guest, GuestAncestorsIterator, GuestCursor, GuestCursorIterator, GuestNonterminalNode, GuestQuery, GuestQueryMatchIterator, diff --git a/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/mod.rs b/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/mod.rs index e05fee5635..6b289c658d 100644 --- a/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/mod.rs +++ b/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/mod.rs @@ -1,5 +1,8 @@ // This file is generated automatically by infrastructure scripts. Please don't edit by hand. mod ast; +mod bindings; +mod compilation; mod cst; mod parser; +mod utils; diff --git a/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/parser/mod.rs b/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/parser/mod.rs index d2e73f91de..01e073bb8d 100644 --- a/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/parser/mod.rs +++ b/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/parser/mod.rs @@ -5,10 +5,10 @@ use std::rc::Rc; use crate::wasm_crate::utils::{define_wrapper, FromFFI, IntoFFI}; mod ffi { - pub use crate::wasm_crate::bindings::exports::nomic_foundation::slang::cst::{ + pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::cst::{ Cursor, NonterminalNode, TextRange, }; - pub use crate::wasm_crate::bindings::exports::nomic_foundation::slang::parser::{ + pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::parser::{ Guest, GuestParseError, GuestParseOutput, GuestParser, NonterminalKind, ParseError, ParseErrorBorrow, ParseOutput, ParseOutputBorrow, Parser, ParserBorrow, }; @@ -35,22 +35,15 @@ define_wrapper! { Parser { rust::Parser::ROOT_KIND._into_ffi() } - fn supported_versions() -> Vec { - rust::Parser::SUPPORTED_VERSIONS - .iter() - .map(|v| v.to_string()) - .collect() - } - - fn create(version: String) -> Result { - semver::Version::parse(&version) - .map_err(|_| format!("Invalid semantic version: '{version}'")) + fn create(language_version: String) -> Result { + semver::Version::parse(&language_version) + .map_err(|_| format!("Invalid semantic version: '{language_version}'")) .and_then(|version| rust::Parser::create(version).map_err(|e| e.to_string())) .map(IntoFFI::_into_ffi) } - fn version(&self) -> String { - self._borrow_ffi().version.to_string() + fn language_version(&self) -> String { + self._borrow_ffi().language_version().to_string() } fn parse(&self, kind: ffi::NonterminalKind, input: String) -> ffi::ParseOutput { diff --git a/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/utils/mod.rs b/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/utils/mod.rs new file mode 100644 index 0000000000..b478ca4299 --- /dev/null +++ b/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/utils/mod.rs @@ -0,0 +1,32 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +use crate::wasm_crate::utils::define_wrapper; + +mod ffi { + pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::utils::{ + Guest, GuestLanguageFacts, LanguageFacts, LanguageFactsBorrow, + }; +} + +mod rust { + pub use crate::rust_crate::utils::LanguageFacts; +} + +impl ffi::Guest for crate::wasm_crate::World { + type LanguageFacts = LanguageFactsWrapper; +} + +//================================================ +// +// resource language-facts +// +//================================================ + +define_wrapper! { LanguageFacts { + fn supported_versions() -> Vec { + rust::LanguageFacts::SUPPORTED_VERSIONS + .iter() + .map(|v| v.to_string()) + .collect() + } +} } diff --git a/crates/testlang/outputs/npm/package/package.json b/crates/testlang/outputs/npm/package/package.json index d70fa9afff..b7d2c74da4 100644 --- a/crates/testlang/outputs/npm/package/package.json +++ b/crates/testlang/outputs/npm/package/package.json @@ -6,8 +6,11 @@ "exports": { ".": "./target/generated/index.mjs", "./ast": "./target/generated/ast/index.mjs", + "./bindings": "./target/generated/bindings/index.mjs", + "./compilation": "./target/generated/compilation/index.mjs", "./cst": "./target/generated/cst/index.mjs", - "./parser": "./target/generated/parser/index.mjs" + "./parser": "./target/generated/parser/index.mjs", + "./utils": "./target/generated/utils/index.mjs" }, "__dependencies_comment__": "__SLANG_NPM_PACKAGE_DEPENDENCIES__ (keep in sync)", "dependencies": { diff --git a/crates/testlang/outputs/npm/package/src/generated/bindings/index.mts b/crates/testlang/outputs/npm/package/src/generated/bindings/index.mts new file mode 100644 index 0000000000..7263f31bdc --- /dev/null +++ b/crates/testlang/outputs/npm/package/src/generated/bindings/index.mts @@ -0,0 +1,23 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +import * as generated from "../../../wasm/index.mjs"; + +export const BindingGraph = generated.bindings.BindingGraph; +export type BindingGraph = generated.bindings.BindingGraph; + +export const Definition = generated.bindings.Definition; +export type Definition = generated.bindings.Definition; + +export const Reference = generated.bindings.Reference; +export type Reference = generated.bindings.Reference; + +export type BindingLocation = generated.bindings.BindingLocation; + +export const BindingLocationType = generated.bindings.BindingLocationType; +export type BindingLocationType = generated.bindings.BindingLocationType; + +export const UserFileLocation = generated.bindings.UserFileLocation; +export type UserFileLocation = generated.bindings.UserFileLocation; + +export const BuiltInLocation = generated.bindings.BuiltInLocation; +export type BuiltInLocation = generated.bindings.BuiltInLocation; diff --git a/crates/testlang/outputs/npm/package/src/generated/compilation/builder.mts b/crates/testlang/outputs/npm/package/src/generated/compilation/builder.mts new file mode 100644 index 0000000000..4649389f8b --- /dev/null +++ b/crates/testlang/outputs/npm/package/src/generated/compilation/builder.mts @@ -0,0 +1,114 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +import { Cursor } from "../cst/index.mjs"; +import { CompilationUnit } from "./index.mjs"; + +import * as generated from "../../../wasm/index.mjs"; + +const InternalCompilationBuilder = generated.compilation.InternalCompilationBuilder; +type InternalCompilationBuilder = generated.compilation.InternalCompilationBuilder; + +/** + * User-provided options and callbacks necessary for the `CompilationBuilder` class to perform its job. + */ +export interface CompilationBuilderConfig { + /** + * The language version to parse files with. + */ + languageVersion: string; + + /** + * Callback used by this builder to load the contents of a file. + * + * The user is responsible for fetching the file from the filesystem. + * If the file is not found, the callback should return undefined. + * Any errors thrown by the callback will be propagated to the caller. + */ + readFile: (fileId: string) => Promise; + + /** + * Callback used by this builder to resolve an import path. + * For example, if a source file contains the following statement: + * + * ```solidity + * import {Foo} from "foo.sol"; + * ``` + * + * Then the API will invoke the callback with a cursor pointing to the `"foo.sol"` string literal. + * + * The user is responsible for resolving it to a file in the compilation, and return its ID. + * If the callback returns `undefined`, the import will stay unresolved. + * Any errors thrown by the callback will be propagated to the caller. + */ + resolveImport: (sourceFileId: string, importPath: Cursor) => Promise; +} + +/** + * A builder for creating compilation units. + * Allows incrementally building a list of all files and their imports. + */ +export class CompilationBuilder { + private readonly seenFiles: Set = new Set(); + + private constructor( + private readonly internalBuilder: InternalCompilationBuilder, + + /** + * The user-supplied configuration. + */ + public readonly config: CompilationBuilderConfig, + ) {} + + /** + * Creates a new compilation builder for the specified language version. + */ + public static create(config: CompilationBuilderConfig): CompilationBuilder { + const internalBuilder = InternalCompilationBuilder.create(config.languageVersion); + return new CompilationBuilder(internalBuilder, config); + } + + /** + * Adds a source file to the compilation unit. + * Typically, users only need to add the "root" file, which contains the main contract they are trying to analyze. + * Any files that are imported by the root file will be discovered and loaded automatically by the config callbacks. + * + * Adding multiple files (roots) is supported. For example, an IDE can choose to add all NPM dependencies, + * regardless of whether they are imported or not, to be able to query the definitions there. + * + * Adding a file that has already been added is a no-op. + */ + public async addFile(id: string): Promise { + if (this.seenFiles.has(id)) { + return; + } else { + this.seenFiles.add(id); + } + + const contents = await this.config.readFile(id); + if (contents === undefined) { + return; + } + + const { importPaths } = this.internalBuilder.addFile(id, contents); + + await Promise.all( + importPaths.map(async (importPath) => { + const destinationFileId = await this.config.resolveImport(id, importPath); + if (destinationFileId === undefined) { + return; + } + + this.internalBuilder.resolveImport(id, importPath, destinationFileId); + + await this.addFile(destinationFileId); + }), + ); + } + + /** + * Builds and returns the final compilation unit. + */ + public build(): CompilationUnit { + return this.internalBuilder.build(); + } +} diff --git a/crates/testlang/outputs/npm/package/src/generated/compilation/index.mts b/crates/testlang/outputs/npm/package/src/generated/compilation/index.mts new file mode 100644 index 0000000000..832fe073b8 --- /dev/null +++ b/crates/testlang/outputs/npm/package/src/generated/compilation/index.mts @@ -0,0 +1,16 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +import * as generated from "../../../wasm/index.mjs"; +import * as builder from "./builder.mjs"; + +// This is a wrapper around 'generated.compilation.InternalCompilationBuilder': +export const CompilationBuilder = builder.CompilationBuilder; +export type CompilationBuilder = builder.CompilationBuilder; + +export type CompilationBuilderConfig = builder.CompilationBuilderConfig; + +export const CompilationUnit = generated.compilation.CompilationUnit; +export type CompilationUnit = generated.compilation.CompilationUnit; + +export const File = generated.compilation.File; +export type File = generated.compilation.File; diff --git a/crates/testlang/outputs/npm/package/src/generated/cst/index.mts b/crates/testlang/outputs/npm/package/src/generated/cst/index.mts index 9ceb7c6f40..2bb806862e 100644 --- a/crates/testlang/outputs/npm/package/src/generated/cst/index.mts +++ b/crates/testlang/outputs/npm/package/src/generated/cst/index.mts @@ -50,10 +50,9 @@ export type TextIndex = generated.cst.TextIndex; export type TextRange = generated.cst.TextRange; -/* - * Helpers: +/** + * Asserts that this node is a `NonterminalNode` with the provided kind and text. */ - export function assertIsNonterminalNode( node: unknown, kind?: NonterminalKind, @@ -72,6 +71,9 @@ export function assertIsNonterminalNode( } } +/** + * Asserts that this node is a `TerminalKind` with the provided kind and text. + */ export function assertIsTerminalNode(node: unknown, kind?: TerminalKind, text?: string): asserts node is TerminalNode { if (!(node instanceof TerminalNode)) { throw new Error("Node provided is not a TerminalNode."); diff --git a/crates/testlang/outputs/npm/package/src/generated/index.mts b/crates/testlang/outputs/npm/package/src/generated/index.mts index 847cd1d82b..9aa39203ba 100644 --- a/crates/testlang/outputs/npm/package/src/generated/index.mts +++ b/crates/testlang/outputs/npm/package/src/generated/index.mts @@ -1,5 +1,8 @@ // This file is generated automatically by infrastructure scripts. Please don't edit by hand. export * as ast from "./ast/index.mjs"; +export * as bindings from "./bindings/index.mjs"; +export * as compilation from "./compilation/index.mjs"; export * as cst from "./cst/index.mjs"; export * as parser from "./parser/index.mjs"; +export * as utils from "./utils/index.mjs"; diff --git a/crates/testlang/outputs/npm/package/src/generated/utils/index.mts b/crates/testlang/outputs/npm/package/src/generated/utils/index.mts new file mode 100644 index 0000000000..f1b7780fcb --- /dev/null +++ b/crates/testlang/outputs/npm/package/src/generated/utils/index.mts @@ -0,0 +1,6 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +import * as generated from "../../../wasm/index.mjs"; + +export const LanguageFacts = generated.utils.LanguageFacts; +export type LanguageFacts = generated.utils.LanguageFacts; diff --git a/crates/testlang/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-bindings.d.ts b/crates/testlang/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-bindings.d.ts new file mode 100644 index 0000000000..b2b0d4dc94 --- /dev/null +++ b/crates/testlang/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-bindings.d.ts @@ -0,0 +1,153 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +export namespace NomicFoundationSlangBindings { + export { BindingGraph }; + export { Definition }; + export { Reference }; + export { UserFileLocation }; + export { BuiltInLocation }; + export { BindingLocation }; + export { BindingLocationType }; +} +import type { Cursor } from "./nomic-foundation-slang-cst.js"; +export { Cursor }; +/** + * 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. + */ +export type BindingLocation = UserFileLocation | BuiltInLocation; +export enum BindingLocationType { + UserFileLocation = "UserFileLocation", + BuiltInLocation = "BuiltInLocation", +} + +/** + * 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. + */ +export class BindingGraph { + /** + * If the provided cursor points at a definition `Identifier`, it will return the + * corresponding definition. Otherwise, it will return `undefined`. + */ + definitionAt(cursor: Cursor): Definition | undefined; + /** + * If the provided cursor points at a reference `Identifier`, it will return the + * corresponding reference. Otherwise, it will return `undefined`. + */ + referenceAt(cursor: Cursor): Reference | undefined; +} + +/** + * Represents a location of a built-in symbol in the language. + */ +export class BuiltInLocation { + /** + * The variant of `BindingLocationType` that corresponds to this class. + */ + readonly type = BindingLocationType.BuiltInLocation; + + /** + * Coerce this variant to a `BuiltInLocation`, or `undefined` if this is not the correct type. + */ + asBuiltInLocation(): this; + + /** + * Return `true` if this object is an instance of `BuiltInLocation`. + */ + isBuiltInLocation(): this is BuiltInLocation; + + /** + * Coerce this variant to a `UserFileLocation`, or `undefined` if this is not the correct type. + */ + asUserFileLocation(): undefined; + + /** + * Return `true` if this object is an instance of `UserFileLocation`. + */ + isUserFileLocation(): false; +} + +/** + * Represents a definition in the binding graph. + */ +export class 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. + */ + get id(): number; + /** + * Returns the location of the definition's name. + * For `contract X {}`, that is the location of the `X` `Identifier` node. + */ + get nameLocation(): BindingLocation; + /** + * Returns the location of the definition's definiens. + * For `contract X {}`, that is the location of the parent `ContractDefinition` node. + */ + get definiensLocation(): BindingLocation; +} + +/** + * Represents a reference in the binding graph. + */ +export class 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. + */ + get id(): number; + /** + * Returns the location of the reference. + * For `new X()`, that is the location of the `X` `Identifier` node. + */ + get location(): BindingLocation; + /** + * 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. + */ + definitions(): Definition[]; +} + +/** + * Represents a location of a user-defined symbol in a user file. + */ +export class UserFileLocation { + /** + * The variant of `BindingLocationType` that corresponds to this class. + */ + readonly type = BindingLocationType.UserFileLocation; + + /** + * Coerce this variant to a `UserFileLocation`, or `undefined` if this is not the correct type. + */ + asUserFileLocation(): this; + + /** + * Return `true` if this object is an instance of `UserFileLocation`. + */ + isUserFileLocation(): this is UserFileLocation; + + /** + * Coerce this variant to a `BuiltInLocation`, or `undefined` if this is not the correct type. + */ + asBuiltInLocation(): undefined; + + /** + * Return `true` if this object is an instance of `BuiltInLocation`. + */ + isBuiltInLocation(): false; + + /** + * Returns the ID of the file that contains the symbol. + */ + get fileId(): string; + /** + * Returns a cursor to the CST node that contains the symbol. + */ + get cursor(): Cursor; +} diff --git a/crates/testlang/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-compilation.d.ts b/crates/testlang/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-compilation.d.ts new file mode 100644 index 0000000000..3c1a6831c1 --- /dev/null +++ b/crates/testlang/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-compilation.d.ts @@ -0,0 +1,98 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +export namespace NomicFoundationSlangCompilation { + export { InternalCompilationBuilder }; + export { CompilationUnit }; + export { File }; +} +import type { BindingGraph } from "./nomic-foundation-slang-bindings.js"; +export { BindingGraph }; +import type { Node } from "./nomic-foundation-slang-cst.js"; +export { Node }; +import type { Cursor } from "./nomic-foundation-slang-cst.js"; +export { Cursor }; +/** + * Contains information about imports found in an added source file. + */ +export interface AddFileResponse { + /** + * List of cursors to any import paths found in the file. + */ + importPaths: Cursor[]; +} + +/** + * A complete compilation unit is a complete view over all compilation inputs: + * + * - All source files, stored as CSTs. + * - Name binding graph that exposes relationships between definitions and references in these files. + * - Any relevant compilation options. + * + * It also exposes utilities to traverse the compilation unit and query it. + */ +export class CompilationUnit { + /** + * Returns the language version this compilation unit is configured for. + */ + get languageVersion(): string; + /** + * Returns a list of all files in the compilation unit. + */ + files(): File[]; + /** + * Returns the file with the specified ID, if it exists. + */ + file(id: string): File | undefined; + /** + * Calculates name binding information for all source files within the compilation unit. + * Returns a graph that contains all found definitions and their references. + * + * Note: building this graph is an expensive operation. + * It is done lazily on the first access, and cached thereafter. + */ + get bindingGraph(): BindingGraph; +} + +/** + * A single source file in the compilation unit. + */ +export class File { + /** + * Returns the unique identifier of this file. + */ + get id(): string; + /** + * Returns the syntax tree of this file. + */ + get tree(): Node; + /** + * Creates a cursor for traversing the syntax tree of this file. + */ + createTreeCursor(): Cursor; +} + +/** + * A builder for creating compilation units. + * Allows incrementally building a transitive list of all files and their imports. + * + * This is an internal API, and exposed via a public `CompilationBuilder` wrapper class written in TypeScript. + * This allows storing/invoking user supplied callbacks in TypeScript, rather than Rust, which has its limitations. + */ +export class InternalCompilationBuilder { + /** + * Creates a new compilation builder for the specified language version. + */ + static create(languageVersion: string): InternalCompilationBuilder; + /** + * Adds a source file to the compilation unit. + */ + addFile(id: string, contents: string): AddFileResponse; + /** + * Resolves an import in the source file to the destination file. + */ + resolveImport(sourceFileId: string, importPath: Cursor, destinationFileId: string): void; + /** + * Builds and returns the final compilation unit. + */ + build(): CompilationUnit; +} diff --git a/crates/testlang/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-parser.d.ts b/crates/testlang/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-parser.d.ts index ba8ffd64a0..07fe4156a6 100644 --- a/crates/testlang/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-parser.d.ts +++ b/crates/testlang/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-parser.d.ts @@ -65,19 +65,14 @@ export class Parser { * This represents the starting point for parsing a complete source file. */ static rootKind(): NonterminalKind; - /** - * Returns a list of language versions supported by this parser. - * Each version string represents a specific grammar configuration. - */ - static supportedVersions(): string[]; /** * Creates a new parser instance for the specified language version. */ - static create(version: string): Parser; + static create(languageVersion: string): Parser; /** * Returns the language version this parser instance is configured for. */ - get version(): string; + get languageVersion(): string; /** * Parses the input string starting from the specified nonterminal kind. */ diff --git a/crates/testlang/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-utils.d.ts b/crates/testlang/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-utils.d.ts new file mode 100644 index 0000000000..0a3e19de1c --- /dev/null +++ b/crates/testlang/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-utils.d.ts @@ -0,0 +1,15 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +export namespace NomicFoundationSlangUtils { + export { LanguageFacts }; +} + +/** + * Provides information about the supported language versions and the grammar. + */ +export class LanguageFacts { + /** + * Returns a list of language versions supported by Slang, sorted ascendingly. + */ + static supportedVersions(): string[]; +} diff --git a/crates/testlang/outputs/npm/package/wasm/generated/testlang_cargo_wasm.component.d.ts b/crates/testlang/outputs/npm/package/wasm/generated/testlang_cargo_wasm.component.d.ts index c7614866dd..959f0ad174 100644 --- a/crates/testlang/outputs/npm/package/wasm/generated/testlang_cargo_wasm.component.d.ts +++ b/crates/testlang/outputs/npm/package/wasm/generated/testlang_cargo_wasm.component.d.ts @@ -2,7 +2,13 @@ import { NomicFoundationSlangCst } from "./interfaces/nomic-foundation-slang-cst.js"; import { NomicFoundationSlangAst } from "./interfaces/nomic-foundation-slang-ast.js"; +import { NomicFoundationSlangBindings } from "./interfaces/nomic-foundation-slang-bindings.js"; +import { NomicFoundationSlangCompilation } from "./interfaces/nomic-foundation-slang-compilation.js"; import { NomicFoundationSlangParser } from "./interfaces/nomic-foundation-slang-parser.js"; +import { NomicFoundationSlangUtils } from "./interfaces/nomic-foundation-slang-utils.js"; export * as cst from "./interfaces/nomic-foundation-slang-cst.js"; export * as ast from "./interfaces/nomic-foundation-slang-ast.js"; +export * as bindings from "./interfaces/nomic-foundation-slang-bindings.js"; +export * as compilation from "./interfaces/nomic-foundation-slang-compilation.js"; export * as parser from "./interfaces/nomic-foundation-slang-parser.js"; +export * as utils from "./interfaces/nomic-foundation-slang-utils.js"; diff --git a/crates/testlang/outputs/npm/tests/src/cst/cursor.test.mts b/crates/testlang/outputs/npm/tests/src/cst/cursor.test.mts index a719094355..1a66818131 100644 --- a/crates/testlang/outputs/npm/tests/src/cst/cursor.test.mts +++ b/crates/testlang/outputs/npm/tests/src/cst/cursor.test.mts @@ -101,9 +101,9 @@ test("use cursor goToNext()", () => { test("access the node using its name", () => { const source = "tree [A [B C] D];"; const parser = Parser.create("1.0.0"); - const parseTree = parser.parse(NonterminalKind.SourceUnit, source); + const parseOutput = parser.parse(NonterminalKind.SourceUnit, source); - const cursor = parseTree.createTreeCursor(); + const cursor = parseOutput.createTreeCursor(); let names: string[] = []; while (cursor.goToNextNonterminalWithKind(NonterminalKind.TreeNode)) { diff --git a/crates/testlang/outputs/npm/tests/src/language/language-facts.test.mts b/crates/testlang/outputs/npm/tests/src/language/language-facts.test.mts new file mode 100644 index 0000000000..0708b4deae --- /dev/null +++ b/crates/testlang/outputs/npm/tests/src/language/language-facts.test.mts @@ -0,0 +1,10 @@ +import { LanguageFacts } from "@slang-private/testlang-npm-package/utils"; + +test("list supported versions", () => { + const versions = LanguageFacts.supportedVersions(); + + expect(versions.length).toBeGreaterThan(0); + + expect(versions.includes("1.0.0")).toBeTruthy(); + expect(versions.includes("0.0.0")).toBeFalsy(); +}); diff --git a/crates/testlang/outputs/npm/tests/src/parser/parse.test.mts b/crates/testlang/outputs/npm/tests/src/parser/parse.test.mts index c5d824d417..4453018134 100644 --- a/crates/testlang/outputs/npm/tests/src/parser/parse.test.mts +++ b/crates/testlang/outputs/npm/tests/src/parser/parse.test.mts @@ -10,10 +10,10 @@ test("parse terminal", () => { const source = "About_time"; const parser = Parser.create("1.0.0"); - const parseTree = parser.parse(NonterminalKind.TreeNodeChild, source).tree; - assertIsNonterminalNode(parseTree, NonterminalKind.TreeNodeChild); + const tree = parser.parse(NonterminalKind.TreeNodeChild, source).tree; + assertIsNonterminalNode(tree, NonterminalKind.TreeNodeChild); - const children = parseTree.children(); + const children = tree.children(); expect(children).toHaveLength(1); assertIsTerminalNode(children[0]!.node, TerminalKind.DelimitedIdentifier, "About_time"); @@ -23,10 +23,10 @@ test("parse nonterminal", () => { const source = `tree [A [B C] D];`; const parser = Parser.create("1.0.0"); - const parseTree = parser.parse(NonterminalKind.SourceUnit, source).tree; - assertIsNonterminalNode(parseTree, NonterminalKind.SourceUnit); + const tree = parser.parse(NonterminalKind.SourceUnit, source).tree; + assertIsNonterminalNode(tree, NonterminalKind.SourceUnit); - const children = parseTree.children(); + const children = tree.children(); expect(children).toHaveLength(1); assertIsNonterminalNode(children[0]!.node, NonterminalKind.SourceUnitMembers); diff --git a/crates/testlang/outputs/npm/tests/src/parser/versions.test.mts b/crates/testlang/outputs/npm/tests/src/parser/versions.test.mts index b07dc37e07..4f239c9ef3 100644 --- a/crates/testlang/outputs/npm/tests/src/parser/versions.test.mts +++ b/crates/testlang/outputs/npm/tests/src/parser/versions.test.mts @@ -1,14 +1,5 @@ import { Parser } from "@slang-private/testlang-npm-package/parser"; -test("list supported versions", () => { - const versions = Parser.supportedVersions(); - - expect(versions.length).toBeGreaterThan(0); - - expect(versions.includes("1.0.0")).toBeTruthy(); - expect(versions.includes("0.0.0")).toBeFalsy(); -}); - test("invalid semantic version", () => { expect(() => Parser.create("foo_bar")).toThrow("Invalid semantic version: 'foo_bar'"); }); diff --git a/crates/testlang/outputs/npm/tests/src/utils/language-facts.test.mts b/crates/testlang/outputs/npm/tests/src/utils/language-facts.test.mts new file mode 100644 index 0000000000..0708b4deae --- /dev/null +++ b/crates/testlang/outputs/npm/tests/src/utils/language-facts.test.mts @@ -0,0 +1,10 @@ +import { LanguageFacts } from "@slang-private/testlang-npm-package/utils"; + +test("list supported versions", () => { + const versions = LanguageFacts.supportedVersions(); + + expect(versions.length).toBeGreaterThan(0); + + expect(versions.includes("1.0.0")).toBeTruthy(); + expect(versions.includes("0.0.0")).toBeFalsy(); +}); diff --git a/documentation/public/user-guide/concepts.md b/documentation/public/user-guide/concepts.md index 121f6fc3a9..41124c852a 100644 --- a/documentation/public/user-guide/concepts.md +++ b/documentation/public/user-guide/concepts.md @@ -10,7 +10,7 @@ The earliest Solidity version we support is `0.4.11`, and we plan on supporting From a `Parser` object, you can analyze any source text according to the nonterminals of that specific version. Providing an accurate language version is important, as it affects the shape of the syntax tree, and possible errors produced. -You can use the `Parser::getSupportedVersions()` API to get a list of all supported versions for the current Slang release. +You can use the `LanguageFacts::supportedVersions()` API to get a list of all supported versions for the current Slang release. The `Parser::parse()` API is the main entry point for the parser, and to generate concrete syntax trees (CSTs) that can be used for further analysis. Each `parse()` operation accepts the input source code, and a `NonterminalKind` variant.