Merge branch 'main' into event-throttle-users-guide

This commit is contained in:
Rob Bocchino 2025-11-04 13:47:08 -08:00
commit ab572348d0
204 changed files with 3704 additions and 1308 deletions

View File

@ -2,8 +2,30 @@
== Requirements
* A Unix environment, such as Linux, Mac OS, or the Windows Subsystem for Linux.
* The https://www.scala-sbt.org[Simple Build Tool (sbt)] for Scala.
. A Unix environment, such as Linux, Mac OS, or the Windows Subsystem for Linux.
. The https://www.scala-sbt.org[Simple Build Tool (sbt)] for Scala.
. Version 11 of the Java Development Kit (JDK).
If you have a different version of Java installed on your system, then
you can do the following:
.. Install version 11 of the JDK.
For example, in MacPorts you can run
+
[source,bash]
----
% sudo port install openjdk11-graalvm
----
.. Set the environment variable `JAVA_HOME` to the home directory associated
with the installation.
For example, on Mac OS:
+
[source,bash]
----
% export JAVA_HOME=/Library/Java/JavaVirtualMachines/openjdk11-graalvm/Contents/Home
----
== Installing
@ -117,7 +139,7 @@ For example, on Mac OS:
+
[source,bash]
----
% export GRAALVM_JAVA_HOME=Library/Java/JavaVirtualMachines/openjdk11-graalvm/Contents/Home
% export GRAALVM_JAVA_HOME=/Library/Java/JavaVirtualMachines/openjdk11-graalvm/Contents/Home
----
. Run `sudo $GRAALVM_JAVA_HOME/bin/gu install native-image`

View File

@ -8,6 +8,9 @@
{
"name":"[Lio.circe.Encoder;"
},
{
"name":"[Ljava.io.File;"
},
{
"name":"[Ljava.lang.String;"
},
@ -1259,42 +1262,6 @@
"name":"fpp.compiler.codegen.AnalysisJsonEncoder$$anon$1909",
"fields":[{"name":"0bitmap$1769"}]
},
{
"name":"fpp.compiler.codegen.AnalysisJsonEncoder$$anon$1910",
"fields":[{"name":"0bitmap$1768"}]
},
{
"name":"fpp.compiler.codegen.AnalysisJsonEncoder$$anon$1911",
"fields":[{"name":"0bitmap$1760"}]
},
{
"name":"fpp.compiler.codegen.AnalysisJsonEncoder$$anon$1912",
"fields":[{"name":"0bitmap$1761"}]
},
{
"name":"fpp.compiler.codegen.AnalysisJsonEncoder$$anon$1913",
"fields":[{"name":"0bitmap$1762"}]
},
{
"name":"fpp.compiler.codegen.AnalysisJsonEncoder$$anon$1914",
"fields":[{"name":"0bitmap$1763"}]
},
{
"name":"fpp.compiler.codegen.AnalysisJsonEncoder$$anon$1915",
"fields":[{"name":"0bitmap$1764"}]
},
{
"name":"fpp.compiler.codegen.AnalysisJsonEncoder$$anon$1916",
"fields":[{"name":"0bitmap$1765"}]
},
{
"name":"fpp.compiler.codegen.AnalysisJsonEncoder$$anon$1917",
"fields":[{"name":"0bitmap$1766"}]
},
{
"name":"fpp.compiler.codegen.AnalysisJsonEncoder$$anon$1918",
"fields":[{"name":"0bitmap$1767"}]
},
{
"name":"fpp.compiler.codegen.AnalysisJsonEncoder$$anon$192",
"fields":[{"name":"0bitmap$183"}]

View File

@ -22,7 +22,7 @@ case class Analysis(
/** The set of files included when parsing input */
includedFileSet: Set[File] = Set(),
/** A map from pairs (spec loc kind, qualified name) to spec locs. */
locationSpecifierMap: Map[(Ast.SpecLoc.Kind, Name.Qualified), Ast.SpecLoc] = Map(),
locationSpecifierMap: Map[(Ast.SpecLoc.Kind, Name.Qualified), AstNode[Ast.SpecLoc]] = Map(),
/** A list of unqualified names representing the enclosing scope names,
* with the innermost name at the head of the list. For exapmle, inside
* module B where B is inside A and A is at the top level, the module name
@ -80,7 +80,9 @@ case class Analysis(
/** Whether dictionary generation is required */
dictionaryGeneration: Boolean = false,
/** The mapping from nodes to implied uses */
impliedUseMap: Map[AstNode.Id, ImpliedUse.Uses] = Map()
impliedUseMap: Map[AstNode.Id, ImpliedUse.Uses] = Map(),
/** The set of symbols defined with a dictionary specifier */
dictionarySymbolSet: Set[Symbol] = Set()
) {
/** Gets the qualified name of a symbol */
@ -394,6 +396,9 @@ case class Analysis(
s"\n\n${Locations.get(id)}\nbecause this type is not displayable$reason"
}
this.typeMap(id) match {
case a: Type.AliasType =>
val id = a.node._2.data.typeName.id
getElementReason(id)
case a: Type.Array =>
val id = a.node._2.data.eltType.id
getElementReason(id)

View File

@ -0,0 +1,55 @@
package fpp.compiler.analysis
import fpp.compiler.ast._
import fpp.compiler.util._
/** Check dictionary definitions */
object CheckDictionaryDefs
extends Analyzer
with ModuleAnalyzer
{
def checkConstantDef(a: Analysis, s: Symbol.Constant) =
if !s.isDictionaryDef
then Right(a)
else
val id = s.getNodeId
val t = a.typeMap(id)
def result =
val a1 = a.copy(dictionarySymbolSet = a.dictionarySymbolSet + s)
Right(a1)
def error =
val loc = Locations.get(id)
val msg = "dictionary constant must have a numeric, Boolean, string, or enum type"
Left(SemanticError.InvalidType(loc, msg))
t match
case _: Type.String | Type.Boolean | _: Type.Enum => result
case _ => if t.isNumeric then result else error
def checkTypeDef(a: Analysis, s: Symbol) =
if s.isDictionaryDef
then
for {
_ <- a.checkDisplayableType(
s.getNodeId,
"dictionary type is not displayable"
)
} yield a.copy(dictionarySymbolSet = a.dictionarySymbolSet + s)
else Right(a)
override def defAliasTypeAnnotatedNode(a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefAliasType]]) =
checkTypeDef(a, Symbol.AliasType(aNode))
override def defArrayAnnotatedNode(a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefArray]]) =
checkTypeDef(a, Symbol.Array(aNode))
override def defEnumAnnotatedNode(a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefEnum]]) =
checkTypeDef(a, Symbol.Enum(aNode))
override def defStructAnnotatedNode(a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefStruct]]) =
checkTypeDef(a, Symbol.Struct(aNode))
override def defConstantAnnotatedNode(a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefConstant]]) =
checkConstantDef(a, Symbol.Constant(aNode))
}

View File

@ -33,9 +33,10 @@ object CheckSemantics {
_ <- CheckComponentInstanceDefs.checkIdRanges(a)
a <- CheckStateMachineDefs.visitList(a, tul, CheckStateMachineDefs.transUnit)
a <- CheckTopologyDefs.visitList(a, tul, CheckTopologyDefs.transUnit)
a <- ConstructDictionaryMap.visitList(a, tul, ConstructDictionaryMap.transUnit)
a <- BuildSpecLocMap.visitList(a, tul, BuildSpecLocMap.transUnit)
a <- CheckSpecLocs.visitList(a, tul, CheckSpecLocs.transUnit)
a <- CheckDictionaryDefs.visitList(a, tul, CheckDictionaryDefs.transUnit)
a <- ConstructDictionaryMap.visitList(a, tul, ConstructDictionaryMap.transUnit)
}
yield a
}

View File

