-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #127 from alephium/goto_enum
GoTo `enum` type, field and usages
- Loading branch information
Showing
7 changed files
with
554 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
81 changes: 81 additions & 0 deletions
81
...ntation-compiler/src/main/scala/org/alephium/ralph/lsp/pc/search/gotodef/GoToTypeId.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
package org.alephium.ralph.lsp.pc.search.gotodef | ||
|
||
import org.alephium.ralph.Ast | ||
import org.alephium.ralph.Ast.Positioned | ||
import org.alephium.ralph.lsp.access.compiler.ast.Tree | ||
import org.alephium.ralph.lsp.access.compiler.ast.node.Node | ||
|
||
import scala.collection.immutable.ArraySeq | ||
|
||
private object GoToTypeId { | ||
|
||
/** | ||
* Navigate to the positioned ASTs for the given type identifier. | ||
* | ||
* @param identNode The node representing the type identifier in the AST. | ||
* @param typeId The type identifier for which the [[Ast.TypeId]] is sought. | ||
* @param source The source tree to search within. | ||
* @return An array sequence of positioned ASTs matching the search result. | ||
* */ | ||
def goTo(identNode: Node[Positioned], | ||
typeId: Ast.TypeId, | ||
source: Tree.Source): ArraySeq[Ast.Positioned] = | ||
identNode | ||
.parent // take one step up to check the type of TypeId node. | ||
.map(_.data) | ||
.to(ArraySeq) | ||
.collect { | ||
case enumFieldSelector: Ast.EnumFieldSelector[_] if enumFieldSelector.enumId == typeId => | ||
// The user clicked on an enum type. Take 'em there! | ||
goToEnumType( | ||
enumSelector = enumFieldSelector, | ||
source = source | ||
) | ||
|
||
case enumDef: Ast.EnumDef if enumDef.id == typeId => | ||
// The user clicked on an enum definition. Take 'em there! | ||
goToEnumTypeCalls( | ||
enumDef = enumDef, | ||
source = source | ||
) | ||
} | ||
.flatten | ||
|
||
/** Navigate to the enum types for the given enum field selector. | ||
* | ||
* @param enumSelector The enum type to find. | ||
* @param source The source tree to search within. | ||
* @return An array sequence of enum [[Ast.TypeId]]s matching the search result. | ||
* */ | ||
private def goToEnumType(enumSelector: Ast.EnumFieldSelector[_], | ||
source: Tree.Source): ArraySeq[Ast.TypeId] = | ||
source.ast match { | ||
case contract: Ast.Contract => | ||
contract | ||
.enums | ||
.filter(_.id == enumSelector.enumId) | ||
.map(_.id) | ||
.to(ArraySeq) | ||
|
||
case _: Ast.ContractInterface | _: Ast.TxScript => | ||
ArraySeq.empty | ||
} | ||
|
||
/** Navigate to the enum type name calls. | ||
* | ||
* @param enumDef The enum definition contain the enum type identifier to find calls for. | ||
* @param source The source tree to search within. | ||
* @return An array sequence of enum type [[Ast.TypeId]]s matching the search result. | ||
* */ | ||
private def goToEnumTypeCalls(enumDef: Ast.EnumDef, | ||
source: Tree.Source): ArraySeq[Ast.TypeId] = | ||
source | ||
.rootNode | ||
.walkDown | ||
.collect { | ||
case Node(selector: Ast.EnumFieldSelector[_], _) if selector.enumId == enumDef.id => | ||
selector.enumId | ||
} | ||
.to(ArraySeq) | ||
|
||
} |
166 changes: 166 additions & 0 deletions
166
...-compiler/src/test/scala/org/alephium/ralph/lsp/pc/search/gotodef/GoToEnumFieldSpec.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
package org.alephium.ralph.lsp.pc.search.gotodef | ||
|
||
import org.alephium.ralph.lsp.pc.search.TestCodeProvider._ | ||
import org.scalatest.matchers.should.Matchers | ||
import org.scalatest.wordspec.AnyWordSpec | ||
|
||
class GoToEnumFieldSpec extends AnyWordSpec with Matchers { | ||
|
||
"return empty" when { | ||
"enum type does not exist" in { | ||
goTo( | ||
""" | ||
|Contract MyContract() { | ||
| pub fn function() -> () { | ||
| let field = EnumType.Fie@@ld0 | ||
| } | ||
|} | ||
|""".stripMargin | ||
) | ||
} | ||
} | ||
|
||
"return non-empty" when { | ||
"user selects the first enum field" in { | ||
goTo( | ||
""" | ||
|Contract MyContract() { | ||
| | ||
| enum EnumType { | ||
| >>Field0 = 0<< | ||
| Field1 = 1 | ||
| } | ||
| | ||
| pub fn function() -> () { | ||
| let field0 = EnumType.Fie@@ld0 | ||
| let field1 = EnumType.Field1 | ||
| } | ||
|} | ||
|""".stripMargin | ||
) | ||
} | ||
|
||
"user selects the second enum field" in { | ||
goTo( | ||
""" | ||
|Contract MyContract() { | ||
| | ||
| enum EnumType { | ||
| Field0 = 0 | ||
| >>Field1 = 1<< | ||
| } | ||
| | ||
| pub fn function() -> () { | ||
| let field0 = EnumType.Field0 | ||
| let field1 = EnumType.Fie@@ld1 | ||
| } | ||
|} | ||
|""".stripMargin | ||
) | ||
} | ||
|
||
"there are duplicate enum types and fields" when { | ||
"user selects the first enum field" in { | ||
goTo( | ||
""" | ||
|Contract MyContract() { | ||
| | ||
| enum EnumType { | ||
| >>Field0 = 0<< | ||
| Field1 = 1 | ||
| } | ||
| | ||
| enum EnumType { | ||
| >>Field0 = 0<< | ||
| Field1 = 1 | ||
| } | ||
| | ||
| pub fn function() -> () { | ||
| let field0 = EnumType.Fi@@eld0 | ||
| let field1 = EnumType.Field1 | ||
| } | ||
|} | ||
|""".stripMargin | ||
) | ||
} | ||
|
||
"user selects the second enum field" in { | ||
goTo( | ||
""" | ||
|Contract MyContract() { | ||
| | ||
| enum EnumType { | ||
| Field0 = 0 | ||
| >>Field1 = 1<< | ||
| } | ||
| | ||
| enum EnumType { | ||
| Field0 = 0 | ||
| >>Field1 = 1<< | ||
| } | ||
| | ||
| pub fn function() -> () { | ||
| let field0 = EnumType.Field0 | ||
| let field1 = EnumType.Fi@@eld1 | ||
| } | ||
|} | ||
|""".stripMargin | ||
) | ||
} | ||
} | ||
|
||
"there are duplicate enum types with distinct fields" when { | ||
"user selects the first enum field" in { | ||
goTo( | ||
""" | ||
|Contract MyContract() { | ||
| | ||
| enum EnumType { | ||
| >>Field0 = 0<< | ||
| Field1 = 1 | ||
| } | ||
| | ||
| enum EnumType { | ||
| Field2 = 2 | ||
| Field3 = 3 | ||
| } | ||
| | ||
| pub fn function() -> () { | ||
| let field0 = EnumType.Fie@@ld0 | ||
| let field1 = EnumType.Field1 | ||
| let field2 = EnumType.Field2 | ||
| let field3 = EnumType.Field3 | ||
| } | ||
|} | ||
|""".stripMargin | ||
) | ||
} | ||
|
||
"user selects the third enum field" in { | ||
goTo( | ||
""" | ||
|Contract MyContract() { | ||
| | ||
| enum EnumType { | ||
| Field0 = 0 | ||
| Field1 = 1 | ||
| } | ||
| | ||
| enum EnumType { | ||
| >>Field2 = 2<< | ||
| Field3 = 3 | ||
| } | ||
| | ||
| pub fn function() -> () { | ||
| let field0 = EnumType.Field0 | ||
| let field1 = EnumType.Field1 | ||
| let field2 = EnumType.Fie@@ld2 | ||
| let field3 = EnumType.Field3 | ||
| } | ||
|} | ||
|""".stripMargin | ||
) | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.