Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Statemachine check #439

Merged
merged 67 commits into from
Jun 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
fd80cbe
add state machine specs and defs
Apr 24, 2024
6710493
Define the state-machine FPP syntax
May 1, 2024
a1ca161
More state-machine FPP syntax
May 1, 2024
017e69f
Start defining AST for state machine
May 2, 2024
a6442da
Add example state machine fpp code
May 6, 2024
7e9cfad
Move all the state machine behavior specs to State-Machine-Behavior d…
May 7, 2024
85a77a7
Try a couple of different fpp syntax for state machines
May 7, 2024
68ff85f
Add actions on initial transitions and explicitly represent junction …
May 8, 2024
4df4035
Update state machine syntax
May 8, 2024
0348890
First cut at state machine syntax after reviews
May 9, 2024
a4cc7c0
Add parser for 'state machine'
May 14, 2024
2c31baa
Add parser for 'state machine instance'
May 15, 2024
e42a8f2
Add state machine to component members
May 15, 2024
6eb6166
Add state machine instance to component members
May 15, 2024
35c635a
Update prettify, vim and emacs
May 15, 2024
120748c
fpp-syntax source and test updated
May 16, 2024
447c647
fpp-format source and test updated for state machines
May 16, 2024
be9e193
Incorporate Bocchino's comments on the state machine spec document
May 16, 2024
7cbd9ac
Fix fpp-to-json test that failed because of keyword state
May 17, 2024
f22c47c
Incorporate state machine definition under module members
May 20, 2024
a561e18
Update fpp-check for duplicate state machine definitions
May 22, 2024
440f729
Merge remote-tracking branch 'fpp/main' into statemachine-merge
May 22, 2024
ef767bc
Add state machine example
May 22, 2024
7eeab7f
Fix EnterSymbols for state machine
May 23, 2024
201d437
Merge branch 'feature/state-machine' into statemachine-merge
May 23, 2024
4f7fbe3
Fix most of the tests except fpp-to-json
May 23, 2024
720e520
Merge branch 'feature/state-machine' into statemachine-merge
May 23, 2024
a053ecf
Merge branch 'feature/state-machine' into statemachine-merge
May 23, 2024
774e837
Merge branch 'statemachine-syntax' into statemachine-merge
May 23, 2024
25a77a2
Update the fpp-to-json test to pass
May 23, 2024
0d3a45c
Add fpp-depend for state machine
May 24, 2024
32f73b1
Fix spaces
May 24, 2024
2609727
Fix spaces
May 24, 2024
00afb6f
Merge remote-tracking branch 'nasa/feature/state-machine' into statem…
bocchino Jun 7, 2024
19be2ea
Update UseAnalyzer
bocchino Jun 7, 2024
8166666
Remove generated files
bocchino Jun 7, 2024
af6fad7
Revert change to Version.scala
bocchino Jun 7, 2024
08387f0
Remove unused token SM
bocchino Jun 7, 2024
e9d04d0
Add fpp-locate-defs for state machines and added test
Jun 12, 2024
d185ed0
Add fpp-locate-uses for state machines and added test
Jun 12, 2024
8e0147a
Remove StateMachineInstance from Symbols
Jun 13, 2024
1664632
Add semantic checks for state machine in active and passive components
Jun 17, 2024
f315b21
Update spec
bocchino Jun 18, 2024
1000129
Merge remote-tracking branch 'fpp/feature/state-machine' into statema…
Jun 18, 2024
3db7567
Fix most small items from pull request review
Jun 18, 2024
9d088eb
Fix the fpp-depend for state machine definitions
Jun 18, 2024
cad8b6f
In the Parser, state must be followed by machine
Jun 18, 2024
0acb564
Check state machine instance access correct symbol
Jun 20, 2024
e75a65c
State machine syntax enforce the colon after the instance identifier
Jun 20, 2024
a75d364
Update tests
Jun 21, 2024
bfa8248
Merge remote-tracking branch 'nasa/feature/state-machine' into statem…
bocchino Jun 21, 2024
240d6be
Restore Version.scala
bocchino Jun 21, 2024
5200b17
Delete generated files
bocchino Jun 21, 2024
6492d90
Revise fpp depend tests
bocchino Jun 21, 2024
1d66c64
Fix bug in name resolution
bocchino Jun 22, 2024
5ccffd9
Revise tests for locate-defs
bocchino Jun 24, 2024
82e2ebf
Revise fpp-check tests
bocchino Jun 24, 2024
201f765
Revise fpp-check tests
bocchino Jun 24, 2024
cd2c86f
Revise fpp-check tests
bocchino Jun 24, 2024
bcbf2e1
Revise fpp-check tests
bocchino Jun 24, 2024
368a31c
Revise fpp-check tests
bocchino Jun 24, 2024
be18ebe
Revise fpp-check tests
bocchino Jun 24, 2024
873e9c5
Revise fpp-check tests
bocchino Jun 24, 2024
0da7537
Revise fpp-check tests
bocchino Jun 24, 2024
db97270
Revert "Revise fpp-check tests"
bocchino Jun 24, 2024
14b4350
Revise fpp-check tests
bocchino Jun 24, 2024
4c91ec0
Update fpp-check tests
bocchino Jun 24, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 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,13 @@ 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
qualIdentNode(stateMachineUse)(a, data.stateMachine)
}


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,17 @@ 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))
}

