Skip to content

Commit

Permalink
Merge pull request #493 from nasa/feature/state-machine-phase-1
Browse files Browse the repository at this point in the history
Phase 1 state machines
  • Loading branch information
bocchino committed Sep 4, 2024
2 parents d9634ad + a4e863d commit 55d4a48
Show file tree
Hide file tree
Showing 177 changed files with 7,584 additions and 2,732 deletions.
1,862 changes: 979 additions & 883 deletions compiler/lib/src/main/resources/META-INF/native-image/reflect-config.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,15 @@ trait TypeExpressionAnalyzer
} yield a
}

override def specStateMachineInstanceAnnotatedNode(
a: Analysis,
aNode: Ast.Annotated[AstNode[Ast.SpecStateMachineInstance]]
) = {
val (_, node, _) = aNode
val data = node.data
opt(exprNode)(a, data.priority)
}

override def specTlmChannelAnnotatedNode(a: Analysis, node: Ast.Annotated[AstNode[Ast.SpecTlmChannel]]) = {
def limit(a: Analysis, value: Ast.SpecTlmChannel.Limit) = {
val (_, e) = value
Expand Down
12 changes: 12 additions & 0 deletions compiler/lib/src/main/scala/analysis/Analyzers/UseAnalyzer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ trait UseAnalyzer extends TypeExpressionAnalyzer {
/** A use of a type definition */
def typeUse(a: Analysis, node: AstNode[Ast.TypeName], use: Name.Qualified): Result = default(a)

/** A use of a state machine definition*/
def stateMachineUse(a: Analysis, node: AstNode[Ast.QualIdent], use: Name.Qualified): Result = default(a)

override def defComponentInstanceAnnotatedNode(a: Analysis, node: Ast.Annotated[AstNode[Ast.DefComponentInstance]]) = {
val (_, node1, _) = node
val data = node1.data
Expand Down Expand Up @@ -62,6 +65,15 @@ trait UseAnalyzer extends TypeExpressionAnalyzer {
qualIdentNode (componentInstanceUse) (a, data.instance)
}

override def specStateMachineInstanceAnnotatedNode(a: Analysis, node: Ast.Annotated[AstNode[Ast.SpecStateMachineInstance]]) = {
val (_, node1, _) = node
val data = node1.data
for {
a <- qualIdentNode(stateMachineUse)(a, data.stateMachine)
a <- super.specStateMachineInstanceAnnotatedNode(a, node)
} yield a
}

override def specConnectionGraphAnnotatedNode(
a: Analysis, node: Ast.Annotated[AstNode[Ast.SpecConnectionGraph]]) = {
def connection(a: Analysis, connection: Ast.SpecConnectionGraph.Connection): Result = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,16 @@ object CheckComponentDefs
yield a.copy(component = Some(component))
}

override def specStateMachineInstanceAnnotatedNode(
a: Analysis,
aNode: Ast.Annotated[AstNode[Ast.SpecStateMachineInstance]]
): Result.Result[Analysis] = {
for {
stateMachineInstance <- StateMachineInstance.fromSpecStateMachine(a, aNode)
component <- a.component.get.addStateMachineInstance(stateMachineInstance)
} yield a.copy(component = Some(component))
}

override def specTlmChannelAnnotatedNode(
a: Analysis,
aNode: Ast.Annotated[AstNode[Ast.SpecTlmChannel]]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,19 @@ object CheckExprTypes extends UseAnalyzer {
yield a
}

override def specStateMachineInstanceAnnotatedNode(
a: Analysis,
aNode: Ast.Annotated[AstNode[Ast.SpecStateMachineInstance]]
) = {
val (_, node, _) = aNode
val data = node.data
for {
a <- super.specStateMachineInstanceAnnotatedNode(a, aNode)
_ <- convertNodeToNumericOpt(a, data.priority)
}
yield a
}

override def specTlmChannelAnnotatedNode(a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecTlmChannel]]) = {
val (_, node, _) = aNode
val data = node.data
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ object CheckUses extends UseAnalyzer {
override def componentUse(a: Analysis, node: AstNode[Ast.QualIdent], use: Name.Qualified) =
visitQualIdentNode (NameGroup.Component) (a, node)

override def stateMachineUse(a: Analysis, node: AstNode[Ast.QualIdent], use: Name.Qualified) =
visitQualIdentNode (NameGroup.StateMachine) (a, node)

override def constantUse(a: Analysis, node: AstNode[Ast.Expr], use: Name.Qualified) = {
def visitExprNode(a: Analysis, node: AstNode[Ast.Expr]): Result = {
def visitExprIdent(a: Analysis, node: AstNode[Ast.Expr], name: Name.Unqualified) = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ object EnterSymbols
val symbol = Symbol.Component(aNode)
for {
nestedScope <- a.nestedScope.put(NameGroup.Component)(name, symbol)
nestedScope <- nestedScope.put(NameGroup.StateMachine)(name, symbol)
nestedScope <- nestedScope.put(NameGroup.Type)(name, symbol)
nestedScope <- nestedScope.put(NameGroup.Value)(name, symbol)
a <- {
Expand Down Expand Up @@ -217,6 +218,19 @@ object EnterSymbols
yield updateMap(a, symbol).copy(nestedScope = nestedScope)
}

override def defStateMachineAnnotatedNode(
a: Analysis,
aNode: Ast.Annotated[AstNode[Ast.DefStateMachine]]
) = {
val (_, node, _) = aNode
val data = node.data
val name = data.name
val symbol = Symbol.StateMachine(aNode)
val nestedScope = a.nestedScope
for (nestedScope <- nestedScope.put(NameGroup.StateMachine)(name, symbol))
yield updateMap(a, symbol).copy(nestedScope = nestedScope)
}

override def defStructAnnotatedNode(
a: Analysis,
aNode: Ast.Annotated[AstNode[Ast.DefStruct]]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ object MapUsesToLocs extends UseAnalyzer {
override def componentInstanceUse(a: Analysis, node: AstNode[Ast.QualIdent], use: Name.Qualified) =
analyzeUse(a, Ast.SpecLoc.ComponentInstance, use)

override def stateMachineUse(a: Analysis, node: AstNode[Ast.QualIdent], use: Name.Qualified) =
analyzeUse(a, Ast.SpecLoc.StateMachine, use)

override def componentUse(a: Analysis, node: AstNode[Ast.QualIdent], use: Name.Qualified) =
analyzeUse(a, Ast.SpecLoc.Component, use)

Expand Down
30 changes: 30 additions & 0 deletions compiler/lib/src/main/scala/analysis/Semantics/Component.scala
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ case class Component(
paramMap: Map[Param.Id, Param] = Map(),
/** The list of port matching specifiers */
specPortMatchingList: List[Ast.Annotated[AstNode[Ast.SpecPortMatching]]] = Nil,
/** The map from state machine instance names to state machine instances */
stateMachineInstanceMap: Map[Name.Unqualified, StateMachineInstance] = Map(),
/** The list of port matching constraints */
portMatchingList: List[Component.PortMatching] = Nil,
/** The next default parameter ID */
Expand Down Expand Up @@ -56,6 +58,9 @@ case class Component(
/** Query whether the component has data products */
def hasDataProducts = (this.recordMap.size + this.containerMap.size) > 0

/** Query whether the component has state machine instances */
def hasStateMachineInstances = this.stateMachineInstanceMap.size > 0

/** Gets the max identifier */
def getMaxId: BigInt = {
def maxInMap[T](map: Map[BigInt, T]): BigInt =
Expand Down Expand Up @@ -113,6 +118,22 @@ case class Component(
}
yield c

/** Add a state machine instance */
def addStateMachineInstance(instance: StateMachineInstance):
Result.Result[Component] = {
val name = instance.getName
stateMachineInstanceMap.get(name) match {
case Some(prevInstance) =>
val loc = instance.getLoc
val prevLoc = prevInstance.getLoc
Left(SemanticError.DuplicateStateMachineInstance(name, loc, prevLoc))
case None =>
val stateMachineInstanceMap = this.stateMachineInstanceMap + (name -> instance)
val component = this.copy(stateMachineInstanceMap = stateMachineInstanceMap)
Right(component)
}
}

/** Add a port instance to the port map */
private def updatePortMap(instance: PortInstance):
Result.Result[Component] = {
Expand Down Expand Up @@ -403,10 +424,19 @@ case class Component(
Left(SemanticError.PassiveAsync(command.getLoc))
case _ => Right(())
}
)
def checkStateMachines() = Result.map(
this.stateMachineInstanceMap.values.toList,
(instance: StateMachineInstance) => {
val loc = instance.getLoc
val error = SemanticError.PassiveStateMachine(loc)
Left(error)
}
)
for {
_ <- checkPortInstances()
_ <- checkCommands()
_ <- checkStateMachines()
}
yield ()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ object NameGroup {
case object ComponentInstance extends NameGroup
case object Component extends NameGroup
case object Port extends NameGroup
case object StateMachine extends NameGroup
case object Topology extends NameGroup
case object Type extends NameGroup
case object Value extends NameGroup
Expand All @@ -15,6 +16,7 @@ object NameGroup {
ComponentInstance,
Component,
Port,
StateMachine,
Topology,
Type,
Value
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package fpp.compiler.analysis

import fpp.compiler.ast._
import fpp.compiler.util._

/** An FPP state machine instance */
final case class StateMachineInstance(
aNode: Ast.Annotated[AstNode[Ast.SpecStateMachineInstance]],
symbol: Symbol.StateMachine,
priority: Option[BigInt],
queueFull: Ast.QueueFull
) {

/** Gets the location of the state machine instance*/
def getLoc: Location = Locations.get(aNode._2.id)

def getNodeId = aNode._2.id

/** Gets the name of the state machine instance */
def getName = aNode._2.data.name

}

object StateMachineInstance {

/** Creates a state machine instance from a state machine instance specifier */
def fromSpecStateMachine(a: Analysis,
aNode: Ast.Annotated[AstNode[Ast.SpecStateMachineInstance]]
) : Result.Result[StateMachineInstance] = {
val data = aNode._2.data
val qid = data.stateMachine
val priorityNode = data.priority
val priority = a.getBigIntValueOpt(priorityNode)
val queueFull = Analysis.getQueueFull(data.queueFull)

for {
symbol <- a.useDefMap(qid.id) match {
case symbol @ Symbol.StateMachine(_) => Right(symbol)
case symbol => Left(SemanticError.InvalidSymbol(
symbol.getUnqualifiedName,
Locations.get(qid.id),
"not a state machine symbol",
symbol.getLoc
))
}
}
yield StateMachineInstance(aNode, symbol, priority, queueFull)
}

}
4 changes: 4 additions & 0 deletions compiler/lib/src/main/scala/analysis/Semantics/Symbol.scala
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ object Symbol {
override def getNodeId = node._2.id
override def getUnqualifiedName = node._2.data.name
}
final case class StateMachine(node: Ast.Annotated[AstNode[Ast.DefStateMachine]]) extends Symbol {
override def getNodeId = node._2.id
override def getUnqualifiedName = node._2.data.name
}
final case class Struct(node: Ast.Annotated[AstNode[Ast.DefStruct]]) extends Symbol {
override def getNodeId = node._2.id
override def getUnqualifiedName = node._2.data.name
Expand Down
7 changes: 7 additions & 0 deletions compiler/lib/src/main/scala/analysis/UsedSymbols.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ object UsedSymbols extends UseAnalyzer {
use: Name.Qualified
) = addSymbol(a, node)

override def stateMachineUse(
a: Analysis,
node: AstNode[Ast.QualIdent],
use: Name.Qualified
) = addSymbol(a, node)

override def componentInstanceUse(
a: Analysis,
node: AstNode[Ast.QualIdent],
Expand Down Expand Up @@ -61,6 +67,7 @@ object UsedSymbols extends UseAnalyzer {
case Symbol.EnumConstant(node) => defEnumConstantAnnotatedNode(a1, node)
case Symbol.Module(node) => defModuleAnnotatedNode(a1, node)
case Symbol.Port(node) => defPortAnnotatedNode(a1, node)
case Symbol.StateMachine(node) => defStateMachineAnnotatedNode(a1, node)
case Symbol.Struct(node) => defStructAnnotatedNode(a1, node)
case Symbol.Topology(node) => defTopologyAnnotatedNode(a1, node)
}
Expand Down
19 changes: 19 additions & 0 deletions compiler/lib/src/main/scala/ast/Ast.scala
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ object Ast {
final case class DefArray(node: AstNode[Ast.DefArray]) extends Node
final case class DefConstant(node: AstNode[Ast.DefConstant]) extends Node
final case class DefEnum(node: AstNode[Ast.DefEnum]) extends Node
final case class DefStateMachine(node: AstNode[Ast.DefStateMachine]) extends Node
final case class DefStruct(node: AstNode[Ast.DefStruct]) extends Node
final case class SpecCommand(node: AstNode[Ast.SpecCommand]) extends Node
final case class SpecContainer(node: AstNode[Ast.SpecContainer]) extends Node
Expand All @@ -65,6 +66,7 @@ object Ast {
final case class SpecPortInstance(node: AstNode[Ast.SpecPortInstance]) extends Node
final case class SpecPortMatching(node: AstNode[Ast.SpecPortMatching]) extends Node
final case class SpecRecord(node: AstNode[Ast.SpecRecord]) extends Node
final case class SpecStateMachineInstance(node: AstNode[Ast.SpecStateMachineInstance]) extends Node
final case class SpecTlmChannel(node: AstNode[Ast.SpecTlmChannel]) extends Node
}

Expand Down Expand Up @@ -136,6 +138,7 @@ object Ast {
final case class DefEnum(node: AstNode[Ast.DefEnum]) extends Node
final case class DefModule(node: AstNode[Ast.DefModule]) extends Node
final case class DefPort(node: AstNode[Ast.DefPort]) extends Node
final case class DefStateMachine(node: AstNode[Ast.DefStateMachine]) extends Node
final case class DefStruct(node: AstNode[Ast.DefStruct]) extends Node
final case class DefTopology(node: AstNode[Ast.DefTopology]) extends Node
final case class SpecInclude(node: AstNode[Ast.SpecInclude]) extends Node
Expand All @@ -149,6 +152,11 @@ object Ast {
returnType: Option[AstNode[TypeName]]
)

/** State machine definition */
final case class DefStateMachine(
name: Ident
)

/** Struct definition */
final case class DefStruct(
name: Ident,
Expand Down Expand Up @@ -461,6 +469,9 @@ object Ast {
case object Port extends Kind {
override def toString = "port"
}
case object StateMachine extends Kind {
override def toString = "state machine"
}
case object Topology extends Kind {
override def toString = "topology"
}
Expand Down Expand Up @@ -587,6 +598,14 @@ object Ast {
id: Option[AstNode[Expr]]
)

/** State machine instance spec */
final case class SpecStateMachineInstance(
name: Ident,
stateMachine: AstNode[QualIdent],
priority: Option[AstNode[Expr]],
queueFull: Option[QueueFull]
)

/** Telemetry channel specifier */
final case class SpecTlmChannel(
name: Ident,
Expand Down
Loading

0 comments on commit 55d4a48

Please sign in to comment.