Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/alephium_config_ts' into alephiu…
Browse files Browse the repository at this point in the history
…m_config_ts_tranformer
  • Loading branch information
tdroxler committed Aug 26, 2024
2 parents 28c32e7 + 6165096 commit d8f82ff
Show file tree
Hide file tree
Showing 33 changed files with 1,075 additions and 248 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ directory under the folder `.ralph-lsp/ralph.json`. The file contains the follow
"ignoreUnusedFieldsWarnings": false,
"ignoreUnusedPrivateFunctionsWarnings": false,
"ignoreUpdateFieldsCheckWarnings": false,
"ignoreCheckExternalCallerWarnings": false
"ignoreCheckExternalCallerWarnings": false,
"ignoreUnusedFunctionReturnWarnings": false
},
"contractPath": "contracts"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,28 @@ object AstExtra {

}

/**
* Fetches the type identifier for a given global definition.
*
* @param ast The type for which to fetch the identifier.
* @return `Some(TypeId)` if the type has an associated [[Ast.TypeId]], otherwise [[None]].
*/
def getTypeId(ast: Ast.GlobalDefinition): Option[Ast.TypeId] =
ast match {
case ast: Ast.ContractWithState =>
Some(ast.ident)

case ast: Ast.Struct =>
Some(ast.id)

case ast: Ast.EnumDef[_] =>
Some(ast.id)

case asset: Ast.AssetScript =>
Some(asset.ident)

case _: Ast.ConstantVarDef[_] =>
None
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -74,22 +74,7 @@ object Tree {
NodeBuilder.buildRootNode(ast)

def typeId(): Option[Ast.TypeId] =
ast match {
case ast: Ast.ContractWithState =>
Some(ast.ident)

case ast: Ast.Struct =>
Some(ast.id)

case ast: Ast.EnumDef[_] =>
Some(ast.id)

case asset: Ast.AssetScript =>
Some(asset.ident)

case _: Ast.ConstantVarDef[_] =>
None
}
AstExtra.getTypeId(ast)

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,39 +34,39 @@ object NodeBuilder extends StrictLogging {
val rootSiblings =
ast match {
case ast: Ast.TxScript =>
buildOne(ast.ident) ++
buildMany(ast.templateVars) ++
buildMany(ast.funcs)
Seq(buildParent(ast.ident)) ++
buildParents(ast.templateVars) ++
buildParents(ast.funcs)

case ast: Ast.Contract =>
buildOne(ast.stdInterfaceId) ++
buildOne(ast.ident) ++
buildMany(ast.templateVars) ++
buildMany(ast.fields) ++
buildMany(ast.funcs) ++
buildMany(ast.events) ++
buildMany(ast.constantVars) ++
buildMany(ast.enums) ++
buildMany(ast.inheritances) ++
buildMany(ast.maps)
buildParents(ast.stdInterfaceId.toSeq) ++
Seq(buildParent(ast.ident)) ++
buildParents(ast.templateVars) ++
buildParents(ast.fields) ++
buildParents(ast.funcs) ++
buildParents(ast.events) ++
buildParents(ast.constantVars) ++
buildParents(ast.enums) ++
buildParents(ast.inheritances) ++
buildParents(ast.maps)

case ast: Ast.ContractInterface =>
buildOne(ast.stdId) ++
buildOne(ast.ident) ++
buildMany(ast.funcs) ++
buildMany(ast.events) ++
buildMany(ast.inheritances)
buildParents(ast.stdId.toSeq) ++
Seq(buildParent(ast.ident)) ++
buildParents(ast.funcs) ++
buildParents(ast.events) ++
buildParents(ast.inheritances)

case ast: Ast.Struct =>
buildOne(ast.id) ++
buildMany(ast.fields)
buildParent(ast.id) +:
buildParents(ast.fields)

case ast: Ast.EnumDef[_] =>
buildOne(ast.id) ++
buildMany(ast.fields)
buildParent(ast.id) +:
buildParents(ast.fields)

case ast: Ast.ConstantVarDef[_] =>
buildOne(ast)
Seq(buildParent(ast))

case _: Ast.AssetScript =>
// AssetScript is not parsed. This will be supported in the future.
Expand All @@ -84,49 +84,76 @@ object NodeBuilder extends StrictLogging {
)
}

private def buildOne(product: Any): List[Node[Ast.Positioned, Ast.Positioned]] =
product match {
/**
* Constructs a parent [[Node]] for the given positioned AST parent.
*
* @param parent The positioned AST node to process.
* @return A Node representing the given parent and its children.
*/
private def buildParent(parent: Ast.Positioned): Node[Positioned, Positioned] = {
val children = processChildren(parent)
Node(parent, children)
}

/**
* Processes the children of the given parent node as independent parent nodes.
*
* @param parent The parent node whose children are to be processed.
* @return A list of nodes representing the children of the given parent node.
*/
private def processChildren(parent: Any): List[Node[Ast.Positioned, Ast.Positioned]] =
parent match {
case product: Product =>
product
.productIterator
.toList
.collect(positionedProducts)
.collect(processParent)
.flatten

case item =>
logger.trace(s"Not a product: $item: ${item.getClass}")
List.empty
}

private def buildMany(products: Seq[Any]): Seq[Node[Ast.Positioned, Ast.Positioned]] =
/**
* Constructs parent [[Node]] objects for each object of type [[Ast.Positioned]] in the given sequence of products.
*
* @param products A sequence of items to process, each representing a parent node.
* @return A sequence of Nodes, each representing a parent node.
*/
private def buildParents(products: Seq[Any]): Seq[Node[Ast.Positioned, Ast.Positioned]] =
products
.collect(positionedProducts)
.collect(processParent)
.flatten

private def positionedProducts: PartialFunction[Any, Seq[Node[Ast.Positioned, Ast.Positioned]]] = {
case positioned: Positioned =>
val children = buildOne(positioned)
List(Node(positioned, children))
/**
* Processes a product containing various types within an AST, checking for the existence
* of an [[Ast.Positioned]] type and processing it accordingly.
*
* @return A partial function that processes input of any type and returns a sequence of Nodes,
* each representing a parent node.
*/
private def processParent: PartialFunction[Any, Seq[Node[Ast.Positioned, Ast.Positioned]]] = {
case parent: Positioned =>
List(buildParent(parent))

case (left: Positioned, right: Positioned) =>
val leftChildren = buildOne(left)
val rightChildren = buildOne(right)
List(
Node(left, leftChildren),
Node(right, rightChildren)
buildParent(left),
buildParent(right)
)

case Some(positioned: Positioned) =>
positionedProducts(positioned)
case positions: Seq[_] =>
buildParents(positions)

case Some(tuple @ (_: Positioned, _: Positioned)) =>
positionedProducts(tuple)
case Some(product) =>
processParent(product)

case positions: Seq[_] =>
buildMany(positions)
case Right(product) =>
processParent(product)

case Some(positions: Seq[_]) =>
buildMany(positions)
case Left(product) =>
processParent(product)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import org.scalatest.Assertions.fail
object TestCodeUtil {

/** Use this in your test-case for */
private val SEARCH_INDICATOR =
val SEARCH_INDICATOR =
"@@"

def codeLines(code: String): Array[String] =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ object PC extends StrictImplicitLogging {
Workspace.buildChanged(
buildURI = fileURI,
code = code,
workspace = aware
workspace = aware,
buildErrors = pcState.buildErrors
)

val newPCState =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import org.alephium.ralph.lsp.pc.log.ClientLogger
import org.alephium.ralph.lsp.pc.search.completion.{Suggestion, CodeCompletionProvider}
import org.alephium.ralph.lsp.pc.search.gotodef.GoToDefinitionProvider
import org.alephium.ralph.lsp.pc.sourcecode.{SourceLocation, SourceCodeState}
import org.alephium.ralph.lsp.pc.util.URIUtil
import org.alephium.ralph.lsp.pc.workspace.{WorkspaceState, WorkspaceSearcher}

import java.net.URI
Expand Down Expand Up @@ -76,6 +77,93 @@ object CodeProvider {
workspace: WorkspaceState.IsSourceAware
)(implicit provider: CodeProvider[A],
logger: ClientLogger): Option[Either[CompilerMessage.Error, Iterator[A]]] =
// if the fileURI belongs to the workspace, then search just within that workspace
if (URIUtil.contains(workspace.build.contractURI, fileURI))
searchWorkspace[A](
line = line,
character = character,
fileURI = fileURI,
workspace = workspace
)
else // else search all source files
searchWorkspaceAndDependencies[A](
line = line,
character = character,
fileURI = fileURI,
workspace = workspace
)

/**
* Executes search on dependencies and the workspace that can use this dependency.
*
* @param character Character offset on a line in a document (zero-based).
* @param fileURI The text document's uri.
* @param workspace Current workspace state.
* @tparam A The type to search.
*/
private def searchWorkspaceAndDependencies[A](
line: Int,
character: Int,
fileURI: URI,
workspace: WorkspaceState.IsSourceAware
)(implicit provider: CodeProvider[A],
logger: ClientLogger): Option[Either[CompilerMessage.Error, Iterator[A]]] =
// Search on dependencies should only run for go-to definitions requests. Code-completion is ignored.
if (provider == CodeProvider.goToDefinition)
workspace
.build
.dependencies
.find { // find the dependency where this search was executed
dependency =>
URIUtil.contains(dependency.build.contractURI, fileURI)
}
.flatMap {
dependency =>
// merge all source files of all dependencies, because dependencies themselves could be interdependent.
val dependencySourceCode =
workspace
.build
.dependencies
.flatMap(_.sourceCode)

// merge all dependencies and workspace source-files.
val mergedSourceCode =
workspace.sourceCode ++ dependencySourceCode

// create one workspace with all source-code.
val mergedWorkspace =
WorkspaceState.UnCompiled(
build = dependency.build,
sourceCode = mergedSourceCode
)

// execute search on that one workspace
searchWorkspace[A](
line = line,
character = character,
fileURI = fileURI,
workspace = mergedWorkspace
)
}
else
None

/**
* Execute search at cursor position within the current workspace state.
*
* @param line Line position in a document (zero-based).
* @param character Character offset on a line in a document (zero-based).
* @param fileURI The text document's uri.
* @param workspace Current workspace state.
* @tparam A The type to search.
*/
private def searchWorkspace[A](
line: Int,
character: Int,
fileURI: URI,
workspace: WorkspaceState.IsSourceAware
)(implicit provider: CodeProvider[A],
logger: ClientLogger): Option[Either[CompilerMessage.Error, Iterator[A]]] =
WorkspaceSearcher
.findParsed( // find the parsed file where this search was executed.
fileURI = fileURI,
Expand Down
Loading

0 comments on commit d8f82ff

Please sign in to comment.