bocchino marked this conversation as resolved.
Show resolved Hide resolved

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 @@ -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)
}

bocchino marked this conversation as resolved.
Show resolved Hide resolved
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
38 changes: 38 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 @@ -113,6 +115,33 @@ case class Component(
}
yield c


def addStateMachineInstance(instance: StateMachineInstance): Result.Result[Component] =
for {
c <- updateStateMachineInstanceMap(instance)
c <- instance match {
case _ => Right(c)
}
}
yield c


/** Add a port instance to the port map */
private def updateStateMachineInstanceMap(instance: StateMachineInstance):
Result.Result[Component] = {
val name = instance.getUnqualifiedName
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 +432,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,55 @@
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]],
specifier: Ast.SpecStateMachineInstance
) {

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

def getNodeId = aNode._2.id

/** Gets the unqualified name of the state machine instance */
def getUnqualifiedName = 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 node = aNode._2
val data = node.data
data match {
case specifier: Ast.SpecStateMachineInstance =>
createStateMachineInstance(a, aNode, specifier)
}
}

private def createStateMachineInstance(
a: Analysis,
aNode: Ast.Annotated[AstNode[Ast.SpecStateMachineInstance]],
specifier: Ast.SpecStateMachineInstance
): Result.Result[StateMachineInstance] = {
val qid = specifier.stateMachine
a.useDefMap(qid.id) match {
case symbol @ Symbol.StateMachine(_) =>
Right(StateMachineInstance(aNode, specifier))
case symbol => Left(SemanticError.InvalidSymbol(
symbol.getUnqualifiedName,
Locations.get(qid.id),
"not a state machine symbol",
symbol.getLoc
))
}
}

}
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
9 changes: 9 additions & 0 deletions compiler/lib/src/main/scala/codegen/LocateDefsFppWriter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,15 @@ object LocateDefsFppWriter extends AstVisitor with LineUtils {
data.members.flatMap(matchComponentMember(s1, _))
}

override def defStateMachineAnnotatedNode(
s: State,
aNode: Ast.Annotated[AstNode[Ast.DefStateMachine]]
) = {
val (_, node, _) = aNode
val data = node.data
writeSpecLoc(s, Ast.SpecLoc.StateMachine, data.name, node)
}

