diff --git a/crates/metaslang/bindings/src/lib.rs b/crates/metaslang/bindings/src/lib.rs index 8c37767b0..d71bb2875 100644 --- a/crates/metaslang/bindings/src/lib.rs +++ b/crates/metaslang/bindings/src/lib.rs @@ -103,6 +103,9 @@ impl Bindings { } pub fn cursor_to_handle(&self, cursor: &Cursor) -> Option> { + // FIXME: in some cases (eg. deconstruction imports without alias) the + // same Cursor will point to two separate handles: a definition and a + // reference. This API does not support such case yet. for (handle, handle_cursor) in &self.cursors { if handle_cursor == cursor { return Some(Handle { diff --git a/crates/solidity/inputs/language/bindings/rules.msgb b/crates/solidity/inputs/language/bindings/rules.msgb index 26e5257c3..8c21323b6 100644 --- a/crates/solidity/inputs/language/bindings/rules.msgb +++ b/crates/solidity/inputs/language/bindings/rules.msgb @@ -129,7 +129,15 @@ attribute symbol_reference = symbol => type = "push_symbol", symbol = symbol, i @source_unit [SourceUnit ... [SourceUnitMembers ... - [SourceUnitMember @import [ImportDirective]] + [SourceUnitMember [ImportDirective + ... + [ImportClause @import ( + [PathImport] + | [NamedImport] + | [ImportDeconstruction] + )] + ... + ]] ... ] ...] { node @import.defs @@ -137,15 +145,13 @@ attribute symbol_reference = symbol => type = "push_symbol", symbol = symbol, i edge @source_unit.lexical_scope -> @import.defs } -;;; This is the `import [as ]` case - -[ImportDirective ... [ImportClause +[ImportClause ... - [PathImport ... @path path: [StringLiteral] ...] + [_ ... @path path: [StringLiteral] ...] ... -] ...] { - ;; This node represents the imported file, and is used by the two following rules - ;; that handle the possible syntaxes: global import and scoped with an alias +] { + ;; 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*$" { @@ -157,27 +163,22 @@ attribute symbol_reference = symbol => type = "push_symbol", symbol = symbol, i edge @path.import -> ROOT_NODE } -@import [ImportDirective ... [ImportClause - ... - [PathImport ... @path path: [StringLiteral]] - ... -] ...] { + +;;; `import ` +@import [PathImport ... @path path: [StringLiteral]] { ;; This is the "lexical" connection, which makes all symbols exported from the ;; imported source unit available for resolution globally at this' source unit ;; scope edge @import.defs -> @path.import } -@import [ImportDirective ... [ImportClause - ... - [PathImport - ... - @path path: [StringLiteral] - alias: [ImportAlias ... @alias [Identifier] ...] - ... - ] - ... -] ...] { +;;; `import as ` +@import [PathImport + ... + @path path: [StringLiteral] + alias: [ImportAlias ... @alias [Identifier] ...] + ... +] { node def attr (def) node_definition = @alias edge @import.defs -> def @@ -191,32 +192,14 @@ attribute symbol_reference = symbol => type = "push_symbol", symbol = symbol, i edge member -> @path.import } - -;;; This is the `import * as from ` case - -@import [ImportDirective ... [ImportClause +;;; `import * as from ` +@import [NamedImport ... - [NamedImport - ... - alias: [ImportAlias ... @alias [Identifier] ...] - ... - @path path: [StringLiteral] - ... - ] + alias: [ImportAlias ... @alias [Identifier]] ... -] ...] { - ;; This node represents the imported file, and is used by the two following rules - ;; that handle the possible syntaxes: global import and scoped with an alias - node @path.import - scan (source-text @path) { - "^\\s*[\"'](.+)[\"']\\s*$" { - let resolved_path = (resolve-path FILE_PATH $1) - attr (@path.import) push_symbol = resolved_path - } - ;; TODO: if there are other cases possible, we should signal it as an error - } - edge @path.import -> ROOT_NODE - + @path path: [StringLiteral] + ... +] { node def attr (def) node_definition = @alias edge @import.defs -> def @@ -230,6 +213,52 @@ attribute symbol_reference = symbol => type = "push_symbol", symbol = symbol, i edge member -> @path.import } +;;; `import { [as ] ...} from ` +@import [ImportDeconstruction + ... + symbols: [ImportDeconstructionSymbols ... @symbol [ImportDeconstructionSymbol] ...] + ... + @path path: [StringLiteral] + ... +] { + ;; We define these intermediate nodes for convenience only, to make the + ;; queries simpler in the two rules below + node @symbol.def + edge @import.defs -> @symbol.def + + node @symbol.import + edge @symbol.import -> @path.import +} + +@symbol [ImportDeconstructionSymbol ... @name name: [Identifier]] { + node def + attr (def) node_definition = @name + edge @symbol.def -> def + + node import + attr (import) node_reference = @name + edge def -> import + + edge import -> @symbol.import +} + +@symbol [ImportDeconstructionSymbol + ... + @name name: [Identifier] + ... + alias: [ImportAlias ... @alias [Identifier]] +] { + node def + attr (def) node_definition = @alias + edge @symbol.def -> def + + node import + attr (import) node_reference = @name + edge def -> import + + edge import -> @symbol.import +} + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Named definitions (contracts, functions, libraries, etc.) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/crates/solidity/outputs/cargo/slang_solidity/src/generated/bindings/generated/binding_rules.rs b/crates/solidity/outputs/cargo/slang_solidity/src/generated/bindings/generated/binding_rules.rs index 48be269c9..5849abdef 100644 --- a/crates/solidity/outputs/cargo/slang_solidity/src/generated/bindings/generated/binding_rules.rs +++ b/crates/solidity/outputs/cargo/slang_solidity/src/generated/bindings/generated/binding_rules.rs @@ -134,7 +134,15 @@ attribute symbol_reference = symbol => type = "push_symbol", symbol = symbol, i @source_unit [SourceUnit ... [SourceUnitMembers ... - [SourceUnitMember @import [ImportDirective]] + [SourceUnitMember [ImportDirective + ... + [ImportClause @import ( + [PathImport] + | [NamedImport] + | [ImportDeconstruction] + )] + ... + ]] ... ] ...] { node @import.defs @@ -142,15 +150,13 @@ attribute symbol_reference = symbol => type = "push_symbol", symbol = symbol, i edge @source_unit.lexical_scope -> @import.defs } -;;; This is the `import [as ]` case - -[ImportDirective ... [ImportClause +[ImportClause ... - [PathImport ... @path path: [StringLiteral] ...] + [_ ... @path path: [StringLiteral] ...] ... -] ...] { - ;; This node represents the imported file, and is used by the two following rules - ;; that handle the possible syntaxes: global import and scoped with an alias +] { + ;; 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*$" { @@ -162,27 +168,22 @@ attribute symbol_reference = symbol => type = "push_symbol", symbol = symbol, i edge @path.import -> ROOT_NODE } -@import [ImportDirective ... [ImportClause - ... - [PathImport ... @path path: [StringLiteral]] - ... -] ...] { + +;;; `import ` +@import [PathImport ... @path path: [StringLiteral]] { ;; This is the "lexical" connection, which makes all symbols exported from the ;; imported source unit available for resolution globally at this' source unit ;; scope edge @import.defs -> @path.import } -@import [ImportDirective ... [ImportClause - ... - [PathImport - ... - @path path: [StringLiteral] - alias: [ImportAlias ... @alias [Identifier] ...] - ... - ] - ... -] ...] { +;;; `import as ` +@import [PathImport + ... + @path path: [StringLiteral] + alias: [ImportAlias ... @alias [Identifier] ...] + ... +] { node def attr (def) node_definition = @alias edge @import.defs -> def @@ -196,32 +197,14 @@ attribute symbol_reference = symbol => type = "push_symbol", symbol = symbol, i edge member -> @path.import } - -;;; This is the `import * as from ` case - -@import [ImportDirective ... [ImportClause +;;; `import * as from ` +@import [NamedImport ... - [NamedImport - ... - alias: [ImportAlias ... @alias [Identifier] ...] - ... - @path path: [StringLiteral] - ... - ] + alias: [ImportAlias ... @alias [Identifier]] ... -] ...] { - ;; This node represents the imported file, and is used by the two following rules - ;; that handle the possible syntaxes: global import and scoped with an alias - node @path.import - scan (source-text @path) { - "^\\s*[\"'](.+)[\"']\\s*$" { - let resolved_path = (resolve-path FILE_PATH $1) - attr (@path.import) push_symbol = resolved_path - } - ;; TODO: if there are other cases possible, we should signal it as an error - } - edge @path.import -> ROOT_NODE - + @path path: [StringLiteral] + ... +] { node def attr (def) node_definition = @alias edge @import.defs -> def @@ -235,6 +218,52 @@ attribute symbol_reference = symbol => type = "push_symbol", symbol = symbol, i edge member -> @path.import } +;;; `import { [as ] ...} from ` +@import [ImportDeconstruction + ... + symbols: [ImportDeconstructionSymbols ... @symbol [ImportDeconstructionSymbol] ...] + ... + @path path: [StringLiteral] + ... +] { + ;; We define these intermediate nodes for convenience only, to make the + ;; queries simpler in the two rules below + node @symbol.def + edge @import.defs -> @symbol.def + + node @symbol.import + edge @symbol.import -> @path.import +} + +@symbol [ImportDeconstructionSymbol ... @name name: [Identifier]] { + node def + attr (def) node_definition = @name + edge @symbol.def -> def + + node import + attr (import) node_reference = @name + edge def -> import + + edge import -> @symbol.import +} + +@symbol [ImportDeconstructionSymbol + ... + @name name: [Identifier] + ... + alias: [ImportAlias ... @alias [Identifier]] +] { + node def + attr (def) node_definition = @alias + edge @symbol.def -> def + + node import + attr (import) node_reference = @name + edge def -> import + + edge import -> @symbol.import +} + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Named definitions (contracts, functions, libraries, etc.) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/crates/solidity/outputs/cargo/tests/fixtures/one.sol b/crates/solidity/outputs/cargo/tests/fixtures/one.sol index 6c743f720..9f2d233c1 100644 --- a/crates/solidity/outputs/cargo/tests/fixtures/one.sol +++ b/crates/solidity/outputs/cargo/tests/fixtures/one.sol @@ -1,6 +1,7 @@ import "./two.sol" as two; import * as three from "./three.sol"; +import {f3 as g3, f4} from './three.sol'; function f1() returns (int) { - return two.f2() + three.f3(); + return two.f2() + three.f3() + g3() + f4(); } diff --git a/crates/solidity/outputs/cargo/tests/fixtures/stackgraph.mmd b/crates/solidity/outputs/cargo/tests/fixtures/stackgraph.mmd index d79785aad..09e33375b 100644 --- a/crates/solidity/outputs/cargo/tests/fixtures/stackgraph.mmd +++ b/crates/solidity/outputs/cargo/tests/fixtures/stackgraph.mmd @@ -1,148 +1,223 @@ graph TD N1[ROOT] N1 --> N5 - N1 --> N49 - N1 --> N65 + N1 --> N75 + N1 --> N91 N2 N3 N3 --> N6 N3 --> N7 - N3 --> N15 + N3 --> N8 + N3 --> N25 N4 N4 --> N6 N4 --> N7 - N4 --> N15 + N4 --> N8 + N4 --> N25 N5[\/home/ggiraldez/Projects/slang/crates/solidity/outputs/cargo/tests/fixtures/one.sol/] N5 --> N4 N6 - N6 --> N9 + N6 --> N10 N7 - N7 --> N12 - N8[//home/ggiraldez/Projects/slang/crates/solidity/outputs/cargo/tests/fixtures/two.sol\] - N8 --> N1 - N9[\two/] - N9 --> N10 - N10[\./] - N10 --> N8 - N11[//home/ggiraldez/Projects/slang/crates/solidity/outputs/cargo/tests/fixtures/three.sol\] - N11 --> N1 - N12[\three/] - N12 --> N13 - N13[\./] - N13 --> N11 - N14 - N14 --> N3 - N14 --> N18 - N15 - N15 --> N16 - N16[\f1/] + N7 --> N13 + N8 + N8 --> N16 + N8 --> N18 + N9[//home/ggiraldez/Projects/slang/crates/solidity/outputs/cargo/tests/fixtures/two.sol\] + N9 --> N1 + N10[\two/] + N10 --> N11 + N11[\./] + N11 --> N9 + N12[//home/ggiraldez/Projects/slang/crates/solidity/outputs/cargo/tests/fixtures/three.sol\] + N12 --> N1 + N13[\three/] + N13 --> N14 + N14[\./] + N14 --> N12 + N15[//home/ggiraldez/Projects/slang/crates/solidity/outputs/cargo/tests/fixtures/three.sol\] + N15 --> N1 + N16 + N16 --> N20 N17 - N17 --> N14 + N17 --> N15 N18 + N18 --> N22 N19 - N19 --> N17 - N20 - N21 - N21 --> N14 - N22 - N23 - N23 --> N21 - N23 --> N24 + N19 --> N15 + N20[\g3/] + N20 --> N21 + N21[/f3\] + N21 --> N17 + N22[\f4/] + N22 --> N23 + N23[/f4\] + N23 --> N19 N24 + N24 --> N3 + N24 --> N28 N25 - N25 --> N23 - N26 + N25 --> N26 + N26[\f1/] N27 - N27 --> N25 + N27 --> N24 N28 N29 N29 --> N27 N30 - N30 --> N31 - N31[/f2\] - N31 --> N32 - N32[/.\] - N32 --> N34 + N31 + N31 --> N24 + N32 N33 - N33 --> N29 + N33 --> N31 + N33 --> N34 N34 - N34 --> N35 - N35[/two\] + N35 N35 --> N33 N36 - N36 --> N27 N37 - N37 --> N25 + N37 --> N35 N38 N39 N39 --> N37 N40 - N40 --> N41 - N41[/f3\] - N41 --> N42 - N42[/.\] - N42 --> N44 + N41 + N41 --> N39 + N42 N43 - N43 --> N39 + N43 --> N41 N44 N44 --> N45 - N45[/three\] - N45 --> N43 - N46 - N46 --> N37 + N45[/f2\] + N45 --> N46 + N46[/.\] + N46 --> N48 N47 - N47 --> N51 + N47 --> N43 N48 - N48 --> N51 - N49[\/home/ggiraldez/Projects/slang/crates/solidity/outputs/cargo/tests/fixtures/two.sol/] - N49 --> N48 + N48 --> N49 + N49[/two\] + N49 --> N47 N50 - N50 --> N47 - N50 --> N54 + N50 --> N41 N51 - N51 --> N52 - N52[\f2/] + N51 --> N39 + N52 N53 - N53 --> N50 + N53 --> N51 N54 - N55 - N55 --> N53 - N56 + N54 --> N55 + N55[/f3\] + N55 --> N56 + N56[/.\] + N56 --> N58 N57 - N57 --> N50 + N57 --> N53 N58 - N59 + N58 --> N59 + N59[/three\] N59 --> N57 - N59 --> N60 N60 + N60 --> N51 N61 - N61 --> N59 + N61 --> N37 N62 N63 - N63 --> N67 + N63 --> N61 N64 - N64 --> N67 - N65[\/home/ggiraldez/Projects/slang/crates/solidity/outputs/cargo/tests/fixtures/three.sol/] - N65 --> N64 + N64 --> N65 + N65[/g3\] + N65 --> N63 N66 - N66 --> N63 - N66 --> N70 + N66 --> N61 N67 - N67 --> N68 - N68[\f3/] + N67 --> N35 + N68 N69 - N69 --> N66 + N69 --> N67 N70 - N71 + N70 --> N71 + N71[/f4\] N71 --> N69 N72 + N72 --> N67 N73 - N73 --> N66 + N73 --> N77 N74 - N75 - N75 --> N73 - N75 --> N76 + N74 --> N77 + N75[\/home/ggiraldez/Projects/slang/crates/solidity/outputs/cargo/tests/fixtures/two.sol/] + N75 --> N74 N76 + N76 --> N73 + N76 --> N80 N77 - N77 --> N75 - N78 + N77 --> N78 + N78[\f2/] + N79 + N79 --> N76 + N80 + N81 + N81 --> N79 + N82 + N83 + N83 --> N76 + N84 + N85 + N85 --> N83 + N85 --> N86 + N86 + N87 + N87 --> N85 + N88 + N89 + N89 --> N93 + N89 --> N106 + N90 + N90 --> N93 + N90 --> N106 + N91[\/home/ggiraldez/Projects/slang/crates/solidity/outputs/cargo/tests/fixtures/three.sol/] + N91 --> N90 + N92 + N92 --> N89 + N92 --> N96 + N93 + N93 --> N94 + N94[\f3/] + N95 + N95 --> N92 + N96 + N97 + N97 --> N95 + N98 + N99 + N99 --> N92 + N100 + N101 + N101 --> N99 + N101 --> N102 + N102 + N103 + N103 --> N101 + N104 + N105 + N105 --> N89 + N105 --> N109 + N106 + N106 --> N107 + N107[\f4/] + N108 + N108 --> N105 + N109 + N110 + N110 --> N108 + N111 + N112 + N112 --> N105 + N113 + N114 + N114 --> N112 + N114 --> N115 + N115 + N116 + N116 --> N114 + N117 diff --git a/crates/solidity/outputs/cargo/tests/fixtures/three.sol b/crates/solidity/outputs/cargo/tests/fixtures/three.sol index 6d3f874ff..d51793307 100644 --- a/crates/solidity/outputs/cargo/tests/fixtures/three.sol +++ b/crates/solidity/outputs/cargo/tests/fixtures/three.sol @@ -1,3 +1,7 @@ function f3() returns (int) { return 3; } + +function f4() returns (int) { + return 4; +} diff --git a/crates/solidity/outputs/cargo/tests/src/binding_imports.rs b/crates/solidity/outputs/cargo/tests/src/binding_imports.rs index 0ab75a34b..b15081dfb 100644 --- a/crates/solidity/outputs/cargo/tests/src/binding_imports.rs +++ b/crates/solidity/outputs/cargo/tests/src/binding_imports.rs @@ -33,7 +33,10 @@ fn test_bindings_are_resolved_across_imported_files() -> Result<()> { bindings::create_with_resolver(version.clone(), Arc::new(SolidityPathResolver {})); bindings.add_file(&one_path.to_string_lossy(), one_parsed.create_tree_cursor()); bindings.add_file(&two_path.to_string_lossy(), two_parsed.create_tree_cursor()); - bindings.add_file(&three_path.to_string_lossy(), three_parsed.create_tree_cursor()); + bindings.add_file( + &three_path.to_string_lossy(), + three_parsed.create_tree_cursor(), + ); let mermaid_path = Path::repo_path("crates/solidity/outputs/cargo/tests/fixtures/stackgraph.mmd");