Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2019 Ossum, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
package com.ossuminc.riddl.passes.symbols
import com.ossuminc.riddl.language.AST.*
import com.ossuminc.riddl.language.Messages
import com.ossuminc.riddl.passes.PassOutput
import com.ossuminc.riddl.passes.symbols.Symbols.*
import scala.collection.mutable
import scala.reflect.{ClassTag, classTag}
/** Output from the Symbols Pass
* @param messages
* The error messages generated by the pass
* @param symTab
* The SymbolTable that handles identifier translation to definitions
*/
case class SymbolsOutput(
root: Root = Root.empty,
messages: Messages.Messages = Messages.empty,
symTab: SymTab = Symbols.emptySymTab,
parentage: Parentage = Symbols.emptyParentage
) extends PassOutput {
/** Get the parent of a definition
*
* @param definition
* The definition whose parent is to be sought.
* @return
* optionally, the parent definition of the given definition
*/
def parentOf(definition: Definition): Option[Parent] =
parentage.get(definition) match {
case Some(parents) => parents.headOption
case None => None
}
/** Get all parents of a definition
*
* @param definition
* The defintiion whose parents are to be sought.
* @return
* the sequence of ParentDefOf parents or empty if none.
*/
def parentsOf(definition: Definition): Parents = {
parentage.get(definition) match {
case Some(list) => list
case None => Parents.empty
}
}
/**
* Find the bounded context in which a give named value is defined
* @param definition
* The [[com.ossuminc.riddl.language.AST.Definition]] whose [[com.ossuminc.riddl.language.AST.Context]] should be
* determined
* @return
* An [[scala.Option]] either providing `Some[Context]`, if found, or `None`, if not.
*/
def contextOf(definition: Definition): Option[Context] = {
definition match {
case c: Context =>
Some(c)
case _ =>
val parents = parentsOf(definition)
val tail = parents.dropWhile(_.getClass != classOf[Context])
val result = tail.headOption.asInstanceOf[Option[Context]]
result
}
}
/** Get the full path of a definition
*
* @param definition
* The definition for which the path name is sought.
* @return
* A list of strings from leaf to root giving the names of the definition and its parents.
*/
def pathOf(definition: Definition): PathNames = {
definition.id.value +: parentsOf(definition).map(_.id.value)
}
private def hasSameParentNames(id: PathNames, parents: Parents): Boolean = {
val containerNames = id.drop(1)
val parentNames = parents.map(_.id.value)
containerNames.zip(parentNames).forall { case (containerName, parentName) =>
containerName == parentName
}
}
/** The result of a lookupSymbol request A lookupSymbol request returns a list of tuples that contain the generic
* definition, as a Definition, and, if the definition matches the type of interest, D, then an Option[D] for
* convenience.
*/
type LookupResult[D <: Definition] = List[(Definition, Option[D])]
/** Look up a symbol in the table
*
* @param id
* The multi-part identifier of the symbol, from leaf to root, that is from most nested to least nested.
* @tparam D
* The expected type of definition
* @return
* A list of matching definitions of 2-tuples giving the definition as a Definition type and optionally as the
* requested type
*/
def lookupSymbol[D <: Definition: ClassTag](
id: PathNames
): LookupResult[D] = {
require(id.nonEmpty, "No name elements provided to lookupSymbol")
val clazz = classTag[D].runtimeClass
val nameList = id.reverse
val leafName = id.head
symTab.get(leafName) match {
case Some(set) =>
set
.filter { case (_: Definition, parents: Parents) =>
// whittle down the list of matches to the ones whose parents names
// have the same as the nameList provided
hasSameParentNames(nameList, parents)
}
.map { case (d: Definition, _: Parents) =>
// If a name match is also the same type as desired by the caller
// then give them the definition in the requested type, optionally
if clazz.isInstance(d) then { (d, Option(d.asInstanceOf[D])) }
else { (d, None) }
}
.toList
case None =>
// Symbol wasn't found
List.empty
}
}
/** Look up a symbol in the table
*
* @param names
* The multi-part identifier of the symbol, from leaf to root, that is from most nested to least nested.
* @return
* A list of matching definitions of 2-tuples giving the definition as a Definition type and optionally as the
* requested type
*/
def lookupParentage(
names: PathNames
): List[Symbols.SymTabItem] = {
require(names.nonEmpty, "No name elements provided to lookupSymbol")
val leafName = names.head
symTab.get(leafName) match {
case Some(set) =>
set.filter { case (_: Definition, parents: Parents) =>
// whittle down the list of matches to the ones whose parents names
// have the same as the nameList provided
hasSameParentNames(names, parents)
}.toList
case None =>
// Symbol wasn't found
List.empty[Symbols.SymTabItem]
}
}
def lookup[D <: Definition: ClassTag](
id: PathNames
): List[D] = {
require(id.nonEmpty, "No name elements provided to lookup")
val clazz = classTag[D].runtimeClass
val leafName = id.head
symTab.get(leafName) match {
case Some(set) =>
val result = set
.filter { case (d: Definition, parents: Parents) =>
if clazz.isInstance(d) then {
// It is in the result set as long as the container names
// given in the provided id are the same as the container
// names in the symbol table.
hasSameParentNames(id, parents)
} else { false }
}
.map(_._1.asInstanceOf[D])
result.toList
case None => List.empty[D]
}
}
def foreachOverloadedSymbol(f: Seq[Seq[Definition]] => Unit): Unit = {
val overloads = symTab.filterNot(_._1.isEmpty).filter(_._2.size > 1)
val defs = overloads.toSeq.map(_._2).map(_.map(_._1).toSeq)
f(defs)
}
}