override def defComponentInstanceAnnotatedNode(
s: State,
aNode: Ast.Annotated[AstNode[Ast.DefComponentInstance]]
Expand Down
3 changes: 2 additions & 1 deletion compiler/lib/src/main/scala/syntax/Parser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,7 @@ object Parser extends Parsers {
constant ^^ { case _ => Ast.SpecLoc.Constant } |
instance ^^ { case _ => Ast.SpecLoc.ComponentInstance } |
port ^^ { case _ => Ast.SpecLoc.Port } |
state ~! machine ^^ { case _ => Ast.SpecLoc.StateMachine } |
topology ^^ { case _ => Ast.SpecLoc.Topology } |
typeToken ^^ { case _ => Ast.SpecLoc.Type } |
failure("location kind expected")
Expand Down Expand Up @@ -577,7 +578,7 @@ object Parser extends Parsers {
}

def specStateMachineInstance: Parser[Ast.SpecStateMachineInstance] = {
(state ~> machine ~> (instance ~> ident) ~ (colon ~>! node(qualIdent))) ^^ {
(state ~> machine ~> (instance ~> ident) ~! (colon ~>! node(qualIdent))) ^^ {
case name ~ statemachine => Ast.SpecStateMachineInstance(name, statemachine)
}
}
Expand Down
12 changes: 12 additions & 0 deletions compiler/lib/src/main/scala/util/Error.scala
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ sealed trait Error {
Error.print (Some(loc)) (s"duplicate port instance ${name}")
System.err.println("previous instance is here:")
System.err.println(prevLoc)
case SemanticError.DuplicateStateMachineInstance(name, loc, prevLoc) =>
Error.print (Some(loc)) (s"duplicate state machine instance name ${name}")
printPrevLoc(prevLoc)
case SemanticError.DuplicateStructMember(name, loc, prevLoc) =>
Error.print (Some(loc)) (s"duplicate struct member ${name}")
System.err.println("previous member is here:")
Expand Down Expand Up @@ -206,6 +209,8 @@ sealed trait Error {
System.err.println(loc2)
case SemanticError.PassiveAsync(loc) =>
Error.print (Some(loc)) ("passive component may not have async input")
case SemanticError.PassiveStateMachine(loc) =>
bocchino marked this conversation as resolved.
Show resolved Hide resolved
Error.print (Some(loc)) ("passive component may not have a state machine instance")
case SemanticError.RedefinedSymbol(name, loc, prevLoc) =>
Error.print (Some(loc)) (s"redefinition of symbol ${name}")
System.err.println("previous definition is here:")
Expand Down Expand Up @@ -332,6 +337,12 @@ object SemanticError {
loc: Location,
prevLoc: Location
) extends Error
/** Duplicate state machine instance */
final case class DuplicateStateMachineInstance(
name: String,
loc: Location,
prevLoc: Location
) extends Error
/** Duplicate struct member */
final case class DuplicateStructMember(
name: String,
Expand Down Expand Up @@ -483,6 +494,7 @@ object SemanticError {
) extends Error
/** Passive async input */
final case class PassiveAsync(loc: Location) extends Error
final case class PassiveStateMachine(loc: Location) extends Error
/** Redefined symbol */
final case class RedefinedSymbol(
name: String,
Expand Down
3 changes: 3 additions & 0 deletions compiler/tools/fpp-check/test/component/ok.fpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,7 @@ active component C {

telemetry port tlmOut

state machine S
state machine instance s: S

}
5 changes: 4 additions & 1 deletion compiler/tools/fpp-check/test/defs/ok.fpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ struct S2 { x: [3] U32 }
enum E1 { X, Y }
enum E2 { X, Y }

state machine S

module M {

type a
Expand All @@ -28,5 +30,6 @@ module M {
enum E1 { X, Y }
enum E2 { X, Y }

}
state machine S

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module M {}

active component C {
state machine instance s1: M
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
fpp-check
[ local path prefix ]/compiler/tools/fpp-check/test/invalid_symbols/module_as_state_machine.fpp:4.32
state machine instance s1: M
^
error: invalid symbol M: not a state machine symbol
symbol is defined here:
[ local path prefix ]/compiler/tools/fpp-check/test/invalid_symbols/module_as_state_machine.fpp:1.1
module M {}
^
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
state machine S
active component C {
state machine instance s: S.s
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
fpp-check
[ local path prefix ]/compiler/tools/fpp-check/test/invalid_symbols/state_machine_as_qualifier.fpp:3.29
state machine instance s: S.s
^
error: invalid symbol S: not a qualifier
symbol is defined here:
[ local path prefix ]/compiler/tools/fpp-check/test/invalid_symbols/state_machine_as_qualifier.fpp:1.1
state machine S
^
2 changes: 2 additions & 0 deletions compiler/tools/fpp-check/test/invalid_symbols/tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ module_as_component
module_as_component_instance
module_as_constant
module_as_port
module_as_state_machine
module_as_topology
module_as_type
module_hides_constant
state_machine_as_qualifier
topology_as_qualifier
type_as_constant
"
Loading