Skip to content

Commit 3b32425

Browse files
authored
Merge pull request #940 from nasa/feature/topology-ports
Topology Ports
2 parents e068ecd + 711ddab commit 3b32425

File tree

229 files changed

+14576
-12548
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

229 files changed

+14576
-12548
lines changed

compiler/lib/src/main/resources/META-INF/native-image/reflect-config.json

Lines changed: 1563 additions & 2933 deletions
Large diffs are not rendered by default.

compiler/lib/src/main/scala/analysis/Analysis.scala

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ case class Analysis(
7171
interfaceMap: Map[Symbol.Interface, Interface] = Map(),
7272
/** The interface under construction */
7373
interface: Option[Interface] = None,
74+
/** The map from topology symbols to 'partial' topologies
75+
* with only port interface/instance information */
76+
partialTopologyMap: Map[Symbol.Topology, Topology] = Map(),
7477
/** The map from topology symbols to topologies */
7578
topologyMap: Map[Symbol.Topology, Topology] = Map(),
7679
/** The topology under construction */
@@ -249,6 +252,29 @@ case class Analysis(
249252
for (cis <- getComponentInstanceSymbol(id))
250253
yield this.componentInstanceMap(cis)
251254

255+
/** Gets an interface instance symbol from the use-def map */
256+
def getInterfaceInstanceSymbol(id: AstNode.Id): Result.Result[InterfaceInstanceSymbol] =
257+
this.useDefMap(id) match {
258+
case cis: Symbol.ComponentInstance => Right(cis)
259+
case ts: Symbol.Topology => Right(ts)
260+
case s => Left(
261+
SemanticError.InvalidSymbol(
262+
s.getUnqualifiedName,
263+
Locations.get(id),
264+
"not a component instance or topology symbol",
265+
s.getLoc
266+
)
267+
)
268+
}
269+
270+
/** Gets an interface instance from the topology or component instance map */
271+
def getInterfaceInstance(id: AstNode.Id): Result.Result[InterfaceInstance] =
272+
for (iis <- getInterfaceInstanceSymbol(id))
273+
yield iis match {
274+
case cis: Symbol.ComponentInstance => InterfaceInstance.fromComponentInstance(this.componentInstanceMap(cis))
275+
case top: Symbol.Topology => InterfaceInstance.fromTopology(this.topologyMap(top))
276+
}
277+
252278
/** Gets an interface symbol from use-def map */
253279
def getInterfaceSymbol(id: AstNode.Id): Result.Result[Symbol.Interface] =
254280
this.useDefMap(id) match {

compiler/lib/src/main/scala/analysis/Analyzers/BasicUseAnalyzer.scala

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,15 @@ trait BasicUseAnalyzer extends TypeExpressionAnalyzer {
1212
/** A use of a component definition */
1313
def componentUse(a: Analysis, node: AstNode[Ast.QualIdent], use: Name.Qualified): Result = default(a)
1414

15-
/** A use of a component instance definition */
16-
def componentInstanceUse(a: Analysis, node: AstNode[Ast.QualIdent], use: Name.Qualified): Result = default(a)
15+
/** A use of a interface instance (topology def or component instance def) */
16+
def interfaceInstanceUse(a: Analysis, node: AstNode[Ast.QualIdent], use: Name.Qualified): Result = default(a)
1717

1818
/** A use of a constant definition or enumerated constant definition */
1919
def constantUse(a: Analysis, node: AstNode[Ast.Expr], use: Name.Qualified): Result = default(a)
2020

2121
/** A use of a port definition */
2222
def portUse(a: Analysis, node: AstNode[Ast.QualIdent], use: Name.Qualified): Result = default(a)
2323

24-
/** A use of a topology definition */
25-
def topologyUse(a: Analysis, node: AstNode[Ast.QualIdent], use: Name.Qualified): Result = default(a)
26-
2724
/** A use of an interface definition */
2825
def interfaceUse(a: Analysis, node: AstNode[Ast.QualIdent], use: Name.Qualified): Result = default(a)
2926

@@ -85,6 +82,13 @@ trait BasicUseAnalyzer extends TypeExpressionAnalyzer {
8582
val id = node._2.id
8683
for {
8784
a <- visitImpliedUses(a, id)
85+
86+
// Visit port interface uses in the implements clause
87+
a <- {
88+
Result.foldLeft (node._2.data.implements) (a) ((a, impl) =>
89+
qualIdentNode(interfaceUse) (a, impl)
90+
)}
91+
8892
a <- super.defTopologyAnnotatedNode(a, node)
8993
} yield a
9094
}
@@ -116,10 +120,10 @@ trait BasicUseAnalyzer extends TypeExpressionAnalyzer {
116120
constantUse(a, node, use)
117121
}
118122

119-
override def specCompInstanceAnnotatedNode(a: Analysis, node: Ast.Annotated[AstNode[Ast.SpecCompInstance]]) = {
123+
override def specInstanceAnnotatedNode(a: Analysis, node: Ast.Annotated[AstNode[Ast.SpecInstance]]) = {
120124
val (_, node1, _) = node
121125
val data = node1.data
122-
qualIdentNode (componentInstanceUse) (a, data.instance)
126+
qualIdentNode (interfaceInstanceUse) (a, data.instance)
123127
}
124128

125129
override def specStateMachineInstanceAnnotatedNode(a: Analysis, node: Ast.Annotated[AstNode[Ast.SpecStateMachineInstance]]) = {
@@ -146,8 +150,8 @@ trait BasicUseAnalyzer extends TypeExpressionAnalyzer {
146150
data match {
147151
case direct : Ast.SpecConnectionGraph.Direct => visitList(a, direct.connections, connection)
148152
case pattern : Ast.SpecConnectionGraph.Pattern => for {
149-
a <- qualIdentNode (componentInstanceUse) (a, pattern.source)
150-
a <- visitList(a, pattern.targets, qualIdentNode(componentInstanceUse))
153+
a <- qualIdentNode (interfaceInstanceUse) (a, pattern.source)
154+
a <- visitList(a, pattern.targets, qualIdentNode(interfaceInstanceUse))
151155
} yield a
152156
}
153157
}
@@ -187,16 +191,16 @@ trait BasicUseAnalyzer extends TypeExpressionAnalyzer {
187191
a <- visitList(a, aNode._2.data.omitted, tlmChannelIdentifierNode)
188192
} yield a
189193

190-
override def specTopImportAnnotatedNode(a: Analysis, node: Ast.Annotated[AstNode[Ast.SpecImport]]) = {
194+
override def specInterfaceImportAnnotatedNode(a: Analysis, node: Ast.Annotated[AstNode[Ast.SpecImport]]) = {
191195
val (_, node1, _) = node
192196
val data = node1.data
193-
qualIdentNode(topologyUse)(a, data.sym)
197+
qualIdentNode(interfaceUse)(a, data.sym)
194198
}
195199

196-
override def specInterfaceImportAnnotatedNode(a: Analysis, node: Ast.Annotated[AstNode[Ast.SpecImport]]) = {
200+
override def specTopPortAnnotatedNode(a: Analysis, node: Ast.Annotated[AstNode[Ast.SpecTopPort]]) = {
197201
val (_, node1, _) = node
198202
val data = node1.data
199-
qualIdentNode(interfaceUse)(a, data.sym)
203+
portInstanceIdentifierNode(a, data.underlyingPort)
200204
}
201205

202206
override def typeNameQualIdentNode(a: Analysis, node: AstNode[Ast.TypeName], tn: Ast.TypeNameQualIdent) = {
@@ -217,7 +221,7 @@ trait BasicUseAnalyzer extends TypeExpressionAnalyzer {
217221
}
218222

219223
private def portInstanceIdentifierNode(a: Analysis, node: AstNode[Ast.PortInstanceIdentifier]): Result =
220-
qualIdentNode (componentInstanceUse) (a, node.data.componentInstance)
224+
qualIdentNode (interfaceInstanceUse) (a, node.data.interfaceInstance)
221225

222226
private def qualIdentNode
223227
(f: (Analysis, AstNode[Ast.QualIdent], Name.Qualified) => Result)
@@ -230,7 +234,7 @@ trait BasicUseAnalyzer extends TypeExpressionAnalyzer {
230234
a: Analysis,
231235
node: AstNode[Ast.TlmChannelIdentifier]
232236
): Result =
233-
qualIdentNode (componentInstanceUse) (a, node.data.componentInstance)
237+
qualIdentNode (interfaceInstanceUse) (a, node.data.componentInstance)
234238

235239
private def tlmPacketMember(a: Analysis, member: Ast.TlmPacketMember) =
236240
member match {

compiler/lib/src/main/scala/analysis/Analyzers/TopologyAnalyzer.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ object TopologyAnalyzer {
2121
node: Ast.Annotated[AstNode[Ast.DefTopology]]
2222
) = {
2323
val (_, node1, _) = node
24-
val Ast.DefTopology(name, members) = node1.data
24+
val Ast.DefTopology(name, members, _) = node1.data
2525
val a1 = a.copy(scopeNameList = name :: a.scopeNameList)
2626
for { a2 <- analyzer.visitList(a1, members, analyzer.matchTopologyMember) }
2727
yield a2.copy(scopeNameList = a.scopeNameList)

compiler/lib/src/main/scala/analysis/Analyzers/UseAnalyzer.scala

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package fpp.compiler.analysis
22

3-
import fpp.compiler.ast._
4-
import fpp.compiler.util._
3+
import fpp.compiler.ast.*
4+
import fpp.compiler.util.*
5+
6+
import scala.annotation.tailrec
57

68
/**
79
* Analyze uses
@@ -10,6 +12,7 @@ import fpp.compiler.util._
1012
trait UseAnalyzer extends BasicUseAnalyzer {
1113

1214
/** Gets a qualified name from a dot expression */
15+
@tailrec
1316
private def getQualifiedName(
1417
e: Ast.Expr,
1518
qualifier: List[Name.Unqualified] = Nil
@@ -18,7 +21,7 @@ trait UseAnalyzer extends BasicUseAnalyzer {
1821
Name.Qualified.fromIdentList(id :: qualifier)
1922
case Ast.ExprDot(e1, id) =>
2023
getQualifiedName(e1.data, id.data :: qualifier)
21-
case _ => throw new InternalError("expected a qualified name")
24+
case _ => throw InternalError("expected a qualified name")
2225
}
2326

2427
override def exprDotNode(a: Analysis, node: AstNode[Ast.Expr], e: Ast.ExprDot) =
@@ -29,7 +32,7 @@ trait UseAnalyzer extends BasicUseAnalyzer {
2932
constantUse(a, node, use)
3033
case Some(_) =>
3134
// This is some other type of symbol, which it shouldn't be
32-
throw new InternalError("expected a constant use")
35+
throw InternalError("expected a constant use")
3336
case None =>
3437
// e is not a use, so it selects a member of a struct value
3538
// Analyze the left-hand expression representing the struct value

compiler/lib/src/main/scala/analysis/CheckSemantics/CheckSemantics.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ object CheckSemantics {
2525
a <- CheckComponentInstanceDefs.visitList(a, tul, CheckComponentInstanceDefs.transUnit)
2626
_ <- CheckComponentInstanceDefs.checkIdRanges(a)
2727
a <- CheckStateMachineDefs.visitList(a, tul, CheckStateMachineDefs.transUnit)
28+
a <- CheckTopologyInstances.visitList(a, tul, CheckTopologyInstances.transUnit)
2829
a <- CheckTopologyDefs.visitList(a, tul, CheckTopologyDefs.transUnit)
2930
a <- BuildSpecLocMap.visitList(a, tul, BuildSpecLocMap.transUnit)
3031
a <- CheckSpecLocs.visitList(a, tul, CheckSpecLocs.transUnit)

compiler/lib/src/main/scala/analysis/CheckSemantics/CheckSpecLocs.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ object CheckSpecLocs
3232
override def defComponentInstanceAnnotatedNode(
3333
a: Analysis,
3434
aNode: Ast.Annotated[AstNode[Ast.DefComponentInstance]]
35-
) = checkSpecLoc(a, Ast.SpecLoc.ComponentInstance, Symbol.ComponentInstance(aNode))
35+
) = checkSpecLoc(a, Ast.SpecLoc.Instance, Symbol.ComponentInstance(aNode))
3636

3737
override def defConstantAnnotatedNode(
3838
a: Analysis,
@@ -67,7 +67,7 @@ object CheckSpecLocs
6767
override def defTopologyAnnotatedNode(
6868
a: Analysis,
6969
aNode: Ast.Annotated[AstNode[Ast.DefTopology]]
70-
) = checkSpecLoc(a, Ast.SpecLoc.Topology, Symbol.Topology(aNode))
70+
) = checkSpecLoc(a, Ast.SpecLoc.Instance, Symbol.Topology(aNode))
7171

7272
private def checkSpecLoc(
7373
a: Analysis,

compiler/lib/src/main/scala/analysis/CheckSemantics/CheckTopologyDefs.scala

Lines changed: 9 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import fpp.compiler.util._
55

66
/** Check topology definitions */
77
object CheckTopologyDefs
8-
extends Analyzer
8+
extends Analyzer
99
with ModuleAnalyzer
1010
with TopologyAnalyzer
1111
{
@@ -18,19 +18,22 @@ object CheckTopologyDefs
1818
a.topologyMap.get(symbol) match {
1919
case None =>
2020
// Topology is not in the map: visit it
21-
val a1 = a.copy(topology = Some(Topology(aNode)))
2221
for {
23-
// Visit topology members and compute unresolved top
24-
a <- super.defTopologyAnnotatedNode(a1, aNode)
25-
top <- Right(a.topology.get)
22+
// Resolve connections on topologies directly imported into this topology
2623
a <- {
2724
// Resolve topologies directly imported by top, updating a
28-
val tops = top.directImportMap.toList
25+
val top = a.partialTopologyMap(symbol)
26+
val tops = top.directTopologies.toList
2927
Result.foldLeft (tops) (a) ((a, tl) => {
3028
defTopologyAnnotatedNode(a, tl._1.node)
3129
})
3230
}
31+
32+
// Visit topology members and compute unresolved top
33+
a <- Right(a.copy(topology = Some(a.partialTopologyMap(symbol))))
34+
a <- super.defTopologyAnnotatedNode(a, aNode)
3335
// Use the updated analysis to resolve top
36+
top <- Right(a.topology.get)
3437
top <- ResolveTopology.resolve(a, top)
3538
}
3639
yield a.copy(topologyMap = a.topologyMap + (symbol -> top))
@@ -41,24 +44,6 @@ object CheckTopologyDefs
4144
}
4245
}
4346

44-
override def specCompInstanceAnnotatedNode(
45-
a: Analysis,
46-
aNode: Ast.Annotated[AstNode[Ast.SpecCompInstance]]
47-
) = {
48-
val node = aNode._2
49-
val visibility = node.data.visibility
50-
val instanceNode = node.data.instance
51-
for {
52-
instance <- a.getComponentInstance(instanceNode.id)
53-
topology <- a.topology.get.addUniqueInstance(
54-
instance,
55-
visibility,
56-
Locations.get(node.id)
57-
)
58-
}
59-
yield a.copy(topology = Some(topology))
60-
}
61-
6247
override def specConnectionGraphAnnotatedNode(
6348
a: Analysis,
6449
aNode: Ast.Annotated[AstNode[Ast.SpecConnectionGraph]]
@@ -79,20 +64,4 @@ object CheckTopologyDefs
7964
} yield a.copy(topology = Some(topology))
8065
}
8166

82-
override def specTopImportAnnotatedNode(
83-
a: Analysis,
84-
aNode: Ast.Annotated[AstNode[Ast.SpecImport]]
85-
) = {
86-
val node = aNode._2
87-
val topNode = node.data.sym
88-
for {
89-
ts <- a.getTopologySymbol(topNode.id)
90-
topology <- a.topology.get.addImportedTopology(
91-
ts,
92-
Locations.get(node.id)
93-
)
94-
}
95-
yield a.copy(topology = Some(topology))
96-
}
97-
9867
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package fpp.compiler.analysis
2+
3+
import fpp.compiler.ast._
4+
import fpp.compiler.util._
5+
6+
/** Check topology instances */
7+
object CheckTopologyInstances
8+
extends Analyzer
9+
with ModuleAnalyzer
10+
with TopologyAnalyzer
11+
{
12+
13+
override def defTopologyAnnotatedNode(
14+
a: Analysis,
15+
aNode: Ast.Annotated[AstNode[Ast.DefTopology]]
16+
) = {
17+
val symbol = Symbol.Topology(aNode)
18+
a.partialTopologyMap.get(symbol) match {
19+
case None =>
20+
// Topology is not in the map: visit it
21+
val a1 = a.copy(topology = Some(Topology(aNode, a.getQualifiedName(symbol))))
22+
for {
23+
// Visit topology members and compute unresolved top
24+
a <- super.defTopologyAnnotatedNode(a1, aNode)
25+
top <- Right(a.topology.get)
26+
a <- {
27+
// Resolve topologies directly imported by top, updating a
28+
val tops = top.directTopologies.toList
29+
Result.foldLeft (tops) (a) ((a, tl) => {
30+
defTopologyAnnotatedNode(a, tl._1.node)
31+
})
32+
}
33+
}
34+
yield a.copy(
35+
partialTopologyMap = a.partialTopologyMap + (symbol -> top)
36+
)
37+
case _ => {
38+
// Topology is already in the map: nothing to do
39+
Right(a)
40+
}
41+
}
42+
}
43+
44+
override def specTopPortAnnotatedNode(
45+
a: Analysis,
46+
aNode: Ast.Annotated[AstNode[Ast.SpecTopPort]]
47+
) = {
48+
Right(a.copy(topology = Some(a.topology.get.addPortNode(aNode))))
49+
}
50+
51+
override def specInstanceAnnotatedNode(
52+
a: Analysis,
53+
aNode: Ast.Annotated[AstNode[Ast.SpecInstance]]
54+
) = {
55+
val node = aNode._2
56+
val instanceNode = node.data.instance
57+
for {
58+
symbol <- a.getInterfaceInstanceSymbol(instanceNode.id)
59+
topology <- a.topology.get.addInstanceSymbol(symbol, Locations.get(node.id))
60+
}
61+
yield a.copy(topology = Some(topology))
62+
}
63+
64+
}

compiler/lib/src/main/scala/analysis/CheckSemantics/CheckUseDefCycles.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ object CheckUseDefCycles extends UseAnalyzer {
5252
override def interfaceUse(a: Analysis, node: AstNode[Ast.QualIdent], use: Name.Qualified) =
5353
visitUse(a, node, use)
5454

55-
override def topologyUse(a: Analysis, node: AstNode[Ast.QualIdent], use: Name.Qualified) =
55+
override def interfaceInstanceUse(a: Analysis, node: AstNode[Ast.QualIdent], use: Name.Qualified) =
5656
visitUse(a, node, use)
5757

5858
override def typeUse(a: Analysis, node: AstNode[Ast.TypeName], use: Name.Qualified) =

0 commit comments

Comments
 (0)