@ -9,58 +9,116 @@ object CheckSpecLocs
with ModuleAnalyzer
{
override def defAbsTypeAnnotatedNode(a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefAbsType]]) = {
val (_, node, _) = aNode
val name = node.data.name
checkSpecLoc(a, Ast.SpecLoc.Type, name, node)
}
override def defAbsTypeAnnotatedNode(
a: Analysis,
aNode: Ast.Annotated[AstNode[Ast.DefAbsType]]
) = checkSpecLoc(a, Ast.SpecLoc.Type, Symbol.AbsType(aNode))
override def defArrayAnnotatedNode(a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefArray]]) = {
val (_, node, _) = aNode
val name = node.data.name
checkSpecLoc(a, Ast.SpecLoc.Type, name, node)
}
override def defAliasTypeAnnotatedNode(
a: Analysis,
aNode: Ast.Annotated[AstNode[Ast.DefAliasType]]
) = checkSpecLoc(a, Ast.SpecLoc.Type, Symbol.AliasType(aNode))
override def defConstantAnnotatedNode(a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefConstant]]) = {
val (_, node, _) = aNode
val name = node.data.name
checkSpecLoc(a, Ast.SpecLoc.Constant, name, node)
}
override def defArrayAnnotatedNode(
a: Analysis,
aNode: Ast.Annotated[AstNode[Ast.DefArray]]
) = checkSpecLoc(a, Ast.SpecLoc.Type, Symbol.Array(aNode))
override def defEnumAnnotatedNode(a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefEnum]]) = {
val (_, node, _) = aNode
val name = node.data.name
checkSpecLoc(a, Ast.SpecLoc.Type, name, node)
}
override def defComponentAnnotatedNode(
a: Analysis,
aNode: Ast.Annotated[AstNode[Ast.DefComponent]]
) = checkSpecLoc(a, Ast.SpecLoc.Component, Symbol.Component(aNode))
override def defPortAnnotatedNode(a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefPort]]) = {
val (_, node, _) = aNode
val name = node.data.name
checkSpecLoc(a, Ast.SpecLoc.Port, name, node)
}
override def defComponentInstanceAnnotatedNode(
a: Analysis,
aNode: Ast.Annotated[AstNode[Ast.DefComponentInstance]]
) = checkSpecLoc(a, Ast.SpecLoc.ComponentInstance, Symbol.ComponentInstance(aNode))
override def defStructAnnotatedNode(a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefStruct]]) = {
val (_, node, _) = aNode
val name = node.data.name
checkSpecLoc(a, Ast.SpecLoc.Type, name, node)
}
override def defConstantAnnotatedNode(
a: Analysis,
aNode: Ast.Annotated[AstNode[Ast.DefConstant]]
) = checkSpecLoc(a, Ast.SpecLoc.Constant, Symbol.Constant(aNode))
private def checkSpecLoc[T](
override def defEnumAnnotatedNode(
a: Analysis,
aNode: Ast.Annotated[AstNode[Ast.DefEnum]]
) = checkSpecLoc(a, Ast.SpecLoc.Type, Symbol.Enum(aNode))
override def defInterfaceAnnotatedNode(
a: Analysis,
aNode: Ast.Annotated[AstNode[Ast.DefInterface]]
) = checkSpecLoc(a, Ast.SpecLoc.Interface, Symbol.Interface(aNode))
override def defPortAnnotatedNode(
a: Analysis,
aNode: Ast.Annotated[AstNode[Ast.DefPort]]
) = checkSpecLoc(a, Ast.SpecLoc.Port, Symbol.Port(aNode))
override def defStructAnnotatedNode(
a: Analysis,
aNode: Ast.Annotated[AstNode[Ast.DefStruct]]
) = checkSpecLoc(a, Ast.SpecLoc.Type, Symbol.Struct(aNode))
override def defTopologyAnnotatedNode(
a: Analysis,
aNode: Ast.Annotated[AstNode[Ast.DefTopology]]
) = checkSpecLoc(a, Ast.SpecLoc.Topology, Symbol.Topology(aNode))
private def checkSpecLoc(
a: Analysis,
kind: Ast.SpecLoc.Kind,
name: Name.Unqualified,
node: AstNode[T]
symbol: Symbol
) = for {
a <- checkPath(a, kind, symbol)
a <- checkDictionarySpecifier(a, kind, symbol)
} yield a
private def checkPath[T](
a: Analysis,
kind: Ast.SpecLoc.Kind,
symbol: Symbol
): Result = {
val name = symbol.getUnqualifiedName
val id = symbol.getNodeId
val qualifiedName = Name.Qualified(a.scopeNameList.reverse, name)
val actualLoc = Locations.get(node.id).tuLocation
val actualLoc = Locations.get(id).tuLocation
a.locationSpecifierMap.get((kind, qualifiedName)) match {
case Some(specLoc) => {
case Some(node) => {
val specLoc = node.data
val specifierLoc = Locations.get(specLoc.file.id)
val specifiedJavaPath = specifierLoc.getRelativePath(specLoc.file.data)
val specifiedJavaPath =
specifierLoc.getRelativePath(specLoc.file.data)
val specifiedPath = File.Path(specifiedJavaPath).toString
val actualPath = actualLoc.file.toString
if (specifiedPath == actualPath) Right(a)
else Left(SemanticError.IncorrectSpecLoc(specifierLoc, specifiedPath, actualLoc))
else Left(
SemanticError.IncorrectLocationPath(
specifierLoc,
specifiedPath,
actualLoc
)
)
}
case None => Right(a)
}
}
private def checkDictionarySpecifier(
a: Analysis,
kind: Ast.SpecLoc.Kind,
symbol: Symbol
) = {
val name = a.getQualifiedName(symbol)
val id = symbol.getNodeId
val defLoc = Locations.get(id)
a.locationSpecifierMap.get((kind, name)) match {
case Some(node) => {
val specifierLoc = Locations.get(node.id)
if symbol.isDictionaryDef == node.data.isDictionaryDef
then Right(a)
else Left(
SemanticError.IncorrectDictionarySpecifier(specifierLoc, defLoc)
)
}
case None => Right(a)
}

View File

@ -17,14 +17,34 @@ object BuildSpecLocMap extends ModuleAnalyzer {
val key = (spec.kind, qualifiedName)
a.locationSpecifierMap.get(key) match {
case None => {
val map = a.locationSpecifierMap + (key -> spec)
val map = a.locationSpecifierMap + (key -> specNode)
Right(a.copy(locationSpecifierMap = map))
}
case Some(spec1) =>
for { _ <- checkPathConsistency(spec, spec1) } yield a
case Some(specNode1) =>
for {
_ <- checkPathConsistency(spec, specNode1.data)
_ <- checkDictionarySpecifierConsistency(specNode, specNode1)
} yield a
}
}
private def checkDictionarySpecifierConsistency(
specNode1: AstNode[Ast.SpecLoc],
specNode2: AstNode[Ast.SpecLoc]
): Result.Result[Unit] = {
val spec1 = specNode1.data
val spec2 = specNode2.data
if(spec1.isDictionaryDef == spec2.isDictionaryDef) then
Right(())
else
Left(
SemanticError.InconsistentDictionarySpecifier(
Locations.get(specNode1.id),
Locations.get(specNode2.id),
)
)
}
private def checkPathConsistency(
spec1: Ast.SpecLoc,
spec2: Ast.SpecLoc
@ -34,7 +54,7 @@ object BuildSpecLocMap extends ModuleAnalyzer {
if (path1 == path2)
Right(())
else Left(
SemanticError.InconsistentSpecLoc(
SemanticError.InconsistentLocationPath(
Locations.get(spec1.file.id),
path1,
Locations.get(spec2.file.id),

View File

@ -23,6 +23,7 @@ object ComputeDependencies {
a <- BuildSpecLocMap.visitList(a, tul, BuildSpecLocMap.transUnit)
a <- ConstructImpliedUseMap.visitList(a, tul, ConstructImpliedUseMap.transUnit)
a <- MapUsesToLocs.visitList(a, tul, MapUsesToLocs.transUnit)
a <- Right(addDictionaryDependencies(a))
}
yield {
val includedFileSet = a.includedFileSet
@ -31,4 +32,16 @@ object ComputeDependencies {
}
}
// Adds the dictionary dependencies to the dependency file set
private def addDictionaryDependencies(a: Analysis) = {
val dfs = a.locationSpecifierMap.foldLeft (a.dependencyFileSet) {
case (s, (_, node)) => {
if node.data.isDictionaryDef
then s + Locations.get(node.data.file.id).file
else s
}
}
a.copy(dependencyFileSet = dfs)
}
}

View File

@ -60,7 +60,7 @@ object MapUsesToLocs extends BasicUseAnalyzer {
nameList match {
case Nil => None
case head :: tail => a.locationSpecifierMap.get((kind, head)) match {
case specLoc @ Some(_) => specLoc
case opt @ Some(_) => opt.map(_.data)
case None => findLocation(tail)
}
}

View File

@ -9,39 +9,47 @@ final case class DictionaryUsedSymbols(a: Analysis, t: Topology) {
d.copy(usedSymbolSet = getUsedSymbolSet)
private def getUsedSymbolSet: Set[Symbol] =
t.instanceMap.keys.toSet.flatMap(getUsedSymbolsForInstance) ++
a.getImpliedUses(ImpliedUse.Kind.Type, t.aNode._2.id).map(iu => a.useDefMap(iu.id)) ++
a.getImpliedUses(ImpliedUse.Kind.Constant, t.aNode._2.id).map(iu => a.useDefMap(iu.id))
val kinds = Set(ImpliedUse.Kind.Type, ImpliedUse.Kind.Constant)
val impliedUses = kinds.flatMap(
k => a.getImpliedUses(k, t.aNode._2.id).map(iu => a.useDefMap(iu.id))
)
val ss = Set.concat(
t.instanceMap.keys.toSet.flatMap(getUsedSymbolsForInstance),
impliedUses,
a.dictionarySymbolSet
)
UsedSymbols.resolveUses(a, ss)
private def getUsedSymbolsForInstance(ci: ComponentInstance) = {
val component = ci.component
val a1 = a.copy(usedSymbolSet = Set())
val commandSymbols = getUsedSymbolsForSpecifier(
component.commandMap,
{
case Command.NonParam(aNode, _) =>
UsedSymbols.specCommandAnnotatedNode(a, aNode)
UsedSymbols.specCommandAnnotatedNode(a1, aNode)
case _ => Right(a.copy(usedSymbolSet = Set()))
}
)
val eventSymbols = getUsedSymbolsForSpecifier(
component.eventMap,
event => UsedSymbols.specEventAnnotatedNode(a, event.aNode)
event => UsedSymbols.specEventAnnotatedNode(a1, event.aNode)
)
val tlmChannelSymbols = getUsedSymbolsForSpecifier(
component.tlmChannelMap,
channel => UsedSymbols.specTlmChannelAnnotatedNode(a, channel.aNode)
channel => UsedSymbols.specTlmChannelAnnotatedNode(a1, channel.aNode)
)
val paramSymbols = getUsedSymbolsForSpecifier(
component.paramMap,
param => UsedSymbols.specParamAnnotatedNode(a, param.aNode)
param => UsedSymbols.specParamAnnotatedNode(a1, param.aNode)
)
val recordSymbols = getUsedSymbolsForSpecifier(
component.recordMap,
record => UsedSymbols.specRecordAnnotatedNode(a, record.aNode)
record => UsedSymbols.specRecordAnnotatedNode(a1, record.aNode)
)
val containerSymbols = getUsedSymbolsForSpecifier(
component.containerMap,
container => UsedSymbols.specContainerAnnotatedNode(a, container.aNode)
container => UsedSymbols.specContainerAnnotatedNode(a1, container.aNode)
)
Set.concat(
commandSymbols,
@ -57,11 +65,11 @@ final case class DictionaryUsedSymbols(a: Analysis, t: Topology) {
map: Map[BigInt, Specifier],
usedSymbols: Specifier => Result.Result[Analysis]
): Set[Symbol] =
map.values.toSet.flatMap {
map.values.toSet.flatMap (
specifier => {
val Right(a) = usedSymbols(specifier)
UsedSymbols.resolveUses(a, a.usedSymbolSet)
a.usedSymbolSet
}
}
)
}

View File

@ -4,7 +4,9 @@ import fpp.compiler.ast._
import fpp.compiler.util._
/** A data structure that represents a definition */
sealed trait Symbol extends SymbolInterface
sealed trait Symbol extends SymbolInterface {
def isDictionaryDef = false
}
object Symbol {
@ -13,10 +15,12 @@ object Symbol {
override def getUnqualifiedName = node._2.data.name
}
final case class AliasType(node: Ast.Annotated[AstNode[Ast.DefAliasType]]) extends Symbol {
override def isDictionaryDef = node._2.data.isDictionaryDef
override def getNodeId = node._2.id
override def getUnqualifiedName = node._2.data.name
}
final case class Array(node: Ast.Annotated[AstNode[Ast.DefArray]]) extends Symbol {
override def isDictionaryDef = node._2.data.isDictionaryDef
override def getNodeId = node._2.id
override def getUnqualifiedName = node._2.data.name
}
@ -29,10 +33,12 @@ object Symbol {
override def getUnqualifiedName = node._2.data.name
}
final case class Constant(node: Ast.Annotated[AstNode[Ast.DefConstant]]) extends Symbol {
override def isDictionaryDef = node._2.data.isDictionaryDef
override def getNodeId = node._2.id
override def getUnqualifiedName = node._2.data.name
}
final case class Enum(node: Ast.Annotated[AstNode[Ast.DefEnum]]) extends Symbol {
override def isDictionaryDef = node._2.data.isDictionaryDef
override def getNodeId = node._2.id
override def getUnqualifiedName = node._2.data.name
}
@ -57,6 +63,7 @@ object Symbol {
override def getUnqualifiedName = node._2.data.name
}
final case class Struct(node: Ast.Annotated[AstNode[Ast.DefStruct]]) extends Symbol {
override def isDictionaryDef = node._2.data.isDictionaryDef
override def getNodeId = node._2.id
override def getUnqualifiedName = node._2.data.name
}

View File

@ -189,7 +189,6 @@ object Type {
case class AliasType(
/** The AST node giving the definition */
node: Ast.Annotated[AstNode[Ast.DefAliasType]],
/** Type that this typedef points to */
aliasType: Type
) extends Type {

View File

@ -3,9 +3,38 @@ package fpp.compiler.analysis
import fpp.compiler.ast.*
import fpp.compiler.util.*
/** Compute used symbols */
/**
* Compute used symbols
*
* There are two forms of resolution:
*
* 1. Shallow resolution (don't follow uses from uses). This is used to
* generate header files. You get this by calling a visitor method
* of UsedSymbols.
*
* 2. Deep resolution (follow uses from uses). This is used to generate
* dictionary symbols. You get this by calling UsedSymbols.resolveUses.
*/
object UsedSymbols extends UseAnalyzer {
// When resolving uses, if the default value of an enum definition is an enum
// constant, then don't visit it. In this case the symbol is ignored (for
// shallow resolution) or converted to a use of this enum (for deep resolution).
// So it adds nothing to the resolution.
override def defEnumAnnotatedNode(a: Analysis, node: Ast.Annotated[AstNode[Ast.DefEnum]]) = {
val (_, node1, _) = node
val data = node1.data
for
a <- opt(typeNameNode)(a, data.typeName)
a <- visitList(a, data.constants, defEnumConstantAnnotatedNode)
a <- node._2.data.default match
case Some(en) => a.useDefMap(en.id) match
case _: Symbol.EnumConstant => Right(a)
case _ => opt(exprNode)(a, data.default)
case None => Right(a)
yield a
}
override def componentUse(
a: Analysis,
node: AstNode[Ast.QualIdent],
@ -47,7 +76,7 @@ object UsedSymbols extends UseAnalyzer {
node: AstNode[Ast.TypeName],
use: Name.Qualified
) = addSymbol(a, node)
override def portUse(
a: Analysis,
node: AstNode[Ast.QualIdent],
@ -55,14 +84,30 @@ object UsedSymbols extends UseAnalyzer {
) = addSymbol(a, node)
private def addSymbol[T](a: Analysis, node: AstNode[T]) = {
// We could convert enum constant symbols to enum symbols here.
// This would convert E.A to a use of E in shallow resolution.
// Currently we don't do this, because we convert E.A to a numeric
// constant in the generated code, so we don't need the dependency
// on E.
val symbol = a.useDefMap(node.id)
Right(a.copy(usedSymbolSet = a.usedSymbolSet + symbol))
}
/** Resolves used symbols recursively */
/** Deep resolution of used symbols
* Replaces uses of enum constants with uses of the corresponding enums */
def resolveUses(a: Analysis, ss: Set[Symbol]): Set[Symbol] = {
// When resolving uses, convert an enum constant symbol to the corresponding
// enum symbol. For example, the use E.A becomes a use of E. This is what
// we want, because E provides the definition of E.A.
def resolveEnumConstant(s: Symbol) =
s match
case Symbol.EnumConstant(node) =>
val t @ Type.Enum(enumNode, _, _) = a.typeMap(node._2.id)
Symbol.Enum(enumNode)
case _ => s
// Helper function for recursive resolution
val a1: Analysis = a.copy(usedSymbolSet = Set())
def helper(s: Symbol): Set[Symbol] = {
def resolveNode(s: Symbol): Set[Symbol] = {
val Right(a2) = s match {
case Symbol.AbsType(node) => defAbsTypeAnnotatedNode(a1, node)
case Symbol.AliasType(node) => defAliasTypeAnnotatedNode(a1, node)
@ -79,9 +124,9 @@ object UsedSymbols extends UseAnalyzer {
case Symbol.Struct(node) => defStructAnnotatedNode(a1, node)
case Symbol.Topology(node) => defTopologyAnnotatedNode(a1, node)
}
a2.usedSymbolSet.flatMap(helper) + s
a2.usedSymbolSet.flatMap(resolveNode) + resolveEnumConstant(s)
}
ss.flatMap(helper)
ss.flatMap(resolveNode)
}
}

View File

@ -78,7 +78,8 @@ object Ast {
/* Aliased type definition */
final case class DefAliasType(
name: Ident,
typeName: AstNode[TypeName]
typeName: AstNode[TypeName],
isDictionaryDef: Boolean
)
/* Array definition */
@ -87,7 +88,8 @@ object Ast {
size: AstNode[Expr],
eltType: AstNode[TypeName],
default: Option[AstNode[Expr]],
format: Option[AstNode[String]]
format: Option[AstNode[String]],
isDictionaryDef: Boolean
)
/** Component definition */
@ -112,14 +114,19 @@ object Ast {
)
/** Constant definition */
final case class DefConstant(name: Ident, value: AstNode[Expr])
final case class DefConstant(
name: Ident,
value: AstNode[Expr],
isDictionaryDef: Boolean
)
/** Enum definition */
final case class DefEnum(
name: Ident,
typeName: Option[AstNode[TypeName]],
constants: List[Annotated[AstNode[DefEnumConstant]]],
default: Option[AstNode[Expr]]
default: Option[AstNode[Expr]],
isDictionaryDef: Boolean
)
/** Enum constant definition */
@ -279,7 +286,8 @@ object Ast {
final case class DefStruct(
name: Ident,
members: List[Annotated[AstNode[StructTypeMember]]],
default: Option[AstNode[Expr]]
default: Option[AstNode[Expr]],
isDictionaryDef: Boolean
)
/** Expression */
@ -578,7 +586,8 @@ object Ast {
final case class SpecLoc(
kind: SpecLoc.Kind,
symbol: AstNode[QualIdent],
file: AstNode[String]
file: AstNode[String],
isDictionaryDef: Boolean
)
object SpecLoc {
/** Location specifier kind */

View File

@ -11,18 +11,16 @@ trait AstVisitor {
def defAbsTypeAnnotatedNode(in: In, node: Ast.Annotated[AstNode[Ast.DefAbsType]]): Out = default(in)
def defAliasTypeAnnotatedNode(in: In, node: Ast.Annotated[AstNode[Ast.DefAliasType]]): Out = default(in)
def defActionAnnotatedNode(in: In, node: Ast.Annotated[AstNode[Ast.DefAction]]): Out = default(in)
def defAliasTypeAnnotatedNode(in: In, node: Ast.Annotated[AstNode[Ast.DefAliasType]]): Out = default(in)
def defArrayAnnotatedNode(in: In, node: Ast.Annotated[AstNode[Ast.DefArray]]): Out = default(in)
def defChoiceAnnotatedNode(in: In, node: Ast.Annotated[AstNode[Ast.DefChoice]]): Out = default(in)
def defComponentAnnotatedNode(in: In, node: Ast.Annotated[AstNode[Ast.DefComponent]]): Out = default(in)
def defInterfaceAnnotatedNode(in: In, node: Ast.Annotated[AstNode[Ast.DefInterface]]): Out = default(in)
def defComponentInstanceAnnotatedNode(in: In, node: Ast.Annotated[AstNode[Ast.DefComponentInstance]]): Out = default(in)
def defConstantAnnotatedNode(in: In, node: Ast.Annotated[AstNode[Ast.DefConstant]]): Out = default(in)
@ -31,6 +29,8 @@ trait AstVisitor {
def defGuardAnnotatedNode(in: In, node: Ast.Annotated[AstNode[Ast.DefGuard]]): Out = default(in)
def defInterfaceAnnotatedNode(in: In, node: Ast.Annotated[AstNode[Ast.DefInterface]]): Out = default(in)
def defModuleAnnotatedNode(in: In, node: Ast.Annotated[AstNode[Ast.DefModule]]): Out = default(in)
def defPortAnnotatedNode(in: In, node: Ast.Annotated[AstNode[Ast.DefPort]]): Out = default(in)

View File

@ -16,7 +16,7 @@ object AstWriter extends AstVisitor with LineUtils {
in: Unit,
aNode: Ast.Annotated[AstNode[Ast.DefAliasType]]): Out = {
val (_, node, _) = aNode
lines("def alias type") ++ (
prefixWithDictionary("def alias type", node.data.isDictionaryDef) ++ (
ident(node.data.name) ++
typeNameNode(node.data.typeName)
).map(indentIn)
@ -49,7 +49,7 @@ object AstWriter extends AstVisitor with LineUtils {
) = {
val (_, node, _) = aNode
val data = node.data
lines("def array") ++
prefixWithDictionary("def array", data.isDictionaryDef) ++
List.concat(
ident(data.name),
addPrefix("size", exprNode) (data.size),
@ -128,8 +128,10 @@ object AstWriter extends AstVisitor with LineUtils {
) = {
val (_, node, _) = aNode
val data = node.data
lines("def constant") ++
(ident(data.name) ++ exprNode(data.value)).map(indentIn)
prefixWithDictionary("def constant", data.isDictionaryDef) ++ (
ident(data.name) ++
exprNode(data.value)
).map(indentIn)
}
override def defEnumAnnotatedNode(
@ -138,7 +140,7 @@ object AstWriter extends AstVisitor with LineUtils {
) = {
val (_, node, _) = aNode
val data = node.data
lines("def enum") ++
prefixWithDictionary("def enum", data.isDictionaryDef) ++
List.concat(
ident(data.name),
linesOpt(typeNameNode, data.typeName),
@ -229,7 +231,7 @@ object AstWriter extends AstVisitor with LineUtils {
) = {
val (_, node, _) = aNode
val data = node.data
lines("def struct") ++
prefixWithDictionary("def struct", data.isDictionaryDef) ++
(
ident(data.name) ++
data.members.flatMap(annotateNode(structTypeMember)) ++
@ -949,4 +951,9 @@ object AstWriter extends AstVisitor with LineUtils {
private def visibility(v: Ast.Visibility) = v.toString
private def prefixWithDictionary(s: String, isDictionaryDef: Boolean) =
if isDictionaryDef then
lines(s"dictionary $s")
else
lines(s)
}

View File

@ -124,7 +124,7 @@ object FppWriter extends AstVisitor with LineUtils {
) = {
val (_, node, _) = aNode
val data = node.data
lines(s"type ${ident(data.name)} = ").
lines(prefixWithDictionary(s"type ${ident(data.name)} = ", data.isDictionaryDef)).
join("") (typeNameNode(data.typeName))
}
@ -153,7 +153,7 @@ object FppWriter extends AstVisitor with LineUtils {
) = {
val (_, node, _) = aNode
val data = node.data
lines(s"array ${ident(data.name)} = [").
lines(prefixWithDictionary(s"array ${ident(data.name)} = [", data.isDictionaryDef)).
join ("") (exprNode(data.size)).
join ("] ") (typeNameNode(data.eltType)).
joinOpt (data.default) (" default ") (exprNode).
@ -223,7 +223,8 @@ object FppWriter extends AstVisitor with LineUtils {
) = {
val (_, node, _) = aNode
val data = node.data
lines(s"constant ${ident(data.name)}").join (" = ") (exprNode(data.value))
lines(prefixWithDictionary(s"constant ${ident(data.name)}", data.isDictionaryDef)).
join (" = ") (exprNode(data.value))
}
override def defEnumAnnotatedNode(
@ -232,7 +233,7 @@ object FppWriter extends AstVisitor with LineUtils {
) = {
val (_, node, _) = aNode
val data = node.data
lines(s"enum ${ident(data.name)}").
lines(prefixWithDictionary(s"enum ${ident(data.name)}", data.isDictionaryDef)).
joinOpt (data.typeName) (": ") (typeNameNode).
joinNoIndent (" ") (
addBraces(data.constants.flatMap(annotateNode(defEnumConstant)))
@ -320,7 +321,7 @@ object FppWriter extends AstVisitor with LineUtils {
) = {
val (_, node, _) = aNode
val data = node.data
lines(s"struct ${ident(data.name)}").
lines(prefixWithDictionary(s"struct ${ident(data.name)}", data.isDictionaryDef)).
joinNoIndent (" ") (
addBraces(data.members.flatMap(annotateNode(structTypeMember)))
).
@ -537,7 +538,7 @@ object FppWriter extends AstVisitor with LineUtils {
val (_, node, _) = aNode
val data = node.data
val kind = data.kind.toString
lines(s"locate ${kind}").
lines(s"locate ${prefixWithDictionary(kind, data.isDictionaryDef)}").
join (" ") (qualIdent(data.symbol.data)).
join (" at ") (string(data.file.data))
}
@ -896,4 +897,9 @@ object FppWriter extends AstVisitor with LineUtils {
private def unop(op: Ast.Unop) = op.toString
private def prefixWithDictionary(s: String, isDictionaryDef: Boolean) =
if isDictionaryDef then
s"dictionary $s"
else
s
}

View File

@ -314,7 +314,7 @@ object AnalysisJsonEncoder extends JsonEncoder{
Encoder.instance(_.toList.asJson)
private implicit val locationSpecifierMapEncoder:
Encoder[Map[(Ast.SpecLoc.Kind, Name.Qualified), Ast.SpecLoc]] =
Encoder[Map[(Ast.SpecLoc.Kind, Name.Qualified), AstNode[Ast.SpecLoc]]] =
Encoder.instance(_.toList.asJson)
private implicit val portNumberMapEncoder: Encoder[Map[Connection, Int]] =
@ -353,7 +353,8 @@ object AnalysisJsonEncoder extends JsonEncoder{
"typeMap" -> a.typeMap.asJson,
"useDefMap" -> a.useDefMap.asJson,
"valueMap" -> a.valueMap.asJson,
"stateMachineMap" -> a.stateMachineMap.asJson
"stateMachineMap" -> a.stateMachineMap.asJson,
"dictionarySymbolSet" -> a.dictionarySymbolSet.asJson
)
}

View File

@ -36,7 +36,7 @@ object LocateDefsFppWriter extends AstVisitor with LineUtils {
) = {
val (_, node, _) = aNode
val data = node.data
writeSpecLoc(s, Ast.SpecLoc.Type, data.name, node)
writeSpecLoc(s, Ast.SpecLoc.Type, data.name, node, data.isDictionaryDef)
}
override def defArrayAnnotatedNode(
@ -45,7 +45,7 @@ object LocateDefsFppWriter extends AstVisitor with LineUtils {
) = {
val (_, node, _) = aNode
val data = node.data
writeSpecLoc(s, Ast.SpecLoc.Type, data.name, node)
writeSpecLoc(s, Ast.SpecLoc.Type, data.name, node, data.isDictionaryDef)
}
override def defComponentAnnotatedNode(
@ -92,7 +92,7 @@ object LocateDefsFppWriter extends AstVisitor with LineUtils {
) = {
val (_, node, _) = aNode
val data = node.data
writeSpecLoc(s, Ast.SpecLoc.Constant, data.name, node)
writeSpecLoc(s, Ast.SpecLoc.Constant, data.name, node, data.isDictionaryDef)
}
override def defEnumAnnotatedNode(
@ -101,7 +101,7 @@ object LocateDefsFppWriter extends AstVisitor with LineUtils {
) = {
val (_, node, _) = aNode
val data = node.data
writeSpecLoc(s, Ast.SpecLoc.Type, data.name, node)
writeSpecLoc(s, Ast.SpecLoc.Type, data.name, node, data.isDictionaryDef)
}
override def defModuleAnnotatedNode(
@ -129,7 +129,7 @@ object LocateDefsFppWriter extends AstVisitor with LineUtils {
) = {
val (_, node, _) = aNode
val data = node.data
writeSpecLoc(s, Ast.SpecLoc.Type, data.name, node)
writeSpecLoc(s, Ast.SpecLoc.Type, data.name, node, data.isDictionaryDef)
}
override def defTopologyAnnotatedNode(
@ -148,7 +148,8 @@ object LocateDefsFppWriter extends AstVisitor with LineUtils {
s: State,
kind: Ast.SpecLoc.Kind,
name: String,
node: AstNode[T]
node: AstNode[T],
isDictionaryDef: Boolean = false
): Out = {
val loc = Locations.get(node.id).tuLocation
loc.file match {
@ -162,7 +163,7 @@ object LocateDefsFppWriter extends AstVisitor with LineUtils {
val baseDirPath = java.nio.file.Paths.get(baseDir).toAbsolutePath
val relativePath = baseDirPath.relativize(path)
val fileNode = AstNode.create(relativePath.normalize.toString)
val specLocNode = AstNode.create(Ast.SpecLoc(kind, qualIdentNode, fileNode))
val specLocNode = AstNode.create(Ast.SpecLoc(kind, qualIdentNode, fileNode, isDictionaryDef))
val specLocAnnotatedNode = (Nil, specLocNode, Nil)
FppWriter.specLocAnnotatedNode((), specLocAnnotatedNode)
}

View File

@ -59,7 +59,8 @@ object ArrayXmlFppWriter extends LineUtils {
AstNode.create(Ast.ExprLiteralInt(xmlSize.text)),
AstNode.create(eltType),
fppDefaultsOpt,
fppFormatOpt.map(AstNode.create(_))
fppFormatOpt.map(AstNode.create(_)),
false
)
(note ++ comment, node, Nil)
}

View File

@ -31,7 +31,7 @@ object EnumXmlFppWriter extends LineUtils {
yield {
val repType = FppBuilder.repType(file)
val default = FppBuilder.default(file)
Ast.DefEnum(name, repType, constants, default)
Ast.DefEnum(name, repType, constants, default, false)
}
def defEnumConstant(

View File

@ -99,7 +99,7 @@ object StructXmlFppWriter extends LineUtils {
structName <- file.getAttribute(file.elem, "name")
members <- structTypeMemberAnnotatedNodeList(file)
}
yield (comment, Ast.DefStruct(structName, members, None), Nil)
yield (comment, Ast.DefStruct(structName, members, None, false), Nil)
}

View File

@ -370,7 +370,7 @@ object XmlFppWriter extends LineUtils {
name <- file.getAttribute(node, "name")
constants <- defEnumConstantNodeAnnotatedList(file)(node)
}
yield (Nil, Ast.DefEnum(name, None, constants, None), Nil)
yield (Nil, Ast.DefEnum(name, None, constants, None, false), Nil)
/** Translates an enum if present in the node */
def defEnumAnnotatedOpt(file: XmlFppWriter.File)(node: scala.xml.Node):

View File

@ -47,6 +47,7 @@ object Lexer {
("cpu", CPU),
("default", DEFAULT),
("diagnostic", DIAGNOSTIC),
("dictionary", DICTIONARY),
("do", DO),
("drop", DROP),
("else", ELSE),
@ -239,6 +240,7 @@ object Lexer {
case CPU => Token.CPU()
case DEFAULT => Token.DEFAULT()
case DIAGNOSTIC => Token.DIAGNOSTIC()
case DICTIONARY => Token.DICTIONARY()
case DO => Token.DO()
case DOT => Token.DOT()
case DROP => Token.DROP()

View File

@ -74,9 +74,10 @@ object Parser extends Parsers {
}
}
private def defAliasType: Parser[Ast.DefAliasType] = {
((typeToken ~> ident) ~ (equals ~> node(typeName))) ^^ {
case ident ~ typeName => Ast.DefAliasType(ident, typeName)
def defAliasType: Parser[Ast.DefAliasType] = {
(opt(dictionary) ~ (typeToken ~> ident) ~ (equals ~> node(typeName))) ^^ {
case dictionary ~ ident ~ typeName =>
Ast.DefAliasType(ident, typeName, dictionary.isDefined)
}
}
@ -91,12 +92,12 @@ object Parser extends Parsers {
}
def defArray: Parser[Ast.DefArray] = {
(array ~>! ident <~! equals) ~!
opt(dictionary) ~ (array ~>! ident <~! equals) ~!
index ~! node(typeName) ~!
opt(default ~>! exprNode) ~!
opt(format ~>! node(literalString)) ^^ {
case name ~ size ~ eltType ~ default ~ format =>
Ast.DefArray(name, size, eltType, default, format)
case dictionary ~ name ~ size ~ eltType ~ default ~ format =>
Ast.DefArray(name, size, eltType, default, format, dictionary.isDefined)
}
}
@ -172,8 +173,9 @@ object Parser extends Parsers {
}
def defConstant: Parser[Ast.DefConstant] = {
(constant ~>! ident) ~! (equals ~>! exprNode) ^^ { case id ~ e =>
Ast.DefConstant(id, e)
opt(dictionary) ~ (constant ~>! ident) ~! (equals ~>! exprNode) ^^ {
case dictionary ~ id ~ e =>
Ast.DefConstant(id, e, dictionary.isDefined)
}
}
@ -182,12 +184,12 @@ object Parser extends Parsers {
def constants = annotatedElementSequence(node(defEnumConstant), comma, id)
(enumeration ~>! ident) ~!
opt(dictionary) ~ (enumeration ~>! ident) ~!
opt(colon ~>! node(typeName)) ~!
(lbrace ~>! constants <~! rbrace) ~!
opt(default ~>! exprNode) ^^ {
case name ~ typeName ~ constants ~ default =>
Ast.DefEnum(name, typeName, constants, default)
case dictionary ~ name ~ typeName ~ constants ~ default =>
Ast.DefEnum(name, typeName, constants, default, dictionary.isDefined)
}
}
@ -241,10 +243,10 @@ object Parser extends Parsers {
def members = annotatedElementSequence(node(structTypeMember), comma, id)
(struct ~>! ident) ~! (lbrace ~>! members <~! rbrace) ~! opt(
opt(dictionary) ~ (struct ~>! ident) ~! (lbrace ~>! members <~! rbrace) ~! opt(
default ~>! exprNode
) ^^ { case name ~ members ~ default =>
Ast.DefStruct(name, members, default)
) ^^ { case dictionary ~ name ~ members ~ default =>
Ast.DefStruct(name, members, default, dictionary.isDefined)
}
}
@ -668,24 +670,33 @@ object Parser extends Parsers {
}
}
def specLoc: Parser[Ast.SpecLoc] = {
def kind = {
def specLoc: Parser[Ast.SpecLoc] =
def maybeDictKind =
constant ^^ (_ => Ast.SpecLoc.Constant) |
typeToken ^^ (_ => Ast.SpecLoc.Type)
def nonDictKind =
component ^^ (_ => Ast.SpecLoc.Component) |
constant ^^ (_ => Ast.SpecLoc.Constant) |
instance ^^ (_ => Ast.SpecLoc.ComponentInstance) |
port ^^ (_ => Ast.SpecLoc.Port) |
state ~! machine ^^ (_ => Ast.SpecLoc.StateMachine) |
topology ^^ (_ => Ast.SpecLoc.Topology) |
typeToken ^^ (_ => Ast.SpecLoc.Type) |
interface ^^ (_ => Ast.SpecLoc.Interface) |
failure("location kind expected")
instance ^^ (_ => Ast.SpecLoc.ComponentInstance) |
port ^^ (_ => Ast.SpecLoc.Port) |
state ~! machine ^^ (_ => Ast.SpecLoc.StateMachine) |
topology ^^ (_ => Ast.SpecLoc.Topology) |
interface ^^ (_ => Ast.SpecLoc.Interface)
def maybeDictPair =
opt(dictionary) ~ maybeDictKind ^^ {
case dictOpt ~ kind => (dictOpt.isDefined, kind)
}
def nonDictPair =
nonDictKind ^^ { case kind => (false, kind) }
def isDictAndKind =
maybeDictPair |
nonDictPair |
failure("dictionary specifier or location kind expected")
(locate ~>! isDictAndKind) ~! node(qualIdent) ~! (at ~>! node(literalString)) ^^ {
case (isDict, kind) ~ symbol ~ file => {
Ast.SpecLoc(kind, symbol, file, isDict)
}
}
(locate ~>! kind) ~! node(qualIdent) ~! (at ~>! node(literalString)) ^^ {
case kind ~ symbol ~ file => Ast.SpecLoc(kind, symbol, file)
}
}
def specParam: Parser[Ast.SpecParam] = {
opt(external) ~ (param ~>! ident) ~ (colon ~>! node(typeName)) ~!
opt(default ~>! exprNode) ~!
@ -1111,6 +1122,8 @@ object Parser extends Parsers {
private def diagnostic =
accept("diagnostic", { case t: Token.DIAGNOSTIC => t })
private def dictionary = accept("dictionary", { case t: Token.DICTIONARY => t })
private def doToken = accept("do", { case t: Token.DO => t })
private def dot = accept(".", { case t: Token.DOT => t })

View File

@ -30,6 +30,7 @@ object Token {
final case class CPU() extends Token
final case class DEFAULT() extends Token
final case class DIAGNOSTIC() extends Token
final case class DICTIONARY() extends Token
final case class DO() extends Token
final case class DOT() extends Token
final case class DROP() extends Token
@ -180,6 +181,7 @@ enum TokenId {
case CPU
case DEFAULT
case DIAGNOSTIC
case DICTIONARY
case DO
case DROP
case ELSE

View File

@ -146,11 +146,20 @@ sealed trait Error {
System.err.println(matchingLoc)
System.err.println("conflicting connection is here:")
System.err.println(prevLoc)
case SemanticError.InconsistentSpecLoc(loc, path, prevLoc, prevPath) =>
case SemanticError.InconsistentDictionarySpecifier(loc, prevLoc) =>
Error.print (Some(loc)) (s"inconsistent location specifier")
printPrevLoc(prevLoc)
printNote("one specifies dictionary and one does not")
case SemanticError.InconsistentLocationPath(loc, path, prevLoc, prevPath) =>
Error.print (Some(loc)) (s"inconsistent location path ${path}")
System.err.println(prevLoc)
printPrevLoc(prevLoc)
System.err.println(s"previous path is ${prevPath}")
case SemanticError.IncorrectSpecLoc(loc, specifiedPath, actualLoc) =>
case SemanticError.IncorrectDictionarySpecifier(loc, defLoc) =>
Error.print (Some(loc)) (s"incorrect location specifier")
System.err.println(s"actual definition is here:")
System.err.println(defLoc)
printNote("one specifies dictionary and one does not")
case SemanticError.IncorrectLocationPath(loc, specifiedPath, actualLoc) =>
Error.print (Some(loc)) (s"incorrect location path ${specifiedPath}")
System.err.println(s"actual location is ${actualLoc}")
case SemanticError.InvalidArraySize(loc, size) =>
@ -514,15 +523,25 @@ object SemanticError {
matchingLoc: Location,
prevLoc: Location
) extends Error
/** Inconsistent dictionary specifiers in location specifiers */
final case class InconsistentDictionarySpecifier(
loc: Location,
prevLoc: Location,
) extends Error
/** Inconsistent location specifiers */
final case class InconsistentSpecLoc(
final case class InconsistentLocationPath(
loc: Location,
path: String,
prevLoc: Location,
prevPath: String
) extends Error
/** Incorrect dictionary specifier in location specifier */
final case class IncorrectDictionarySpecifier(
loc: Location,
defLoc: Location
) extends Error
/** Incorrect location specifiers */
final case class IncorrectSpecLoc(
final case class IncorrectLocationPath(
loc: Location,
specifiedPath: String,
actualLoc: Location

View File

@ -19,7 +19,7 @@ object Types {
def aliasType(name: Ast.Ident, ty: Type, id: AstNode.Id = 0): AliasType = {
val typeNameNode = AstNode.create(Ast.TypeNameInt(Ast.U32()), id)
val d = Ast.DefAliasType(name, typeNameNode)
val d = Ast.DefAliasType(name, typeNameNode, false)
val anode = annotatedNode(d, id)
AliasType(anode, ty)
}
@ -27,19 +27,19 @@ object Types {
def array(name: Ast.Ident, anonArray: AnonArray = AnonArray(None, U32), id: AstNode.Id = 0): Array = {
val size = AstNode.create(Ast.ExprLiteralInt("1"))
val eltType = AstNode.create(Ast.TypeNameInt(Ast.U32()))
val d = Ast.DefArray(name, size, eltType, None, None)
val d = Ast.DefArray(name, size, eltType, None, None, false)
val anode = annotatedNode(d, id)
Array(anode, anonArray)
}
def enumeration(name: Ast.Ident, repType: Type.PrimitiveInt = I32, id: AstNode.Id = 0): Enum = {
val d = Ast.DefEnum(name, None, List(), None)
val d = Ast.DefEnum(name, None, List(), None, false)
val anode = annotatedNode(d, id)
Enum(anode, repType)
}
def struct(name: Ast.Ident, anonStruct: AnonStruct = AnonStruct(Map()), id: AstNode.Id = 0): Struct = {
val d = Ast.DefStruct(name, List(), None)
val d = Ast.DefStruct(name, List(), None, false)
val anode = annotatedNode(d, id)
Struct(anode, anonStruct)
}

View File

@ -57,6 +57,17 @@ class ParserSpec extends AnyWordSpec {
)
}
"def alias type OK" should {
parseAllOK(
Parser.defAliasType,
List(
"type a = U32",
"type a = F32",
"dictionary type a = string"
)
)
}
"def array OK" should {
parseAllOK(
Parser.defArray,
@ -64,6 +75,7 @@ class ParserSpec extends AnyWordSpec {
"array a = [10] U32",
"array a = [10] U32 default 0",
"array a = [10] U32 default 0 format \"{} counts\"",
"dictionary array a = [10] U32"
)
)
}
@ -122,6 +134,7 @@ class ParserSpec extends AnyWordSpec {
Parser.defConstant,
List(
"constant a = 0",
"dictionary constant a = 0"
)
)
}
@ -138,6 +151,7 @@ class ParserSpec extends AnyWordSpec {
@ Pre
Y = 1 @< Post
}""",
"dictionary enum E { X = 0 }"
)
)
}
@ -206,6 +220,7 @@ class ParserSpec extends AnyWordSpec {
@ Pre
y: F32 @< Post
}""",
"dictionary struct S { x: [3] U32 }"
)
)
}
@ -491,6 +506,8 @@ class ParserSpec extends AnyWordSpec {
"locate port a.b at \"c.fpp\"",
"locate topology a.b at \"c.fpp\"",
"locate type a.b at \"c.fpp\"",
"locate dictionary type a.b at \"c.fpp\"",
"locate dictionary constant a.b at \"c.fpp\"",
)
)
}

View File

@ -0,0 +1,2 @@
type T
dictionary array A = [3] T

View File

@ -0,0 +1,15 @@
fpp-check
[ local path prefix ]/compiler/tools/fpp-check/test/array/dictionary_not_displayable.fpp:2.1
dictionary array A = [3] T
^
error: dictionary type is not displayable
[ local path prefix ]/compiler/tools/fpp-check/test/array/dictionary_not_displayable.fpp:2.26
dictionary array A = [3] T
^
because this type is not displayable
[ local path prefix ]/compiler/tools/fpp-check/test/array/dictionary_not_displayable.fpp:1.1
type T
^
Type is defined here

View File

@ -0,0 +1 @@
dictionary array A = [3] U32

View File

@ -3,6 +3,8 @@ array_default_error
array_default_ok
array_no_default_ok
default_ok
dictionary_not_displayable
dictionary_ok
enum_default_error
enum_default_ok
enum_no_default_ok

View File

@ -0,0 +1 @@
dictionary constant c = { x = 0, y = 1 }

View File

@ -0,0 +1,5 @@
fpp-check
[ local path prefix ]/compiler/tools/fpp-check/test/constant/dictionary_error.fpp:1.1
dictionary constant c = { x = 0, y = 1 }
^
error: dictionary constant must have a numeric, Boolean, string, or enum type

View File

@ -0,0 +1 @@
dictionary constant c = 42

View File

@ -1,6 +1,8 @@
tests="
array_index_negative
array_index_out_of_bounds
dictionary_error
dictionary_ok
invalid_array_index_type
invalid_array_type
undef_1

View File

@ -0,0 +1 @@
dictionary enum E { A, B }

View File

@ -5,6 +5,7 @@ bad_constant
bad_default
bad_rep_type
default_ok
dictionary_ok
duplicate_value
explicit
implied

View File

@ -0,0 +1,2 @@
locate dictionary type T at "abs_type_dictionary_error.fpp"
type T

View File

@ -0,0 +1,10 @@
fpp-check
[ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/abs_type_dictionary_error.fpp:1.1
locate dictionary type T at "abs_type_dictionary_error.fpp"
^
error: incorrect location specifier
actual definition is here:
[ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/abs_type_dictionary_error.fpp:2.1
type T
^
note: one specifies dictionary and one does not

View File

@ -1,8 +1,8 @@
fpp-check
[ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/abs_type_error.fpp:1.18
[ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/abs_type_path_error.fpp:1.18
locate type T at "incorrect.fpp"
^
error: incorrect location path [ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/incorrect.fpp
actual location is [ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/abs_type_error.fpp:2.1
actual location is [ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/abs_type_path_error.fpp:2.1
type T
^

View File

@ -0,0 +1,2 @@
locate type T at "alias_type_dictionary_error.fpp"
dictionary type T = U32

View File

@ -0,0 +1,10 @@
fpp-check
[ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/alias_type_dictionary_error.fpp:1.1
locate type T at "alias_type_dictionary_error.fpp"
^
error: incorrect location specifier
actual definition is here:
[ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/alias_type_dictionary_error.fpp:2.1
dictionary type T = U32
^
note: one specifies dictionary and one does not

View File

@ -0,0 +1,2 @@
locate type T at "alias_type_ok.fpp"
type T = U32

View File

@ -0,0 +1,2 @@
locate type T at "incorrect.fpp"
type T = U32

View File

@ -0,0 +1,8 @@
fpp-check
[ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/alias_type_path_error.fpp:1.18
locate type T at "incorrect.fpp"
^
error: incorrect location path [ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/incorrect.fpp
actual location is [ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/alias_type_path_error.fpp:2.1
type T = U32
^

View File

@ -0,0 +1,2 @@
locate dictionary type A at "array_dictionary_error.fpp"
array A = [3] U32

View File

@ -0,0 +1,10 @@
fpp-check
[ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/array_dictionary_error.fpp:1.1
locate dictionary type A at "array_dictionary_error.fpp"
^
error: incorrect location specifier
actual definition is here:
[ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/array_dictionary_error.fpp:2.1
array A = [3] U32
^
note: one specifies dictionary and one does not

View File

@ -1,8 +1,8 @@
fpp-check
[ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/array_error.fpp:1.18
[ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/array_path_error.fpp:1.18
locate type A at "incorrect.fpp"
^
error: incorrect location path [ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/incorrect.fpp
actual location is [ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/array_error.fpp:2.1
actual location is [ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/array_path_error.fpp:2.1
array A = [3] U32
^

View File

@ -0,0 +1,7 @@
locate instance i at "component_instance_ok.fpp"
passive component C {
}
instance i: C base id 0x100

View File

@ -0,0 +1,7 @@
locate instance i at "incorrect.fpp"
passive component C {
}
instance i: C base id 0x100

View File

@ -0,0 +1,8 @@
fpp-check
[ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/component_instance_path_error.fpp:1.22
locate instance i at "incorrect.fpp"
^
error: incorrect location path [ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/incorrect.fpp
actual location is [ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/component_instance_path_error.fpp:7.1
instance i: C base id 0x100
^

View File

@ -0,0 +1,4 @@
locate component C at "component_ok.fpp"
passive component C {
}

View File

@ -0,0 +1,4 @@
locate component C at "incorrect.fpp"
passive component C {
}

View File

@ -0,0 +1,8 @@
fpp-check
[ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/component_path_error.fpp:1.23
locate component C at "incorrect.fpp"
^
error: incorrect location path [ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/incorrect.fpp
actual location is [ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/component_path_error.fpp:2.1
passive component C {
^

View File

@ -0,0 +1,2 @@
locate constant c at "constant_dictionary_error.fpp"
dictionary constant c = 0

View File

@ -0,0 +1,10 @@
fpp-check
[ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/constant_dictionary_error.fpp:1.1
locate constant c at "constant_dictionary_error.fpp"
^
error: incorrect location specifier
actual definition is here:
[ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/constant_dictionary_error.fpp:2.1
dictionary constant c = 0
^
note: one specifies dictionary and one does not

View File

@ -1,8 +1,8 @@
fpp-check
[ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/constant_error.fpp:1.22
[ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/constant_path_error.fpp:1.22
locate constant c at "incorrect.fpp"
^
error: incorrect location path [ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/incorrect.fpp
actual location is [ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/constant_error.fpp:2.1
actual location is [ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/constant_path_error.fpp:2.1
constant c = 0
^

View File

@ -0,0 +1,2 @@
locate dictionary type E at "enum_dictionary_error.fpp"
enum E { X }

View File

@ -0,0 +1,10 @@
fpp-check
[ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/enum_dictionary_error.fpp:1.1
locate dictionary type E at "enum_dictionary_error.fpp"
^
error: incorrect location specifier
actual definition is here:
[ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/enum_dictionary_error.fpp:2.1
enum E { X }
^
note: one specifies dictionary and one does not

View File

@ -1,8 +1,8 @@
fpp-check
[ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/enum_error.fpp:1.18
[ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/enum_path_error.fpp:1.18
locate type E at "incorrect.fpp"
^
error: incorrect location path [ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/incorrect.fpp
actual location is [ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/enum_error.fpp:2.1
actual location is [ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/enum_path_error.fpp:2.1
enum E { X }
^

View File

@ -0,0 +1,5 @@
locate interface I at "interface_ok.fpp"
interface I {
}

View File

@ -0,0 +1,5 @@
locate interface I at "incorrect.fpp"
interface I {
}

View File

@ -0,0 +1,8 @@
fpp-check
[ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/interface_path_error.fpp:1.23
locate interface I at "incorrect.fpp"
^
error: incorrect location path [ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/incorrect.fpp
actual location is [ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/interface_path_error.fpp:3.1
interface I {
^

View File

@ -1,8 +1,8 @@
fpp-check
[ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/port_error.fpp:1.18
[ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/port_path_error.fpp:1.18
locate port P at "incorrect.fpp"
^
error: incorrect location path [ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/incorrect.fpp
actual location is [ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/port_error.fpp:3.1
actual location is [ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/port_path_error.fpp:3.1
port P
^

View File

@ -0,0 +1,3 @@
locate type S at "struct_dictionary_error.fpp"
dictionary struct S { x: U32 }

View File

@ -0,0 +1,10 @@
fpp-check
[ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/struct_dictionary_error.fpp:1.1
locate type S at "struct_dictionary_error.fpp"
^
error: incorrect location specifier
actual definition is here:
[ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/struct_dictionary_error.fpp:3.1
dictionary struct S { x: U32 }
^
note: one specifies dictionary and one does not

View File

@ -1,8 +1,8 @@
fpp-check
[ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/struct_error.fpp:1.18
[ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/struct_path_error.fpp:1.18
locate type S at "incorrect.fpp"
^
error: incorrect location path [ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/incorrect.fpp
actual location is [ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/struct_error.fpp:3.1
actual location is [ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/struct_path_error.fpp:3.1
struct S { x: U32 }
^

View File

@ -1,15 +1,31 @@
tests="
abs_type_error
abs_type_dictionary_error
abs_type_ok
array_error
abs_type_path_error
alias_type_dictionary_error
alias_type_ok
alias_type_path_error
array_dictionary_error
array_ok
constant_error
array_path_error
component_instance_ok
component_instance_path_error
component_ok
component_path_error
constant_dictionary_error
constant_ok
enum_error
constant_path_error
enum_dictionary_error
enum_ok
enum_path_error
include_ok
port_error
interface_ok
interface_path_error
port_ok
struct_error
port_path_error
struct_dictionary_error
struct_ok
struct_path_error
topology_ok
topology_path_error
"

View File

@ -0,0 +1,5 @@
locate topology T at "topology_ok.fpp"
topology T {
}

View File

@ -0,0 +1,5 @@
locate topology T at "incorrect.fpp"
topology T {
}

View File

@ -0,0 +1,8 @@
fpp-check
[ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/topology_path_error.fpp:1.22
locate topology T at "incorrect.fpp"
^
error: incorrect location path [ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/incorrect.fpp
actual location is [ local path prefix ]/compiler/tools/fpp-check/test/spec_loc/topology_path_error.fpp:3.1
topology T {
^

View File

@ -0,0 +1,2 @@
type T
dictionary struct S { x: T }

View File

@ -0,0 +1,15 @@
fpp-check
[ local path prefix ]/compiler/tools/fpp-check/test/struct/dictionary_not_displayable.fpp:2.1
dictionary struct S { x: T }
^
error: dictionary type is not displayable
[ local path prefix ]/compiler/tools/fpp-check/test/struct/dictionary_not_displayable.fpp:2.26
dictionary struct S { x: T }
^
because this type is not displayable
[ local path prefix ]/compiler/tools/fpp-check/test/struct/dictionary_not_displayable.fpp:1.1
type T
^
Type is defined here

View File

@ -0,0 +1 @@
dictionary struct S { x: U32 }

View File

@ -1,6 +1,8 @@
tests="
default_error
default_ok
dictionary_not_displayable
dictionary_ok
duplicate_names
format_alias_not_numeric
format_alias_numeric

View File

@ -0,0 +1,2 @@
type T1
dictionary type T2 = T1

View File

@ -0,0 +1,15 @@
fpp-check
[ local path prefix ]/compiler/tools/fpp-check/test/type/alias_dictionary_not_displayable.fpp:2.1
dictionary type T2 = T1
^
error: dictionary type is not displayable
[ local path prefix ]/compiler/tools/fpp-check/test/type/alias_dictionary_not_displayable.fpp:2.22
dictionary type T2 = T1
^
because this type is not displayable
[ local path prefix ]/compiler/tools/fpp-check/test/type/alias_dictionary_not_displayable.fpp:1.1
type T1
^
Type is defined here

View File

@ -0,0 +1 @@
dictionary type T = U32

View File

@ -1,4 +1,6 @@
tests="
alias_dictionary_not_displayable
alias_dictionary_ok
alias_type_ok
string_size_negative
string_size_not_numeric

View File

@ -1,5 +1,8 @@
locate type T at "T.fpp"
locate type C.T at "C.fpp"
locate dictionary type T2 at "T2.fpp"
locate type T3 at "T3.fpp"
type A1 = T
type A2 = C.T
type A3 = T2

View File

@ -1,2 +1,4 @@
[ local path prefix ]/compiler/tools/fpp-depend/test/C.fpp
[ local path prefix ]/compiler/tools/fpp-depend/test/T.fpp
[ local path prefix ]/compiler/tools/fpp-depend/test/T2.fpp
[ local path prefix ]/compiler/tools/fpp-depend/test/def_alias.fpp

View File

@ -1,9 +1,12 @@
locate constant a at "a.fpp"
locate constant b at "b.fpp"
locate constant c at "c.fpp"
locate dictionary constant d at "d.fpp"
locate type T at "T.fpp"
locate type C.T at "C.fpp"
locate dictionary type T2 at "T2.fpp"
array A1 = [a] T default b
array A2 = [a] C.T
dictionary array A3 = [d] T2

Some files were not shown because too many files have changed in this diff Show More