Skip to content

Commit

Permalink
Support deconstruction imports directives
Browse files Browse the repository at this point in the history
  • Loading branch information
ggiraldez committed Jul 12, 2024
1 parent b55de79 commit ec45c10
Show file tree
Hide file tree
Showing 7 changed files with 328 additions and 184 deletions.
3 changes: 3 additions & 0 deletions crates/metaslang/bindings/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ impl<KT: KindTypes + 'static> Bindings<KT> {
}

pub fn cursor_to_handle(&self, cursor: &Cursor<KT>) -> Option<Handle<'_, KT>> {
// 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 {
Expand Down
123 changes: 76 additions & 47 deletions crates/solidity/inputs/language/bindings/rules.msgb
Original file line number Diff line number Diff line change
Expand Up @@ -129,23 +129,29 @@ 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
edge @source_unit.defs -> @import.defs
edge @source_unit.lexical_scope -> @import.defs
}

;;; This is the `import <URI> [as <IDENT>]` 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*$" {
Expand All @@ -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 <URI>`
@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 <URI> as <IDENT>`
@import [PathImport
...
@path path: [StringLiteral]
alias: [ImportAlias ... @alias [Identifier] ...]
...
] {
node def
attr (def) node_definition = @alias
edge @import.defs -> def
Expand All @@ -191,32 +192,14 @@ attribute symbol_reference = symbol => type = "push_symbol", symbol = symbol, i
edge member -> @path.import
}


;;; This is the `import * as <IDENT> from <URI>` case

@import [ImportDirective ... [ImportClause
;;; `import * as <IDENT> from <URI>`
@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
Expand All @@ -230,6 +213,52 @@ attribute symbol_reference = symbol => type = "push_symbol", symbol = symbol, i
edge member -> @path.import
}

;;; `import {<SYMBOL> [as <IDENT>] ...} from <PATH>`
@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.)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion crates/solidity/outputs/cargo/tests/fixtures/one.sol
Original file line number Diff line number Diff line change
@@ -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();
}
Loading

0 comments on commit ec45c10

Please sign in to comment.