From c423feca7583bd474ff982cd0baa7df052698126 Mon Sep 17 00:00:00 2001 From: jawest Date: Wed, 28 Aug 2024 17:08:24 -0700 Subject: [PATCH 01/73] update spec, add unmatched keyword --- compiler/lib/src/main/scala/ast/Ast.scala | 10 ++++ .../lib/src/main/scala/syntax/Lexer.scala | 1 + .../lib/src/main/scala/syntax/Parser.scala | 14 ++++-- .../lib/src/main/scala/syntax/Token.scala | 1 + docs/README.adoc | 8 +++ docs/code-prettify/run_prettify.js | 1 + docs/fpp-spec.html | 49 ++++++++++++++----- .../Definitions/Topology-Definitions.adoc | 24 +++++---- docs/spec/Lexical-Elements.adoc | 1 + .../Connection-Graph-Specifiers.adoc | 11 ++++- editors/emacs/fpp-mode.el | 2 +- editors/vim/fpp.vim | 1 + 12 files changed, 95 insertions(+), 28 deletions(-) diff --git a/compiler/lib/src/main/scala/ast/Ast.scala b/compiler/lib/src/main/scala/ast/Ast.scala index 26768d018..d65eb7755 100644 --- a/compiler/lib/src/main/scala/ast/Ast.scala +++ b/compiler/lib/src/main/scala/ast/Ast.scala @@ -374,6 +374,7 @@ object Ast { /** Connection */ final case class Connection( + unmatched: Option[ConnectionMatching], fromPort: AstNode[PortInstanceIdentifier], fromIndex: Option[AstNode[Expr]], toPort: AstNode[PortInstanceIdentifier], @@ -706,4 +707,13 @@ object Ast { } } + sealed trait ConnectionMatching + object ConnectionMatching { + case object Unmatched extends ConnectionMatching { + override def toString = "unmatched" + } + case object PossiblyMatched extends ConnectionMatching { + override def toString = "possibly matched" + } + } } diff --git a/compiler/lib/src/main/scala/syntax/Lexer.scala b/compiler/lib/src/main/scala/syntax/Lexer.scala index 5002f6dbc..f3d84486b 100644 --- a/compiler/lib/src/main/scala/syntax/Lexer.scala +++ b/compiler/lib/src/main/scala/syntax/Lexer.scala @@ -324,6 +324,7 @@ object Lexer extends RegexParsers { ("topology", (u: Unit) => Token.TOPOLOGY()), ("true", (u: Unit) => Token.TRUE()), ("type", (u: Unit) => Token.TYPE()), + ("unmatched", (u: Unit) => Token.UNMATCHED()), ("update", (u: Unit) => Token.UPDATE()), ("warning", (u: Unit) => Token.WARNING()), ("with", (u: Unit) => Token.WITH()), diff --git a/compiler/lib/src/main/scala/syntax/Parser.scala b/compiler/lib/src/main/scala/syntax/Parser.scala index 136495a86..b5020164a 100644 --- a/compiler/lib/src/main/scala/syntax/Parser.scala +++ b/compiler/lib/src/main/scala/syntax/Parser.scala @@ -46,9 +46,10 @@ object Parser extends Parsers { def connection: Parser[Ast.SpecConnectionGraph.Connection] = { def connectionPort = node(portInstanceIdentifier) ~! opt(index) - connectionPort ~! (rarrow ~>! connectionPort) ^^ { - case (fromPort ~ fromIndex) ~ (toPort ~ toIndex) => { + opt(unmatched) ~! connectionPort ~! (rarrow ~>! connectionPort) ^^ { + case maybeUnmatched ~ (fromPort ~ fromIndex) ~ (toPort ~ toIndex) => { Ast.SpecConnectionGraph.Connection( + maybeUnmatched, fromPort, fromIndex, toPort, @@ -388,7 +389,9 @@ object Parser extends Parsers { def specConnectionGraph: Parser[Ast.SpecConnectionGraph] = { def directGraph = { (connections ~> ident) ~! (lbrace ~>! elementSequence(connection, comma) <~! rbrace) ^^ { - case ident ~ connections => Ast.SpecConnectionGraph.Direct(ident, connections) + case ident ~ connections => { + Ast.SpecConnectionGraph.Direct(ident, connections) + } } } def patternGraph = { @@ -911,6 +914,11 @@ object Parser extends Parsers { private def typeToken = accept("type", { case t : Token.TYPE => t }) + private def unmatched = accept("unmatched", { + case t : Token.UNMATCHED => Ast.ConnectionMatching.Unmatched + case _ => Ast.ConnectionMatching.PossiblyMatched + }) + private def update = accept("update", { case t : Token.UPDATE => t }) private def warning = accept("warning", { case t : Token.WARNING => t }) diff --git a/compiler/lib/src/main/scala/syntax/Token.scala b/compiler/lib/src/main/scala/syntax/Token.scala index fd735b5eb..cfc58b32c 100644 --- a/compiler/lib/src/main/scala/syntax/Token.scala +++ b/compiler/lib/src/main/scala/syntax/Token.scala @@ -115,6 +115,7 @@ object Token { final case class U32() extends Token final case class U64() extends Token final case class U8() extends Token + final case class UNMATCHED() extends Token final case class UNUSED() extends Token final case class UPDATE() extends Token final case class WARNING() extends Token diff --git a/docs/README.adoc b/docs/README.adoc index 54ff2a773..d6ad7b97f 100644 --- a/docs/README.adoc +++ b/docs/README.adoc @@ -11,3 +11,11 @@ system: Once you have these tools installed, you can run `redo` in this directory to regenerate the HTML files from the AsciiDoc source files. + + +== Adding Keywords to FPP Specification +. To add a new FPP keyword, first update the Lexical Elements section of the FPP spec. +. Next, update the `doc/code-prettify/run_prettify.js` file so it includes the new keyword. +. Doing this will add highlight the keyword in the FPP spec. +. Finally, update `editors/emacs/fpp-mode.el` and `editors/vim/fpp.vim` so the emacs and vim +editors syntax highlighting for the new keyword. \ No newline at end of file diff --git a/docs/code-prettify/run_prettify.js b/docs/code-prettify/run_prettify.js index d791d31d6..a8a498e07 100644 --- a/docs/code-prettify/run_prettify.js +++ b/docs/code-prettify/run_prettify.js @@ -479,6 +479,7 @@ var IN_GLOBAL_SCOPE = false; "time," + "topology," + "type," + + "unmatched," + "update," + "warning," + "with," + diff --git a/docs/fpp-spec.html b/docs/fpp-spec.html index 06d2d3c6f..601aee82d 100644 --- a/docs/fpp-spec.html +++ b/docs/fpp-spec.html @@ -140,7 +140,7 @@ #content::before{content:none} #header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0} #header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #dddddf} -#header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px} +#header>h1:only-child{border-bottom:1px solid #dddddf;padding-bottom:8px} #header .details{border-bottom:1px solid #dddddf;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:flex;flex-flow:row wrap} #header .details span:first-child{margin-left:-.125em} #header .details span.email a{color:rgba(0,0,0,.85)} @@ -162,6 +162,7 @@ #toctitle{color:#7a2518;font-size:1.2em} @media screen and (min-width:768px){#toctitle{font-size:1.375em} body.toc2{padding-left:15em;padding-right:0} +body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px} #toc.toc2{margin-top:0!important;background:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #e7e7e9;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto} #toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em} #toc.toc2>ul{font-size:.9em;margin-bottom:0} @@ -327,7 +328,7 @@ a.image object{pointer-events:none} sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super} sup.footnote a,sup.footnoteref a{text-decoration:none} -sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline} +sup.footnote a:active,sup.footnoteref a:active,#footnotes .footnote a:first-of-type:active{text-decoration:underline} #footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em} #footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em;border-width:1px 0 0} #footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;margin-bottom:.2em} @@ -1006,6 +1007,7 @@

3.1. Reserved Words

guarded health high +hook id import include @@ -1053,6 +1055,7 @@

3.1. Reserved Words

topology true type +unmatched update warning with @@ -2861,7 +2864,12 @@
  1. -

    For each connection \$c_1\$ with an endpoint at I . \$p_1\$:

    +

    Any connection that names I . \$p_1\$ or I . \$p_2\$ +is match constrained. If a match constrained connection is marked +unmatched then it is unmatched; otherwise it is matched.

    +
  2. +
  3. +

    For each matched connection \$c_1\$ with an endpoint at I . \$p_1\$:

    1. @@ -2869,24 +2877,24 @@
    2. -

      Check that there is one and only one connection -\$c_2\$ from I' to I . \$p_2\$.

      +

      Check that there is one +and only one connection \$c_2\$ from I' to I . \$p_2\$.

  4. Check that the connections \$c_2\$ computed in the previous -step are all the connections at I . \$p_2\$.

    +step are all the matched connections at I . \$p_2\$.

  5. -

    For each pair \$(c_1,c_2)\$ that has both port numbers assigned, -check that the port numbers match. -For each pair \$(c_1,c_2)\$ that has exactly one port number assigned, +

    For each pair P with \$(c_1,c_2)\$ computed in step b, if P +has both numbers assigned, check that the port numbers match. +For each P that has exactly one port number assigned, assign the other one to match.

  6. -

    Traverse the pairs \$(c_1,c_2)\$ according to the +

    Traverse the pairs \$(c_1,c_2)\$ computed in step b according to the order of the connections \$c_1\$, least to greatest. For each pair \$(c_1,c_2)\$ that does not yet have assigned port numbers, find the lowest available port number @@ -3482,7 +3490,10 @@

    6.3.1. Syntax

    A connection is the following:

    -

    port-instance-id +

    [ +unmatched +] +port-instance-id [ [ expression @@ -3543,7 +3554,8 @@

    6.3.2. Semantics

  7. The connection sequence specifies the set of connections in the graph. -For each connection C:

    +For each +match constrained connection C:

    1. @@ -3551,6 +3563,11 @@

      6.3.2. Semantics

      1. +

        The optional keyword unmatched, if present, specifies that +the connection is explicitly unmatched. unmatched must only be used on +matched connections.

        +
      2. +
      3. The component instance named in I must be available in the enclosing topology, either through @@ -4595,6 +4612,9 @@

        6.11.1. Syntax

      4. drop

      5. +
      6. +

        hook

        +
      @@ -4747,6 +4767,9 @@

      6.11.2. Semantics

    2. drop means that the message is dropped.

    3. +
    4. +

      hook means that the message is passed to a user-supplied hook function.

      +
    @@ -8551,7 +8574,7 @@

    20.4. Translation Tools

    diff --git a/docs/spec/Definitions/Topology-Definitions.adoc b/docs/spec/Definitions/Topology-Definitions.adoc index 8eeeb0896..bc605e768 100644 --- a/docs/spec/Definitions/Topology-Definitions.adoc +++ b/docs/spec/Definitions/Topology-Definitions.adoc @@ -140,24 +140,28 @@ For each instance _I_ in the topology: . For each <> `match` stem:[p_1] `with` stem:[p_2] appearing in the definition of _C_: + +.. Any connection that names _I_ `.` stem:[p_1] or _I_ `.` stem:[p_2] +is *match constrained*. If a match constrained connection is marked +`unmatched` then it is *unmatched*; otherwise it is *matched*. -.. For each connection stem:[c_1] with an endpoint at _I_ `.` stem:[p_1]: - +.. For each matched connection stem:[c_1] with an endpoint at _I_ `.` stem:[p_1]: + ... Let _I'_ be the component instance at the other endpoint of stem:[c_1]. -... Check that there is one and only one connection -stem:[c_2] from _I'_ to _I_ `.` stem:[p_2]. +... Check that there is one +and only one connection stem:[c_2] from _I'_ to _I_ `.` stem:[p_2]. -.. Check that the connections stem:[c_2] computed in the previous -step are all the connections at _I_ `.` stem:[p_2]. +.. Check that the connections stem:[c_2] computed in the previous +step are all the matched connections at _I_ `.` stem:[p_2]. -.. For each pair stem:[(c_1,c_2)] that has both port numbers assigned, -check that the port numbers match. -For each pair stem:[(c_1,c_2)] that has exactly one port number assigned, +.. For each pair _P_ with stem:[(c_1,c_2)] computed in step b, if _P_ +has both numbers assigned, check that the port numbers match. +For each _P_ that has exactly one port number assigned, assign the other one to match. -.. Traverse the pairs stem:[(c_1,c_2)] according to the +.. Traverse the pairs stem:[(c_1,c_2)] computed in step b according to the <> of the connections stem:[c_1], least to greatest. For each pair stem:[(c_1,c_2)] that does not yet have assigned diff --git a/docs/spec/Lexical-Elements.adoc b/docs/spec/Lexical-Elements.adoc index 8f1234414..a1baf6016 100644 --- a/docs/spec/Lexical-Elements.adoc +++ b/docs/spec/Lexical-Elements.adoc @@ -118,6 +118,7 @@ time topology true type +unmatched update warning with diff --git a/docs/spec/Specifiers/Connection-Graph-Specifiers.adoc b/docs/spec/Specifiers/Connection-Graph-Specifiers.adoc index 77cc42eec..32747c6bd 100644 --- a/docs/spec/Specifiers/Connection-Graph-Specifiers.adoc +++ b/docs/spec/Specifiers/Connection-Graph-Specifiers.adoc @@ -34,6 +34,9 @@ which each element is a *connection*, and the terminating punctuation is a comma. A connection is the following: +_[_ +`unmatched` +_]_ <> _[_ `[` @@ -77,10 +80,16 @@ A direct graph specifier directly specifies a named connection graph. the connection graph. . The connection sequence specifies the set of connections in the graph. -For each connection _C_: +For each +<> connection _C_: .. For each of the two port instance identifiers _I_ appearing in _C_: +... The optional keyword `unmatched`, if present, specifies that +the connection is explicitly unmatched. `unmatched` must only be used on +matched connections. + ... The component instance named in _I_ must be available in the enclosing topology, either through diff --git a/editors/emacs/fpp-mode.el b/editors/emacs/fpp-mode.el index 9b0f20584..142ed7282 100644 --- a/editors/emacs/fpp-mode.el +++ b/editors/emacs/fpp-mode.el @@ -50,7 +50,7 @@ "queue" "queued" "raw" "recv" "red" "ref" "reg" "resp" "save" "serial" "set" "severity" "size" "stack" "sync" "telemetry" "text" "throttle" - "time" "true" "update" "warning" "with" "yellow") + "time" "true" "unmatched" "update" "warning" "with" "yellow") "All non-definition keywords for FPP.") (defconst fpp-mode-types diff --git a/editors/vim/fpp.vim b/editors/vim/fpp.vim index 33ca7edf8..e7d92e4f6 100644 --- a/editors/vim/fpp.vim +++ b/editors/vim/fpp.vim @@ -83,6 +83,7 @@ syn keyword fppKeyword time syn keyword fppKeyword topology syn keyword fppKeyword true syn keyword fppKeyword type +syn keyword fppKeyword unmatched syn keyword fppKeyword update syn keyword fppKeyword warning syn keyword fppKeyword with From c734be20c65d45faaff8043b0a1a8c9e28358f1c Mon Sep 17 00:00:00 2001 From: jawest Date: Wed, 28 Aug 2024 17:10:26 -0700 Subject: [PATCH 02/73] fix formatting --- docs/README.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/README.adoc b/docs/README.adoc index d6ad7b97f..b2b16964a 100644 --- a/docs/README.adoc +++ b/docs/README.adoc @@ -15,7 +15,7 @@ to regenerate the HTML files from the AsciiDoc source files. == Adding Keywords to FPP Specification . To add a new FPP keyword, first update the Lexical Elements section of the FPP spec. -. Next, update the `doc/code-prettify/run_prettify.js` file so it includes the new keyword. -. Doing this will add highlight the keyword in the FPP spec. +. Next, update the `doc/code-prettify/run_prettify.js` file so it includes the new keyword. +Doing this will add syntax highlighting the keyword in the FPP spec. . Finally, update `editors/emacs/fpp-mode.el` and `editors/vim/fpp.vim` so the emacs and vim editors syntax highlighting for the new keyword. \ No newline at end of file From 1b8ff6be922c900780d3d059591ee4504dd0d06a Mon Sep 17 00:00:00 2001 From: jawest Date: Thu, 5 Sep 2024 17:45:49 -0700 Subject: [PATCH 03/73] update matched port numbering, add connection matching semantics --- .../scala/analysis/Semantics/Connection.scala | 46 ++++++++++++++++++- .../MatchedPortNumbering.scala | 24 ++++++---- .../ResolveTopology/PatternResolver.scala | 2 +- compiler/lib/src/main/scala/ast/Ast.scala | 2 +- .../XmlFppWriter/TopologyXmlFppWriter.scala | 1 + .../lib/src/main/scala/syntax/Parser.scala | 9 ++-- compiler/lib/src/main/scala/util/Error.scala | 5 ++ 7 files changed, 70 insertions(+), 19 deletions(-) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/Connection.scala b/compiler/lib/src/main/scala/analysis/Semantics/Connection.scala index 7dc1d04f4..59464f1cb 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/Connection.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/Connection.scala @@ -5,6 +5,7 @@ import fpp.compiler.util._ /** An FPP connection */ case class Connection( + connectionMatching: Connection.ConnectionMatching, /** The from endpoint */ from: Connection.Endpoint, /** The to endpoint */ @@ -141,7 +142,8 @@ object Connection { for { from <- Endpoint.fromAst(a, connection.fromPort, connection.fromIndex) to <- Endpoint.fromAst(a, connection.toPort, connection.toIndex) - connection <- Right(Connection(from, to)) + connectionMatching <- ConnectionMatching.fromAst(connection.connectionMatching, from, to) + connection <- Right(Connection(connectionMatching, from, to)) _ <- connection.checkDirections _ <- connection.checkTypes _ <- connection.checkSerialWithTypedInput @@ -184,7 +186,30 @@ object Connection { else Left(SemanticError.InvalidPortNumber(loc, n, name, size, specLoc)) case None => Right(()) } + } + case class ConnectionMatching( + isUnmatched: Boolean + ) { + + def checkMatchingPorts(from: Connection.Endpoint, to: Connection.Endpoint): Result.Result[Unit] = { + def checkMatch(pml: List[Component.PortMatching], pi: PortInstance): Result.Result[Unit] = + if(pml.exists(pm => pi.equals(pm.instance1) || pi.equals(pm.instance2))) then Right(()) + else Left(SemanticError.MissingPortMatching(pi.getLoc)) + + val fromPi = from.port.portInstance + val toPi = to.port.portInstance + val fromPml = from.port.componentInstance.component.portMatchingList + val toPml = to.port.componentInstance.component.portMatchingList + + if(fromPml.isEmpty & toPml.isEmpty) then Left(SemanticError.MissingPortMatching(from.loc)) + else { + for { + _ <- if(!fromPml.isEmpty) then checkMatch(fromPml, fromPi) else Right(()) + _ <- if(!toPml.isEmpty) then checkMatch(toPml, toPi) else Right(()) + } yield Right(()) + } + } } object Endpoint { @@ -207,4 +232,23 @@ object Connection { } + object ConnectionMatching { + + def fromAst( + connectionMatchingAst: Ast.ConnectionMatching, + from: Connection.Endpoint, + to: Connection.Endpoint + ): Result.Result[ConnectionMatching] = for { + connectionMatching <- connectionMatchingAst match { + case Ast.ConnectionMatching.Unmatched => Right(ConnectionMatching(true)) + case _ => Right(ConnectionMatching(false)) + } + _ <- { + if(connectionMatching.isUnmatched) then connectionMatching.checkMatchingPorts(from, to) + else Right(()) + } + } yield connectionMatching + + } + } diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala index 0264bc048..065904400 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala @@ -161,17 +161,21 @@ object MatchedPortNumbering { val pii = PortInstanceIdentifier(ci, pi) val cs = t.getConnectionsAt(pii).toList.sorted Result.foldLeft (cs) (empty) ((m, c) => { - val piiRemote = c.getOtherEndpoint(pi).port - val ciRemote = piiRemote.componentInstance - m.get(ciRemote) match { - case Some(cPrev) => Left( - SemanticError.DuplicateMatchedConnection( - c.getLoc, - cPrev.getLoc, - portMatching.getLoc + if(c.connectionMatching.isUnmatched) + Right(m) + else { + val piiRemote = c.getOtherEndpoint(pi).port + val ciRemote = piiRemote.componentInstance + m.get(ciRemote) match { + case Some(cPrev) => Left( + SemanticError.DuplicateMatchedConnection( + c.getLoc, + cPrev.getLoc, + portMatching.getLoc + ) ) - ) - case None => Right(m + (ciRemote -> c)) + case None => Right(m + (ciRemote -> c)) + } } }) } diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PatternResolver.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PatternResolver.scala index 7c66be44d..da95d3790 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PatternResolver.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PatternResolver.scala @@ -108,7 +108,7 @@ object PatternResolver { ) = { val from = Connection.Endpoint(loc, fromPii) val to = Connection.Endpoint(loc, toPii) - Connection(from, to) + Connection(Connection.ConnectionMatching(false), from, to) } private def missingPort[T]( diff --git a/compiler/lib/src/main/scala/ast/Ast.scala b/compiler/lib/src/main/scala/ast/Ast.scala index d65eb7755..085481776 100644 --- a/compiler/lib/src/main/scala/ast/Ast.scala +++ b/compiler/lib/src/main/scala/ast/Ast.scala @@ -374,7 +374,7 @@ object Ast { /** Connection */ final case class Connection( - unmatched: Option[ConnectionMatching], + connectionMatching: ConnectionMatching, fromPort: AstNode[PortInstanceIdentifier], fromIndex: Option[AstNode[Expr]], toPort: AstNode[PortInstanceIdentifier], diff --git a/compiler/lib/src/main/scala/codegen/XmlFppWriter/TopologyXmlFppWriter.scala b/compiler/lib/src/main/scala/codegen/XmlFppWriter/TopologyXmlFppWriter.scala index fa6843ef1..d5b710ae7 100644 --- a/compiler/lib/src/main/scala/codegen/XmlFppWriter/TopologyXmlFppWriter.scala +++ b/compiler/lib/src/main/scala/codegen/XmlFppWriter/TopologyXmlFppWriter.scala @@ -129,6 +129,7 @@ object TopologyXmlFppWriter extends LineUtils { } yield { Ast.SpecConnectionGraph.Connection( + Ast.ConnectionMatching.PossiblyMatched, from._1, from._2, to._1, diff --git a/compiler/lib/src/main/scala/syntax/Parser.scala b/compiler/lib/src/main/scala/syntax/Parser.scala index b5020164a..9df852482 100644 --- a/compiler/lib/src/main/scala/syntax/Parser.scala +++ b/compiler/lib/src/main/scala/syntax/Parser.scala @@ -47,9 +47,9 @@ object Parser extends Parsers { def connection: Parser[Ast.SpecConnectionGraph.Connection] = { def connectionPort = node(portInstanceIdentifier) ~! opt(index) opt(unmatched) ~! connectionPort ~! (rarrow ~>! connectionPort) ^^ { - case maybeUnmatched ~ (fromPort ~ fromIndex) ~ (toPort ~ toIndex) => { + case unmatched ~ (fromPort ~ fromIndex) ~ (toPort ~ toIndex) => { Ast.SpecConnectionGraph.Connection( - maybeUnmatched, + unmatched.getOrElse(Ast.ConnectionMatching.PossiblyMatched), fromPort, fromIndex, toPort, @@ -914,10 +914,7 @@ object Parser extends Parsers { private def typeToken = accept("type", { case t : Token.TYPE => t }) - private def unmatched = accept("unmatched", { - case t : Token.UNMATCHED => Ast.ConnectionMatching.Unmatched - case _ => Ast.ConnectionMatching.PossiblyMatched - }) + private def unmatched = accept("unmatched", { case t : Token.UNMATCHED => Ast.ConnectionMatching.Unmatched }) private def update = accept("update", { case t : Token.UPDATE => t }) diff --git a/compiler/lib/src/main/scala/util/Error.scala b/compiler/lib/src/main/scala/util/Error.scala index adacc24ab..f8ce44252 100644 --- a/compiler/lib/src/main/scala/util/Error.scala +++ b/compiler/lib/src/main/scala/util/Error.scala @@ -192,6 +192,8 @@ sealed trait Error { case SemanticError.MissingConnection(loc, matchingLoc) => Error.print (Some(loc)) ("no match for this connection") printMatchingLoc(matchingLoc) + case SemanticError.MissingPortMatching(loc) => + Error.print (Some(loc)) ("unmatched connections must use port matching") case SemanticError.MissingPort(loc, specMsg, portMsg) => Error.print (Some(loc)) (s"component with $specMsg must have $portMsg") case SemanticError.OverlappingIdRanges( @@ -472,6 +474,9 @@ object SemanticError { specMsg: String, portmsg: String ) extends Error + final case class MissingPortMatching( + loc: Location + ) extends Error /** Overlapping ID ranges */ final case class OverlappingIdRanges( maxId1: BigInt, From d3c3de33a86c534e2daaac01f43be389cb6e66e6 Mon Sep 17 00:00:00 2001 From: jawest Date: Thu, 5 Sep 2024 17:51:50 -0700 Subject: [PATCH 04/73] update docs readme --- docs/README.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.adoc b/docs/README.adoc index b2b16964a..39e6acd2a 100644 --- a/docs/README.adoc +++ b/docs/README.adoc @@ -16,6 +16,6 @@ to regenerate the HTML files from the AsciiDoc source files. == Adding Keywords to FPP Specification . To add a new FPP keyword, first update the Lexical Elements section of the FPP spec. . Next, update the `doc/code-prettify/run_prettify.js` file so it includes the new keyword. -Doing this will add syntax highlighting the keyword in the FPP spec. +Doing this will add syntax highlighting to the keyword in the FPP spec. . Finally, update `editors/emacs/fpp-mode.el` and `editors/vim/fpp.vim` so the emacs and vim editors syntax highlighting for the new keyword. \ No newline at end of file From ed4e051a19e873fd90b306fa0f41c384705680c6 Mon Sep 17 00:00:00 2001 From: jawest Date: Mon, 16 Sep 2024 08:55:59 -0700 Subject: [PATCH 05/73] cleanup --- .../scala/analysis/Semantics/Connection.scala | 67 ++++++------------- .../MatchedPortNumbering.scala | 2 +- .../ResolveTopology/PatternResolver.scala | 2 +- compiler/lib/src/main/scala/ast/Ast.scala | 12 +--- .../src/main/scala/codegen/AstWriter.scala | 2 +- .../src/main/scala/codegen/FppWriter.scala | 10 +-- .../XmlFppWriter/TopologyXmlFppWriter.scala | 2 +- .../lib/src/main/scala/syntax/Parser.scala | 4 +- docs/README.adoc | 8 --- 9 files changed, 33 insertions(+), 76 deletions(-) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/Connection.scala b/compiler/lib/src/main/scala/analysis/Semantics/Connection.scala index 59464f1cb..9af4c027a 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/Connection.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/Connection.scala @@ -5,7 +5,7 @@ import fpp.compiler.util._ /** An FPP connection */ case class Connection( - connectionMatching: Connection.ConnectionMatching, + isUnmatched: Boolean, /** The from endpoint */ from: Connection.Endpoint, /** The to endpoint */ @@ -104,6 +104,18 @@ case class Connection( } } + def checkMatchConstraint: Boolean = { + def portMatchingExists(pml: List[Component.PortMatching], pi: PortInstance): Boolean = + pml.exists(pm => pi.equals(pm.instance1) || pi.equals(pm.instance2)) + + val fromPi = from.port.portInstance + val toPi = to.port.portInstance + val fromPml = from.port.componentInstance.component.portMatchingList + val toPml = to.port.componentInstance.component.portMatchingList + + portMatchingExists(fromPml, fromPi) || portMatchingExists(toPml, toPi) + } + /** Compare two connections */ override def compare(that: Connection) = { val fromCompare = this.from.compare(that.from) @@ -142,11 +154,16 @@ object Connection { for { from <- Endpoint.fromAst(a, connection.fromPort, connection.fromIndex) to <- Endpoint.fromAst(a, connection.toPort, connection.toIndex) - connectionMatching <- ConnectionMatching.fromAst(connection.connectionMatching, from, to) - connection <- Right(Connection(connectionMatching, from, to)) + connection <- Right(Connection(connection.isUnmatched, from, to)) _ <- connection.checkDirections _ <- connection.checkTypes _ <- connection.checkSerialWithTypedInput + _ <- { + if !connection.checkMatchConstraint & connection.isUnmatched then + Left(SemanticError.MissingPortMatching(connection.getLoc)) + else + Right(()) + } } yield connection @@ -188,30 +205,6 @@ object Connection { } } - case class ConnectionMatching( - isUnmatched: Boolean - ) { - - def checkMatchingPorts(from: Connection.Endpoint, to: Connection.Endpoint): Result.Result[Unit] = { - def checkMatch(pml: List[Component.PortMatching], pi: PortInstance): Result.Result[Unit] = - if(pml.exists(pm => pi.equals(pm.instance1) || pi.equals(pm.instance2))) then Right(()) - else Left(SemanticError.MissingPortMatching(pi.getLoc)) - - val fromPi = from.port.portInstance - val toPi = to.port.portInstance - val fromPml = from.port.componentInstance.component.portMatchingList - val toPml = to.port.componentInstance.component.portMatchingList - - if(fromPml.isEmpty & toPml.isEmpty) then Left(SemanticError.MissingPortMatching(from.loc)) - else { - for { - _ <- if(!fromPml.isEmpty) then checkMatch(fromPml, fromPi) else Right(()) - _ <- if(!toPml.isEmpty) then checkMatch(toPml, toPi) else Right(()) - } yield Right(()) - } - } - } - object Endpoint { /** Constructs a connection endpoint from AST info */ @@ -229,26 +222,6 @@ object Connection { case None => Right(()) } } yield endpoint - - } - - object ConnectionMatching { - - def fromAst( - connectionMatchingAst: Ast.ConnectionMatching, - from: Connection.Endpoint, - to: Connection.Endpoint - ): Result.Result[ConnectionMatching] = for { - connectionMatching <- connectionMatchingAst match { - case Ast.ConnectionMatching.Unmatched => Right(ConnectionMatching(true)) - case _ => Right(ConnectionMatching(false)) - } - _ <- { - if(connectionMatching.isUnmatched) then connectionMatching.checkMatchingPorts(from, to) - else Right(()) - } - } yield connectionMatching - } } diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala index 065904400..da67a1494 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala @@ -161,7 +161,7 @@ object MatchedPortNumbering { val pii = PortInstanceIdentifier(ci, pi) val cs = t.getConnectionsAt(pii).toList.sorted Result.foldLeft (cs) (empty) ((m, c) => { - if(c.connectionMatching.isUnmatched) + if(c.isUnmatched) Right(m) else { val piiRemote = c.getOtherEndpoint(pi).port diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PatternResolver.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PatternResolver.scala index da95d3790..f8cb0a2de 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PatternResolver.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PatternResolver.scala @@ -108,7 +108,7 @@ object PatternResolver { ) = { val from = Connection.Endpoint(loc, fromPii) val to = Connection.Endpoint(loc, toPii) - Connection(Connection.ConnectionMatching(false), from, to) + Connection(false, from, to) } private def missingPort[T]( diff --git a/compiler/lib/src/main/scala/ast/Ast.scala b/compiler/lib/src/main/scala/ast/Ast.scala index 085481776..b583d3431 100644 --- a/compiler/lib/src/main/scala/ast/Ast.scala +++ b/compiler/lib/src/main/scala/ast/Ast.scala @@ -374,7 +374,7 @@ object Ast { /** Connection */ final case class Connection( - connectionMatching: ConnectionMatching, + isUnmatched: Boolean, fromPort: AstNode[PortInstanceIdentifier], fromIndex: Option[AstNode[Expr]], toPort: AstNode[PortInstanceIdentifier], @@ -706,14 +706,4 @@ object Ast { override def toString = "public" } } - - sealed trait ConnectionMatching - object ConnectionMatching { - case object Unmatched extends ConnectionMatching { - override def toString = "unmatched" - } - case object PossiblyMatched extends ConnectionMatching { - override def toString = "possibly matched" - } - } } diff --git a/compiler/lib/src/main/scala/codegen/AstWriter.scala b/compiler/lib/src/main/scala/codegen/AstWriter.scala index 843223eb5..c08c060bd 100644 --- a/compiler/lib/src/main/scala/codegen/AstWriter.scala +++ b/compiler/lib/src/main/scala/codegen/AstWriter.scala @@ -270,7 +270,7 @@ object AstWriter extends AstVisitor with LineUtils { ) = { def direct(g: Ast.SpecConnectionGraph.Direct) = { def connection(c: Ast.SpecConnectionGraph.Connection) = { - lines("connection") ++ ( + lines(if c.isUnmatched then "unmatched connection" else "connection") ++ ( addPrefix("from port", portInstanceIdentifier) (c.fromPort.data) ++ linesOpt(addPrefix("index", exprNode), c.fromIndex) ++ addPrefix("to port", portInstanceIdentifier) (c.toPort.data) ++ diff --git a/compiler/lib/src/main/scala/codegen/FppWriter.scala b/compiler/lib/src/main/scala/codegen/FppWriter.scala index 3d24bfd5e..499263f47 100644 --- a/compiler/lib/src/main/scala/codegen/FppWriter.scala +++ b/compiler/lib/src/main/scala/codegen/FppWriter.scala @@ -617,10 +617,11 @@ object FppWriter extends AstVisitor with LineUtils { addSuffix(s".${ident(pii.portName.data)}") private def connection(c: Ast.SpecConnectionGraph.Connection) = - portInstanceId(c.fromPort.data). - joinOpt (c.fromIndex) ("") (bracketExprNode). - join (" -> ") (portInstanceId(c.toPort.data)). - joinOpt (c.toIndex) ("") (bracketExprNode) + lines(if c.isUnmatched then "unmatched " else ""). + join ("") (portInstanceId(c.fromPort.data)). + joinOpt (c.fromIndex) ("") (bracketExprNode). + join (" -> ") (portInstanceId(c.toPort.data)). + joinOpt (c.toIndex) ("") (bracketExprNode) private def typeNameNode(node: AstNode[Ast.TypeName]) = matchTypeNameNode((), node) @@ -714,6 +715,7 @@ object FppWriter extends AstVisitor with LineUtils { "topology", "true", "type", + "unmatched", "update", "warning", "with", diff --git a/compiler/lib/src/main/scala/codegen/XmlFppWriter/TopologyXmlFppWriter.scala b/compiler/lib/src/main/scala/codegen/XmlFppWriter/TopologyXmlFppWriter.scala index d5b710ae7..7423ec3fc 100644 --- a/compiler/lib/src/main/scala/codegen/XmlFppWriter/TopologyXmlFppWriter.scala +++ b/compiler/lib/src/main/scala/codegen/XmlFppWriter/TopologyXmlFppWriter.scala @@ -129,7 +129,7 @@ object TopologyXmlFppWriter extends LineUtils { } yield { Ast.SpecConnectionGraph.Connection( - Ast.ConnectionMatching.PossiblyMatched, + false, from._1, from._2, to._1, diff --git a/compiler/lib/src/main/scala/syntax/Parser.scala b/compiler/lib/src/main/scala/syntax/Parser.scala index 9df852482..4026e867a 100644 --- a/compiler/lib/src/main/scala/syntax/Parser.scala +++ b/compiler/lib/src/main/scala/syntax/Parser.scala @@ -49,7 +49,7 @@ object Parser extends Parsers { opt(unmatched) ~! connectionPort ~! (rarrow ~>! connectionPort) ^^ { case unmatched ~ (fromPort ~ fromIndex) ~ (toPort ~ toIndex) => { Ast.SpecConnectionGraph.Connection( - unmatched.getOrElse(Ast.ConnectionMatching.PossiblyMatched), + unmatched.isDefined, fromPort, fromIndex, toPort, @@ -914,7 +914,7 @@ object Parser extends Parsers { private def typeToken = accept("type", { case t : Token.TYPE => t }) - private def unmatched = accept("unmatched", { case t : Token.UNMATCHED => Ast.ConnectionMatching.Unmatched }) + private def unmatched = accept("unmatched", { case t : Token.UNMATCHED => t }) private def update = accept("update", { case t : Token.UPDATE => t }) diff --git a/docs/README.adoc b/docs/README.adoc index 39e6acd2a..54ff2a773 100644 --- a/docs/README.adoc +++ b/docs/README.adoc @@ -11,11 +11,3 @@ system: Once you have these tools installed, you can run `redo` in this directory to regenerate the HTML files from the AsciiDoc source files. - - -== Adding Keywords to FPP Specification -. To add a new FPP keyword, first update the Lexical Elements section of the FPP spec. -. Next, update the `doc/code-prettify/run_prettify.js` file so it includes the new keyword. -Doing this will add syntax highlighting to the keyword in the FPP spec. -. Finally, update `editors/emacs/fpp-mode.el` and `editors/vim/fpp.vim` so the emacs and vim -editors syntax highlighting for the new keyword. \ No newline at end of file From a04f484ce10a29fd50462336ec5edb91b5dfe473 Mon Sep 17 00:00:00 2001 From: jawest Date: Thu, 19 Sep 2024 13:52:05 -0700 Subject: [PATCH 06/73] added unit tests, cleanup --- .../scala/analysis/Semantics/Connection.scala | 18 +++--- .../ResolveTopology/PatternResolver.scala | 2 +- compiler/lib/src/main/scala/util/Error.scala | 2 +- .../invalid_unmatched_connection.fpp | 31 ++++++++++ .../invalid_unmatched_connection.ref.txt | 5 ++ .../fpp-check/test/connection_direct/ok.fpp | 17 ++++++ .../fpp-check/test/connection_direct/tests.sh | 1 + .../tools/fpp-format/test/include.ref.txt | 2 + .../tools/fpp-format/test/no_include.ref.txt | 2 + compiler/tools/fpp-format/test/syntax.fpp | 6 +- .../tools/fpp-syntax/test/syntax-ast.ref.txt | 8 +++ .../test/syntax-include-ast.ref.txt | 8 +++ .../fpp-syntax/test/syntax-stdin.ref.txt | 8 +++ compiler/tools/fpp-syntax/test/syntax.fpp | 6 +- .../unmatched/C1ComponentAi.ref.xml | 16 +++++ .../unmatched/C2ComponentAi.ref.xml | 16 +++++ .../top_numbering/unmatched/PPortAi.ref.xml | 8 +++ .../unmatched/TTopologyAppAi.ref.xml | 60 +++++++++++++++++++ .../test/top_numbering/unmatched/check-xml | 5 ++ .../test/top_numbering/unmatched/clean | 5 ++ .../test/top_numbering/unmatched/run | 5 ++ .../test/top_numbering/unmatched/run.sh | 5 ++ .../test/top_numbering/unmatched/tests.sh | 3 + .../unmatched/unmatched_connections.fpp | 59 ++++++++++++++++++ .../unmatched/unmatched_connections.ref.txt | 0 .../test/top_numbering/unmatched/update-ref | 5 ++ .../top_numbering/unmatched/update-ref.sh | 5 ++ 27 files changed, 294 insertions(+), 14 deletions(-) create mode 100644 compiler/tools/fpp-check/test/connection_direct/invalid_unmatched_connection.fpp create mode 100644 compiler/tools/fpp-check/test/connection_direct/invalid_unmatched_connection.ref.txt create mode 100644 compiler/tools/fpp-to-xml/test/top_numbering/unmatched/C1ComponentAi.ref.xml create mode 100644 compiler/tools/fpp-to-xml/test/top_numbering/unmatched/C2ComponentAi.ref.xml create mode 100644 compiler/tools/fpp-to-xml/test/top_numbering/unmatched/PPortAi.ref.xml create mode 100644 compiler/tools/fpp-to-xml/test/top_numbering/unmatched/TTopologyAppAi.ref.xml create mode 100755 compiler/tools/fpp-to-xml/test/top_numbering/unmatched/check-xml create mode 100755 compiler/tools/fpp-to-xml/test/top_numbering/unmatched/clean create mode 100755 compiler/tools/fpp-to-xml/test/top_numbering/unmatched/run create mode 100644 compiler/tools/fpp-to-xml/test/top_numbering/unmatched/run.sh create mode 100644 compiler/tools/fpp-to-xml/test/top_numbering/unmatched/tests.sh create mode 100644 compiler/tools/fpp-to-xml/test/top_numbering/unmatched/unmatched_connections.fpp create mode 100644 compiler/tools/fpp-to-xml/test/top_numbering/unmatched/unmatched_connections.ref.txt create mode 100755 compiler/tools/fpp-to-xml/test/top_numbering/unmatched/update-ref create mode 100644 compiler/tools/fpp-to-xml/test/top_numbering/unmatched/update-ref.sh diff --git a/compiler/lib/src/main/scala/analysis/Semantics/Connection.scala b/compiler/lib/src/main/scala/analysis/Semantics/Connection.scala index 9af4c027a..b84251d52 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/Connection.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/Connection.scala @@ -5,11 +5,11 @@ import fpp.compiler.util._ /** An FPP connection */ case class Connection( - isUnmatched: Boolean, /** The from endpoint */ from: Connection.Endpoint, /** The to endpoint */ - to: Connection.Endpoint + to: Connection.Endpoint, + isUnmatched: Boolean = false ) extends Ordered[Connection] { override def toString = s"${from.toString} -> ${to.toString}" @@ -104,7 +104,7 @@ case class Connection( } } - def checkMatchConstraint: Boolean = { + def isMatchConstrained: Boolean = { def portMatchingExists(pml: List[Component.PortMatching], pi: PortInstance): Boolean = pml.exists(pm => pi.equals(pm.instance1) || pi.equals(pm.instance2)) @@ -154,16 +154,14 @@ object Connection { for { from <- Endpoint.fromAst(a, connection.fromPort, connection.fromIndex) to <- Endpoint.fromAst(a, connection.toPort, connection.toIndex) - connection <- Right(Connection(connection.isUnmatched, from, to)) + connection <- Right(Connection(from, to, connection.isUnmatched)) _ <- connection.checkDirections _ <- connection.checkTypes _ <- connection.checkSerialWithTypedInput - _ <- { - if !connection.checkMatchConstraint & connection.isUnmatched then - Left(SemanticError.MissingPortMatching(connection.getLoc)) - else - Right(()) - } + _ <- + if !connection.isMatchConstrained && connection.isUnmatched + then Left(SemanticError.MissingPortMatching(connection.getLoc)) + else Right(()) } yield connection diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PatternResolver.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PatternResolver.scala index f8cb0a2de..7c66be44d 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PatternResolver.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PatternResolver.scala @@ -108,7 +108,7 @@ object PatternResolver { ) = { val from = Connection.Endpoint(loc, fromPii) val to = Connection.Endpoint(loc, toPii) - Connection(false, from, to) + Connection(from, to) } private def missingPort[T]( diff --git a/compiler/lib/src/main/scala/util/Error.scala b/compiler/lib/src/main/scala/util/Error.scala index f8ce44252..d6ff30be2 100644 --- a/compiler/lib/src/main/scala/util/Error.scala +++ b/compiler/lib/src/main/scala/util/Error.scala @@ -193,7 +193,7 @@ sealed trait Error { Error.print (Some(loc)) ("no match for this connection") printMatchingLoc(matchingLoc) case SemanticError.MissingPortMatching(loc) => - Error.print (Some(loc)) ("unmatched connections must use port matching") + Error.print (Some(loc)) ("unmatched connection must go from or to a matched port") case SemanticError.MissingPort(loc, specMsg, portMsg) => Error.print (Some(loc)) (s"component with $specMsg must have $portMsg") case SemanticError.OverlappingIdRanges( diff --git a/compiler/tools/fpp-check/test/connection_direct/invalid_unmatched_connection.fpp b/compiler/tools/fpp-check/test/connection_direct/invalid_unmatched_connection.fpp new file mode 100644 index 000000000..a099472f6 --- /dev/null +++ b/compiler/tools/fpp-check/test/connection_direct/invalid_unmatched_connection.fpp @@ -0,0 +1,31 @@ +port P1 +port P2 + +passive component C1 { + + output port p1Out: [5] P1 + sync input port p1In: [5] P1 + + output port p2Out: P2 + sync input port p2In: P2 + +} + +instance c1: C1 base id 0x100 +instance c2: C1 base id 0x200 + +topology T { + + instance c1 + instance c2 + + connections P1 { + unmatched c1.p1Out[0] -> c2.p1In[0] + unmatched c1.p1Out -> c2.p1In + } + + connections P2 { + c1.p2Out -> c2.p2In + } + +} diff --git a/compiler/tools/fpp-check/test/connection_direct/invalid_unmatched_connection.ref.txt b/compiler/tools/fpp-check/test/connection_direct/invalid_unmatched_connection.ref.txt new file mode 100644 index 000000000..0fcf6e1d7 --- /dev/null +++ b/compiler/tools/fpp-check/test/connection_direct/invalid_unmatched_connection.ref.txt @@ -0,0 +1,5 @@ +fpp-check +[ local path prefix ]/compiler/tools/fpp-check/test/connection_direct/invalid_unmatched_connection.fpp:23.15 + unmatched c1.p1Out[0] -> c2.p1In[0] + ^ +error: unmatched connection must go from or to a matched port diff --git a/compiler/tools/fpp-check/test/connection_direct/ok.fpp b/compiler/tools/fpp-check/test/connection_direct/ok.fpp index 7a2f66a7d..0ae1443b0 100644 --- a/compiler/tools/fpp-check/test/connection_direct/ok.fpp +++ b/compiler/tools/fpp-check/test/connection_direct/ok.fpp @@ -1,4 +1,6 @@ port P +port P2 + passive component C1 { output port pOut: [2] P output port serialOut: [2] serial @@ -7,15 +9,30 @@ passive component C2 { sync input port pIn: P sync input port serialIn: serial } + +passive component C3 { + output port pOut: [5] P2 + sync input port pIn: [5] P2 + match pOut with pIn +} + instance c1: C1 base id 0x100 instance c2: C2 base id 0x200 +instance c3: C3 base id 0x300 +instance c4: C3 base id 0x400 + topology T { instance c1 instance c2 + instance c3 + instance c4 connections C { c1.pOut -> c2.pIn c1.serialOut -> c2.pIn c1.pOut -> c2.serialIn c1.serialOut -> c2.serialIn + + unmatched c3.pOut[0] -> c4.pIn[0] + unmatched c3.pOut -> c4.pIn } } diff --git a/compiler/tools/fpp-check/test/connection_direct/tests.sh b/compiler/tools/fpp-check/test/connection_direct/tests.sh index e8f2c0690..3f5b34d7b 100644 --- a/compiler/tools/fpp-check/test/connection_direct/tests.sh +++ b/compiler/tools/fpp-check/test/connection_direct/tests.sh @@ -4,6 +4,7 @@ internal_port invalid_directions invalid_port_instance invalid_port_number +invalid_unmatched_connection mismatched_port_types ok serial_to_typed_with_return diff --git a/compiler/tools/fpp-format/test/include.ref.txt b/compiler/tools/fpp-format/test/include.ref.txt index f417f168f..2d8e5b332 100644 --- a/compiler/tools/fpp-format/test/include.ref.txt +++ b/compiler/tools/fpp-format/test/include.ref.txt @@ -165,6 +165,8 @@ module DefinitionsAndSpecifiers { @ Direct connection graph specifier connections C { i1.p[0] -> i2.p[1] + unmatched i1.p1[0] -> i2.p2[0] + unmatched i1.p1 -> i2.p2 } @< Direct connection graph specifier @ Graph pattern specifier diff --git a/compiler/tools/fpp-format/test/no_include.ref.txt b/compiler/tools/fpp-format/test/no_include.ref.txt index c805ea27d..1340c0920 100644 --- a/compiler/tools/fpp-format/test/no_include.ref.txt +++ b/compiler/tools/fpp-format/test/no_include.ref.txt @@ -165,6 +165,8 @@ module DefinitionsAndSpecifiers { @ Direct connection graph specifier connections C { i1.p[0] -> i2.p[1] + unmatched i1.p1[0] -> i2.p2[0] + unmatched i1.p1 -> i2.p2 } @< Direct connection graph specifier @ Graph pattern specifier diff --git a/compiler/tools/fpp-format/test/syntax.fpp b/compiler/tools/fpp-format/test/syntax.fpp index 2b99a8f60..615113ef4 100644 --- a/compiler/tools/fpp-format/test/syntax.fpp +++ b/compiler/tools/fpp-format/test/syntax.fpp @@ -137,7 +137,11 @@ module DefinitionsAndSpecifiers { @< Private instance specifier @ Direct connection graph specifier - connections C { i1.p[0] -> i2.p[1] } + connections C { + i1.p[0] -> i2.p[1] + unmatched i1.p1[0] -> i2.p2[0] + unmatched i1.p1 -> i2.p2 + } @< Direct connection graph specifier @ Graph pattern specifier diff --git a/compiler/tools/fpp-syntax/test/syntax-ast.ref.txt b/compiler/tools/fpp-syntax/test/syntax-ast.ref.txt index e9b9c7547..42a82ad0a 100644 --- a/compiler/tools/fpp-syntax/test/syntax-ast.ref.txt +++ b/compiler/tools/fpp-syntax/test/syntax-ast.ref.txt @@ -275,6 +275,14 @@ def module index literal int 0 to port qual ident i2.p index literal int 1 + unmatched connection + from port qual ident i1.p1 + index literal int 0 + to port qual ident i2.p2 + index literal int 0 + unmatched connection + from port qual ident i1.p1 + to port qual ident i2.p2 @< Direct connection graph specifier @ Graph pattern specifier spec connection graph pattern diff --git a/compiler/tools/fpp-syntax/test/syntax-include-ast.ref.txt b/compiler/tools/fpp-syntax/test/syntax-include-ast.ref.txt index bdea0bad2..bfb368c7d 100644 --- a/compiler/tools/fpp-syntax/test/syntax-include-ast.ref.txt +++ b/compiler/tools/fpp-syntax/test/syntax-include-ast.ref.txt @@ -276,6 +276,14 @@ def module index literal int 0 to port qual ident i2.p index literal int 1 + unmatched connection + from port qual ident i1.p1 + index literal int 0 + to port qual ident i2.p2 + index literal int 0 + unmatched connection + from port qual ident i1.p1 + to port qual ident i2.p2 @< Direct connection graph specifier @ Graph pattern specifier spec connection graph pattern diff --git a/compiler/tools/fpp-syntax/test/syntax-stdin.ref.txt b/compiler/tools/fpp-syntax/test/syntax-stdin.ref.txt index bdea0bad2..bfb368c7d 100644 --- a/compiler/tools/fpp-syntax/test/syntax-stdin.ref.txt +++ b/compiler/tools/fpp-syntax/test/syntax-stdin.ref.txt @@ -276,6 +276,14 @@ def module index literal int 0 to port qual ident i2.p index literal int 1 + unmatched connection + from port qual ident i1.p1 + index literal int 0 + to port qual ident i2.p2 + index literal int 0 + unmatched connection + from port qual ident i1.p1 + to port qual ident i2.p2 @< Direct connection graph specifier @ Graph pattern specifier spec connection graph pattern diff --git a/compiler/tools/fpp-syntax/test/syntax.fpp b/compiler/tools/fpp-syntax/test/syntax.fpp index 2b99a8f60..615113ef4 100644 --- a/compiler/tools/fpp-syntax/test/syntax.fpp +++ b/compiler/tools/fpp-syntax/test/syntax.fpp @@ -137,7 +137,11 @@ module DefinitionsAndSpecifiers { @< Private instance specifier @ Direct connection graph specifier - connections C { i1.p[0] -> i2.p[1] } + connections C { + i1.p[0] -> i2.p[1] + unmatched i1.p1[0] -> i2.p2[0] + unmatched i1.p1 -> i2.p2 + } @< Direct connection graph specifier @ Graph pattern specifier diff --git a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/C1ComponentAi.ref.xml b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/C1ComponentAi.ref.xml new file mode 100644 index 000000000..8a186df23 --- /dev/null +++ b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/C1ComponentAi.ref.xml @@ -0,0 +1,16 @@ + + + + + + PPortAi.xml + + + + + + + diff --git a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/C2ComponentAi.ref.xml b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/C2ComponentAi.ref.xml new file mode 100644 index 000000000..b875e5dc6 --- /dev/null +++ b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/C2ComponentAi.ref.xml @@ -0,0 +1,16 @@ + + + + + + PPortAi.xml + + + + + + + diff --git a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/PPortAi.ref.xml b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/PPortAi.ref.xml new file mode 100644 index 000000000..64b132daf --- /dev/null +++ b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/PPortAi.ref.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/TTopologyAppAi.ref.xml b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/TTopologyAppAi.ref.xml new file mode 100644 index 000000000..3eb2191a5 --- /dev/null +++ b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/TTopologyAppAi.ref.xml @@ -0,0 +1,60 @@ + + + + + + C1ComponentAi.xml + C2ComponentAi.xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/check-xml b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/check-xml new file mode 100755 index 000000000..50af24b01 --- /dev/null +++ b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/check-xml @@ -0,0 +1,5 @@ +#!/bin/sh -e + +export COMPILER_ROOT=$PWD/../../../../.. + +sh ../../scripts/check-xml.sh diff --git a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/clean b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/clean new file mode 100755 index 000000000..8d322fe40 --- /dev/null +++ b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/clean @@ -0,0 +1,5 @@ +#!/bin/sh -e + +export COMPILER_ROOT=../../../../.. + +sh ../../scripts/clean.sh diff --git a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/run b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/run new file mode 100755 index 000000000..6bcb2b473 --- /dev/null +++ b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/run @@ -0,0 +1,5 @@ +#!/bin/sh + +export COMPILER_ROOT=../../../../.. + +sh ../../scripts/run.sh diff --git a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/run.sh b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/run.sh new file mode 100644 index 000000000..a38d9a73d --- /dev/null +++ b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/run.sh @@ -0,0 +1,5 @@ +numbering_matched() +{ + run_test "-p $PWD" unmatched_connections && \ + diff_xml PPort C1Component C2Component TTopologyApp +} diff --git a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/tests.sh b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/tests.sh new file mode 100644 index 000000000..bdd8decc1 --- /dev/null +++ b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/tests.sh @@ -0,0 +1,3 @@ +tests=" +unmatched_connections +" diff --git a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/unmatched_connections.fpp b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/unmatched_connections.fpp new file mode 100644 index 000000000..30d413f88 --- /dev/null +++ b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/unmatched_connections.fpp @@ -0,0 +1,59 @@ +module M { + + port P + + passive component C1 { + + output port pOut: [6] P + sync input port pIn: [6] P + + match pOut with pIn + } + + passive component C2 { + + output port pOut: [6] P + sync input port pIn: [6] P + + match pOut with pIn + } + + instance c1: C1 base id 0x100 + instance c2: C1 base id 0x200 + instance c3: C2 base id 0x300 + instance c4: C2 base id 0x400 + + topology T { + + instance c1 + instance c2 + instance c3 + instance c4 + + connections P { + # Case 1: 2 ports that go to the same component + unmatched c1.pOut -> c1.pIn + unmatched c2.pOut -> c1.pIn + unmatched c3.pOut -> c3.pIn + unmatched c4.pOut -> c4.pIn + + # Case 2: Have a connection out of A at some index i and + # some connection at B at same index i but they go to different components + unmatched c1.pOut[1] -> c1.pIn[1] + unmatched c2.pOut[1] -> c2.pIn[1] + + + # Case 3: Have a connection out of A at index i and + # some connection at B index at j not equal to i going to same component + unmatched c3.pOut[2] -> c3.pIn[2] + unmatched c4.pOut[3] -> c3.pIn[3] + + # Case 4: Have a connection out of A at index i and + # some connection at B index at j not equal to i going to different component + unmatched c3.pOut[4] -> c3.pIn[4] + unmatched c4.pOut[5] -> c4.pIn[5] + + } + } + +} diff --git a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/unmatched_connections.ref.txt b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/unmatched_connections.ref.txt new file mode 100644 index 000000000..e69de29bb diff --git a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/update-ref b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/update-ref new file mode 100755 index 000000000..2889a0733 --- /dev/null +++ b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/update-ref @@ -0,0 +1,5 @@ +#!/bin/sh + +export COMPILER_ROOT=../../../../.. + +sh ../../scripts/update-ref.sh diff --git a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/update-ref.sh b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/update-ref.sh new file mode 100644 index 000000000..ad8ab30d7 --- /dev/null +++ b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/update-ref.sh @@ -0,0 +1,5 @@ +numbering_matched() +{ + update "-p $PWD" unmatched_connections + move_xml PPort C1Component C2Component TTopologyApp +} From 1ee946a906eb66ebcf8a5cb1ed5a169c11068547 Mon Sep 17 00:00:00 2001 From: jawest Date: Thu, 19 Sep 2024 18:07:46 -0700 Subject: [PATCH 07/73] update user guide --- docs/users-guide/Defining-Topologies.adoc | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/docs/users-guide/Defining-Topologies.adoc b/docs/users-guide/Defining-Topologies.adoc index 2b5f3f7b5..6d0adbb65 100644 --- a/docs/users-guide/Defining-Topologies.adoc +++ b/docs/users-guide/Defining-Topologies.adoc @@ -27,8 +27,9 @@ fit together. port P passive component C { - sync input port pIn: P - output port pOut: P + sync input port pIn: [3] P + output port pOut: [3] P + match pOut with pIn } instance c1: C base id 0x100 @@ -45,6 +46,8 @@ topology Simple { @ This code specifies a connection graph C1 connections C1 { c1.pOut -> c2.pIn + unmatched c1.pOut[1] -> c2.pIn[1] + unmatched c1.pOut[2] -> c2.pIn[2] } @ This code specifies a connection graph C2 @@ -58,6 +61,7 @@ topology Simple { In this example, we define a <> `P`. Then we define a <> `C` with an input port and an output port, both of type `P`. +We specify that the output port and the input port are matched. We define two <> of `C`, `c1` and `c2`. We put these instances into a topology called `Simple`. @@ -113,10 +117,13 @@ An endpoint is the name of a component instance (which in general may be a qualified name), a dot, and the name of a port of that component instance. -In this example there are two connection graphs, each containing -one connection: +In this example there are two connection graphs: + +. A connection graph `C1` containing: +.. A connection from `c1.pOut` to `c2.pIn`. +.. An unmatched connection from `c1.pOut[1]` to `c2.pIn[1]` +.. An unmatched connection from `c1.pOut[2]` to `c2.pIn[2]` -. A connection graph `C1` containing a connection from `c1.pOut` to `c2.pIn`. . A connection graph `C2` containing a connection from `c2.pOut` to `c1.pIn`. @@ -242,6 +249,8 @@ In particular, serial to serial connections are allowed. then the port type of _P_ may not specify a <>. +* `unmatched` specifiers must only be specified on connections that are match constrained. + ==== Pattern Graph Specifiers A few connection patterns are so common in F Prime that they @@ -699,7 +708,7 @@ When you use matched numbering with direct graph specifiers, you must obey the following rules: . When a component has the matching specifier -`match p1 with p2`, for every connection between `p1` +`match p1 with p2`, for every matched connection between `p1` and another component, there must be a corresponding connection between that other component and `p2`. From 5f8c36501ee372ae999fd80b0f5a3513200cb673 Mon Sep 17 00:00:00 2001 From: jawest Date: Tue, 24 Sep 2024 15:49:46 -0700 Subject: [PATCH 08/73] revert doc changes --- docs/fpp-spec.html | 2 +- docs/fpp-users-guide.html | 20 ++++++++++---------- docs/index.html | 7 ++++--- docs/users-guide/Defining-Topologies.adoc | 15 ++++----------- 4 files changed, 19 insertions(+), 25 deletions(-) diff --git a/docs/fpp-spec.html b/docs/fpp-spec.html index a8dead3d8..a5ee716f0 100644 --- a/docs/fpp-spec.html +++ b/docs/fpp-spec.html @@ -9801,7 +9801,7 @@

    21.4. Translation Tools

    diff --git a/docs/fpp-users-guide.html b/docs/fpp-users-guide.html index 1965c0706..80e5bb742 100644 --- a/docs/fpp-users-guide.html +++ b/docs/fpp-users-guide.html @@ -140,7 +140,7 @@ #content::before{content:none} #header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0} #header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #dddddf} -#header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px} +#header>h1:only-child{border-bottom:1px solid #dddddf;padding-bottom:8px} #header .details{border-bottom:1px solid #dddddf;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:flex;flex-flow:row wrap} #header .details span:first-child{margin-left:-.125em} #header .details span.email a{color:rgba(0,0,0,.85)} @@ -162,6 +162,7 @@ #toctitle{color:#7a2518;font-size:1.2em} @media screen and (min-width:768px){#toctitle{font-size:1.375em} body.toc2{padding-left:15em;padding-right:0} +body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px} #toc.toc2{margin-top:0!important;background:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #e7e7e9;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto} #toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em} #toc.toc2>ul{font-size:.9em;margin-bottom:0} @@ -327,7 +328,7 @@ a.image object{pointer-events:none} sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super} sup.footnote a,sup.footnoteref a{text-decoration:none} -sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline} +sup.footnote a:active,sup.footnoteref a:active,#footnotes .footnote a:first-of-type:active{text-decoration:underline} #footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em} #footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em;border-width:1px 0 0} #footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;margin-bottom:.2em} @@ -7618,8 +7619,8 @@

    12.1. A Simple Example

    port P
     
     passive component C {
    -  sync input port pIn: P
    -  output port pOut: P
    +  sync input port pIn: [3] P
    +  output port pOut: [3] P
     }
     
     instance c1: C base id 0x100
    @@ -7717,14 +7718,13 @@ 

    12.1. A Simple Example

    In this example there are two connection graphs, each containing -one connection:

    +one connection: +. A connection graph C1 containing: +. A connection from c1.pOut to c2.pIn.

    1. -

      A connection graph C1 containing a connection from c1.pOut to c2.pIn.

      -
    2. -
    3. A connection graph C2 containing a connection from c2.pOut to c1.pIn.

    @@ -8396,7 +8396,7 @@

    12.3.2. Matched Nu
    1. When a component has the matching specifier -match p1 with p2, for every connection between p1 +match p1 with p2, for every matched connection between p1 and another component, there must be a corresponding connection between that other component and p2.

    2. @@ -12530,7 +12530,7 @@

    diff --git a/docs/index.html b/docs/index.html index 07e30b8d1..2b4d9282a 100644 --- a/docs/index.html +++ b/docs/index.html @@ -140,7 +140,7 @@ #content::before{content:none} #header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0} #header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #dddddf} -#header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px} +#header>h1:only-child{border-bottom:1px solid #dddddf;padding-bottom:8px} #header .details{border-bottom:1px solid #dddddf;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:flex;flex-flow:row wrap} #header .details span:first-child{margin-left:-.125em} #header .details span.email a{color:rgba(0,0,0,.85)} @@ -162,6 +162,7 @@ #toctitle{color:#7a2518;font-size:1.2em} @media screen and (min-width:768px){#toctitle{font-size:1.375em} body.toc2{padding-left:15em;padding-right:0} +body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px} #toc.toc2{margin-top:0!important;background:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #e7e7e9;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto} #toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em} #toc.toc2>ul{font-size:.9em;margin-bottom:0} @@ -327,7 +328,7 @@ a.image object{pointer-events:none} sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super} sup.footnote a,sup.footnoteref a{text-decoration:none} -sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline} +sup.footnote a:active,sup.footnoteref a:active,#footnotes .footnote a:first-of-type:active{text-decoration:underline} #footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em} #footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em;border-width:1px 0 0} #footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;margin-bottom:.2em} @@ -463,7 +464,7 @@

    F Prime Prime (FPP)

    diff --git a/docs/users-guide/Defining-Topologies.adoc b/docs/users-guide/Defining-Topologies.adoc index 6d0adbb65..5e821a3bf 100644 --- a/docs/users-guide/Defining-Topologies.adoc +++ b/docs/users-guide/Defining-Topologies.adoc @@ -29,7 +29,6 @@ port P passive component C { sync input port pIn: [3] P output port pOut: [3] P - match pOut with pIn } instance c1: C base id 0x100 @@ -46,8 +45,6 @@ topology Simple { @ This code specifies a connection graph C1 connections C1 { c1.pOut -> c2.pIn - unmatched c1.pOut[1] -> c2.pIn[1] - unmatched c1.pOut[2] -> c2.pIn[2] } @ This code specifies a connection graph C2 @@ -61,7 +58,6 @@ topology Simple { In this example, we define a <> `P`. Then we define a <> `C` with an input port and an output port, both of type `P`. -We specify that the output port and the input port are matched. We define two <> of `C`, `c1` and `c2`. We put these instances into a topology called `Simple`. @@ -117,12 +113,11 @@ An endpoint is the name of a component instance (which in general may be a qualified name), a dot, and the name of a port of that component instance. -In this example there are two connection graphs: - +In this example there are two connection graphs, each containing +one connection: . A connection graph `C1` containing: -.. A connection from `c1.pOut` to `c2.pIn`. -.. An unmatched connection from `c1.pOut[1]` to `c2.pIn[1]` -.. An unmatched connection from `c1.pOut[2]` to `c2.pIn[2]` +. A connection from `c1.pOut` to `c2.pIn`. + . A connection graph `C2` containing a connection from `c2.pOut` to `c1.pIn`. @@ -249,8 +244,6 @@ In particular, serial to serial connections are allowed. then the port type of _P_ may not specify a <>. -* `unmatched` specifiers must only be specified on connections that are match constrained. - ==== Pattern Graph Specifiers A few connection patterns are so common in F Prime that they From e09201991d7bbbed85585b2cbf512b157c652102 Mon Sep 17 00:00:00 2001 From: jawest Date: Tue, 24 Sep 2024 15:53:21 -0700 Subject: [PATCH 09/73] revert user guide --- docs/fpp-users-guide.html | 15 ++++++++------- docs/users-guide/Defining-Topologies.adoc | 10 ++++------ 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/docs/fpp-users-guide.html b/docs/fpp-users-guide.html index 80e5bb742..d23bb136b 100644 --- a/docs/fpp-users-guide.html +++ b/docs/fpp-users-guide.html @@ -7619,8 +7619,8 @@

    12.1. A Simple Example

    port P
     
     passive component C {
    -  sync input port pIn: [3] P
    -  output port pOut: [3] P
    +  sync input port pIn: P
    +  output port pOut: P
     }
     
     instance c1: C base id 0x100
    @@ -7718,14 +7718,15 @@ 

    12.1. A Simple Example

    In this example there are two connection graphs, each containing -one connection: -. A connection graph C1 containing: -. A connection from c1.pOut to c2.pIn.

    +one connection:

    1. -

      A connection graph C2 containing a connection from c2.pOut to c1.pIn.

      +

      A connection graph C1 containing a connection from c1.pOut to c2.pIn.

      +
    2. +
    3. +

      A connection from c1.pOut to c2.pIn.

    @@ -12530,7 +12531,7 @@

    diff --git a/docs/users-guide/Defining-Topologies.adoc b/docs/users-guide/Defining-Topologies.adoc index 5e821a3bf..2539998e9 100644 --- a/docs/users-guide/Defining-Topologies.adoc +++ b/docs/users-guide/Defining-Topologies.adoc @@ -27,8 +27,8 @@ fit together. port P passive component C { - sync input port pIn: [3] P - output port pOut: [3] P + sync input port pIn: P + output port pOut: P } instance c1: C base id 0x100 @@ -115,12 +115,10 @@ and the name of a port of that component instance. In this example there are two connection graphs, each containing one connection: -. A connection graph `C1` containing: -. A connection from `c1.pOut` to `c2.pIn`. - +. A connection graph `C1` containing a connection from `c1.pOut` to `c2.pIn`. -. A connection graph `C2` containing a connection from `c2.pOut` to `c1.pIn`. +. A connection from `c1.pOut` to `c2.pIn`. As shown, topologies and their members are <>. From ccaf6e07d9e60c8426a571cbbef089214068ad77 Mon Sep 17 00:00:00 2001 From: jawest Date: Tue, 24 Sep 2024 16:03:34 -0700 Subject: [PATCH 10/73] revert user guide --- docs/fpp-users-guide.html | 4 ++-- docs/users-guide/Defining-Topologies.adoc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/fpp-users-guide.html b/docs/fpp-users-guide.html index d23bb136b..4faf327a0 100644 --- a/docs/fpp-users-guide.html +++ b/docs/fpp-users-guide.html @@ -7726,7 +7726,7 @@

    12.1. A Simple Example

    A connection graph C1 containing a connection from c1.pOut to c2.pIn.

  8. -

    A connection from c1.pOut to c2.pIn.

    +

    A connection graph C2 containing a connection from c2.pOut to c1.pIn.

@@ -12531,7 +12531,7 @@

diff --git a/docs/users-guide/Defining-Topologies.adoc b/docs/users-guide/Defining-Topologies.adoc index 2539998e9..8d1131e5f 100644 --- a/docs/users-guide/Defining-Topologies.adoc +++ b/docs/users-guide/Defining-Topologies.adoc @@ -118,7 +118,7 @@ one connection: . A connection graph `C1` containing a connection from `c1.pOut` to `c2.pIn`. -. A connection from `c1.pOut` to `c2.pIn`. +. A connection graph `C2` containing a connection from `c2.pOut` to `c1.pIn`. As shown, topologies and their members are <>. From 20e925f7b87eeadc8a55eb309b4aab3fd4a1b690 Mon Sep 17 00:00:00 2001 From: jawest Date: Tue, 24 Sep 2024 17:04:09 -0700 Subject: [PATCH 11/73] update user guide --- docs/fpp-users-guide.html | 75 ++++++++++++++++++++++- docs/users-guide/Defining-Topologies.adoc | 69 +++++++++++++++++++++ 2 files changed, 143 insertions(+), 1 deletion(-) diff --git a/docs/fpp-users-guide.html b/docs/fpp-users-guide.html index 4faf327a0..b2feb5216 100644 --- a/docs/fpp-users-guide.html +++ b/docs/fpp-users-guide.html @@ -8443,6 +8443,79 @@

12.3.2. Matched Nu Instead we define a symbolic constant Ports.StaticMemory.uplink and use that twice to do the matching by hand.

+
+

Unmatched connections: +Unmatched connections can be used in a topology to bypass match +constraints that are specified in component definitions. Doing so +allows you to skip port matching requirements without receiving an +error if a match constraint is violated.

+
+
+

To specify that a connection is unmatched, start the connection +with the unmatched keyword.

+
+
+
+
unmatched c1.pOut -> c2.pIn
+
+
+
+

Note that unmatched connections are only allowed when a match +constraint has been specified. In the below example, unmatched +connections would not be valid since neither ports pIn or pOut +are match constrained.

+
+
+
+
Port P
+
+passive component C {
+  sync input port pIn: [3] P
+  output port pOut: [3] P
+}
+
+
+
+

Below is a valid example for using unmatched connections:

+
+
+
+
Port P
+
+passive component C {
+  sync input port pIn: [3] P
+  output port pOut: [3] P
+
+  match pOut with pIn
+}
+
+instance c1: C base id 0x100
+instance c2: C base id 0x200
+
+topology T {
+
+  @ This specifier says that instance c1 is part of the topology
+  instance c1
+  @ This specifier says that instance c2 is part of the topology
+  instance c2
+
+  @ This code specifies a connection graph C1
+  connections C1 {
+    unmatched c1.pOut[0] -> c2.pIn[0]
+    unmatched c1.pOut[1] -> c2.pIn[1]
+  }
+
+}
+
+
+
+

This example consists of a component C with ports pOut and pIn +that are match constrained by the matching specifier match pOut with pIn. +In addition, The topology T contains two unmatched connections that go +from c1.pOut[0] to c2.pIn[0] and from c1.pOut[1] to c2.pIn[1]. +Since pOut and pIn are match constrained, the unmatched keyword can be used +to mark the connection as unmatched and bypass the port matching requirement.

+

12.3.3. General Numbering

@@ -12531,7 +12604,7 @@

diff --git a/docs/users-guide/Defining-Topologies.adoc b/docs/users-guide/Defining-Topologies.adoc index 8d1131e5f..effeb8dad 100644 --- a/docs/users-guide/Defining-Topologies.adoc +++ b/docs/users-guide/Defining-Topologies.adoc @@ -739,6 +739,75 @@ component instances, we can't used automatic matched numbering. Instead we define a symbolic constant `Ports.StaticMemory.uplink` and use that twice to do the matching by hand. +*Unmatched connections:* +Unmatched connections can be used in a topology to bypass match +constraints that are specified in component definitions. Doing so +allows you to skip port matching requirements without receiving an +error if a match constraint is violated. + +To specify that a connection is unmatched, start the connection +with the `unmatched` keyword. + +[source,fpp] +-------- +unmatched c1.pOut -> c2.pIn +-------- + +Note that unmatched connections are only allowed when a match +constraint has been specified. In the below example, unmatched +connections would not be valid since neither ports `pIn` or `pOut` +are match constrained. + +[source,fpp] +-------- +Port P + +passive component C { + sync input port pIn: [3] P + output port pOut: [3] P +} +-------- + +Below is a valid example for using unmatched connections: + +[source,fpp] +-------- +Port P + +passive component C { + sync input port pIn: [3] P + output port pOut: [3] P + + match pOut with pIn +} + +instance c1: C base id 0x100 +instance c2: C base id 0x200 + +topology T { + + @ This specifier says that instance c1 is part of the topology + instance c1 + @ This specifier says that instance c2 is part of the topology + instance c2 + + @ This code specifies a connection graph C1 + connections C1 { + unmatched c1.pOut[0] -> c2.pIn[0] + unmatched c1.pOut[1] -> c2.pIn[1] + } + +} +-------- + +This example consists of a component `C` with ports `pOut` and `pIn` +that are match constrained by the matching specifier `match pOut with pIn`. +In addition, The topology `T` contains two unmatched connections that go +from `c1.pOut[0]` to `c2.pIn[0]` and from `c1.pOut[1]` to `c2.pIn[1]`. +Since `pOut` and `pIn` are match constrained, the unmatched keyword can be used +to mark the connection as unmatched and bypass the port matching requirement. + + ==== General Numbering After resolving From d21b0be45426e3f72a13971f64e3b208b4d11e3b Mon Sep 17 00:00:00 2001 From: jawest Date: Wed, 25 Sep 2024 18:17:27 -0700 Subject: [PATCH 12/73] refactor matched port numbering --- .../GeneralPortNumbering.scala | 2 +- .../MatchedPortNumbering.scala | 60 +++++++++++---- .../ResolveTopology/PortNumberingState.scala | 21 ++++- compiler/lib/src/main/scala/util/Error.scala | 16 ++++ .../unmatched/TTopologyAppAi.ref.xml | 77 +++++++++++++++---- .../unmatched/unmatched_connections.fpp | 72 ++++++++++------- docs/fpp-spec.html | 20 ++++- docs/fpp-users-guide.html | 2 +- 8 files changed, 210 insertions(+), 60 deletions(-) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/GeneralPortNumbering.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/GeneralPortNumbering.scala index 8ea038e6d..411c77c09 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/GeneralPortNumbering.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/GeneralPortNumbering.scala @@ -28,7 +28,7 @@ object GeneralPortNumbering { val pi = pii.portInstance val cs = t.getConnectionsFrom(pii).toArray.sorted val usedPortNumbers = t.getUsedPortNumbers(pi, cs) - val state = PortNumberingState.initial(usedPortNumbers) + val state = PortNumberingState.initial(Set(), usedPortNumbers) val (_, t1) = cs.foldLeft ((state, t)) ({ case ((s,t), c) => t.getPortNumber(pi, c) match { case Some(n) => (s, t) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala index da67a1494..06c72c0b6 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala @@ -60,18 +60,36 @@ object MatchedPortNumbering { } case (Some(n1), None) => // Only pi1 has a number: assign it to pi2 - val t1 = t.assignPortNumber(pi2, c2, n1) - Right(state.copy(t = t1)) + if PortNumberingState.checkPortNumberInUse(n1, state.numbering.usedPorts2) + then Left(SemanticError.PortNumberAlreadyInUse(n1)) + else { + val t1 = t.assignPortNumber(pi2, c2, n1) + val num = state.numbering.setUsedPorts(state.numbering.usedPorts1, state.numbering.usedPorts2 + n1) + Right(state.copy(t = t1, numbering = num)) + } case (None, Some(n2)) => // Only pi2 has a number: assign it to pi1 - val t1 = t.assignPortNumber(pi1, c1, n2) - Right(state.copy(t = t1)) + if PortNumberingState.checkPortNumberInUse(n2, state.numbering.usedPorts1) + then Left(SemanticError.PortNumberAlreadyInUse(n2)) + else { + val t1 = t.assignPortNumber(pi1, c1, n2) + val num = state.numbering.setUsedPorts(state.numbering.usedPorts1 + n2, state.numbering.usedPorts2) + Right(state.copy(t = t1, numbering = num)) + } case (None, None) => // Neither port has a number: assign a new one + val maxSize1 = pi1.getArraySize + val maxSize2 = pi2.getArraySize val (numbering, n) = state.numbering.getPortNumber - val t1 = t.assignPortNumber(pi1, c1, n). - assignPortNumber(pi2, c2, n) - Right(state.copy(t = t1, numbering = numbering)) + if(n > maxSize1 - 1) + then Left(SemanticError.PortNumberOutOfRange(n, pi1.toString, maxSize1)) + else if(n > maxSize2 - 1) + then Left(SemanticError.PortNumberOutOfRange(n, pi2.toString, maxSize2)) + else { + val t1 = t.assignPortNumber(pi1, c1, n).assignPortNumber(pi2, c2, n) + val num = state.numbering.setUsedPorts(state.numbering.usedPorts1 + n, state.numbering.usedPorts2 + n) + Right(state.copy(t = t1, numbering = num)) + } } } @@ -99,18 +117,17 @@ object MatchedPortNumbering { pi1: PortInstance, map1: ConnectionMap, pi2: PortInstance, - map2: ConnectionMap + map2: ConnectionMap, + usedPorts1: Set[Int], + usedPorts2: Set[Int] ): State = { - // Compute the used port numbers - val usedPortNumbers = t.getUsedPortNumbers(pi1, map1.values) ++ - t.getUsedPortNumbers(pi2, map2.values) State( t, pi1, map1, pi2, map2, - PortNumberingState.initial(usedPortNumbers) + PortNumberingState.initial(usedPorts1, usedPorts2) ) } @@ -179,15 +196,32 @@ object MatchedPortNumbering { } }) } + + def computeUsedPortNumbers(pi: PortInstance): Result.Result[Set[Int]] = { + val empty: Set[Int] = Set() + val pii = PortInstanceIdentifier(ci, pi) + val cs = t.getConnectionsAt(pii).toList.sorted + Result.foldLeft (cs) (empty) ((s, c) => { + val used = t.getUsedPortNumbers(pi, List(c)) + val intersection = s.intersect(used) + if intersection.nonEmpty + then Left(SemanticError.MultipleConnectionsAtPortIndex(intersection.toString)) + else + Right(s ++ used) + }) + } + val pi1 = portMatching.instance1 val pi2 = portMatching.instance2 val loc = portMatching.getLoc for { map1 <- constructMap(loc, pi1) map2 <- constructMap(loc, pi2) + usedPorts1 <- computeUsedPortNumbers(pi1) + usedPorts2 <- computeUsedPortNumbers(pi2) _ <- checkForMissingConnections(loc, map1, map2) state <- { - val state = State.initial(t, pi1, map1, pi2, map2) + val state = State.initial(t, pi1, map1, pi2, map2, usedPorts1, usedPorts2) State.assignNumbers(loc, state) } } diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala index 2d3f606b4..68153f981 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala @@ -5,6 +5,8 @@ import fpp.compiler.util._ /** Port numbering state */ case class PortNumberingState private ( + usedPorts1: Set[Int], + usedPorts2: Set[Int], /** The used port numbers */ usedPortNumbers: Set[Int], /** The next port number */ @@ -19,7 +21,7 @@ case class PortNumberingState private ( nextPortNumber, s ) - PortNumberingState(s, n) + PortNumberingState(usedPorts1, usedPorts2, s, n) } /** Gets the next port number and updates the state */ @@ -28,14 +30,24 @@ case class PortNumberingState private ( (s, nextPortNumber) } + def setUsedPorts(u1: Set[Int], u2: Set[Int]): PortNumberingState = { + val updatedUsedPortNumbers = u1 ++ u2 + val updatedNextPortNumber = PortNumberingState.getNextNumber( + nextPortNumber, + updatedUsedPortNumbers + ) + PortNumberingState(u1, u2, updatedUsedPortNumbers, nextPortNumber) + } + } object PortNumberingState { /** Construct an initial state */ - def initial(usedPortNumbers: Set[Int]): PortNumberingState = { + def initial(usedPorts1: Set[Int], usedPorts2: Set[Int]): PortNumberingState = { + val usedPortNumbers = usedPorts1 ++ usedPorts2 val nextPortNumber = getNextNumber(0, usedPortNumbers) - PortNumberingState(usedPortNumbers, nextPortNumber) + PortNumberingState(usedPorts1, usedPorts2, usedPortNumbers, nextPortNumber) } /** Gets the next available port number */ @@ -47,4 +59,7 @@ object PortNumberingState { helper(from) } + def checkPortNumberInUse(n: Int, used: Set[Int]) = + used.contains(n) + } diff --git a/compiler/lib/src/main/scala/util/Error.scala b/compiler/lib/src/main/scala/util/Error.scala index 21160c1c5..33bc613bd 100644 --- a/compiler/lib/src/main/scala/util/Error.scala +++ b/compiler/lib/src/main/scala/util/Error.scala @@ -153,6 +153,8 @@ sealed trait Error { Error.print (Some(loc)) (msg) System.err.println(s"port definition is here:") System.err.println(defLoc) + case SemanticError.MultipleConnectionsAtPortIndex(portIndexString) => + Error.print (None) (s"multiple connections appear at port indices $portIndexString") case SemanticError.InvalidPortInstanceId(loc, portName, componentName) => Error.print (Some(loc)) (s"$portName is not a port instance of component $componentName") case SemanticError.InvalidPortKind(loc, msg, specLoc) => @@ -161,10 +163,14 @@ sealed trait Error { System.err.println(specLoc) case SemanticError.InvalidPortMatching(loc, msg) => Error.print (Some(loc)) (msg) + case SemanticError.PortNumberAlreadyInUse(n) => + Error.print (None) (s"port number $n is already in use") case SemanticError.InvalidPortNumber(loc, portNumber, port, arraySize, specLoc) => Error.print (Some(loc)) (s"invalid port number $portNumber for port $port (max is ${arraySize - 1})") System.err.println(s"port instance is specified here:") System.err.println(specLoc) + case SemanticError.PortNumberOutOfRange(portNumber, port, arraySize) => + Error.print (None) (s"port number $portNumber out of range for port $port (max is ${arraySize - 1})") case SemanticError.InvalidPriority(loc) => Error.print (Some(loc)) ("only async input may have a priority") case SemanticError.InvalidQueueFull(loc) => @@ -425,6 +431,9 @@ object SemanticError { msg: String, defLoc: Location ) extends Error + final case class MultipleConnectionsAtPortIndex( + portIndexString: String + ) extends Error /** Invalid port instance identifier */ final case class InvalidPortInstanceId( loc: Location, @@ -439,6 +448,7 @@ object SemanticError { ) extends Error /** Invalid port matching */ final case class InvalidPortMatching(loc: Location, msg: String) extends Error + final case class PortNumberAlreadyInUse(n: Int) extends Error /** Invalid port number */ final case class InvalidPortNumber( loc: Location, @@ -447,6 +457,12 @@ object SemanticError { size: Int, specLoc: Location ) extends Error + /** Port number out of range */ + final case class PortNumberOutOfRange( + portNumber: Int, + port: String, + size: Int, + ) extends Error /** Invalid priority specifier */ final case class InvalidPriority(loc: Location) extends Error /** Invalid queue full specifier */ diff --git a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/TTopologyAppAi.ref.xml b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/TTopologyAppAi.ref.xml index 3eb2191a5..ed4d71c1b 100644 --- a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/TTopologyAppAi.ref.xml +++ b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/TTopologyAppAi.ref.xml @@ -7,12 +7,15 @@ Generated by fpp-to-xml C1ComponentAi.xml - C2ComponentAi.xml - - + + + + + + @@ -21,7 +24,11 @@ Generated by fpp-to-xml - + + + + + @@ -29,31 +36,75 @@ Generated by fpp-to-xml - + - - + + - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + diff --git a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/unmatched_connections.fpp b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/unmatched_connections.fpp index 30d413f88..252cb9ab7 100644 --- a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/unmatched_connections.fpp +++ b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/unmatched_connections.fpp @@ -4,24 +4,20 @@ module M { passive component C1 { - output port pOut: [6] P - sync input port pIn: [6] P - - match pOut with pIn - } - - passive component C2 { - - output port pOut: [6] P - sync input port pIn: [6] P + output port pOut: [4] P + sync input port pIn: [4] P match pOut with pIn } instance c1: C1 base id 0x100 instance c2: C1 base id 0x200 - instance c3: C2 base id 0x300 - instance c4: C2 base id 0x400 + instance c3: C1 base id 0x300 + instance c4: C1 base id 0x400 + instance c5: C1 base id 0x500 + instance c6: C1 base id 0x600 + instance c7: C1 base id 0x700 + instance c8: C1 base id 0x800 topology T { @@ -29,30 +25,54 @@ module M { instance c2 instance c3 instance c4 + instance c5 + instance c6 + instance c7 + instance c8 connections P { - # Case 1: 2 ports that go to the same component + # Case 1: 2 ports that go to the same component instance + # unmatched connections unmatched c1.pOut -> c1.pIn unmatched c2.pOut -> c1.pIn - unmatched c3.pOut -> c3.pIn - unmatched c4.pOut -> c4.pIn + # implicit matched connections + c1.pOut -> c1.pIn + c2.pOut -> c1.pIn + # explicit matched connection + c1.pOut[1] -> c2.pIn[1] # Case 2: Have a connection out of A at some index i and - # some connection at B at same index i but they go to different components - unmatched c1.pOut[1] -> c1.pIn[1] - unmatched c2.pOut[1] -> c2.pIn[1] - + # some connection at B at same index i but they go to different component instances + unmatched c3.pOut[0] -> c3.pIn[0] + unmatched c4.pOut[0] -> c4.pIn[0] + # implicit matched connections + c3.pOut -> c4.pIn + c4.pOut -> c3.pIn + # explicit matched connections + c3.pOut[1] -> c3.pIn[1] + c4.pOut[1] -> c4.pIn[1] # Case 3: Have a connection out of A at index i and - # some connection at B index at j not equal to i going to same component - unmatched c3.pOut[2] -> c3.pIn[2] - unmatched c4.pOut[3] -> c3.pIn[3] + # some connection at B index at j not equal to i going to same component instance + unmatched c5.pOut[0] -> c5.pIn[0] + unmatched c6.pOut[1] -> c5.pIn[1] + # implicit matched connections + c5.pOut -> c5.pIn + c6.pOut -> c5.pIn + # explicit matched connection + c5.pOut[2] -> c6.pIn[2] # Case 4: Have a connection out of A at index i and - # some connection at B index at j not equal to i going to different component - unmatched c3.pOut[4] -> c3.pIn[4] - unmatched c4.pOut[5] -> c4.pIn[5] - + # some connection at B index at j not equal to i going to different component instances + unmatched c7.pOut[0] -> c7.pIn[0] + unmatched c8.pOut[1] -> c8.pIn[1] + # implicit matched connections + c7.pOut -> c8.pIn + c8.pOut -> c7.pIn + # explicit matched connections + c7.pOut[2] -> c7.pIn[2] + c8.pOut[3] -> c8.pIn[3] + } } diff --git a/docs/fpp-spec.html b/docs/fpp-spec.html index a5ee716f0..c06cae7f5 100644 --- a/docs/fpp-spec.html +++ b/docs/fpp-spec.html @@ -3335,6 +3335,20 @@
unmatched then it is unmatched; otherwise it is matched.

  • +

    For each connection that appears from \$p_1\$ and \$p_2\$:

    +
    +
      +
    1. +

      Compute the set of port numbers that are already in use.

      +
    2. +
    3. +

      Check that the port numbers computed in the previous step to +ensure there are no duplicate port numbers.

      +
    4. +
    +
    +
  • +
  • For each matched connection \$c_1\$ with an endpoint at I . \$p_1\$:

      @@ -3356,8 +3370,8 @@

      For each pair P with \$(c_1,c_2)\$ computed in step b, if P has both numbers assigned, check that the port numbers match. -For each P that has exactly one port number assigned, -assign the other one to match.

      +For each P that has exactly one port number assigned, check that the +port number is not in use and assign it to match.

    1. Traverse the pairs \$(c_1,c_2)\$ computed in step b according to the @@ -9801,7 +9815,7 @@

      21.4. Translation Tools

    diff --git a/docs/fpp-users-guide.html b/docs/fpp-users-guide.html index b2feb5216..a9081d842 100644 --- a/docs/fpp-users-guide.html +++ b/docs/fpp-users-guide.html @@ -12604,7 +12604,7 @@

    From 3cb179356609e2b4fdaac88a390e638e8cb68e74 Mon Sep 17 00:00:00 2001 From: jawest Date: Wed, 25 Sep 2024 18:50:20 -0700 Subject: [PATCH 13/73] add comments, cleanup --- .../scala/analysis/Semantics/Connection.scala | 1 + .../GeneralPortNumbering.scala | 3 ++ .../MatchedPortNumbering.scala | 10 +++++- .../ResolveTopology/PortNumberingState.scala | 5 +++ compiler/lib/src/main/scala/util/Error.scala | 34 ++++++++++--------- 5 files changed, 36 insertions(+), 17 deletions(-) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/Connection.scala b/compiler/lib/src/main/scala/analysis/Semantics/Connection.scala index b84251d52..a68214f34 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/Connection.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/Connection.scala @@ -104,6 +104,7 @@ case class Connection( } } + /** Checks to see if a connection is match constrained */ def isMatchConstrained: Boolean = { def portMatchingExists(pml: List[Component.PortMatching], pi: PortInstance): Boolean = pml.exists(pm => pi.equals(pm.instance1) || pi.equals(pm.instance2)) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/GeneralPortNumbering.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/GeneralPortNumbering.scala index 411c77c09..d793302fb 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/GeneralPortNumbering.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/GeneralPortNumbering.scala @@ -28,6 +28,9 @@ object GeneralPortNumbering { val pi = pii.portInstance val cs = t.getConnectionsFrom(pii).toArray.sorted val usedPortNumbers = t.getUsedPortNumbers(pi, cs) + // Initialize the PortNumberingState with an empty set as one + // of its args since in GeneralPortNumbering we are only + // working with one set of port numbers at a time val state = PortNumberingState.initial(Set(), usedPortNumbers) val (_, t1) = cs.foldLeft ((state, t)) ({ case ((s,t), c) => t.getPortNumber(pi, c) match { diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala index 06c72c0b6..7b7976894 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala @@ -60,19 +60,23 @@ object MatchedPortNumbering { } case (Some(n1), None) => // Only pi1 has a number: assign it to pi2 + // Check to see if the port number is already in use if PortNumberingState.checkPortNumberInUse(n1, state.numbering.usedPorts2) then Left(SemanticError.PortNumberAlreadyInUse(n1)) else { val t1 = t.assignPortNumber(pi2, c2, n1) + // Update the set of used ports so that the new port number is tracked val num = state.numbering.setUsedPorts(state.numbering.usedPorts1, state.numbering.usedPorts2 + n1) Right(state.copy(t = t1, numbering = num)) } case (None, Some(n2)) => // Only pi2 has a number: assign it to pi1 + // Check to see if the port number is already in use if PortNumberingState.checkPortNumberInUse(n2, state.numbering.usedPorts1) then Left(SemanticError.PortNumberAlreadyInUse(n2)) else { val t1 = t.assignPortNumber(pi1, c1, n2) + // Update the set of used ports so that the new port number is tracked val num = state.numbering.setUsedPorts(state.numbering.usedPorts1 + n2, state.numbering.usedPorts2) Right(state.copy(t = t1, numbering = num)) } @@ -81,12 +85,14 @@ object MatchedPortNumbering { val maxSize1 = pi1.getArraySize val maxSize2 = pi2.getArraySize val (numbering, n) = state.numbering.getPortNumber + // Check to see if the port number is out of range for either of the port array sizes if(n > maxSize1 - 1) then Left(SemanticError.PortNumberOutOfRange(n, pi1.toString, maxSize1)) else if(n > maxSize2 - 1) then Left(SemanticError.PortNumberOutOfRange(n, pi2.toString, maxSize2)) else { val t1 = t.assignPortNumber(pi1, c1, n).assignPortNumber(pi2, c2, n) + // Update the set of used ports so that the new port number is tracked val num = state.numbering.setUsedPorts(state.numbering.usedPorts1 + n, state.numbering.usedPorts2 + n) Right(state.copy(t = t1, numbering = num)) } @@ -197,6 +203,7 @@ object MatchedPortNumbering { }) } + // Computes the set of used ports for all connections at a specific port instance def computeUsedPortNumbers(pi: PortInstance): Result.Result[Set[Int]] = { val empty: Set[Int] = Set() val pii = PortInstanceIdentifier(ci, pi) @@ -204,8 +211,9 @@ object MatchedPortNumbering { Result.foldLeft (cs) (empty) ((s, c) => { val used = t.getUsedPortNumbers(pi, List(c)) val intersection = s.intersect(used) + // Do not allow duplicate port numbers if intersection.nonEmpty - then Left(SemanticError.MultipleConnectionsAtPortIndex(intersection.toString)) + then Left(SemanticError.MultipleConnectionsAtPortIndex(intersection.mkString(", "))) else Right(s ++ used) }) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala index 68153f981..d9c2722a8 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala @@ -5,7 +5,9 @@ import fpp.compiler.util._ /** Port numbering state */ case class PortNumberingState private ( + /** First set of used ports */ usedPorts1: Set[Int], + /** Second set of used ports */ usedPorts2: Set[Int], /** The used port numbers */ usedPortNumbers: Set[Int], @@ -30,6 +32,8 @@ case class PortNumberingState private ( (s, nextPortNumber) } + // Takes in the updated sets, updated the usedPortNumbers set + // (ie: union of usedPorts1 and usedPorts2) and figure out the new next port number def setUsedPorts(u1: Set[Int], u2: Set[Int]): PortNumberingState = { val updatedUsedPortNumbers = u1 ++ u2 val updatedNextPortNumber = PortNumberingState.getNextNumber( @@ -59,6 +63,7 @@ object PortNumberingState { helper(from) } + // Checks to see if a port number is already in use def checkPortNumberInUse(n: Int, used: Set[Int]) = used.contains(n) diff --git a/compiler/lib/src/main/scala/util/Error.scala b/compiler/lib/src/main/scala/util/Error.scala index 33bc613bd..2b41d0ceb 100644 --- a/compiler/lib/src/main/scala/util/Error.scala +++ b/compiler/lib/src/main/scala/util/Error.scala @@ -153,8 +153,6 @@ sealed trait Error { Error.print (Some(loc)) (msg) System.err.println(s"port definition is here:") System.err.println(defLoc) - case SemanticError.MultipleConnectionsAtPortIndex(portIndexString) => - Error.print (None) (s"multiple connections appear at port indices $portIndexString") case SemanticError.InvalidPortInstanceId(loc, portName, componentName) => Error.print (Some(loc)) (s"$portName is not a port instance of component $componentName") case SemanticError.InvalidPortKind(loc, msg, specLoc) => @@ -163,14 +161,10 @@ sealed trait Error { System.err.println(specLoc) case SemanticError.InvalidPortMatching(loc, msg) => Error.print (Some(loc)) (msg) - case SemanticError.PortNumberAlreadyInUse(n) => - Error.print (None) (s"port number $n is already in use") case SemanticError.InvalidPortNumber(loc, portNumber, port, arraySize, specLoc) => Error.print (Some(loc)) (s"invalid port number $portNumber for port $port (max is ${arraySize - 1})") System.err.println(s"port instance is specified here:") System.err.println(specLoc) - case SemanticError.PortNumberOutOfRange(portNumber, port, arraySize) => - Error.print (None) (s"port number $portNumber out of range for port $port (max is ${arraySize - 1})") case SemanticError.InvalidPriority(loc) => Error.print (Some(loc)) ("only async input may have a priority") case SemanticError.InvalidQueueFull(loc) => @@ -205,6 +199,8 @@ sealed trait Error { Error.print (Some(loc)) ("unmatched connection must go from or to a matched port") case SemanticError.MissingPort(loc, specMsg, portMsg) => Error.print (Some(loc)) (s"component with $specMsg must have $portMsg") + case SemanticError.MultipleConnectionsAtPortIndex(portIndexString) => + Error.print (None) (s"multiple connections appear at port indices $portIndexString") case SemanticError.OverlappingIdRanges( maxId1, name1, loc1, baseId2, name2, loc2 ) => @@ -219,6 +215,10 @@ sealed trait Error { Error.print (Some(loc)) ("passive component may not have async input") case SemanticError.PassiveStateMachine(loc) => Error.print (Some(loc)) ("passive component may not have a state machine instance") + case SemanticError.PortNumberAlreadyInUse(n) => + Error.print (None) (s"port number $n is already in use") + case SemanticError.PortNumberOutOfRange(portNumber, port, arraySize) => + Error.print (None) (s"port number $portNumber out of range for port $port (max is ${arraySize - 1})") case SemanticError.RedefinedSymbol(name, loc, prevLoc) => Error.print (Some(loc)) (s"redefinition of symbol ${name}") System.err.println("previous definition is here:") @@ -431,9 +431,6 @@ object SemanticError { msg: String, defLoc: Location ) extends Error - final case class MultipleConnectionsAtPortIndex( - portIndexString: String - ) extends Error /** Invalid port instance identifier */ final case class InvalidPortInstanceId( loc: Location, @@ -448,7 +445,6 @@ object SemanticError { ) extends Error /** Invalid port matching */ final case class InvalidPortMatching(loc: Location, msg: String) extends Error - final case class PortNumberAlreadyInUse(n: Int) extends Error /** Invalid port number */ final case class InvalidPortNumber( loc: Location, @@ -457,12 +453,6 @@ object SemanticError { size: Int, specLoc: Location ) extends Error - /** Port number out of range */ - final case class PortNumberOutOfRange( - portNumber: Int, - port: String, - size: Int, - ) extends Error /** Invalid priority specifier */ final case class InvalidPriority(loc: Location) extends Error /** Invalid queue full specifier */ @@ -504,6 +494,10 @@ object SemanticError { final case class MissingPortMatching( loc: Location ) extends Error + /** Multiple connections are using the same port index */ + final case class MultipleConnectionsAtPortIndex( + portIndexString: String + ) extends Error /** Overlapping ID ranges */ final case class OverlappingIdRanges( maxId1: BigInt, @@ -516,6 +510,14 @@ object SemanticError { /** Passive async input */ final case class PassiveAsync(loc: Location) extends Error final case class PassiveStateMachine(loc: Location) extends Error + /** Port number has already been assigned */ + final case class PortNumberAlreadyInUse(n: Int) extends Error + /** Port number out of range */ + final case class PortNumberOutOfRange( + portNumber: Int, + port: String, + size: Int, + ) extends Error /** Redefined symbol */ final case class RedefinedSymbol( name: String, From 54ea1ffb5e0e69f3828a40c0212d7e9a6cc4215c Mon Sep 17 00:00:00 2001 From: jawest Date: Wed, 25 Sep 2024 19:01:26 -0700 Subject: [PATCH 14/73] check use ports for the case of implicit port number --- .../Semantics/ResolveTopology/MatchedPortNumbering.scala | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala index 7b7976894..b1f3235d6 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala @@ -90,6 +90,9 @@ object MatchedPortNumbering { then Left(SemanticError.PortNumberOutOfRange(n, pi1.toString, maxSize1)) else if(n > maxSize2 - 1) then Left(SemanticError.PortNumberOutOfRange(n, pi2.toString, maxSize2)) + // Check to see if the port number is already in use + else if PortNumberingState.checkPortNumberInUse(n, state.numbering.usedPortNumbers) + then Left(SemanticError.PortNumberAlreadyInUse(n)) else { val t1 = t.assignPortNumber(pi1, c1, n).assignPortNumber(pi2, c2, n) // Update the set of used ports so that the new port number is tracked From 06645813a4165ed65b295e3017c36a17884b16fd Mon Sep 17 00:00:00 2001 From: jawest Date: Fri, 27 Sep 2024 17:02:26 -0700 Subject: [PATCH 15/73] set next available port --- .../analysis/Semantics/ResolveTopology/PortNumberingState.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala index d9c2722a8..8711fabb7 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala @@ -40,7 +40,7 @@ case class PortNumberingState private ( nextPortNumber, updatedUsedPortNumbers ) - PortNumberingState(u1, u2, updatedUsedPortNumbers, nextPortNumber) + PortNumberingState(u1, u2, updatedUsedPortNumbers, updatedNextPortNumber) } } From 01280b5c7a9d94df0335f1ffa785d95a48ec40a8 Mon Sep 17 00:00:00 2001 From: jawest Date: Fri, 27 Sep 2024 17:06:45 -0700 Subject: [PATCH 16/73] update `fpp-to-json` test ref files --- .../test/importedTopologies.ref.txt | 106 ++++++++++++------ .../fpp-to-json/test/simpleTopology.ref.txt | 38 +++++-- .../tools/fpp-to-json/test/syntaxOnly.ref.txt | 6 + 3 files changed, 104 insertions(+), 46 deletions(-) diff --git a/compiler/tools/fpp-to-json/test/importedTopologies.ref.txt b/compiler/tools/fpp-to-json/test/importedTopologies.ref.txt index 731223018..399d2ddfb 100644 --- a/compiler/tools/fpp-to-json/test/importedTopologies.ref.txt +++ b/compiler/tools/fpp-to-json/test/importedTopologies.ref.txt @@ -401,6 +401,7 @@ "name" : "C1", "connections" : [ { + "isUnmatched" : false, "fromPort" : { "AstNode" : { "data" : { @@ -474,6 +475,7 @@ "name" : "C2", "connections" : [ { + "isUnmatched" : false, "fromPort" : { "AstNode" : { "data" : { @@ -661,6 +663,7 @@ "name" : "C3", "connections" : [ { + "isUnmatched" : false, "fromPort" : { "AstNode" : { "data" : { @@ -734,6 +737,7 @@ "name" : "C4", "connections" : [ { + "isUnmatched" : false, "fromPort" : { "AstNode" : { "data" : { @@ -1956,7 +1960,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false } ], "C2" : [ @@ -2096,7 +2101,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false } ] }, @@ -2238,7 +2244,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false } ], "C2" : [ @@ -2378,7 +2385,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false } ] }, @@ -2581,7 +2589,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false } ] ], @@ -2783,7 +2792,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false } ] ] @@ -2987,7 +2997,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false } ] ], @@ -3189,7 +3200,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false } ] ] @@ -3332,7 +3344,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false }, 0 ], @@ -3473,7 +3486,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false }, 0 ] @@ -3616,7 +3630,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false }, 0 ], @@ -3757,7 +3772,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false }, 0 ] @@ -4037,7 +4053,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false } ], "C4" : [ @@ -4177,7 +4194,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false } ] }, @@ -4319,7 +4337,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false } ], "C4" : [ @@ -4459,7 +4478,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false } ] }, @@ -4662,7 +4682,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false } ] ], @@ -4864,7 +4885,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false } ] ] @@ -5068,7 +5090,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false } ] ], @@ -5270,7 +5293,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false } ] ] @@ -5413,7 +5437,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false }, 0 ], @@ -5554,7 +5579,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false }, 0 ] @@ -5697,7 +5723,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false }, 0 ], @@ -5838,7 +5865,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false }, 0 ] @@ -6243,7 +6271,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false } ], "C4" : [ @@ -6383,7 +6412,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false } ] }, @@ -6589,7 +6619,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false } ] ], @@ -6791,7 +6822,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false } ] ] @@ -6995,7 +7027,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false } ] ], @@ -7197,7 +7230,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false } ] ] @@ -7340,7 +7374,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false }, 0 ], @@ -7481,7 +7516,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false }, 0 ] @@ -7624,7 +7660,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false }, 0 ], @@ -7765,7 +7802,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false }, 0 ] diff --git a/compiler/tools/fpp-to-json/test/simpleTopology.ref.txt b/compiler/tools/fpp-to-json/test/simpleTopology.ref.txt index d84335af9..4ce2f85d5 100644 --- a/compiler/tools/fpp-to-json/test/simpleTopology.ref.txt +++ b/compiler/tools/fpp-to-json/test/simpleTopology.ref.txt @@ -309,6 +309,7 @@ "name" : "C1", "connections" : [ { + "isUnmatched" : false, "fromPort" : { "AstNode" : { "data" : { @@ -382,6 +383,7 @@ "name" : "C2", "connections" : [ { + "isUnmatched" : false, "fromPort" : { "AstNode" : { "data" : { @@ -1190,7 +1192,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false } ], "C2" : [ @@ -1330,7 +1333,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false } ] }, @@ -1472,7 +1476,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false } ], "C2" : [ @@ -1612,7 +1617,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false } ] }, @@ -1815,7 +1821,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false } ] ], @@ -2017,7 +2024,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false } ] ] @@ -2221,7 +2229,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false } ] ], @@ -2423,7 +2432,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false } ] ] @@ -2566,7 +2576,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false }, 0 ], @@ -2707,7 +2718,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false }, 0 ] @@ -2850,7 +2862,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false }, 0 ], @@ -2991,7 +3004,8 @@ } }, "portNumber" : "None" - } + }, + "isUnmatched" : false }, 0 ] diff --git a/compiler/tools/fpp-to-json/test/syntaxOnly.ref.txt b/compiler/tools/fpp-to-json/test/syntaxOnly.ref.txt index 2d4534e6c..aa7a54b8e 100644 --- a/compiler/tools/fpp-to-json/test/syntaxOnly.ref.txt +++ b/compiler/tools/fpp-to-json/test/syntaxOnly.ref.txt @@ -1197,6 +1197,7 @@ "name" : "A", "connections" : [ { + "isUnmatched" : false, "fromPort" : { "AstNode" : { "data" : { @@ -1247,6 +1248,7 @@ "toIndex" : "None" }, { + "isUnmatched" : false, "fromPort" : { "AstNode" : { "data" : { @@ -1297,6 +1299,7 @@ "toIndex" : "None" }, { + "isUnmatched" : false, "fromPort" : { "AstNode" : { "data" : { @@ -1347,6 +1350,7 @@ "toIndex" : "None" }, { + "isUnmatched" : false, "fromPort" : { "AstNode" : { "data" : { @@ -1397,6 +1401,7 @@ "toIndex" : "None" }, { + "isUnmatched" : false, "fromPort" : { "AstNode" : { "data" : { @@ -1447,6 +1452,7 @@ "toIndex" : "None" }, { + "isUnmatched" : false, "fromPort" : { "AstNode" : { "data" : { From 41191a59899de3777fae2a9b6d9803242c5ef166 Mon Sep 17 00:00:00 2001 From: jawest Date: Mon, 30 Sep 2024 11:43:21 -0700 Subject: [PATCH 17/73] remove redundant error, fix error wording --- .../ResolveTopology/MatchedPortNumbering.scala | 4 ++-- compiler/lib/src/main/scala/util/Error.scala | 10 +--------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala index b1f3235d6..c7796bf1d 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala @@ -87,9 +87,9 @@ object MatchedPortNumbering { val (numbering, n) = state.numbering.getPortNumber // Check to see if the port number is out of range for either of the port array sizes if(n > maxSize1 - 1) - then Left(SemanticError.PortNumberOutOfRange(n, pi1.toString, maxSize1)) + then Left(SemanticError.InvalidPortNumber(pi1.getLoc, n, pi1.toString, maxSize1, pi1.getLoc)) else if(n > maxSize2 - 1) - then Left(SemanticError.PortNumberOutOfRange(n, pi2.toString, maxSize2)) + then Left(SemanticError.InvalidPortNumber(pi2.getLoc, n, pi2.toString, maxSize2, pi2.getLoc)) // Check to see if the port number is already in use else if PortNumberingState.checkPortNumberInUse(n, state.numbering.usedPortNumbers) then Left(SemanticError.PortNumberAlreadyInUse(n)) diff --git a/compiler/lib/src/main/scala/util/Error.scala b/compiler/lib/src/main/scala/util/Error.scala index 2b41d0ceb..143f7e8a3 100644 --- a/compiler/lib/src/main/scala/util/Error.scala +++ b/compiler/lib/src/main/scala/util/Error.scala @@ -200,7 +200,7 @@ sealed trait Error { case SemanticError.MissingPort(loc, specMsg, portMsg) => Error.print (Some(loc)) (s"component with $specMsg must have $portMsg") case SemanticError.MultipleConnectionsAtPortIndex(portIndexString) => - Error.print (None) (s"multiple connections appear at port indices $portIndexString") + Error.print (None) (s"multiple connections appear at port index $portIndexString") case SemanticError.OverlappingIdRanges( maxId1, name1, loc1, baseId2, name2, loc2 ) => @@ -217,8 +217,6 @@ sealed trait Error { Error.print (Some(loc)) ("passive component may not have a state machine instance") case SemanticError.PortNumberAlreadyInUse(n) => Error.print (None) (s"port number $n is already in use") - case SemanticError.PortNumberOutOfRange(portNumber, port, arraySize) => - Error.print (None) (s"port number $portNumber out of range for port $port (max is ${arraySize - 1})") case SemanticError.RedefinedSymbol(name, loc, prevLoc) => Error.print (Some(loc)) (s"redefinition of symbol ${name}") System.err.println("previous definition is here:") @@ -512,12 +510,6 @@ object SemanticError { final case class PassiveStateMachine(loc: Location) extends Error /** Port number has already been assigned */ final case class PortNumberAlreadyInUse(n: Int) extends Error - /** Port number out of range */ - final case class PortNumberOutOfRange( - portNumber: Int, - port: String, - size: Int, - ) extends Error /** Redefined symbol */ final case class RedefinedSymbol( name: String, From 1f7aae6f57d5834c50341a8ba3143ad275157578 Mon Sep 17 00:00:00 2001 From: jawest Date: Mon, 30 Sep 2024 12:23:27 -0700 Subject: [PATCH 18/73] fix unmatched connection parser --- compiler/lib/src/main/scala/syntax/Parser.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/lib/src/main/scala/syntax/Parser.scala b/compiler/lib/src/main/scala/syntax/Parser.scala index 252082701..00ccc78e3 100644 --- a/compiler/lib/src/main/scala/syntax/Parser.scala +++ b/compiler/lib/src/main/scala/syntax/Parser.scala @@ -48,7 +48,7 @@ object Parser extends Parsers { def connection: Parser[Ast.SpecConnectionGraph.Connection] = { def connectionPort = node(portInstanceIdentifier) ~! opt(index) - opt(unmatched) ~! connectionPort ~! (rarrow ~>! connectionPort) ^^ { + opt(unmatched) ~ connectionPort ~! (rarrow ~>! connectionPort) ^^ { case unmatched ~ (fromPort ~ fromIndex) ~ (toPort ~ toIndex) => { Ast.SpecConnectionGraph.Connection( unmatched.isDefined, From 2e3ad401b64478122de57b9c3958fec0aadec0b0 Mon Sep 17 00:00:00 2001 From: jawest Date: Wed, 9 Oct 2024 18:23:37 -0700 Subject: [PATCH 19/73] refactor how we compute used ports in matched port numbering --- .../GeneralPortNumbering.scala | 16 ++- .../MatchedPortNumbering.scala | 106 ++++++++++++------ .../ResolveTopology/PortNumberingState.scala | 16 +-- compiler/lib/src/main/scala/util/Error.scala | 28 +++-- docs/fpp-spec.html | 10 +- docs/fpp-users-guide.html | 8 +- docs/users-guide/Defining-Components.adoc | 3 + docs/users-guide/Defining-Topologies.adoc | 2 + 8 files changed, 126 insertions(+), 63 deletions(-) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/GeneralPortNumbering.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/GeneralPortNumbering.scala index d793302fb..6e5decf74 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/GeneralPortNumbering.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/GeneralPortNumbering.scala @@ -26,12 +26,18 @@ object GeneralPortNumbering { pii: PortInstanceIdentifier ): Topology = { val pi = pii.portInstance - val cs = t.getConnectionsFrom(pii).toArray.sorted - val usedPortNumbers = t.getUsedPortNumbers(pi, cs) - // Initialize the PortNumberingState with an empty set as one + val cs = t.getConnectionsFrom(pii).toList.sorted + val usedPortNumbers = + cs.foldLeft (Map[Int, Connection]()) ((m, c) => + t.getPortNumber(pi, c) match { + case Some(n) => m + (n -> c) + case None => m + } + ) + // Initialize the PortNumberingState with an empty map as one // of its args since in GeneralPortNumbering we are only - // working with one set of port numbers at a time - val state = PortNumberingState.initial(Set(), usedPortNumbers) + // working with one map of port numbers to connections at a time + val state = PortNumberingState.initial(Map(), usedPortNumbers) val (_, t1) = cs.foldLeft ((state, t)) ({ case ((s,t), c) => t.getPortNumber(pi, c) match { case Some(n) => (s, t) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala index c7796bf1d..1ce4d5df0 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala @@ -39,6 +39,8 @@ object MatchedPortNumbering { val n1Opt = t.getPortNumber(pi1, c1) val pi2 = state.pi2 val n2Opt = t.getPortNumber(pi2, c2) + val u1 = state.numbering.usedPorts1 + val u2 = state.numbering.usedPorts2 (n1Opt, n2Opt) match { case (Some(n1), Some(n2)) => // Both ports have a number: check that they match @@ -61,24 +63,24 @@ object MatchedPortNumbering { case (Some(n1), None) => // Only pi1 has a number: assign it to pi2 // Check to see if the port number is already in use - if PortNumberingState.checkPortNumberInUse(n1, state.numbering.usedPorts2) - then Left(SemanticError.PortNumberAlreadyInUse(n1)) - else { - val t1 = t.assignPortNumber(pi2, c2, n1) - // Update the set of used ports so that the new port number is tracked - val num = state.numbering.setUsedPorts(state.numbering.usedPorts1, state.numbering.usedPorts2 + n1) - Right(state.copy(t = t1, numbering = num)) + state.numbering.usedPorts2.get(n1) match { + case Some(prevC) => Left(SemanticError.PortNumberAlreadyInUse(n1, c2.getLoc, prevC.getLoc)) + case None => + val t1 = t.assignPortNumber(pi2, c2, n1) + // Update the set of used ports so that the new port number is tracked + val num = state.numbering.setUsedPorts(state.numbering.usedPorts1, state.numbering.usedPorts2 + (n1 -> c2)) + Right(state.copy(t = t1, numbering = num)) } case (None, Some(n2)) => // Only pi2 has a number: assign it to pi1 // Check to see if the port number is already in use - if PortNumberingState.checkPortNumberInUse(n2, state.numbering.usedPorts1) - then Left(SemanticError.PortNumberAlreadyInUse(n2)) - else { - val t1 = t.assignPortNumber(pi1, c1, n2) - // Update the set of used ports so that the new port number is tracked - val num = state.numbering.setUsedPorts(state.numbering.usedPorts1 + n2, state.numbering.usedPorts2) - Right(state.copy(t = t1, numbering = num)) + state.numbering.usedPorts1.get(n2) match { + case Some(prevC) => Left(SemanticError.PortNumberAlreadyInUse(n2, c1.getLoc, prevC.getLoc)) + case None => + val t1 = t.assignPortNumber(pi1, c1, n2) + // Update the set of used ports so that the new port number is tracked + val num = state.numbering.setUsedPorts(state.numbering.usedPorts1 + (n2 -> c1), state.numbering.usedPorts2) + Right(state.copy(t = t1, numbering = num)) } case (None, None) => // Neither port has a number: assign a new one @@ -87,17 +89,19 @@ object MatchedPortNumbering { val (numbering, n) = state.numbering.getPortNumber // Check to see if the port number is out of range for either of the port array sizes if(n > maxSize1 - 1) - then Left(SemanticError.InvalidPortNumber(pi1.getLoc, n, pi1.toString, maxSize1, pi1.getLoc)) + then Left(SemanticError.NoPortFoundByMatchedPortNumbering(pi1.getLoc)) else if(n > maxSize2 - 1) - then Left(SemanticError.InvalidPortNumber(pi2.getLoc, n, pi2.toString, maxSize2, pi2.getLoc)) + then Left(SemanticError.NoPortFoundByMatchedPortNumbering(pi2.getLoc)) // Check to see if the port number is already in use - else if PortNumberingState.checkPortNumberInUse(n, state.numbering.usedPortNumbers) - then Left(SemanticError.PortNumberAlreadyInUse(n)) - else { - val t1 = t.assignPortNumber(pi1, c1, n).assignPortNumber(pi2, c2, n) - // Update the set of used ports so that the new port number is tracked - val num = state.numbering.setUsedPorts(state.numbering.usedPorts1 + n, state.numbering.usedPorts2 + n) - Right(state.copy(t = t1, numbering = num)) + (state.numbering.usedPorts1.get(n), state.numbering.usedPorts2.get(n)) match { + case (Some(prevC), None) => Left(SemanticError.PortNumberAlreadyInUse(n, c2.getLoc, prevC.getLoc)) + case (None, Some(prevC)) => Left(SemanticError.PortNumberAlreadyInUse(n, c1.getLoc, prevC.getLoc)) + case (Some(prevC1), Some(prevC2)) => Left(SemanticError.PortNumberAlreadyInUse(n, c2.getLoc, prevC1.getLoc)) + case (None, None) => + val t1 = t.assignPortNumber(pi1, c1, n).assignPortNumber(pi2, c2, n) + // Update the set of used ports so that the new port number is tracked + val num = state.numbering.setUsedPorts(state.numbering.usedPorts1 + (n -> c1), state.numbering.usedPorts2 + (n -> c2)) + Right(state.copy(t = t1, numbering = num)) } } } @@ -127,8 +131,8 @@ object MatchedPortNumbering { map1: ConnectionMap, pi2: PortInstance, map2: ConnectionMap, - usedPorts1: Set[Int], - usedPorts2: Set[Int] + usedPorts1: Map[Int, Connection], + usedPorts2: Map[Int, Connection] ): State = { State( t, @@ -206,19 +210,51 @@ object MatchedPortNumbering { }) } + def checkRemoteUsedPorts(piiRemote: PortInstanceIdentifier, used: Map[Int, Connection]) = { + val csRemote = t.getConnectionsAt(piiRemote).toList.sorted + Result.foldLeft (csRemote) (()) ((r, cRemote) => { + t.getPortNumber(piiRemote.portInstance, cRemote) match { + case Some(n) => + used.get(n) match { + case Some(c) => + if ((c != cRemote) && (ci == piiRemote.componentInstance)) + then Left(SemanticError.PortNumberAlreadyInUse(n, cRemote.getLoc, c.getLoc)) + else + Right(()) + case None => Right(()) + } + case None => Right(()) + } + }) + } + // Computes the set of used ports for all connections at a specific port instance - def computeUsedPortNumbers(pi: PortInstance): Result.Result[Set[Int]] = { - val empty: Set[Int] = Set() + def computeUsedPortNumbers(pi: PortInstance): Result.Result[Map[Int, Connection]] = { val pii = PortInstanceIdentifier(ci, pi) val cs = t.getConnectionsAt(pii).toList.sorted - Result.foldLeft (cs) (empty) ((s, c) => { - val used = t.getUsedPortNumbers(pi, List(c)) - val intersection = s.intersect(used) - // Do not allow duplicate port numbers - if intersection.nonEmpty - then Left(SemanticError.MultipleConnectionsAtPortIndex(intersection.mkString(", "))) - else - Right(s ++ used) + Result.foldLeft (cs) (Map[Int, Connection]()) ((m, c) => { + val piiRemote = c.getOtherEndpoint(pi).port + for { + used <- t.getPortNumber(pi, c) match { + case Some(n) => { + m.get(n) match { + case Some(prevC) => + val loc = c.getLoc + val prevLoc = prevC.getLoc + Left( + SemanticError.DuplicateConnectionAtMatchedPort(loc, pi.toString, prevLoc, n) + ) + case None => { + Right(m + (n -> c)) + } + } + } + case None => { + Right(m) + } + } + _ <- checkRemoteUsedPorts(piiRemote, used) + } yield used }) } diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala index 8711fabb7..6fbb27159 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala @@ -6,9 +6,9 @@ import fpp.compiler.util._ /** Port numbering state */ case class PortNumberingState private ( /** First set of used ports */ - usedPorts1: Set[Int], + usedPorts1: Map[Int, Connection], /** Second set of used ports */ - usedPorts2: Set[Int], + usedPorts2: Map[Int, Connection], /** The used port numbers */ usedPortNumbers: Set[Int], /** The next port number */ @@ -34,8 +34,8 @@ case class PortNumberingState private ( // Takes in the updated sets, updated the usedPortNumbers set // (ie: union of usedPorts1 and usedPorts2) and figure out the new next port number - def setUsedPorts(u1: Set[Int], u2: Set[Int]): PortNumberingState = { - val updatedUsedPortNumbers = u1 ++ u2 + def setUsedPorts(u1: Map[Int, Connection], u2: Map[Int, Connection]): PortNumberingState = { + val updatedUsedPortNumbers = Set(u1.keys.toList:_*) ++ Set(u2.keys.toList:_*) val updatedNextPortNumber = PortNumberingState.getNextNumber( nextPortNumber, updatedUsedPortNumbers @@ -48,8 +48,8 @@ case class PortNumberingState private ( object PortNumberingState { /** Construct an initial state */ - def initial(usedPorts1: Set[Int], usedPorts2: Set[Int]): PortNumberingState = { - val usedPortNumbers = usedPorts1 ++ usedPorts2 + def initial(usedPorts1: Map[Int, Connection], usedPorts2: Map[Int, Connection]): PortNumberingState = { + val usedPortNumbers = Set(usedPorts1.keys.toList:_*) ++ Set(usedPorts2.keys.toList:_*) val nextPortNumber = getNextNumber(0, usedPortNumbers) PortNumberingState(usedPorts1, usedPorts2, usedPortNumbers, nextPortNumber) } @@ -63,8 +63,4 @@ object PortNumberingState { helper(from) } - // Checks to see if a port number is already in use - def checkPortNumberInUse(n: Int, used: Set[Int]) = - used.contains(n) - } diff --git a/compiler/lib/src/main/scala/util/Error.scala b/compiler/lib/src/main/scala/util/Error.scala index 143f7e8a3..a0916a831 100644 --- a/compiler/lib/src/main/scala/util/Error.scala +++ b/compiler/lib/src/main/scala/util/Error.scala @@ -45,6 +45,9 @@ sealed trait Error { Error.print (Some(loc)) (s"cannot resolve path $name") case SemanticError.DivisionByZero(loc) => Error.print (Some(loc)) ("division by zero") + case SemanticError.DuplicateConnectionAtMatchedPort(loc, port, prevLoc, n) => + Error.print (Some(loc)) (s"duplicate connection at matched port $port[$n]") + printPrevLoc(prevLoc) case SemanticError.DuplicateDictionaryName(kind, name, loc, prevLoc) => Error.print (Some(loc)) (s"duplicate ${kind} name ${name}") printPrevLoc(prevLoc) @@ -199,8 +202,8 @@ sealed trait Error { Error.print (Some(loc)) ("unmatched connection must go from or to a matched port") case SemanticError.MissingPort(loc, specMsg, portMsg) => Error.print (Some(loc)) (s"component with $specMsg must have $portMsg") - case SemanticError.MultipleConnectionsAtPortIndex(portIndexString) => - Error.print (None) (s"multiple connections appear at port index $portIndexString") + case SemanticError.NoPortFoundByMatchedPortNumbering(loc) => + Error.print (Some(loc)) (s"matched port numbering could not find an available port number on both sides of the matching") case SemanticError.OverlappingIdRanges( maxId1, name1, loc1, baseId2, name2, loc2 ) => @@ -215,8 +218,10 @@ sealed trait Error { Error.print (Some(loc)) ("passive component may not have async input") case SemanticError.PassiveStateMachine(loc) => Error.print (Some(loc)) ("passive component may not have a state machine instance") - case SemanticError.PortNumberAlreadyInUse(n) => - Error.print (None) (s"port number $n is already in use") + case SemanticError.PortNumberAlreadyInUse(n, loc, prevLoc) => + Error.print (Some(loc)) (s"port number $n is already in use") + System.err.println("previous usage is here:") + System.err.println(prevLoc) case SemanticError.RedefinedSymbol(name, loc, prevLoc) => Error.print (Some(loc)) (s"redefinition of symbol ${name}") System.err.println("previous definition is here:") @@ -271,6 +276,13 @@ object SemanticError { final case class EmptyArray(loc: Location) extends Error /** Division by zero */ final case class DivisionByZero(loc: Location) extends Error + /** Duplicate connections at matched port */ + final case class DuplicateConnectionAtMatchedPort( + loc: Location, + port: String, + prevLoc: Location, + n: Int + ) extends Error /** Duplicate name in dictionary */ final case class DuplicateDictionaryName( kind: String, @@ -492,9 +504,9 @@ object SemanticError { final case class MissingPortMatching( loc: Location ) extends Error - /** Multiple connections are using the same port index */ - final case class MultipleConnectionsAtPortIndex( - portIndexString: String + /** Matched port numbering could not find a valid port number */ + final case class NoPortFoundByMatchedPortNumbering( + loc: Location ) extends Error /** Overlapping ID ranges */ final case class OverlappingIdRanges( @@ -509,7 +521,7 @@ object SemanticError { final case class PassiveAsync(loc: Location) extends Error final case class PassiveStateMachine(loc: Location) extends Error /** Port number has already been assigned */ - final case class PortNumberAlreadyInUse(n: Int) extends Error + final case class PortNumberAlreadyInUse(n: Int, loc: Location, prevLoc: Location) extends Error /** Redefined symbol */ final case class RedefinedSymbol( name: String, diff --git a/docs/fpp-spec.html b/docs/fpp-spec.html index c06cae7f5..856e3edfe 100644 --- a/docs/fpp-spec.html +++ b/docs/fpp-spec.html @@ -3339,11 +3339,13 @@
    1. -

      Compute the set of port numbers that are already in use.

      +

      Compute the set of port numbers that are already in use for the connections at \$p_1\$.

    2. -

      Check that the port numbers computed in the previous step to -ensure there are no duplicate port numbers.

      +

      Compute the set of port numbers that are already in use for the connections at \$p_2\$.

      +
    3. +
    4. +

      Check that the port numbers computed in the previous steps do not have duplicates.

    @@ -9815,7 +9817,7 @@

    21.4. Translation Tools

    diff --git a/docs/fpp-users-guide.html b/docs/fpp-users-guide.html index a9081d842..64f51ee4b 100644 --- a/docs/fpp-users-guide.html +++ b/docs/fpp-users-guide.html @@ -6644,6 +6644,9 @@

    10.13. Matched Ports

    The matched pairs in item 2 must be connected to the same port numbers at p1 and p2.

  • +
  • +

    Multiple connections can not use the same port number even if the port is an input port.

    +
  • @@ -8396,6 +8399,9 @@

    12.3.2. Matched Nu
    1. +

      Multiple connections can not use the same port number even if the port is an input port.

      +
    2. +
    3. When a component has the matching specifier match p1 with p2, for every matched connection between p1 and another component, there must be a corresponding @@ -12604,7 +12610,7 @@

    diff --git a/docs/users-guide/Defining-Components.adoc b/docs/users-guide/Defining-Components.adoc index e0625131d..f499d7b55 100644 --- a/docs/users-guide/Defining-Components.adoc +++ b/docs/users-guide/Defining-Components.adoc @@ -2677,6 +2677,9 @@ component instance and `p2`. . The matched pairs in item 2 must be connected to the same port numbers at `p1` and `p2`. +. Multiple connections can not use the same port number even if the port is an input port. + + In this case we call `p1` and `p2` a pair of *matched ports*. For example: diff --git a/docs/users-guide/Defining-Topologies.adoc b/docs/users-guide/Defining-Topologies.adoc index effeb8dad..d72cfc6eb 100644 --- a/docs/users-guide/Defining-Topologies.adoc +++ b/docs/users-guide/Defining-Topologies.adoc @@ -698,6 +698,8 @@ Sequencer component. When you use matched numbering with direct graph specifiers, you must obey the following rules: +. Multiple connections can not use the same port number even if the port is an input port. + . When a component has the matching specifier `match p1 with p2`, for every matched connection between `p1` and another component, there must be a corresponding From 295b72d090ca96ae393880f4f3b63e37a92303c9 Mon Sep 17 00:00:00 2001 From: jawest Date: Thu, 10 Oct 2024 12:03:04 -0700 Subject: [PATCH 20/73] fix remote used port check --- .../Semantics/ResolveTopology/MatchedPortNumbering.scala | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala index 1ce4d5df0..db19a3fa6 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala @@ -217,8 +217,13 @@ object MatchedPortNumbering { case Some(n) => used.get(n) match { case Some(c) => - if ((c != cRemote) && (ci == piiRemote.componentInstance)) - then Left(SemanticError.PortNumberAlreadyInUse(n, cRemote.getLoc, c.getLoc)) + var cFromPii = c.from.port + var cToPii = c.to.port + var cRemoteFromPii = cRemote.from.port + var cRemoteToPii = cRemote.to.port + if ((c != cRemote) && (cFromPii == cRemoteFromPii || cToPii == cRemoteToPii)) { + Left(SemanticError.PortNumberAlreadyInUse(n, c.getLoc, cRemote.getLoc)) + } else Right(()) case None => Right(()) From 3a0bf372033659ee9756f2699e36bc4728cbd2a4 Mon Sep 17 00:00:00 2001 From: jawest Date: Thu, 10 Oct 2024 17:59:30 -0700 Subject: [PATCH 21/73] cleanup and additional test cases --- .../MatchedPortNumbering.scala | 39 ++----------------- ...icate_input_connection_at_matched_port.fpp | 30 ++++++++++++++ ...e_input_connection_at_matched_port.ref.txt | 9 +++++ .../fpp-check/test/port_numbering/tests.sh | 4 ++ ...atched_connection_port_number_in_use_1.fpp | 30 ++++++++++++++ ...ed_connection_port_number_in_use_1.ref.txt | 9 +++++ ...atched_connection_port_number_in_use_2.fpp | 29 ++++++++++++++ ...ed_connection_port_number_in_use_2.ref.txt | 9 +++++ ...atched_connection_port_number_in_use_3.fpp | 31 +++++++++++++++ ...ed_connection_port_number_in_use_3.ref.txt | 9 +++++ .../unmatched/unmatched_connections.fpp | 3 +- 11 files changed, 165 insertions(+), 37 deletions(-) create mode 100644 compiler/tools/fpp-check/test/port_numbering/duplicate_input_connection_at_matched_port.fpp create mode 100644 compiler/tools/fpp-check/test/port_numbering/duplicate_input_connection_at_matched_port.ref.txt create mode 100644 compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_1.fpp create mode 100644 compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_1.ref.txt create mode 100644 compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_2.fpp create mode 100644 compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_2.ref.txt create mode 100644 compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_3.fpp create mode 100644 compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_3.ref.txt diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala index db19a3fa6..29473eefc 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala @@ -210,38 +210,14 @@ object MatchedPortNumbering { }) } - def checkRemoteUsedPorts(piiRemote: PortInstanceIdentifier, used: Map[Int, Connection]) = { - val csRemote = t.getConnectionsAt(piiRemote).toList.sorted - Result.foldLeft (csRemote) (()) ((r, cRemote) => { - t.getPortNumber(piiRemote.portInstance, cRemote) match { - case Some(n) => - used.get(n) match { - case Some(c) => - var cFromPii = c.from.port - var cToPii = c.to.port - var cRemoteFromPii = cRemote.from.port - var cRemoteToPii = cRemote.to.port - if ((c != cRemote) && (cFromPii == cRemoteFromPii || cToPii == cRemoteToPii)) { - Left(SemanticError.PortNumberAlreadyInUse(n, c.getLoc, cRemote.getLoc)) - } - else - Right(()) - case None => Right(()) - } - case None => Right(()) - } - }) - } - // Computes the set of used ports for all connections at a specific port instance def computeUsedPortNumbers(pi: PortInstance): Result.Result[Map[Int, Connection]] = { val pii = PortInstanceIdentifier(ci, pi) val cs = t.getConnectionsAt(pii).toList.sorted Result.foldLeft (cs) (Map[Int, Connection]()) ((m, c) => { val piiRemote = c.getOtherEndpoint(pi).port - for { - used <- t.getPortNumber(pi, c) match { - case Some(n) => { + t.getPortNumber(pi, c) match { + case Some(n) => m.get(n) match { case Some(prevC) => val loc = c.getLoc @@ -249,17 +225,10 @@ object MatchedPortNumbering { Left( SemanticError.DuplicateConnectionAtMatchedPort(loc, pi.toString, prevLoc, n) ) - case None => { - Right(m + (n -> c)) - } + case None => Right(m + (n -> c)) } - } - case None => { - Right(m) - } + case None => Right(m) } - _ <- checkRemoteUsedPorts(piiRemote, used) - } yield used }) } diff --git a/compiler/tools/fpp-check/test/port_numbering/duplicate_input_connection_at_matched_port.fpp b/compiler/tools/fpp-check/test/port_numbering/duplicate_input_connection_at_matched_port.fpp new file mode 100644 index 000000000..876c616dd --- /dev/null +++ b/compiler/tools/fpp-check/test/port_numbering/duplicate_input_connection_at_matched_port.fpp @@ -0,0 +1,30 @@ +module M { + + port P + + passive component C1 { + + output port pOut: [4] P + sync input port pIn: [4] P + + match pOut with pIn + } + + instance c1: C1 base id 0x100 + instance c2: C1 base id 0x200 + instance c3: C1 base id 0x300 + + topology T1 { + + instance c1 + instance c2 + instance c3 + + connections P { + c1.pOut -> c2.pIn + c2.pOut -> c1.pIn[0] + c3.pOut -> c1.pIn[0] + } + } + +} diff --git a/compiler/tools/fpp-check/test/port_numbering/duplicate_input_connection_at_matched_port.ref.txt b/compiler/tools/fpp-check/test/port_numbering/duplicate_input_connection_at_matched_port.ref.txt new file mode 100644 index 000000000..7ef5d9e70 --- /dev/null +++ b/compiler/tools/fpp-check/test/port_numbering/duplicate_input_connection_at_matched_port.ref.txt @@ -0,0 +1,9 @@ +fpp-check +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/duplicate_input_connection_at_matched_port.fpp:26.9 + c3.pOut -> c1.pIn[0] + ^ +error: duplicate connection at matched port pIn[0] +previous occurrence is here: +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/duplicate_input_connection_at_matched_port.fpp:25.9 + c2.pOut -> c1.pIn[0] + ^ diff --git a/compiler/tools/fpp-check/test/port_numbering/tests.sh b/compiler/tools/fpp-check/test/port_numbering/tests.sh index d3995c2e1..686afaba8 100644 --- a/compiler/tools/fpp-check/test/port_numbering/tests.sh +++ b/compiler/tools/fpp-check/test/port_numbering/tests.sh @@ -1,8 +1,12 @@ tests=" +duplicate_input_connection_at_matched_port duplicate_matched_connection duplicate_output_connection mismatched_port_numbers ok negative_port_number too_many_output_ports +unmatched_connection_port_number_in_use_1 +unmatched_connection_port_number_in_use_2 +unmatched_connection_port_number_in_use_3 " diff --git a/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_1.fpp b/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_1.fpp new file mode 100644 index 000000000..ef959a99a --- /dev/null +++ b/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_1.fpp @@ -0,0 +1,30 @@ +module M { + + port P + + passive component C1 { + + output port pOut: [4] P + sync input port pIn: [4] P + + match pOut with pIn + } + + instance c1: C1 base id 0x100 + instance c2: C1 base id 0x200 + instance c3: C1 base id 0x300 + + topology T { + + instance c1 + instance c2 + instance c3 + + connections P { + c1.pOut -> c2.pIn + c2.pOut -> c1.pIn[0] + unmatched c1.pOut[0] -> c3.pIn + } + } + +} diff --git a/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_1.ref.txt b/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_1.ref.txt new file mode 100644 index 000000000..c7b3e4423 --- /dev/null +++ b/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_1.ref.txt @@ -0,0 +1,9 @@ +fpp-check +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_1.fpp:24.7 + c1.pOut -> c2.pIn + ^ +error: port number 0 is already in use +previous usage is here: +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_1.fpp:26.17 + unmatched c1.pOut[0] -> c3.pIn + ^ diff --git a/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_2.fpp b/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_2.fpp new file mode 100644 index 000000000..e574a69a7 --- /dev/null +++ b/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_2.fpp @@ -0,0 +1,29 @@ +module M { + + port P + + passive component C1 { + + output port pOut: [4] P + sync input port pIn: [4] P + + match pOut with pIn + } + + instance c1: C1 base id 0x100 + instance c2: C1 base id 0x200 + + topology T { + + instance c1 + instance c2 + + connections P { + + c1.pOut[0] -> c2.pIn + c2.pOut -> c1.pIn + unmatched c2.pOut -> c1.pIn[0] + } + } + +} diff --git a/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_2.ref.txt b/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_2.ref.txt new file mode 100644 index 000000000..19b8edafd --- /dev/null +++ b/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_2.ref.txt @@ -0,0 +1,9 @@ +fpp-check +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_2.fpp:24.7 + c2.pOut -> c1.pIn + ^ +error: port number 0 is already in use +previous usage is here: +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_2.fpp:25.17 + unmatched c2.pOut -> c1.pIn[0] + ^ diff --git a/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_3.fpp b/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_3.fpp new file mode 100644 index 000000000..8b5b59dad --- /dev/null +++ b/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_3.fpp @@ -0,0 +1,31 @@ +module M { + + port P + + passive component C1 { + + output port pOut: [4] P + sync input port pIn: [4] P + + match pOut with pIn + } + + instance c1: C1 base id 0x100 + instance c2: C1 base id 0x200 + instance c3: C1 base id 0x300 + + topology T { + + instance c1 + instance c2 + instance c3 + + connections P { + + c1.pOut -> c2.pIn[0] + c2.pOut -> c1.pIn + unmatched c2.pOut[0] -> c3.pIn + } + } + +} diff --git a/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_3.ref.txt b/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_3.ref.txt new file mode 100644 index 000000000..16ab19543 --- /dev/null +++ b/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_3.ref.txt @@ -0,0 +1,9 @@ +fpp-check +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_3.fpp:26.7 + c2.pOut -> c1.pIn + ^ +error: port number 0 is already in use +previous usage is here: +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_3.fpp:27.17 + unmatched c2.pOut[0] -> c3.pIn + ^ diff --git a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/unmatched_connections.fpp b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/unmatched_connections.fpp index 252cb9ab7..caa74787c 100644 --- a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/unmatched_connections.fpp +++ b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/unmatched_connections.fpp @@ -56,8 +56,7 @@ module M { # some connection at B index at j not equal to i going to same component instance unmatched c5.pOut[0] -> c5.pIn[0] unmatched c6.pOut[1] -> c5.pIn[1] - # implicit matched connections - c5.pOut -> c5.pIn + # implicit matched connection c6.pOut -> c5.pIn # explicit matched connection c5.pOut[2] -> c6.pIn[2] From 12679b59823fc1bdca2f2f63ff6b65b6ce2fa479 Mon Sep 17 00:00:00 2001 From: jawest Date: Wed, 16 Oct 2024 18:27:28 -0700 Subject: [PATCH 22/73] cleanup, add test case --- .../GeneralPortNumbering.scala | 13 +- .../MatchedPortNumbering.scala | 37 ++- .../ResolveTopology/PortNumberingState.scala | 19 +- compiler/lib/src/main/scala/util/Error.scala | 10 +- ... matched_port_numbering_no_valid_port.fpp} | 15 +- ...tched_port_numbering_no_valid_port.ref.txt | 9 + .../fpp-check/test/port_numbering/tests.sh | 6 +- ...ed_connection_port_number_in_use_3.ref.txt | 9 - ...tion_port_number_in_use_by_input_port.fpp} | 10 +- ..._port_number_in_use_by_input_port.ref.txt} | 4 +- ...ion_port_number_in_use_by_output_port.fpp} | 12 +- ...port_number_in_use_by_output_port.ref.txt} | 4 +- docs/fpp-spec.html | 229 ++++-------------- docs/fpp-users-guide.html | 2 +- 14 files changed, 130 insertions(+), 249 deletions(-) rename compiler/tools/fpp-check/test/port_numbering/{unmatched_connection_port_number_in_use_3.fpp => matched_port_numbering_no_valid_port.fpp} (55%) create mode 100644 compiler/tools/fpp-check/test/port_numbering/matched_port_numbering_no_valid_port.ref.txt delete mode 100644 compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_3.ref.txt rename compiler/tools/fpp-check/test/port_numbering/{unmatched_connection_port_number_in_use_2.fpp => unmatched_connection_port_number_in_use_by_input_port.fpp} (73%) rename compiler/tools/fpp-check/test/port_numbering/{unmatched_connection_port_number_in_use_2.ref.txt => unmatched_connection_port_number_in_use_by_input_port.ref.txt} (68%) rename compiler/tools/fpp-check/test/port_numbering/{unmatched_connection_port_number_in_use_1.fpp => unmatched_connection_port_number_in_use_by_output_port.fpp} (69%) rename compiler/tools/fpp-check/test/port_numbering/{unmatched_connection_port_number_in_use_1.ref.txt => unmatched_connection_port_number_in_use_by_output_port.ref.txt} (68%) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/GeneralPortNumbering.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/GeneralPortNumbering.scala index 6e5decf74..9398af426 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/GeneralPortNumbering.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/GeneralPortNumbering.scala @@ -27,17 +27,8 @@ object GeneralPortNumbering { ): Topology = { val pi = pii.portInstance val cs = t.getConnectionsFrom(pii).toList.sorted - val usedPortNumbers = - cs.foldLeft (Map[Int, Connection]()) ((m, c) => - t.getPortNumber(pi, c) match { - case Some(n) => m + (n -> c) - case None => m - } - ) - // Initialize the PortNumberingState with an empty map as one - // of its args since in GeneralPortNumbering we are only - // working with one map of port numbers to connections at a time - val state = PortNumberingState.initial(Map(), usedPortNumbers) + val usedPortNumbers = t.getUsedPortNumbers(pi, cs) + val state = PortNumberingState.initial(usedPortNumbers=usedPortNumbers) val (_, t1) = cs.foldLeft ((state, t)) ({ case ((s,t), c) => t.getPortNumber(pi, c) match { case Some(n) => (s, t) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala index 29473eefc..f449b49f2 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala @@ -77,31 +77,22 @@ object MatchedPortNumbering { state.numbering.usedPorts1.get(n2) match { case Some(prevC) => Left(SemanticError.PortNumberAlreadyInUse(n2, c1.getLoc, prevC.getLoc)) case None => - val t1 = t.assignPortNumber(pi1, c1, n2) + val t1 = t.assignPortNumber(pi1, c1, n2) // Update the set of used ports so that the new port number is tracked val num = state.numbering.setUsedPorts(state.numbering.usedPorts1 + (n2 -> c1), state.numbering.usedPorts2) Right(state.copy(t = t1, numbering = num)) } case (None, None) => // Neither port has a number: assign a new one - val maxSize1 = pi1.getArraySize - val maxSize2 = pi2.getArraySize val (numbering, n) = state.numbering.getPortNumber - // Check to see if the port number is out of range for either of the port array sizes - if(n > maxSize1 - 1) - then Left(SemanticError.NoPortFoundByMatchedPortNumbering(pi1.getLoc)) - else if(n > maxSize2 - 1) - then Left(SemanticError.NoPortFoundByMatchedPortNumbering(pi2.getLoc)) - // Check to see if the port number is already in use - (state.numbering.usedPorts1.get(n), state.numbering.usedPorts2.get(n)) match { - case (Some(prevC), None) => Left(SemanticError.PortNumberAlreadyInUse(n, c2.getLoc, prevC.getLoc)) - case (None, Some(prevC)) => Left(SemanticError.PortNumberAlreadyInUse(n, c1.getLoc, prevC.getLoc)) - case (Some(prevC1), Some(prevC2)) => Left(SemanticError.PortNumberAlreadyInUse(n, c2.getLoc, prevC1.getLoc)) - case (None, None) => - val t1 = t.assignPortNumber(pi1, c1, n).assignPortNumber(pi2, c2, n) - // Update the set of used ports so that the new port number is tracked - val num = state.numbering.setUsedPorts(state.numbering.usedPorts1 + (n -> c1), state.numbering.usedPorts2 + (n -> c2)) - Right(state.copy(t = t1, numbering = num)) + // Throw an error if the port number is out of range + if(n >= pi1.getArraySize) + then Left(SemanticError.NoPortFoundByMatchedPortNumbering(c1.getLoc, c2.getLoc)) + else { + val t1 = t.assignPortNumber(pi1, c1, n).assignPortNumber(pi2, c2, n) + // Update the set of used ports so that the new port number is tracked + val num = state.numbering.setUsedPorts(state.numbering.usedPorts1 + (n -> c1), state.numbering.usedPorts2 + (n -> c2)) + Right(state.copy(t = t1, numbering = num)) } } } @@ -129,9 +120,9 @@ object MatchedPortNumbering { t: Topology, pi1: PortInstance, map1: ConnectionMap, + usedPorts1: Map[Int, Connection], pi2: PortInstance, map2: ConnectionMap, - usedPorts1: Map[Int, Connection], usedPorts2: Map[Int, Connection] ): State = { State( @@ -140,7 +131,11 @@ object MatchedPortNumbering { map1, pi2, map2, - PortNumberingState.initial(usedPorts1, usedPorts2) + PortNumberingState.initial( + usedPorts1=usedPorts1, + usedPorts2=usedPorts2, + usedPortNumbers=Set(usedPorts1.keys.toList:_*) ++ Set(usedPorts2.keys.toList:_*) + ) ) } @@ -242,7 +237,7 @@ object MatchedPortNumbering { usedPorts2 <- computeUsedPortNumbers(pi2) _ <- checkForMissingConnections(loc, map1, map2) state <- { - val state = State.initial(t, pi1, map1, pi2, map2, usedPorts1, usedPorts2) + val state = State.initial(t, pi1, map1, usedPorts1, pi2, map2, usedPorts2) State.assignNumbers(loc, state) } } diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala index 6fbb27159..c9145c936 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala @@ -5,14 +5,14 @@ import fpp.compiler.util._ /** Port numbering state */ case class PortNumberingState private ( - /** First set of used ports */ - usedPorts1: Map[Int, Connection], - /** Second set of used ports */ - usedPorts2: Map[Int, Connection], /** The used port numbers */ usedPortNumbers: Set[Int], /** The next port number */ - nextPortNumber: Int + nextPortNumber: Int, + /** First map of used ports for port instance 1 */ + usedPorts1: Map[Int, Connection] = Map(), + /** Second map of used ports for port instance 2 */ + usedPorts2: Map[Int, Connection] = Map() ) { /** Marks the next port number as used and generates @@ -23,7 +23,7 @@ case class PortNumberingState private ( nextPortNumber, s ) - PortNumberingState(usedPorts1, usedPorts2, s, n) + PortNumberingState(s, n, usedPorts1, usedPorts2) } /** Gets the next port number and updates the state */ @@ -40,7 +40,7 @@ case class PortNumberingState private ( nextPortNumber, updatedUsedPortNumbers ) - PortNumberingState(u1, u2, updatedUsedPortNumbers, updatedNextPortNumber) + PortNumberingState(usedPortNumbers, nextPortNumber, usedPorts1, usedPorts2) } } @@ -48,10 +48,9 @@ case class PortNumberingState private ( object PortNumberingState { /** Construct an initial state */ - def initial(usedPorts1: Map[Int, Connection], usedPorts2: Map[Int, Connection]): PortNumberingState = { - val usedPortNumbers = Set(usedPorts1.keys.toList:_*) ++ Set(usedPorts2.keys.toList:_*) + def initial(usedPortNumbers: Set[Int], usedPorts1: Map[Int, Connection] = Map(), usedPorts2: Map[Int, Connection] = Map()): PortNumberingState = { val nextPortNumber = getNextNumber(0, usedPortNumbers) - PortNumberingState(usedPorts1, usedPorts2, usedPortNumbers, nextPortNumber) + PortNumberingState(usedPortNumbers, nextPortNumber, usedPorts1, usedPorts2) } /** Gets the next available port number */ diff --git a/compiler/lib/src/main/scala/util/Error.scala b/compiler/lib/src/main/scala/util/Error.scala index a0916a831..9199bacd3 100644 --- a/compiler/lib/src/main/scala/util/Error.scala +++ b/compiler/lib/src/main/scala/util/Error.scala @@ -202,8 +202,11 @@ sealed trait Error { Error.print (Some(loc)) ("unmatched connection must go from or to a matched port") case SemanticError.MissingPort(loc, specMsg, portMsg) => Error.print (Some(loc)) (s"component with $specMsg must have $portMsg") - case SemanticError.NoPortFoundByMatchedPortNumbering(loc) => - Error.print (Some(loc)) (s"matched port numbering could not find an available port number on both sides of the matching") + case SemanticError.NoPortFoundByMatchedPortNumbering(loc1, loc2) => + Error.print (None) (s"matched port numbering could not find an available port number on both sides of the matching") + System.err.println("connections are defined here") + System.err.println(loc1) + System.err.println(loc2) case SemanticError.OverlappingIdRanges( maxId1, name1, loc1, baseId2, name2, loc2 ) => @@ -506,7 +509,8 @@ object SemanticError { ) extends Error /** Matched port numbering could not find a valid port number */ final case class NoPortFoundByMatchedPortNumbering( - loc: Location + loc1: Location, + loc2: Location ) extends Error /** Overlapping ID ranges */ final case class OverlappingIdRanges( diff --git a/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_3.fpp b/compiler/tools/fpp-check/test/port_numbering/matched_port_numbering_no_valid_port.fpp similarity index 55% rename from compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_3.fpp rename to compiler/tools/fpp-check/test/port_numbering/matched_port_numbering_no_valid_port.fpp index 8b5b59dad..fcb88737d 100644 --- a/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_3.fpp +++ b/compiler/tools/fpp-check/test/port_numbering/matched_port_numbering_no_valid_port.fpp @@ -10,6 +10,14 @@ module M { match pOut with pIn } + passive component C2 { + + output port pOut: [4] P + sync input port pIn: [4] P + + match pOut with pIn + } + instance c1: C1 base id 0x100 instance c2: C1 base id 0x200 instance c3: C1 base id 0x300 @@ -21,10 +29,13 @@ module M { instance c3 connections P { + unmatched c1.pOut -> c2.pIn[0] + unmatched c1.pOut -> c2.pIn[1] + unmatched c1.pOut -> c2.pIn[2] + unmatched c2.pOut -> c2.pIn[3] - c1.pOut -> c2.pIn[0] + c1.pOut -> c2.pIn c2.pOut -> c1.pIn - unmatched c2.pOut[0] -> c3.pIn } } diff --git a/compiler/tools/fpp-check/test/port_numbering/matched_port_numbering_no_valid_port.ref.txt b/compiler/tools/fpp-check/test/port_numbering/matched_port_numbering_no_valid_port.ref.txt new file mode 100644 index 000000000..03b571afb --- /dev/null +++ b/compiler/tools/fpp-check/test/port_numbering/matched_port_numbering_no_valid_port.ref.txt @@ -0,0 +1,9 @@ +fpp-check +error: matched port numbering could not find an available port number on both sides of the matching +connections are defined here +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/matched_port_numbering_no_valid_port.fpp:38.7 + c2.pOut -> c1.pIn + ^ +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/matched_port_numbering_no_valid_port.fpp:37.7 + c1.pOut -> c2.pIn + ^ diff --git a/compiler/tools/fpp-check/test/port_numbering/tests.sh b/compiler/tools/fpp-check/test/port_numbering/tests.sh index 686afaba8..6837232cb 100644 --- a/compiler/tools/fpp-check/test/port_numbering/tests.sh +++ b/compiler/tools/fpp-check/test/port_numbering/tests.sh @@ -2,11 +2,11 @@ tests=" duplicate_input_connection_at_matched_port duplicate_matched_connection duplicate_output_connection +matched_port_numbering_no_valid_port mismatched_port_numbers ok negative_port_number too_many_output_ports -unmatched_connection_port_number_in_use_1 -unmatched_connection_port_number_in_use_2 -unmatched_connection_port_number_in_use_3 +unmatched_connection_port_number_in_use_by_input_port +unmatched_connection_port_number_in_use_by_output_port " diff --git a/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_3.ref.txt b/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_3.ref.txt deleted file mode 100644 index 16ab19543..000000000 --- a/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_3.ref.txt +++ /dev/null @@ -1,9 +0,0 @@ -fpp-check -[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_3.fpp:26.7 - c2.pOut -> c1.pIn - ^ -error: port number 0 is already in use -previous usage is here: -[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_3.fpp:27.17 - unmatched c2.pOut[0] -> c3.pIn - ^ diff --git a/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_2.fpp b/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_input_port.fpp similarity index 73% rename from compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_2.fpp rename to compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_input_port.fpp index e574a69a7..d18c259a2 100644 --- a/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_2.fpp +++ b/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_input_port.fpp @@ -10,8 +10,16 @@ module M { match pOut with pIn } + passive component C2 { + + output port pOut: [4] P + sync input port pIn: [4] P + + } + + instance c1: C1 base id 0x100 - instance c2: C1 base id 0x200 + instance c2: C2 base id 0x200 topology T { diff --git a/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_2.ref.txt b/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_input_port.ref.txt similarity index 68% rename from compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_2.ref.txt rename to compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_input_port.ref.txt index 19b8edafd..fee33f84f 100644 --- a/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_2.ref.txt +++ b/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_input_port.ref.txt @@ -1,9 +1,9 @@ fpp-check -[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_2.fpp:24.7 +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_input_port.fpp:32.7 c2.pOut -> c1.pIn ^ error: port number 0 is already in use previous usage is here: -[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_2.fpp:25.17 +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_input_port.fpp:33.17 unmatched c2.pOut -> c1.pIn[0] ^ diff --git a/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_1.fpp b/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_output_port.fpp similarity index 69% rename from compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_1.fpp rename to compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_output_port.fpp index ef959a99a..211bbdd2c 100644 --- a/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_1.fpp +++ b/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_output_port.fpp @@ -10,9 +10,17 @@ module M { match pOut with pIn } + passive component C2 { + + output port pOut: [4] P + sync input port pIn: [4] P + + } + + instance c1: C1 base id 0x100 - instance c2: C1 base id 0x200 - instance c3: C1 base id 0x300 + instance c2: C2 base id 0x200 + instance c3: C2 base id 0x300 topology T { diff --git a/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_1.ref.txt b/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_output_port.ref.txt similarity index 68% rename from compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_1.ref.txt rename to compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_output_port.ref.txt index c7b3e4423..c1949f88e 100644 --- a/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_1.ref.txt +++ b/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_output_port.ref.txt @@ -1,9 +1,9 @@ fpp-check -[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_1.fpp:24.7 +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_output_port.fpp:32.7 c1.pOut -> c2.pIn ^ error: port number 0 is already in use previous usage is here: -[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_1.fpp:26.17 +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_output_port.fpp:34.17 unmatched c1.pOut[0] -> c3.pIn ^ diff --git a/docs/fpp-spec.html b/docs/fpp-spec.html index 360aa0fc6..c05cd74e6 100644 --- a/docs/fpp-spec.html +++ b/docs/fpp-spec.html @@ -527,9 +527,10 @@

    The F Prime Prime (FPP) Language Specification, v2.2.0

  • 5.10. State Machine Definitions
  • 5.11. Struct Definitions @@ -2799,7 +2800,9 @@

    5.10. State Machine Definitions

    Implementation note: -As of FPP v2.2.0, only external state machine definitions are implemented.

    +Support for state machines will be implemented in two phases. +Phase 1 will implement external state machine definitions only. +Phase 2 will add support for internal state machine definitions.

    5.10.1. Syntax

    @@ -2836,14 +2839,9 @@

    5.10.1. Syntax

  • -
    -

    The transitive members of a state machine definition M are -(1) the elements of M and (2) -the members of any state definition that is a transitive member of M.

    -
    -

    5.10.2. Static Semantics

    +

    5.10.2. Semantics

    1. @@ -2869,21 +2867,17 @@

      5.10.2. Static S

    2. M must satisfy the rules described -below +below for the induced transition graph.

    3. -
    4. -

      M must satisfy the rules described -below -for typed elements.

      -
    -
    -
    The Transition Graph
    +
    +
    +

    5.10.3. The Transition Graph

    If present, the optional state machine member sequence M induces a directed graph called the transition graph, defined as @@ -2892,30 +2886,24 @@

    1. -

      The nodes of the transition graph are the state definitions and +

      The nodes of the transition graph are the initial transition specifiers, +state definitions, and junction definitions that are transitive members of M.

    2. -

      The initial node of the transition graph is the state definition -or junction definition referred to in the unique initial transition specifier -that is an element of M.

      +

      The transitive members of M are (i) the elements of M and (ii) +the members of any state definition that is a transitive member of M.

    3. -

      The arcs of the transition graph are given by the -transition expressions e that appear in (1) initial transition specifiers -that are members of states that are transitive members of M and (2) -state transition specifiers that are transitive members of M and (3) -junction definitions that are transitive members of M. -Each transition expression represents an arc from a start node to an -end node. -The start node is defined as follows:

      +

      The arcs of the transition graph are given by the enter expressions e that are parts of transitive members of M. +Each enter expression represents an arc from an initial node to a terminal node. +The initial node is defined as follows:

      1. If e appears in an -initial transition specifier I, then the initial node is the -state definition -immediately enclosing I.

        +initial transition specifier I, then the initial node +is I.

      2. If e appears in a @@ -2932,9 +2920,10 @@

        -

        The terminal node is the state or junction definition -referred to -in e.

        +

        In any case, +the terminal node is the state definition or junction definition +referred to +in e after the keyword enter.

    @@ -2946,96 +2935,20 @@
    1. -

      Each state definition and each junction definition in -T must be reachable from the initial node of T.

      +

      Each state machine definition and each junction definition in +T must be the terminal node of at least one arc.

    2. Let S be the subgraph of T consisting of all -and only the junction definitions and the arcs whose start -and end nodes are junction definitions. +and only the junction definitions and the arcs whose initial +and terminal nodes are junction definitions. There must be no cycles in S.

    -
    -
    Typed Elements
    -
    -

    A typed element e is an -initial transition specifier, -a -state entry specifier, -a -state transition specifier, -a -state exit specifier, -or a -junction definition. -A typed element e points to a junction J if

    -
    -
    -
      -
    1. -

      e is an initial transition specifier, and its transition expression -refers to J; or

      -
    2. -
    3. -

      e is a state transition specifier with a transition expression that refers to -J; or

      -
    4. -
    5. -

      e is a junction, and at least one of its transition expressions -refers to J.

      -
    6. -
    -
    -
    -

    It must be possible to assign type options -to all the typed elements in a state machine definition in -the following way. -If not, an error results.

    -
    -
    -
      -
    1. -

      The type option of each initial transition specifier, state entry -specifier, and state exit specifier is None.

      -
    2. -
    3. -

      The type option of each state transition specifier S is the type -option specified in the definition of the signal specified in S -after the keyword on.

      -
    4. -
    5. -

      The type option of a junction J is the -common type option of the type options of the typed elements -that point to J.

      -
    6. -
    -
    -
    -

    For each typed element e

    -
    -
    -
      -
    1. -

      Let O be the type option assigned to e as described above.

      -
    2. -
    3. -

      For every action A appearing in the list of do actions specified in e, -O must be convertible to -the type option specified in A.

      -
    4. -
    5. -

      For every guard G appearing in an if construct in e, -O must be convertible to -the type option specified in G.

      -
    6. -
    -
    -
    -
    -
    Scoping of Names
    +
    +

    5.10.4. Scoping of Names

    Inside the optional state machine member sequence, the following rules govern the assignment of names to definitions and the resolution @@ -3109,67 +3022,31 @@

    -
    -
    -

    5.10.3. Dynamic Semantics

    -
    -

    An internal state machine M has the following runtime behavior:

    -
    -
    -
      -
    1. -

      M maintains a current state S. -The current state is undefined until initialization occurs. -From that point on, the current state is always a leaf state.

      -
    2. -
    3. -

      M provides a function for initializing the state machine. -It runs the -behavior associated with the initial transition specifier of M.

      -
    4. -
    5. -

      For each signal s, M provides a function for sending s. -This function has a typed argument with type T if and only if -the definition of signal s -has type T. -It runs the -behavior associated with s in the current state S. -This behavior may cause one or more actions to be performed, -and it may cause the current state to change.

      -
    6. -
    -
    -
    -

    The functions are called by the code that is generated when a -state machine is instantiated -as part of an active or queued component.

    -
    -
    -

    5.10.4. Examples

    +

    5.10.5. Examples

    state machine MonitorSm {
     
    -  action doCalibrate
    +  signal Complete
    +  signal Drive
    +  signal Calibrate
    +  signal RTI
    +  signal Stop
    +  signal Fault
    +
       action init2
    +  action doCalibrate
       action motorControl
       action reportFault
     
       guard calibrateReady
     
    -  signal Calibrate
    -  signal Complete
    -  signal Drive
    -  signal Fault
    -  signal RTI
    -  signal Stop
    -
       initial enter DeviceOn
     
       state DeviceOn {
     
    -    initial do { init2 } enter Initializing
    +    initial do init2 enter Initializing
     
         state Initializing {
           on Complete enter Idle
    @@ -3181,13 +3058,13 @@ 

    5.10.4. Examples

    } state Calibrating { - on RTI do { doCalibrate } - on Fault do { reportFault } enter Idle + on RTI do doCalibrate + on Fault do reportFault enter Idle on Complete enter Idle } state Driving { - on RTI do { motorControl } + on RTI do motorControl on Stop enter Idle } @@ -3497,20 +3374,8 @@
    unmatched then it is unmatched; otherwise it is matched.

  • -

    For each connection that appears from \$p_1\$ and \$p_2\$:

    -
    -
      -
    1. -

      Compute the set of port numbers that are already in use for the connections at \$p_1\$.

      -
    2. -
    3. -

      Compute the set of port numbers that are already in use for the connections at \$p_2\$.

      -
    4. -
    5. -

      Check that the port numbers computed in the previous steps do not have duplicates.

      -
    6. -
    -
    +

    For each of the connections at I . \$p_1\$ and I . \$p_2\$, +check that there are not multiple connections at the same port number.

  • For each matched connection \$c_1\$ with an endpoint at I . \$p_1\$:

    @@ -10559,7 +10424,7 @@

    22.4. Translation Tools

  • diff --git a/docs/fpp-users-guide.html b/docs/fpp-users-guide.html index 0ca6bd79e..dd3290658 100644 --- a/docs/fpp-users-guide.html +++ b/docs/fpp-users-guide.html @@ -12685,7 +12685,7 @@

    From 382152faac612584c9a93289d116044eff4ed700 Mon Sep 17 00:00:00 2001 From: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com> Date: Tue, 15 Oct 2024 13:20:16 -0700 Subject: [PATCH 23/73] Lock CI runs-on to ubuntu-22.04 --- .github/workflows/build-test.yml | 2 +- .github/workflows/native-build.yml | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 6543bf6c4..fa340f2ef 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -12,7 +12,7 @@ permissions: jobs: build: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/native-build.yml b/.github/workflows/native-build.yml index 849f4ab5f..bfed9670e 100644 --- a/.github/workflows/native-build.yml +++ b/.github/workflows/native-build.yml @@ -49,7 +49,7 @@ on: type: boolean jobs: build-jars: - runs-on: "ubuntu-latest" + runs-on: "ubuntu-22.04" name: "Build Standard JARs" steps: - name: "Checkout repository" @@ -90,7 +90,7 @@ jobs: outputs: native: ${{ steps.set-matrix.outputs.native }} tags: ${{ steps.set-matrix.outputs.tags }} - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - id: set-matrix shell: python @@ -105,7 +105,7 @@ jobs: "tag": "macosx_12_0_universal2" }, { - "runner": "ubuntu-latest", + "runner": "ubuntu-22.04", "tag": "manylinux2014_x86_64", "container": "quay.io/pypa/manylinux2014_x86_64" } @@ -174,7 +174,7 @@ jobs: ${{ inputs.test }} build-wheels: needs: [build-jars, build-native-images, generate-run-matricies] - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 strategy: matrix: ${{ fromJson(needs.generate-run-matricies.outputs.tags) }} steps: @@ -242,7 +242,7 @@ jobs: publish-wheels: if: ${{ github.event_name == 'release' }} needs: [test-wheels, generate-run-matricies] - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 strategy: matrix: ${{ fromJson(needs.generate-run-matricies.outputs.tags) }} steps: From ff003a9794659df18a757ba8b0bb197e1dad038a Mon Sep 17 00:00:00 2001 From: jawest Date: Wed, 16 Oct 2024 19:18:06 -0700 Subject: [PATCH 24/73] make sure we update the used ports after assigning them --- .../analysis/Semantics/ResolveTopology/PortNumberingState.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala index c9145c936..6770ecbda 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala @@ -40,7 +40,7 @@ case class PortNumberingState private ( nextPortNumber, updatedUsedPortNumbers ) - PortNumberingState(usedPortNumbers, nextPortNumber, usedPorts1, usedPorts2) + PortNumberingState(usedPortNumbers, updatedNextPortNumber, u1, u2) } } From 629c4fe28a6f537a2df0baa87dbd8b5f6441f581 Mon Sep 17 00:00:00 2001 From: jawest Date: Wed, 16 Oct 2024 19:19:57 -0700 Subject: [PATCH 25/73] updated used port num set after assigning a port number --- .../analysis/Semantics/ResolveTopology/PortNumberingState.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala index 6770ecbda..e31185603 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala @@ -40,7 +40,7 @@ case class PortNumberingState private ( nextPortNumber, updatedUsedPortNumbers ) - PortNumberingState(usedPortNumbers, updatedNextPortNumber, u1, u2) + PortNumberingState(updatedUsedPortNumbers, updatedNextPortNumber, u1, u2) } } From a50fc4875aadfa909354feff2415df23daedbfaa Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Mon, 28 Oct 2024 09:30:13 -0700 Subject: [PATCH 26/73] Regenerate docs --- docs/code-prettify/run_prettify.js | 5 +- docs/fpp-spec.html | 226 ++++++++++++++++++++++------- docs/fpp-users-guide.html | 7 +- docs/index.html | 7 +- 4 files changed, 182 insertions(+), 63 deletions(-) diff --git a/docs/code-prettify/run_prettify.js b/docs/code-prettify/run_prettify.js index 7e3509a71..54a0907fe 100644 --- a/docs/code-prettify/run_prettify.js +++ b/docs/code-prettify/run_prettify.js @@ -427,9 +427,11 @@ var IN_GLOBAL_SCOPE = false; "do," + "drop," + "else," + - "enter" + + "enter," + + "entry," + "enum," + "event," + + "exit," + "fatal," + "format," + "get," + @@ -477,6 +479,7 @@ var IN_GLOBAL_SCOPE = false; "serial," + "set," + "severity," + + "signal," + "size," + "stack," + "state," + diff --git a/docs/fpp-spec.html b/docs/fpp-spec.html index c05cd74e6..9639022c6 100644 --- a/docs/fpp-spec.html +++ b/docs/fpp-spec.html @@ -140,7 +140,7 @@ #content::before{content:none} #header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0} #header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #dddddf} -#header>h1:only-child{border-bottom:1px solid #dddddf;padding-bottom:8px} +#header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px} #header .details{border-bottom:1px solid #dddddf;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:flex;flex-flow:row wrap} #header .details span:first-child{margin-left:-.125em} #header .details span.email a{color:rgba(0,0,0,.85)} @@ -162,7 +162,6 @@ #toctitle{color:#7a2518;font-size:1.2em} @media screen and (min-width:768px){#toctitle{font-size:1.375em} body.toc2{padding-left:15em;padding-right:0} -body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px} #toc.toc2{margin-top:0!important;background:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #e7e7e9;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto} #toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em} #toc.toc2>ul{font-size:.9em;margin-bottom:0} @@ -328,7 +327,7 @@ a.image object{pointer-events:none} sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super} sup.footnote a,sup.footnoteref a{text-decoration:none} -sup.footnote a:active,sup.footnoteref a:active,#footnotes .footnote a:first-of-type:active{text-decoration:underline} +sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline} #footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em} #footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em;border-width:1px 0 0} #footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;margin-bottom:.2em} @@ -527,10 +526,9 @@

    The F Prime Prime (FPP) Language Specification, v2.2.0

  • 5.10. State Machine Definitions
  • 5.11. Struct Definitions @@ -2800,9 +2798,7 @@

    5.10. State Machine Definitions

    Implementation note: -Support for state machines will be implemented in two phases. -Phase 1 will implement external state machine definitions only. -Phase 2 will add support for internal state machine definitions.

    +As of FPP v2.2.0, only external state machine definitions are implemented.

    5.10.1. Syntax

    @@ -2839,9 +2835,14 @@

    5.10.1. Syntax

  • +
    +

    The transitive members of a state machine definition M are +(1) the elements of M and (2) +the members of any state definition that is a transitive member of M.

    +
    -

    5.10.2. Semantics

    +

    5.10.2. Static Semantics

    1. @@ -2867,17 +2868,21 @@

      5.10.2. Semantics

    2. M must satisfy the rules described -below +below for the induced transition graph.

    3. +
    4. +

      M must satisfy the rules described +below +for typed elements.

      +
    - -
    -

    5.10.3. The Transition Graph

    +
    +
    The Transition Graph

    If present, the optional state machine member sequence M induces a directed graph called the transition graph, defined as @@ -2886,24 +2891,30 @@

    5.10.3. The
    1. -

      The nodes of the transition graph are the initial transition specifiers, -state definitions, and +

      The nodes of the transition graph are the state definitions and junction definitions that are transitive members of M.

    2. -

      The transitive members of M are (i) the elements of M and (ii) -the members of any state definition that is a transitive member of M.

      +

      The initial node of the transition graph is the state definition +or junction definition referred to in the unique initial transition specifier +that is an element of M.

    3. -

      The arcs of the transition graph are given by the enter expressions e that are parts of transitive members of M. -Each enter expression represents an arc from an initial node to a terminal node. -The initial node is defined as follows:

      +

      The arcs of the transition graph are given by the +transition expressions e that appear in (1) initial transition specifiers +that are members of states that are transitive members of M and (2) +state transition specifiers that are transitive members of M and (3) +junction definitions that are transitive members of M. +Each transition expression represents an arc from a start node to an +end node. +The start node is defined as follows:

      1. If e appears in an -initial transition specifier I, then the initial node -is I.

        +initial transition specifier I, then the initial node is the +state definition +immediately enclosing I.

      2. If e appears in a @@ -2920,10 +2931,9 @@

        5.10.3. The

      -

      In any case, -the terminal node is the state definition or junction definition -referred to -in e after the keyword enter.

      +

      The terminal node is the state or junction definition +referred to +in e.

    @@ -2935,20 +2945,96 @@

    5.10.3. The
    1. -

      Each state machine definition and each junction definition in -T must be the terminal node of at least one arc.

      +

      Each state definition and each junction definition in +T must be reachable from the initial node of T.

    2. Let S be the subgraph of T consisting of all -and only the junction definitions and the arcs whose initial -and terminal nodes are junction definitions. +and only the junction definitions and the arcs whose start +and end nodes are junction definitions. There must be no cycles in S.

    -
    -

    5.10.4. Scoping of Names

    +
    +
    Typed Elements
    +
    +

    A typed element e is an +initial transition specifier, +a +state entry specifier, +a +state transition specifier, +a +state exit specifier, +or a +junction definition. +A typed element e points to a junction J if

    +
    +
    +
      +
    1. +

      e is an initial transition specifier, and its transition expression +refers to J; or

      +
    2. +
    3. +

      e is a state transition specifier with a transition expression that refers to +J; or

      +
    4. +
    5. +

      e is a junction, and at least one of its transition expressions +refers to J.

      +
    6. +
    +
    +
    +

    It must be possible to assign type options +to all the typed elements in a state machine definition in +the following way. +If not, an error results.

    +
    +
    +
      +
    1. +

      The type option of each initial transition specifier, state entry +specifier, and state exit specifier is None.

      +
    2. +
    3. +

      The type option of each state transition specifier S is the type +option specified in the definition of the signal specified in S +after the keyword on.

      +
    4. +
    5. +

      The type option of a junction J is the +common type option of the type options of the typed elements +that point to J.

      +
    6. +
    +
    +
    +

    For each typed element e

    +
    +
    +
      +
    1. +

      Let O be the type option assigned to e as described above.

      +
    2. +
    3. +

      For every action A appearing in the list of do actions specified in e, +O must be convertible to +the type option specified in A.

      +
    4. +
    5. +

      For every guard G appearing in an if construct in e, +O must be convertible to +the type option specified in G.

      +
    6. +
    +
    +
    +
    +
    Scoping of Names

    Inside the optional state machine member sequence, the following rules govern the assignment of names to definitions and the resolution @@ -3022,31 +3108,67 @@

    5.10.4. Scoping

    +
    -

    5.10.5. Examples

    +

    5.10.3. Dynamic Semantics

    +
    +

    An internal state machine M has the following runtime behavior:

    +
    +
    +
      +
    1. +

      M maintains a current state S. +The current state is undefined until initialization occurs. +From that point on, the current state is always a leaf state.

      +
    2. +
    3. +

      M provides a function for initializing the state machine. +It runs the +behavior associated with the initial transition specifier of M.

      +
    4. +
    5. +

      For each signal s, M provides a function for sending s. +This function has a typed argument with type T if and only if +the definition of signal s +has type T. +It runs the +behavior associated with s in the current state S. +This behavior may cause one or more actions to be performed, +and it may cause the current state to change.

      +
    6. +
    +
    +
    +

    The functions are called by the code that is generated when a +state machine is instantiated +as part of an active or queued component.

    +
    +
    +
    +

    5.10.4. Examples

    state machine MonitorSm {
     
    -  signal Complete
    -  signal Drive
    -  signal Calibrate
    -  signal RTI
    -  signal Stop
    -  signal Fault
    -
    -  action init2
       action doCalibrate
    +  action init2
       action motorControl
       action reportFault
     
       guard calibrateReady
     
    +  signal Calibrate
    +  signal Complete
    +  signal Drive
    +  signal Fault
    +  signal RTI
    +  signal Stop
    +
       initial enter DeviceOn
     
       state DeviceOn {
     
    -    initial do init2 enter Initializing
    +    initial do { init2 } enter Initializing
     
         state Initializing {
           on Complete enter Idle
    @@ -3058,13 +3180,13 @@ 

    5.10.5. Examples

    } state Calibrating { - on RTI do doCalibrate - on Fault do reportFault enter Idle + on RTI do { doCalibrate } + on Fault do { reportFault } enter Idle on Complete enter Idle } state Driving { - on RTI do motorControl + on RTI do { motorControl } on Stop enter Idle } @@ -3374,10 +3496,6 @@
    unmatched then it is unmatched; otherwise it is matched.

  • -

    For each of the connections at I . \$p_1\$ and I . \$p_2\$, -check that there are not multiple connections at the same port number.

    -
  • -
  • For each matched connection \$c_1\$ with an endpoint at I . \$p_1\$:

      @@ -3399,8 +3517,8 @@

      For each pair P with \$(c_1,c_2)\$ computed in step b, if P has both numbers assigned, check that the port numbers match. -For each P that has exactly one port number assigned, check that the -port number is not in use and assign it to match.

      +For each P that has exactly one port number assigned, +assign the other one to match.

    1. Traverse the pairs \$(c_1,c_2)\$ computed in step b according to the @@ -10424,7 +10542,7 @@

      22.4. Translation Tools

    diff --git a/docs/fpp-users-guide.html b/docs/fpp-users-guide.html index dd3290658..cb1684ace 100644 --- a/docs/fpp-users-guide.html +++ b/docs/fpp-users-guide.html @@ -140,7 +140,7 @@ #content::before{content:none} #header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0} #header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #dddddf} -#header>h1:only-child{border-bottom:1px solid #dddddf;padding-bottom:8px} +#header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px} #header .details{border-bottom:1px solid #dddddf;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:flex;flex-flow:row wrap} #header .details span:first-child{margin-left:-.125em} #header .details span.email a{color:rgba(0,0,0,.85)} @@ -162,7 +162,6 @@ #toctitle{color:#7a2518;font-size:1.2em} @media screen and (min-width:768px){#toctitle{font-size:1.375em} body.toc2{padding-left:15em;padding-right:0} -body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px} #toc.toc2{margin-top:0!important;background:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #e7e7e9;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto} #toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em} #toc.toc2>ul{font-size:.9em;margin-bottom:0} @@ -328,7 +327,7 @@ a.image object{pointer-events:none} sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super} sup.footnote a,sup.footnoteref a{text-decoration:none} -sup.footnote a:active,sup.footnoteref a:active,#footnotes .footnote a:first-of-type:active{text-decoration:underline} +sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline} #footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em} #footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em;border-width:1px 0 0} #footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;margin-bottom:.2em} @@ -12685,7 +12684,7 @@

  • diff --git a/docs/index.html b/docs/index.html index 2b4d9282a..2a38442c0 100644 --- a/docs/index.html +++ b/docs/index.html @@ -140,7 +140,7 @@ #content::before{content:none} #header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0} #header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #dddddf} -#header>h1:only-child{border-bottom:1px solid #dddddf;padding-bottom:8px} +#header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px} #header .details{border-bottom:1px solid #dddddf;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:flex;flex-flow:row wrap} #header .details span:first-child{margin-left:-.125em} #header .details span.email a{color:rgba(0,0,0,.85)} @@ -162,7 +162,6 @@ #toctitle{color:#7a2518;font-size:1.2em} @media screen and (min-width:768px){#toctitle{font-size:1.375em} body.toc2{padding-left:15em;padding-right:0} -body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px} #toc.toc2{margin-top:0!important;background:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #e7e7e9;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto} #toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em} #toc.toc2>ul{font-size:.9em;margin-bottom:0} @@ -328,7 +327,7 @@ a.image object{pointer-events:none} sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super} sup.footnote a,sup.footnoteref a{text-decoration:none} -sup.footnote a:active,sup.footnoteref a:active,#footnotes .footnote a:first-of-type:active{text-decoration:underline} +sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline} #footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em} #footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em;border-width:1px 0 0} #footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;margin-bottom:.2em} @@ -464,7 +463,7 @@

    F Prime Prime (FPP)

    From 4cb8cc368aa16672df80fdeeec136fdc889f687a Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Mon, 28 Oct 2024 09:38:41 -0700 Subject: [PATCH 27/73] Revise spec --- docs/fpp-spec.html | 12 ++++++------ .../spec/Specifiers/Connection-Graph-Specifiers.adoc | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/fpp-spec.html b/docs/fpp-spec.html index 9639022c6..1126e2427 100644 --- a/docs/fpp-spec.html +++ b/docs/fpp-spec.html @@ -5228,8 +5228,7 @@

    7.3.2. Semantics

  • The connection sequence specifies the set of connections in the graph. -For each -match constrained connection C:

    +For each connection C:

    1. @@ -5237,9 +5236,10 @@

      7.3.2. Semantics

      1. -

        The optional keyword unmatched, if present, specifies that -the connection is explicitly unmatched. unmatched must only be used on -matched connections.

        +

        The optional keyword unmatched may be present only if I is +match constrained. +In this case, if the keyword unmatched is present, then I is +unmatched.

      2. The component instance named in I @@ -10542,7 +10542,7 @@

        22.4. Translation Tools

      diff --git a/docs/spec/Specifiers/Connection-Graph-Specifiers.adoc b/docs/spec/Specifiers/Connection-Graph-Specifiers.adoc index 9593fffeb..0e3c100da 100644 --- a/docs/spec/Specifiers/Connection-Graph-Specifiers.adoc +++ b/docs/spec/Specifiers/Connection-Graph-Specifiers.adoc @@ -80,15 +80,15 @@ A direct graph specifier directly specifies a named connection graph. the connection graph. . The connection sequence specifies the set of connections in the graph. -For each -<> connection _C_: +For each connection _C_: .. For each of the two port instance identifiers _I_ appearing in _C_: -... The optional keyword `unmatched`, if present, specifies that -the connection is explicitly unmatched. `unmatched` must only be used on -matched connections. +... The optional keyword `unmatched` may be present only if _I_ is +<>. +In this case, if the keyword `unmatched` is present, then _I_ is +unmatched. ... The component instance named in _I_ must be available in the enclosing topology, From 41f64a69d4fbc2383a1ac56c983acc139efb17c1 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Mon, 28 Oct 2024 13:45:42 -0700 Subject: [PATCH 28/73] Revise spec --- docs/fpp-spec.html | 85 +++++++++++++------ .../Definitions/Topology-Definitions.adoc | 64 ++++++++------ .../Connection-Graph-Specifiers.adoc | 8 +- 3 files changed, 104 insertions(+), 53 deletions(-) diff --git a/docs/fpp-spec.html b/docs/fpp-spec.html index 1126e2427..c5e4c04de 100644 --- a/docs/fpp-spec.html +++ b/docs/fpp-spec.html @@ -3491,6 +3491,10 @@
      1. +

        For each of i = 1 and i = 2, check that no two distinct connections +at I . \$p_i\$ have the same port number assigned to them.

        +
      2. +
      3. Any connection that names I . \$p_1\$ or I . \$p_2\$ is match constrained. If a match constrained connection is marked unmatched then it is unmatched; otherwise it is matched.

        @@ -3504,8 +3508,8 @@
      4. -

        Check that there is one -and only one connection \$c_2\$ from I' to I . \$p_2\$.

        +

        Check that there is one and only one matched connection +\$c_2\$ between I' and I . \$p_2\$.

    @@ -3515,21 +3519,59 @@
    I . \$p_2\$.

  • -

    For each pair P with \$(c_1,c_2)\$ computed in step b, if P -has both numbers assigned, check that the port numbers match. -For each P that has exactly one port number assigned, -assign the other one to match.

    +

    For each pair \$(c_1,c_2)\$ computed in step c:

    +
    +
      +
    1. +

      If \$c_1\$ has a port number \$n_1\$ assigned at I . \$p_1\$ and +\$c_2\$ has a port number \$n_2\$ assigned at +I . \$p_2\$, then check that \$n_1 = n_2\$.

      +
    2. +
    3. +

      Otherwise if \$c_1\$ has a port number n assigned at I . \$p_1\$,

      +
      +
        +
      1. +

        If no connection at I . \$p_2\$ has port number n assigned to it, +then assign n to \$c_2\$ at I . \$p_2\$.

        +
      2. +
      3. +

        Otherwise an error occurs.

        +
      4. +
      +
      +
    4. +
    5. +

      Otherwise if \$c_2\$ has a port number n assigned at I . \$p_2\$,

      +
      +
        +
      1. +

        If no connection at I . \$p_1\$ has port number n assigned to it, +then assign n to \$c_1\$ at I . \$p_1\$.

        +
      2. +
      3. +

        Otherwise an error occurs.

        +
      4. +
      +
      +
    6. +
    +
  • -

    Traverse the pairs \$(c_1,c_2)\$ computed in step b according to the +

    Traverse the pairs \$(c_1,c_2)\$ computed in step c according to the order of the connections \$c_1\$, least to greatest. For each pair \$(c_1,c_2)\$ that does not yet have assigned port numbers, find the lowest available port number and assign it at I . \$p_1\$ and I . \$p_2\$. -A port number is available if (a) it is in bounds for the -port instance being numbered; and (b) -it is not already assigned to the same port instance -in the topology.

    +A port number n is available if (a) n is in bounds for I . \$p_1\$ +and I . \$p_2\$; and (b) +n is not already assigned to a connection at I . \$p_1\$; and (c) +n is not already assigned to a connection at I . \$p_2\$. +If no port number is available, then an error occurs. +Note that \$p_1\$ and \$p_2\$ +are required to have the +same size for their port arrays.

  • @@ -3537,13 +3579,6 @@

    -

    Note that in the last step, -the two ports I . \$p_1\$ and I . \$p_2\$. -have the same array size and -the same port numbers assigned so far, so the lowest -available port number is the same for both.

    -
    -

    Apply general numbering: Fill in any remaining port numbers.

    @@ -5232,16 +5267,16 @@

    7.3.2. Semantics

    1. -

      For each of the two port instance identifiers I appearing in C:

      -
      -
        -
      1. -

        The optional keyword unmatched may be present only if I is +

        The optional keyword unmatched is allowed only if C is match constrained. -In this case, if the keyword unmatched is present, then I is +In this case, if the keyword unmatched is present, then C is unmatched.

      2. +

        For each of the two port instance identifiers I appearing in C:

        +
        +
          +
        1. The component instance named in I must be available in the enclosing topology, either through @@ -10542,7 +10577,7 @@

          22.4. Translation Tools

        diff --git a/docs/spec/Definitions/Topology-Definitions.adoc b/docs/spec/Definitions/Topology-Definitions.adoc index 54d5de163..a89a6e1e7 100644 --- a/docs/spec/Definitions/Topology-Definitions.adoc +++ b/docs/spec/Definitions/Topology-Definitions.adoc @@ -141,42 +141,58 @@ For each instance _I_ in the topology: <> `match` stem:[p_1] `with` stem:[p_2] appearing in the definition of _C_: -.. Any connection that names _I_ `.` stem:[p_1] or _I_ `.` stem:[p_2] -is *match constrained*. If a match constrained connection is marked +.. For each of _i_ = 1 and _i_ = 2, check that no two distinct connections +at _I_ `.` stem:[p_i] have the same port number assigned to them. + +.. Any connection that names _I_ `.` stem:[p_1] or _I_ `.` stem:[p_2] +is *match constrained*. If a match constrained connection is marked `unmatched` then it is *unmatched*; otherwise it is *matched*. - + .. For each matched connection stem:[c_1] with an endpoint at _I_ `.` stem:[p_1]: ... Let _I'_ be the component instance at the other endpoint of stem:[c_1]. - -... Check that there is one -and only one connection stem:[c_2] from _I'_ to _I_ `.` stem:[p_2]. -.. Check that the connections stem:[c_2] computed in the previous +... Check that there is one and only one matched connection +stem:[c_2] between _I'_ and _I_ `.` stem:[p_2]. + +.. Check that the connections stem:[c_2] computed in the previous step are all the matched connections at _I_ `.` stem:[p_2]. - -.. For each pair _P_ with stem:[(c_1,c_2)] computed in step b, if _P_ -has both numbers assigned, check that the port numbers match. -For each _P_ that has exactly one port number assigned, -assign the other one to match. - -.. Traverse the pairs stem:[(c_1,c_2)] computed in step b according to the + +.. For each pair stem:[(c_1,c_2)] computed in step c: + +... If stem:[c_1] has a port number stem:[n_1] assigned at _I_ `.` stem:[p_1] and +stem:[c_2] has a port number stem:[n_2] assigned at +_I_ `.` stem:[p_2], then check that stem:[n_1 = n_2]. + +... Otherwise if stem:[c_1] has a port number _n_ assigned at _I_ `.` stem:[p_1], + +.... If no connection at _I_ `.` stem:[p_2] has port number _n_ assigned to it, +then assign _n_ to stem:[c_2] at _I_ `.` stem:[p_2]. + +.... Otherwise an error occurs. + +... Otherwise if stem:[c_2] has a port number _n_ assigned at _I_ `.` stem:[p_2], + +.... If no connection at _I_ `.` stem:[p_1] has port number _n_ assigned to it, +then assign _n_ to stem:[c_1] at _I_ `.` stem:[p_1]. + +.... Otherwise an error occurs. + +.. Traverse the pairs stem:[(c_1,c_2)] computed in step c according to the <> of the connections stem:[c_1], least to greatest. For each pair stem:[(c_1,c_2)] that does not yet have assigned port numbers, find the lowest available port number and assign it at _I_ `.` stem:[p_1] and _I_ `.` stem:[p_2]. -A port number is available if (a) it is in bounds for the -port instance being numbered; and (b) -it is not already assigned to the same port instance -in the topology. - -Note that in the last step, -the two ports _I_ `.` stem:[p_1] and _I_ `.` stem:[p_2]. -have the same array size and -the same port numbers assigned so far, so the lowest -available port number is the same for both. +A port number _n_ is available if (a) _n_ is in bounds for _I_ `.` stem:[p_1] +and _I_ `.` stem:[p_2]; and (b) +_n_ is not already assigned to a connection at _I_ `.` stem:[p_1]; and (c) +_n_ is not already assigned to a connection at _I_ `.` stem:[p_2]. +If no port number is available, then an error occurs. +Note that stem:[p_1] and stem:[p_2] +<>. *Apply general numbering:* Fill in any remaining port numbers. diff --git a/docs/spec/Specifiers/Connection-Graph-Specifiers.adoc b/docs/spec/Specifiers/Connection-Graph-Specifiers.adoc index 0e3c100da..42473fd0d 100644 --- a/docs/spec/Specifiers/Connection-Graph-Specifiers.adoc +++ b/docs/spec/Specifiers/Connection-Graph-Specifiers.adoc @@ -82,14 +82,14 @@ the connection graph. . The connection sequence specifies the set of connections in the graph. For each connection _C_: -.. For each of the two port instance identifiers _I_ appearing in _C_: - -... The optional keyword `unmatched` may be present only if _I_ is +.. The optional keyword `unmatched` is allowed only if _C_ is <>. -In this case, if the keyword `unmatched` is present, then _I_ is +In this case, if the keyword `unmatched` is present, then _C_ is unmatched. +.. For each of the two port instance identifiers _I_ appearing in _C_: + ... The component instance named in _I_ must be available in the enclosing topology, either through From 2d6b24fd54e82441b068a2765e303e07f7fce42e Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Mon, 28 Oct 2024 14:13:46 -0700 Subject: [PATCH 29/73] Remove unused token --- compiler/lib/src/main/scala/syntax/Token.scala | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/lib/src/main/scala/syntax/Token.scala b/compiler/lib/src/main/scala/syntax/Token.scala index f5595e2b2..83059c846 100644 --- a/compiler/lib/src/main/scala/syntax/Token.scala +++ b/compiler/lib/src/main/scala/syntax/Token.scala @@ -118,7 +118,6 @@ object Token { final case class U64() extends Token final case class U8() extends Token final case class UNMATCHED() extends Token - final case class UNUSED() extends Token final case class UPDATE() extends Token final case class WARNING() extends Token final case class WITH() extends Token From 2098bf75488a96e055be982aa0dc9551b8f75d0b Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Mon, 28 Oct 2024 14:34:37 -0700 Subject: [PATCH 30/73] Restore blank lines --- .../lib/src/main/scala/analysis/Semantics/Connection.scala | 2 ++ compiler/lib/src/main/scala/syntax/Parser.scala | 4 +--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/Connection.scala b/compiler/lib/src/main/scala/analysis/Semantics/Connection.scala index a68214f34..1fc891cbb 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/Connection.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/Connection.scala @@ -202,6 +202,7 @@ object Connection { else Left(SemanticError.InvalidPortNumber(loc, n, name, size, specLoc)) case None => Right(()) } + } object Endpoint { @@ -221,6 +222,7 @@ object Connection { case None => Right(()) } } yield endpoint + } } diff --git a/compiler/lib/src/main/scala/syntax/Parser.scala b/compiler/lib/src/main/scala/syntax/Parser.scala index 00ccc78e3..8ae204736 100644 --- a/compiler/lib/src/main/scala/syntax/Parser.scala +++ b/compiler/lib/src/main/scala/syntax/Parser.scala @@ -398,9 +398,7 @@ object Parser extends Parsers { def specConnectionGraph: Parser[Ast.SpecConnectionGraph] = { def directGraph = { (connections ~> ident) ~! (lbrace ~>! elementSequence(connection, comma) <~! rbrace) ^^ { - case ident ~ connections => { - Ast.SpecConnectionGraph.Direct(ident, connections) - } + case ident ~ connections => Ast.SpecConnectionGraph.Direct(ident, connections) } } def patternGraph = { From 2795b70ce87a56385318836a51fd7d0a13568ea7 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Mon, 28 Oct 2024 14:52:52 -0700 Subject: [PATCH 31/73] Code formatting --- .../Semantics/ResolveTopology/PortNumberingState.scala | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala index e31185603..5b88af744 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala @@ -48,7 +48,11 @@ case class PortNumberingState private ( object PortNumberingState { /** Construct an initial state */ - def initial(usedPortNumbers: Set[Int], usedPorts1: Map[Int, Connection] = Map(), usedPorts2: Map[Int, Connection] = Map()): PortNumberingState = { + def initial( + usedPortNumbers: Set[Int], + usedPorts1: Map[Int, Connection] = Map(), + usedPorts2: Map[Int, Connection] = Map() + ): PortNumberingState = { val nextPortNumber = getNextNumber(0, usedPortNumbers) PortNumberingState(usedPortNumbers, nextPortNumber, usedPorts1, usedPorts2) } From 2d585e45ed2b564b057f458a0296df21fbdd3330 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 29 Oct 2024 08:40:59 -0700 Subject: [PATCH 32/73] Refactor ResolveTopology --- .../Semantics/ResolveTopology/GeneralPortNumbering.scala | 4 ++-- .../Semantics/ResolveTopology/MatchedPortNumbering.scala | 7 ++++++- compiler/lib/src/main/scala/util/Error.scala | 8 ++++---- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/GeneralPortNumbering.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/GeneralPortNumbering.scala index 9398af426..8ea038e6d 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/GeneralPortNumbering.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/GeneralPortNumbering.scala @@ -26,9 +26,9 @@ object GeneralPortNumbering { pii: PortInstanceIdentifier ): Topology = { val pi = pii.portInstance - val cs = t.getConnectionsFrom(pii).toList.sorted + val cs = t.getConnectionsFrom(pii).toArray.sorted val usedPortNumbers = t.getUsedPortNumbers(pi, cs) - val state = PortNumberingState.initial(usedPortNumbers=usedPortNumbers) + val state = PortNumberingState.initial(usedPortNumbers) val (_, t1) = cs.foldLeft ((state, t)) ({ case ((s,t), c) => t.getPortNumber(pi, c) match { case Some(n) => (s, t) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala index f449b49f2..2dbf418ba 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala @@ -218,7 +218,12 @@ object MatchedPortNumbering { val loc = c.getLoc val prevLoc = prevC.getLoc Left( - SemanticError.DuplicateConnectionAtMatchedPort(loc, pi.toString, prevLoc, n) + SemanticError.DuplicateConnectionAtMatchedPort( + loc, + pi.toString, + n, + prevLoc + ) ) case None => Right(m + (n -> c)) } diff --git a/compiler/lib/src/main/scala/util/Error.scala b/compiler/lib/src/main/scala/util/Error.scala index 9199bacd3..b25a4517e 100644 --- a/compiler/lib/src/main/scala/util/Error.scala +++ b/compiler/lib/src/main/scala/util/Error.scala @@ -45,8 +45,8 @@ sealed trait Error { Error.print (Some(loc)) (s"cannot resolve path $name") case SemanticError.DivisionByZero(loc) => Error.print (Some(loc)) ("division by zero") - case SemanticError.DuplicateConnectionAtMatchedPort(loc, port, prevLoc, n) => - Error.print (Some(loc)) (s"duplicate connection at matched port $port[$n]") + case SemanticError.DuplicateConnectionAtMatchedPort(loc, port, portNum, prevLoc) => + Error.print (Some(loc)) (s"duplicate connection at matched port $port[$portNum]") printPrevLoc(prevLoc) case SemanticError.DuplicateDictionaryName(kind, name, loc, prevLoc) => Error.print (Some(loc)) (s"duplicate ${kind} name ${name}") @@ -283,8 +283,8 @@ object SemanticError { final case class DuplicateConnectionAtMatchedPort( loc: Location, port: String, - prevLoc: Location, - n: Int + portNum: Int, + prevLoc: Location ) extends Error /** Duplicate name in dictionary */ final case class DuplicateDictionaryName( From c2637a0b73de03169df6700f2b65c777c50f3a39 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 29 Oct 2024 08:52:54 -0700 Subject: [PATCH 33/73] Code cleanup --- .../ResolveTopology/MatchedPortNumbering.scala | 10 +++++----- .../Semantics/ResolveTopology/PortNumberingState.scala | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala index 2dbf418ba..591710493 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala @@ -97,7 +97,7 @@ object MatchedPortNumbering { } } - // For each pair of connections (c1, c2), check that numbers + // For each pair of connections (c1, c2), check that numbers // match and/or assign numbers def assignNumbers( matchingLoc: Location, @@ -132,9 +132,9 @@ object MatchedPortNumbering { pi2, map2, PortNumberingState.initial( - usedPorts1=usedPorts1, - usedPorts2=usedPorts2, - usedPortNumbers=Set(usedPorts1.keys.toList:_*) ++ Set(usedPorts2.keys.toList:_*) + usedPorts1.keys.toSet ++ usedPorts2.keys.toSet, + usedPorts1, + usedPorts2 ) ) } @@ -214,7 +214,7 @@ object MatchedPortNumbering { t.getPortNumber(pi, c) match { case Some(n) => m.get(n) match { - case Some(prevC) => + case Some(prevC) => val loc = c.getLoc val prevLoc = prevC.getLoc Left( diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala index 5b88af744..2e2263259 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala @@ -32,10 +32,10 @@ case class PortNumberingState private ( (s, nextPortNumber) } - // Takes in the updated sets, updated the usedPortNumbers set - // (ie: union of usedPorts1 and usedPorts2) and figure out the new next port number + // Takes in the updated sets, updated the usedPortNumbers set + // (ie: union of usedPorts1 and usedPorts2) and figure out the new next port number def setUsedPorts(u1: Map[Int, Connection], u2: Map[Int, Connection]): PortNumberingState = { - val updatedUsedPortNumbers = Set(u1.keys.toList:_*) ++ Set(u2.keys.toList:_*) + val updatedUsedPortNumbers = u1.keys.toSet ++ u2.keys.toSet val updatedNextPortNumber = PortNumberingState.getNextNumber( nextPortNumber, updatedUsedPortNumbers @@ -59,7 +59,7 @@ object PortNumberingState { /** Gets the next available port number */ def getNextNumber(from: Int, used: Set[Int]): Int = { - def helper(n: Int): Int = + def helper(n: Int): Int = if (!used.contains(n)) n else helper(n + 1) From 860149d50dcb4249d7380bdc2bc6472ae01dbc7f Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 29 Oct 2024 09:21:43 -0700 Subject: [PATCH 34/73] Revise error reporting --- .../MatchedPortNumbering.scala | 21 ++++++++++--------- compiler/lib/src/main/scala/util/Error.scala | 6 ++++-- ...e_input_connection_at_matched_port.ref.txt | 4 ++++ 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala index 591710493..73521fa4a 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala @@ -44,8 +44,7 @@ object MatchedPortNumbering { (n1Opt, n2Opt) match { case (Some(n1), Some(n2)) => // Both ports have a number: check that they match - if (n1 == n2) - Right(state) + if (n1 == n2) Right(state) else { // Error: numbers don't match val p1Loc = c1.getThisEndpoint(pi1).loc @@ -62,13 +61,14 @@ object MatchedPortNumbering { } case (Some(n1), None) => // Only pi1 has a number: assign it to pi2 - // Check to see if the port number is already in use - state.numbering.usedPorts2.get(n1) match { - case Some(prevC) => Left(SemanticError.PortNumberAlreadyInUse(n1, c2.getLoc, prevC.getLoc)) + // Check to see if the port number is already assigned + u2.get(n1) match { + case Some(prevC) => + Left(SemanticError.PortNumberAlreadyInUse(n1, c2.getLoc, prevC.getLoc)) case None => val t1 = t.assignPortNumber(pi2, c2, n1) // Update the set of used ports so that the new port number is tracked - val num = state.numbering.setUsedPorts(state.numbering.usedPorts1, state.numbering.usedPorts2 + (n1 -> c2)) + val num = state.numbering.setUsedPorts(u1, u2 + (n1 -> c2)) Right(state.copy(t = t1, numbering = num)) } case (None, Some(n2)) => @@ -181,7 +181,7 @@ object MatchedPortNumbering { portMatching: Component.PortMatching ) = { // Map remote components to connections at pi - def constructMap(loc: Location, pi: PortInstance) = { + def constructMap(pi: PortInstance) = { val empty: ConnectionMap = Map() val pii = PortInstanceIdentifier(ci, pi) val cs = t.getConnectionsAt(pii).toList.sorted @@ -222,7 +222,8 @@ object MatchedPortNumbering { loc, pi.toString, n, - prevLoc + prevLoc, + portMatching.getLoc ) ) case None => Right(m + (n -> c)) @@ -236,8 +237,8 @@ object MatchedPortNumbering { val pi2 = portMatching.instance2 val loc = portMatching.getLoc for { - map1 <- constructMap(loc, pi1) - map2 <- constructMap(loc, pi2) + map1 <- constructMap(pi1) + map2 <- constructMap(pi2) usedPorts1 <- computeUsedPortNumbers(pi1) usedPorts2 <- computeUsedPortNumbers(pi2) _ <- checkForMissingConnections(loc, map1, map2) diff --git a/compiler/lib/src/main/scala/util/Error.scala b/compiler/lib/src/main/scala/util/Error.scala index b25a4517e..31797cab9 100644 --- a/compiler/lib/src/main/scala/util/Error.scala +++ b/compiler/lib/src/main/scala/util/Error.scala @@ -45,9 +45,10 @@ sealed trait Error { Error.print (Some(loc)) (s"cannot resolve path $name") case SemanticError.DivisionByZero(loc) => Error.print (Some(loc)) ("division by zero") - case SemanticError.DuplicateConnectionAtMatchedPort(loc, port, portNum, prevLoc) => + case SemanticError.DuplicateConnectionAtMatchedPort(loc, port, portNum, prevLoc, matchingLoc) => Error.print (Some(loc)) (s"duplicate connection at matched port $port[$portNum]") printPrevLoc(prevLoc) + printMatchingLoc(matchingLoc) case SemanticError.DuplicateDictionaryName(kind, name, loc, prevLoc) => Error.print (Some(loc)) (s"duplicate ${kind} name ${name}") printPrevLoc(prevLoc) @@ -284,7 +285,8 @@ object SemanticError { loc: Location, port: String, portNum: Int, - prevLoc: Location + prevLoc: Location, + matchingLoc: Location ) extends Error /** Duplicate name in dictionary */ final case class DuplicateDictionaryName( diff --git a/compiler/tools/fpp-check/test/port_numbering/duplicate_input_connection_at_matched_port.ref.txt b/compiler/tools/fpp-check/test/port_numbering/duplicate_input_connection_at_matched_port.ref.txt index 7ef5d9e70..3cfa45a49 100644 --- a/compiler/tools/fpp-check/test/port_numbering/duplicate_input_connection_at_matched_port.ref.txt +++ b/compiler/tools/fpp-check/test/port_numbering/duplicate_input_connection_at_matched_port.ref.txt @@ -7,3 +7,7 @@ previous occurrence is here: [ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/duplicate_input_connection_at_matched_port.fpp:25.9 c2.pOut -> c1.pIn[0] ^ +port matching is specified here: +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/duplicate_input_connection_at_matched_port.fpp:10.5 + match pOut with pIn + ^ From 78fa66b33ddd60629eb568936516997a12bcc661 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 29 Oct 2024 09:38:25 -0700 Subject: [PATCH 35/73] Fix error in User's Guide --- docs/fpp-users-guide.html | 4 ++-- docs/users-guide/Analyzing-and-Translating-Models.adoc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/fpp-users-guide.html b/docs/fpp-users-guide.html index cb1684ace..0a3fbcd62 100644 --- a/docs/fpp-users-guide.html +++ b/docs/fpp-users-guide.html @@ -12075,7 +12075,7 @@

        14.9. Generatin With this option, fpp-to-json generates the AST and the location map only; it doesn’t generate the Analysis data structure. Because semantic analysis is not run, you don’t have to present -a complete or syntactically correct FPP model to the tool.

        +a complete or semantically correct FPP model to the tool.

      @@ -12684,7 +12684,7 @@

    diff --git a/docs/users-guide/Analyzing-and-Translating-Models.adoc b/docs/users-guide/Analyzing-and-Translating-Models.adoc index f03644854..eade29d1b 100644 --- a/docs/users-guide/Analyzing-and-Translating-Models.adoc +++ b/docs/users-guide/Analyzing-and-Translating-Models.adoc @@ -1465,5 +1465,5 @@ when running `fpp-to-xml`: With this option, `fpp-to-json` generates the AST and the location map only; it doesn't generate the Analysis data structure. Because semantic analysis is not run, you don't have to present -a complete or syntactically correct FPP model to the tool. +a complete or semantically correct FPP model to the tool. From 2d20d24b13c914a99af697ecd092d495c81d6ae6 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 29 Oct 2024 09:51:37 -0700 Subject: [PATCH 36/73] Refactor MatchedPortNumbering --- .../MatchedPortNumbering.scala | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala index 73521fa4a..67fcba75c 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala @@ -64,35 +64,45 @@ object MatchedPortNumbering { // Check to see if the port number is already assigned u2.get(n1) match { case Some(prevC) => - Left(SemanticError.PortNumberAlreadyInUse(n1, c2.getLoc, prevC.getLoc)) + Left( + SemanticError.PortNumberAlreadyInUse(n1, c2.getLoc, prevC.getLoc) +// SemanticError.DuplicateConnectionAtMatchedPort( +// c2.getLoc, +// pi2.toString, +// n1, +// prevC.getLoc, +// matchingLoc +// ) + ) case None => val t1 = t.assignPortNumber(pi2, c2, n1) // Update the set of used ports so that the new port number is tracked - val num = state.numbering.setUsedPorts(u1, u2 + (n1 -> c2)) - Right(state.copy(t = t1, numbering = num)) + val numbering = state.numbering.setUsedPorts(u1, u2 + (n1 -> c2)) + Right(state.copy(t = t1, numbering = numbering)) } case (None, Some(n2)) => // Only pi2 has a number: assign it to pi1 // Check to see if the port number is already in use state.numbering.usedPorts1.get(n2) match { - case Some(prevC) => Left(SemanticError.PortNumberAlreadyInUse(n2, c1.getLoc, prevC.getLoc)) + case Some(prevC) => + Left(SemanticError.PortNumberAlreadyInUse(n2, c1.getLoc, prevC.getLoc)) case None => val t1 = t.assignPortNumber(pi1, c1, n2) // Update the set of used ports so that the new port number is tracked - val num = state.numbering.setUsedPorts(state.numbering.usedPorts1 + (n2 -> c1), state.numbering.usedPorts2) - Right(state.copy(t = t1, numbering = num)) + val numbering = state.numbering.setUsedPorts(u1 + (n2 -> c1), u2) + Right(state.copy(t = t1, numbering = numbering)) } case (None, None) => // Neither port has a number: assign a new one val (numbering, n) = state.numbering.getPortNumber - // Throw an error if the port number is out of range + // Return an error if the port number is out of range if(n >= pi1.getArraySize) then Left(SemanticError.NoPortFoundByMatchedPortNumbering(c1.getLoc, c2.getLoc)) else { val t1 = t.assignPortNumber(pi1, c1, n).assignPortNumber(pi2, c2, n) // Update the set of used ports so that the new port number is tracked - val num = state.numbering.setUsedPorts(state.numbering.usedPorts1 + (n -> c1), state.numbering.usedPorts2 + (n -> c2)) - Right(state.copy(t = t1, numbering = num)) + val numbering = state.numbering.setUsedPorts(u1 + (n -> c1), u2 + (n -> c2)) + Right(state.copy(t = t1, numbering = numbering)) } } } From 253e783d96c7910ef9a6d6b94a0da37f2700cdd1 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 29 Oct 2024 11:14:48 -0700 Subject: [PATCH 37/73] Revise error reporting --- .../MatchedPortNumbering.scala | 31 ++++++++++++------ compiler/lib/src/main/scala/util/Error.scala | 32 +++++++++++++++---- ...n_port_number_in_use_by_input_port.ref.txt | 12 +++++-- ..._port_number_in_use_by_output_port.ref.txt | 12 +++++-- 4 files changed, 66 insertions(+), 21 deletions(-) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala index 67fcba75c..755d556af 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala @@ -65,14 +65,14 @@ object MatchedPortNumbering { u2.get(n1) match { case Some(prevC) => Left( - SemanticError.PortNumberAlreadyInUse(n1, c2.getLoc, prevC.getLoc) -// SemanticError.DuplicateConnectionAtMatchedPort( -// c2.getLoc, -// pi2.toString, -// n1, -// prevC.getLoc, -// matchingLoc -// ) + SemanticError.ImplicitDuplicateConnectionAtMatchedPort( + c2.getLoc, + pi2.toString, + n1, + c1.getLoc, + matchingLoc, + prevC.getLoc, + ) ) case None => val t1 = t.assignPortNumber(pi2, c2, n1) @@ -85,7 +85,17 @@ object MatchedPortNumbering { // Check to see if the port number is already in use state.numbering.usedPorts1.get(n2) match { case Some(prevC) => - Left(SemanticError.PortNumberAlreadyInUse(n2, c1.getLoc, prevC.getLoc)) + Left( + SemanticError.ImplicitDuplicateConnectionAtMatchedPort( + c1.getLoc, + pi1.toString, + n2, + c2.getLoc, + matchingLoc, + prevC.getLoc + ) + //SemanticError.PortNumberAlreadyInUse(n2, c1.getLoc, prevC.getLoc) + ) case None => val t1 = t.assignPortNumber(pi1, c1, n2) // Update the set of used ports so that the new port number is tracked @@ -97,7 +107,8 @@ object MatchedPortNumbering { val (numbering, n) = state.numbering.getPortNumber // Return an error if the port number is out of range if(n >= pi1.getArraySize) - then Left(SemanticError.NoPortFoundByMatchedPortNumbering(c1.getLoc, c2.getLoc)) + then Left( + SemanticError.NoPortFoundByMatchedPortNumbering(c1.getLoc, c2.getLoc)) else { val t1 = t.assignPortNumber(pi1, c1, n).assignPortNumber(pi2, c2, n) // Update the set of used ports so that the new port number is tracked diff --git a/compiler/lib/src/main/scala/util/Error.scala b/compiler/lib/src/main/scala/util/Error.scala index 31797cab9..833b578c0 100644 --- a/compiler/lib/src/main/scala/util/Error.scala +++ b/compiler/lib/src/main/scala/util/Error.scala @@ -105,6 +105,21 @@ sealed trait Error { printPrevLoc(prevLoc) case SemanticError.EmptyArray(loc) => Error.print (Some(loc)) ("array expression may not be empty") + case SemanticError.ImplicitDuplicateConnectionAtMatchedPort( + loc, + port, + portNum, + implyingLoc, + matchingLoc, + prevLoc + ) => + Error.print (Some(loc)) (s"implicit duplicate connection at matched port $port[$portNum]") + System.err.println("connection is implied here:") + System.err.println(implyingLoc) + System.err.println("because of matching specified here:") + System.err.println(matchingLoc) + System.err.println("conflicting connection is here:") + System.err.println(prevLoc) case SemanticError.InconsistentSpecLoc(loc, path, prevLoc, prevPath) => Error.print (Some(loc)) (s"inconsistent location path ${path}") System.err.println(prevLoc) @@ -222,10 +237,6 @@ sealed trait Error { Error.print (Some(loc)) ("passive component may not have async input") case SemanticError.PassiveStateMachine(loc) => Error.print (Some(loc)) ("passive component may not have a state machine instance") - case SemanticError.PortNumberAlreadyInUse(n, loc, prevLoc) => - Error.print (Some(loc)) (s"port number $n is already in use") - System.err.println("previous usage is here:") - System.err.println(prevLoc) case SemanticError.RedefinedSymbol(name, loc, prevLoc) => Error.print (Some(loc)) (s"redefinition of symbol ${name}") System.err.println("previous definition is here:") @@ -280,7 +291,7 @@ object SemanticError { final case class EmptyArray(loc: Location) extends Error /** Division by zero */ final case class DivisionByZero(loc: Location) extends Error - /** Duplicate connections at matched port */ + /** Duplicate connection at matched port */ final case class DuplicateConnectionAtMatchedPort( loc: Location, port: String, @@ -378,6 +389,15 @@ object SemanticError { loc: Location, prevLoc: Location ) extends Error + /** Implicit duplicate connection at matched port */ + final case class ImplicitDuplicateConnectionAtMatchedPort( + loc: Location, + port: String, + portNum: Int, + implyingLoc: Location, + matchingLoc: Location, + prevLoc: Location + ) extends Error /** Inconsistent location specifiers */ final case class InconsistentSpecLoc( loc: Location, @@ -526,8 +546,6 @@ object SemanticError { /** Passive async input */ final case class PassiveAsync(loc: Location) extends Error final case class PassiveStateMachine(loc: Location) extends Error - /** Port number has already been assigned */ - final case class PortNumberAlreadyInUse(n: Int, loc: Location, prevLoc: Location) extends Error /** Redefined symbol */ final case class RedefinedSymbol( name: String, diff --git a/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_input_port.ref.txt b/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_input_port.ref.txt index fee33f84f..ef669fa84 100644 --- a/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_input_port.ref.txt +++ b/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_input_port.ref.txt @@ -2,8 +2,16 @@ fpp-check [ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_input_port.fpp:32.7 c2.pOut -> c1.pIn ^ -error: port number 0 is already in use -previous usage is here: +error: implicit duplicate connection at matched port pIn[0] +connection is implied here: +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_input_port.fpp:31.7 + c1.pOut[0] -> c2.pIn + ^ +because of matching specified here: +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_input_port.fpp:10.5 + match pOut with pIn + ^ +conflicting connection is here: [ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_input_port.fpp:33.17 unmatched c2.pOut -> c1.pIn[0] ^ diff --git a/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_output_port.ref.txt b/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_output_port.ref.txt index c1949f88e..360b7f224 100644 --- a/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_output_port.ref.txt +++ b/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_output_port.ref.txt @@ -2,8 +2,16 @@ fpp-check [ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_output_port.fpp:32.7 c1.pOut -> c2.pIn ^ -error: port number 0 is already in use -previous usage is here: +error: implicit duplicate connection at matched port pOut[0] +connection is implied here: +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_output_port.fpp:33.7 + c2.pOut -> c1.pIn[0] + ^ +because of matching specified here: +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_output_port.fpp:10.5 + match pOut with pIn + ^ +conflicting connection is here: [ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_output_port.fpp:34.17 unmatched c1.pOut[0] -> c3.pIn ^ From c020fab6bc657aba95b144d753f77b232e4fbc9e Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 29 Oct 2024 13:09:13 -0700 Subject: [PATCH 38/73] Revise error reporting and tests --- .../MatchedPortNumbering.scala | 10 ++++++--- compiler/lib/src/main/scala/util/Error.scala | 22 +++++++++++-------- .../lib/src/main/scala/util/Version.scala | 2 +- ... duplicate_connection_at_matched_port.fpp} | 0 ...licate_connection_at_matched_port.ref.txt} | 6 ++--- ...tched_port_numbering_no_valid_port.ref.txt | 9 ++++++-- .../fpp-check/test/port_numbering/tests.sh | 2 +- 7 files changed, 32 insertions(+), 19 deletions(-) rename compiler/tools/fpp-check/test/port_numbering/{duplicate_input_connection_at_matched_port.fpp => duplicate_connection_at_matched_port.fpp} (100%) rename compiler/tools/fpp-check/test/port_numbering/{duplicate_input_connection_at_matched_port.ref.txt => duplicate_connection_at_matched_port.ref.txt} (71%) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala index 755d556af..ae7fedc57 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala @@ -94,7 +94,6 @@ object MatchedPortNumbering { matchingLoc, prevC.getLoc ) - //SemanticError.PortNumberAlreadyInUse(n2, c1.getLoc, prevC.getLoc) ) case None => val t1 = t.assignPortNumber(pi1, c1, n2) @@ -107,8 +106,13 @@ object MatchedPortNumbering { val (numbering, n) = state.numbering.getPortNumber // Return an error if the port number is out of range if(n >= pi1.getArraySize) - then Left( - SemanticError.NoPortFoundByMatchedPortNumbering(c1.getLoc, c2.getLoc)) + Left( + SemanticError.NoPortAvailableForMatchedNumbering( + c1.getLoc, + c2.getLoc, + matchingLoc + ) + ) else { val t1 = t.assignPortNumber(pi1, c1, n).assignPortNumber(pi2, c2, n) // Update the set of used ports so that the new port number is tracked diff --git a/compiler/lib/src/main/scala/util/Error.scala b/compiler/lib/src/main/scala/util/Error.scala index 833b578c0..fb415ab69 100644 --- a/compiler/lib/src/main/scala/util/Error.scala +++ b/compiler/lib/src/main/scala/util/Error.scala @@ -39,9 +39,9 @@ sealed trait Error { case CodeGenError.EmptyStruct(loc) => Error.print (Some(loc)) (s"cannot write XML for an empty struct") case IncludeError.Cycle(loc, msg) => Error.print (Some(loc)) (msg) - case FileError.CannotOpen(locOpt, name) => + case FileError.CannotOpen(locOpt, name) => Error.print (locOpt) (s"cannot open file $name") - case FileError.CannotResolvePath(loc, name) => + case FileError.CannotResolvePath(loc, name) => Error.print (Some(loc)) (s"cannot resolve path $name") case SemanticError.DivisionByZero(loc) => Error.print (Some(loc)) ("division by zero") @@ -71,7 +71,7 @@ sealed trait Error { loc, prevLoc, matchingLoc - ) => + ) => Error.print (Some(loc)) ("duplicate connection between a matched port array and a single instance") printPrevLoc(prevLoc) printMatchingLoc(matchingLoc) @@ -103,7 +103,7 @@ sealed trait Error { case SemanticError.DuplicateTopology(name, loc, prevLoc) => Error.print (Some(loc)) (s"duplicate topology ${name}") printPrevLoc(prevLoc) - case SemanticError.EmptyArray(loc) => + case SemanticError.EmptyArray(loc) => Error.print (Some(loc)) ("array expression may not be empty") case SemanticError.ImplicitDuplicateConnectionAtMatchedPort( loc, @@ -218,11 +218,14 @@ sealed trait Error { Error.print (Some(loc)) ("unmatched connection must go from or to a matched port") case SemanticError.MissingPort(loc, specMsg, portMsg) => Error.print (Some(loc)) (s"component with $specMsg must have $portMsg") - case SemanticError.NoPortFoundByMatchedPortNumbering(loc1, loc2) => - Error.print (None) (s"matched port numbering could not find an available port number on both sides of the matching") - System.err.println("connections are defined here") + case SemanticError.NoPortAvailableForMatchedNumbering(loc1, loc2, matchingLoc) => + Error.print (None) (s"no port available for matched numbering") + System.err.println("matched connections are specified here:") System.err.println(loc1) System.err.println(loc2) + printMatchingLoc(matchingLoc) + System.err.println("note: to be available, a port number must be in bounds and " ++ + "unassigned at both of the matched ports") case SemanticError.OverlappingIdRanges( maxId1, name1, loc1, baseId2, name2, loc2 ) => @@ -530,9 +533,10 @@ object SemanticError { loc: Location ) extends Error /** Matched port numbering could not find a valid port number */ - final case class NoPortFoundByMatchedPortNumbering( + final case class NoPortAvailableForMatchedNumbering( loc1: Location, - loc2: Location + loc2: Location, + matchingLoc: Location ) extends Error /** Overlapping ID ranges */ final case class OverlappingIdRanges( diff --git a/compiler/lib/src/main/scala/util/Version.scala b/compiler/lib/src/main/scala/util/Version.scala index 5e1209628..68af01bbf 100644 --- a/compiler/lib/src/main/scala/util/Version.scala +++ b/compiler/lib/src/main/scala/util/Version.scala @@ -3,6 +3,6 @@ package fpp.compiler.util /** The compiler version */ object Version { - val v = "[unknown version]" + val v = "v2.2.0-52-g253e783d9" } diff --git a/compiler/tools/fpp-check/test/port_numbering/duplicate_input_connection_at_matched_port.fpp b/compiler/tools/fpp-check/test/port_numbering/duplicate_connection_at_matched_port.fpp similarity index 100% rename from compiler/tools/fpp-check/test/port_numbering/duplicate_input_connection_at_matched_port.fpp rename to compiler/tools/fpp-check/test/port_numbering/duplicate_connection_at_matched_port.fpp diff --git a/compiler/tools/fpp-check/test/port_numbering/duplicate_input_connection_at_matched_port.ref.txt b/compiler/tools/fpp-check/test/port_numbering/duplicate_connection_at_matched_port.ref.txt similarity index 71% rename from compiler/tools/fpp-check/test/port_numbering/duplicate_input_connection_at_matched_port.ref.txt rename to compiler/tools/fpp-check/test/port_numbering/duplicate_connection_at_matched_port.ref.txt index 3cfa45a49..511919b54 100644 --- a/compiler/tools/fpp-check/test/port_numbering/duplicate_input_connection_at_matched_port.ref.txt +++ b/compiler/tools/fpp-check/test/port_numbering/duplicate_connection_at_matched_port.ref.txt @@ -1,13 +1,13 @@ fpp-check -[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/duplicate_input_connection_at_matched_port.fpp:26.9 +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/duplicate_connection_at_matched_port.fpp:26.9 c3.pOut -> c1.pIn[0] ^ error: duplicate connection at matched port pIn[0] previous occurrence is here: -[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/duplicate_input_connection_at_matched_port.fpp:25.9 +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/duplicate_connection_at_matched_port.fpp:25.9 c2.pOut -> c1.pIn[0] ^ port matching is specified here: -[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/duplicate_input_connection_at_matched_port.fpp:10.5 +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/duplicate_connection_at_matched_port.fpp:10.5 match pOut with pIn ^ diff --git a/compiler/tools/fpp-check/test/port_numbering/matched_port_numbering_no_valid_port.ref.txt b/compiler/tools/fpp-check/test/port_numbering/matched_port_numbering_no_valid_port.ref.txt index 03b571afb..f69920543 100644 --- a/compiler/tools/fpp-check/test/port_numbering/matched_port_numbering_no_valid_port.ref.txt +++ b/compiler/tools/fpp-check/test/port_numbering/matched_port_numbering_no_valid_port.ref.txt @@ -1,9 +1,14 @@ fpp-check -error: matched port numbering could not find an available port number on both sides of the matching -connections are defined here +error: no port available for matched numbering +matched connections are specified here: [ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/matched_port_numbering_no_valid_port.fpp:38.7 c2.pOut -> c1.pIn ^ [ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/matched_port_numbering_no_valid_port.fpp:37.7 c1.pOut -> c2.pIn ^ +port matching is specified here: +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/matched_port_numbering_no_valid_port.fpp:10.5 + match pOut with pIn + ^ +note: to be available, a port number must be in bounds and unassigned at both of the matched ports diff --git a/compiler/tools/fpp-check/test/port_numbering/tests.sh b/compiler/tools/fpp-check/test/port_numbering/tests.sh index 6837232cb..adfe55afc 100644 --- a/compiler/tools/fpp-check/test/port_numbering/tests.sh +++ b/compiler/tools/fpp-check/test/port_numbering/tests.sh @@ -1,5 +1,5 @@ tests=" -duplicate_input_connection_at_matched_port +duplicate_connection_at_matched_port duplicate_matched_connection duplicate_output_connection matched_port_numbering_no_valid_port From a08274f275fd44c383cfb63127d4920826f646a0 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 29 Oct 2024 13:15:23 -0700 Subject: [PATCH 39/73] Revise tests --- ...plicit_duplicate_connection_at_matched_input_port.fpp} | 0 ...it_duplicate_connection_at_matched_input_port.ref.txt} | 8 ++++---- ...licit_duplicate_connection_at_matched_output_port.fpp} | 0 ...t_duplicate_connection_at_matched_output_port.ref.txt} | 8 ++++---- compiler/tools/fpp-check/test/port_numbering/tests.sh | 6 +++--- 5 files changed, 11 insertions(+), 11 deletions(-) rename compiler/tools/fpp-check/test/port_numbering/{unmatched_connection_port_number_in_use_by_input_port.fpp => implicit_duplicate_connection_at_matched_input_port.fpp} (100%) rename compiler/tools/fpp-check/test/port_numbering/{unmatched_connection_port_number_in_use_by_input_port.ref.txt => implicit_duplicate_connection_at_matched_input_port.ref.txt} (68%) rename compiler/tools/fpp-check/test/port_numbering/{unmatched_connection_port_number_in_use_by_output_port.fpp => implicit_duplicate_connection_at_matched_output_port.fpp} (100%) rename compiler/tools/fpp-check/test/port_numbering/{unmatched_connection_port_number_in_use_by_output_port.ref.txt => implicit_duplicate_connection_at_matched_output_port.ref.txt} (68%) diff --git a/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_input_port.fpp b/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_input_port.fpp similarity index 100% rename from compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_input_port.fpp rename to compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_input_port.fpp diff --git a/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_input_port.ref.txt b/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_input_port.ref.txt similarity index 68% rename from compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_input_port.ref.txt rename to compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_input_port.ref.txt index ef669fa84..6f34fa936 100644 --- a/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_input_port.ref.txt +++ b/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_input_port.ref.txt @@ -1,17 +1,17 @@ fpp-check -[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_input_port.fpp:32.7 +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_input_port.fpp:32.7 c2.pOut -> c1.pIn ^ error: implicit duplicate connection at matched port pIn[0] connection is implied here: -[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_input_port.fpp:31.7 +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_input_port.fpp:31.7 c1.pOut[0] -> c2.pIn ^ because of matching specified here: -[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_input_port.fpp:10.5 +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_input_port.fpp:10.5 match pOut with pIn ^ conflicting connection is here: -[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_input_port.fpp:33.17 +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_input_port.fpp:33.17 unmatched c2.pOut -> c1.pIn[0] ^ diff --git a/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_output_port.fpp b/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_output_port.fpp similarity index 100% rename from compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_output_port.fpp rename to compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_output_port.fpp diff --git a/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_output_port.ref.txt b/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_output_port.ref.txt similarity index 68% rename from compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_output_port.ref.txt rename to compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_output_port.ref.txt index 360b7f224..03c03841b 100644 --- a/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_output_port.ref.txt +++ b/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_output_port.ref.txt @@ -1,17 +1,17 @@ fpp-check -[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_output_port.fpp:32.7 +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_output_port.fpp:32.7 c1.pOut -> c2.pIn ^ error: implicit duplicate connection at matched port pOut[0] connection is implied here: -[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_output_port.fpp:33.7 +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_output_port.fpp:33.7 c2.pOut -> c1.pIn[0] ^ because of matching specified here: -[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_output_port.fpp:10.5 +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_output_port.fpp:10.5 match pOut with pIn ^ conflicting connection is here: -[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/unmatched_connection_port_number_in_use_by_output_port.fpp:34.17 +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_output_port.fpp:34.17 unmatched c1.pOut[0] -> c3.pIn ^ diff --git a/compiler/tools/fpp-check/test/port_numbering/tests.sh b/compiler/tools/fpp-check/test/port_numbering/tests.sh index adfe55afc..4d98a8803 100644 --- a/compiler/tools/fpp-check/test/port_numbering/tests.sh +++ b/compiler/tools/fpp-check/test/port_numbering/tests.sh @@ -2,11 +2,11 @@ tests=" duplicate_connection_at_matched_port duplicate_matched_connection duplicate_output_connection +implicit_duplicate_connection_at_matched_input_port +implicit_duplicate_connection_at_matched_output_port matched_port_numbering_no_valid_port mismatched_port_numbers -ok negative_port_number +ok too_many_output_ports -unmatched_connection_port_number_in_use_by_input_port -unmatched_connection_port_number_in_use_by_output_port " From 5dc7285bec6dac92365f2e814de3c3b785792796 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 29 Oct 2024 13:26:51 -0700 Subject: [PATCH 40/73] Revert change to Version.scala --- compiler/lib/src/main/scala/util/Version.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/lib/src/main/scala/util/Version.scala b/compiler/lib/src/main/scala/util/Version.scala index 68af01bbf..5e1209628 100644 --- a/compiler/lib/src/main/scala/util/Version.scala +++ b/compiler/lib/src/main/scala/util/Version.scala @@ -3,6 +3,6 @@ package fpp.compiler.util /** The compiler version */ object Version { - val v = "v2.2.0-52-g253e783d9" + val v = "[unknown version]" } From 9be0894cc299023be6666390f9b8390bb025fbbd Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 29 Oct 2024 13:38:58 -0700 Subject: [PATCH 41/73] Revise tests --- .../implicit_duplicate_connection_at_matched_input_port.fpp | 1 - ...licit_duplicate_connection_at_matched_input_port.ref.txt | 6 +++--- ...implicit_duplicate_connection_at_matched_output_port.fpp | 1 - ...icit_duplicate_connection_at_matched_output_port.ref.txt | 6 +++--- ...port.fpp => no_port_available_for_matched_numbering.fpp} | 0 ....txt => no_port_available_for_matched_numbering.ref.txt} | 6 +++--- compiler/tools/fpp-check/test/port_numbering/tests.sh | 2 +- 7 files changed, 10 insertions(+), 12 deletions(-) rename compiler/tools/fpp-check/test/port_numbering/{matched_port_numbering_no_valid_port.fpp => no_port_available_for_matched_numbering.fpp} (100%) rename compiler/tools/fpp-check/test/port_numbering/{matched_port_numbering_no_valid_port.ref.txt => no_port_available_for_matched_numbering.ref.txt} (76%) diff --git a/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_input_port.fpp b/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_input_port.fpp index d18c259a2..7adf9a7b4 100644 --- a/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_input_port.fpp +++ b/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_input_port.fpp @@ -17,7 +17,6 @@ module M { } - instance c1: C1 base id 0x100 instance c2: C2 base id 0x200 diff --git a/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_input_port.ref.txt b/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_input_port.ref.txt index 6f34fa936..00b605973 100644 --- a/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_input_port.ref.txt +++ b/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_input_port.ref.txt @@ -1,10 +1,10 @@ fpp-check -[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_input_port.fpp:32.7 +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_input_port.fpp:31.7 c2.pOut -> c1.pIn ^ error: implicit duplicate connection at matched port pIn[0] connection is implied here: -[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_input_port.fpp:31.7 +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_input_port.fpp:30.7 c1.pOut[0] -> c2.pIn ^ because of matching specified here: @@ -12,6 +12,6 @@ because of matching specified here: match pOut with pIn ^ conflicting connection is here: -[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_input_port.fpp:33.17 +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_input_port.fpp:32.17 unmatched c2.pOut -> c1.pIn[0] ^ diff --git a/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_output_port.fpp b/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_output_port.fpp index 211bbdd2c..5c8d87502 100644 --- a/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_output_port.fpp +++ b/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_output_port.fpp @@ -17,7 +17,6 @@ module M { } - instance c1: C1 base id 0x100 instance c2: C2 base id 0x200 instance c3: C2 base id 0x300 diff --git a/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_output_port.ref.txt b/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_output_port.ref.txt index 03c03841b..cbb976f61 100644 --- a/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_output_port.ref.txt +++ b/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_output_port.ref.txt @@ -1,10 +1,10 @@ fpp-check -[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_output_port.fpp:32.7 +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_output_port.fpp:31.7 c1.pOut -> c2.pIn ^ error: implicit duplicate connection at matched port pOut[0] connection is implied here: -[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_output_port.fpp:33.7 +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_output_port.fpp:32.7 c2.pOut -> c1.pIn[0] ^ because of matching specified here: @@ -12,6 +12,6 @@ because of matching specified here: match pOut with pIn ^ conflicting connection is here: -[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_output_port.fpp:34.17 +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_output_port.fpp:33.17 unmatched c1.pOut[0] -> c3.pIn ^ diff --git a/compiler/tools/fpp-check/test/port_numbering/matched_port_numbering_no_valid_port.fpp b/compiler/tools/fpp-check/test/port_numbering/no_port_available_for_matched_numbering.fpp similarity index 100% rename from compiler/tools/fpp-check/test/port_numbering/matched_port_numbering_no_valid_port.fpp rename to compiler/tools/fpp-check/test/port_numbering/no_port_available_for_matched_numbering.fpp diff --git a/compiler/tools/fpp-check/test/port_numbering/matched_port_numbering_no_valid_port.ref.txt b/compiler/tools/fpp-check/test/port_numbering/no_port_available_for_matched_numbering.ref.txt similarity index 76% rename from compiler/tools/fpp-check/test/port_numbering/matched_port_numbering_no_valid_port.ref.txt rename to compiler/tools/fpp-check/test/port_numbering/no_port_available_for_matched_numbering.ref.txt index f69920543..3131d3e10 100644 --- a/compiler/tools/fpp-check/test/port_numbering/matched_port_numbering_no_valid_port.ref.txt +++ b/compiler/tools/fpp-check/test/port_numbering/no_port_available_for_matched_numbering.ref.txt @@ -1,14 +1,14 @@ fpp-check error: no port available for matched numbering matched connections are specified here: -[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/matched_port_numbering_no_valid_port.fpp:38.7 +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/no_port_available_for_matched_numbering.fpp:38.7 c2.pOut -> c1.pIn ^ -[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/matched_port_numbering_no_valid_port.fpp:37.7 +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/no_port_available_for_matched_numbering.fpp:37.7 c1.pOut -> c2.pIn ^ port matching is specified here: -[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/matched_port_numbering_no_valid_port.fpp:10.5 +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/no_port_available_for_matched_numbering.fpp:10.5 match pOut with pIn ^ note: to be available, a port number must be in bounds and unassigned at both of the matched ports diff --git a/compiler/tools/fpp-check/test/port_numbering/tests.sh b/compiler/tools/fpp-check/test/port_numbering/tests.sh index 4d98a8803..a2dfce315 100644 --- a/compiler/tools/fpp-check/test/port_numbering/tests.sh +++ b/compiler/tools/fpp-check/test/port_numbering/tests.sh @@ -4,9 +4,9 @@ duplicate_matched_connection duplicate_output_connection implicit_duplicate_connection_at_matched_input_port implicit_duplicate_connection_at_matched_output_port -matched_port_numbering_no_valid_port mismatched_port_numbers negative_port_number +no_port_available_for_matched_numbering ok too_many_output_ports " From b4f7f1a41a4e39d62f630dcffe045d95b0a14bf1 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 29 Oct 2024 13:48:03 -0700 Subject: [PATCH 42/73] Revise tests --- .../duplicate_connection_at_matched_port.fpp | 10 +++++++--- .../duplicate_connection_at_matched_port.ref.txt | 12 ++++++------ ...it_duplicate_connection_at_matched_input_port.fpp | 3 +++ ...uplicate_connection_at_matched_input_port.ref.txt | 6 +++--- ...t_duplicate_connection_at_matched_output_port.fpp | 4 ++++ ...plicate_connection_at_matched_output_port.ref.txt | 6 +++--- .../no_port_available_for_matched_numbering.fpp | 5 +++++ .../no_port_available_for_matched_numbering.ref.txt | 4 ++-- 8 files changed, 33 insertions(+), 17 deletions(-) diff --git a/compiler/tools/fpp-check/test/port_numbering/duplicate_connection_at_matched_port.fpp b/compiler/tools/fpp-check/test/port_numbering/duplicate_connection_at_matched_port.fpp index 876c616dd..c40355646 100644 --- a/compiler/tools/fpp-check/test/port_numbering/duplicate_connection_at_matched_port.fpp +++ b/compiler/tools/fpp-check/test/port_numbering/duplicate_connection_at_matched_port.fpp @@ -8,6 +8,7 @@ module M { sync input port pIn: [4] P match pOut with pIn + } instance c1: C1 base id 0x100 @@ -21,10 +22,13 @@ module M { instance c3 connections P { - c1.pOut -> c2.pIn - c2.pOut -> c1.pIn[0] - c3.pOut -> c1.pIn[0] + + c1.pOut -> c2.pIn + c2.pOut -> c1.pIn[0] + c3.pOut -> c1.pIn[0] + } + } } diff --git a/compiler/tools/fpp-check/test/port_numbering/duplicate_connection_at_matched_port.ref.txt b/compiler/tools/fpp-check/test/port_numbering/duplicate_connection_at_matched_port.ref.txt index 511919b54..4156de2cf 100644 --- a/compiler/tools/fpp-check/test/port_numbering/duplicate_connection_at_matched_port.ref.txt +++ b/compiler/tools/fpp-check/test/port_numbering/duplicate_connection_at_matched_port.ref.txt @@ -1,12 +1,12 @@ fpp-check -[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/duplicate_connection_at_matched_port.fpp:26.9 - c3.pOut -> c1.pIn[0] - ^ +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/duplicate_connection_at_matched_port.fpp:28.7 + c3.pOut -> c1.pIn[0] + ^ error: duplicate connection at matched port pIn[0] previous occurrence is here: -[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/duplicate_connection_at_matched_port.fpp:25.9 - c2.pOut -> c1.pIn[0] - ^ +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/duplicate_connection_at_matched_port.fpp:27.7 + c2.pOut -> c1.pIn[0] + ^ port matching is specified here: [ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/duplicate_connection_at_matched_port.fpp:10.5 match pOut with pIn diff --git a/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_input_port.fpp b/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_input_port.fpp index 7adf9a7b4..a8cde3d2c 100644 --- a/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_input_port.fpp +++ b/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_input_port.fpp @@ -8,6 +8,7 @@ module M { sync input port pIn: [4] P match pOut with pIn + } passive component C2 { @@ -30,7 +31,9 @@ module M { c1.pOut[0] -> c2.pIn c2.pOut -> c1.pIn unmatched c2.pOut -> c1.pIn[0] + } + } } diff --git a/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_input_port.ref.txt b/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_input_port.ref.txt index 00b605973..6f34fa936 100644 --- a/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_input_port.ref.txt +++ b/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_input_port.ref.txt @@ -1,10 +1,10 @@ fpp-check -[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_input_port.fpp:31.7 +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_input_port.fpp:32.7 c2.pOut -> c1.pIn ^ error: implicit duplicate connection at matched port pIn[0] connection is implied here: -[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_input_port.fpp:30.7 +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_input_port.fpp:31.7 c1.pOut[0] -> c2.pIn ^ because of matching specified here: @@ -12,6 +12,6 @@ because of matching specified here: match pOut with pIn ^ conflicting connection is here: -[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_input_port.fpp:32.17 +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_input_port.fpp:33.17 unmatched c2.pOut -> c1.pIn[0] ^ diff --git a/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_output_port.fpp b/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_output_port.fpp index 5c8d87502..c6b4236d1 100644 --- a/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_output_port.fpp +++ b/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_output_port.fpp @@ -8,6 +8,7 @@ module M { sync input port pIn: [4] P match pOut with pIn + } passive component C2 { @@ -28,10 +29,13 @@ module M { instance c3 connections P { + c1.pOut -> c2.pIn c2.pOut -> c1.pIn[0] unmatched c1.pOut[0] -> c3.pIn + } + } } diff --git a/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_output_port.ref.txt b/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_output_port.ref.txt index cbb976f61..5b06c2733 100644 --- a/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_output_port.ref.txt +++ b/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_output_port.ref.txt @@ -1,10 +1,10 @@ fpp-check -[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_output_port.fpp:31.7 +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_output_port.fpp:33.7 c1.pOut -> c2.pIn ^ error: implicit duplicate connection at matched port pOut[0] connection is implied here: -[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_output_port.fpp:32.7 +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_output_port.fpp:34.7 c2.pOut -> c1.pIn[0] ^ because of matching specified here: @@ -12,6 +12,6 @@ because of matching specified here: match pOut with pIn ^ conflicting connection is here: -[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_output_port.fpp:33.17 +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/implicit_duplicate_connection_at_matched_output_port.fpp:35.17 unmatched c1.pOut[0] -> c3.pIn ^ diff --git a/compiler/tools/fpp-check/test/port_numbering/no_port_available_for_matched_numbering.fpp b/compiler/tools/fpp-check/test/port_numbering/no_port_available_for_matched_numbering.fpp index fcb88737d..c7e12a1a8 100644 --- a/compiler/tools/fpp-check/test/port_numbering/no_port_available_for_matched_numbering.fpp +++ b/compiler/tools/fpp-check/test/port_numbering/no_port_available_for_matched_numbering.fpp @@ -8,6 +8,7 @@ module M { sync input port pIn: [4] P match pOut with pIn + } passive component C2 { @@ -16,6 +17,7 @@ module M { sync input port pIn: [4] P match pOut with pIn + } instance c1: C1 base id 0x100 @@ -29,6 +31,7 @@ module M { instance c3 connections P { + unmatched c1.pOut -> c2.pIn[0] unmatched c1.pOut -> c2.pIn[1] unmatched c1.pOut -> c2.pIn[2] @@ -36,7 +39,9 @@ module M { c1.pOut -> c2.pIn c2.pOut -> c1.pIn + } + } } diff --git a/compiler/tools/fpp-check/test/port_numbering/no_port_available_for_matched_numbering.ref.txt b/compiler/tools/fpp-check/test/port_numbering/no_port_available_for_matched_numbering.ref.txt index 3131d3e10..600622501 100644 --- a/compiler/tools/fpp-check/test/port_numbering/no_port_available_for_matched_numbering.ref.txt +++ b/compiler/tools/fpp-check/test/port_numbering/no_port_available_for_matched_numbering.ref.txt @@ -1,10 +1,10 @@ fpp-check error: no port available for matched numbering matched connections are specified here: -[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/no_port_available_for_matched_numbering.fpp:38.7 +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/no_port_available_for_matched_numbering.fpp:41.7 c2.pOut -> c1.pIn ^ -[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/no_port_available_for_matched_numbering.fpp:37.7 +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/no_port_available_for_matched_numbering.fpp:40.7 c1.pOut -> c2.pIn ^ port matching is specified here: From 4da4b03da53b4d6566245282c1c7a76c35166035 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 29 Oct 2024 14:19:01 -0700 Subject: [PATCH 43/73] Refactor matched numbering --- .../MatchedPortNumbering.scala | 35 +++++---- .../MatchedPortNumberingState.scala | 75 +++++++++++++++++++ .../ResolveTopology/PortNumberingState.scala | 29 ++----- 3 files changed, 101 insertions(+), 38 deletions(-) create mode 100644 compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala index ae7fedc57..0ce7c4fa6 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala @@ -9,6 +9,9 @@ object MatchedPortNumbering { // A mapping from component instances to connections private type ConnectionMap = Map[ComponentInstance, Connection] + // A mapping from port numbers to connections + type UsedPortMap = Map[Int, Connection] + // State for matched numbering private case class State private( // The topology @@ -22,7 +25,7 @@ object MatchedPortNumbering { // The map from component instances to connections for port 2 map2: ConnectionMap, // Port numbering state - numbering: PortNumberingState + numbering: MatchedPortNumberingState ) private object State { @@ -44,7 +47,8 @@ object MatchedPortNumbering { (n1Opt, n2Opt) match { case (Some(n1), Some(n2)) => // Both ports have a number: check that they match - if (n1 == n2) Right(state) + if (n1 == n2) + Right(state) else { // Error: numbers don't match val p1Loc = c1.getThisEndpoint(pi1).loc @@ -145,19 +149,21 @@ object MatchedPortNumbering { t: Topology, pi1: PortInstance, map1: ConnectionMap, - usedPorts1: Map[Int, Connection], + usedPorts1: UsedPortMap, pi2: PortInstance, map2: ConnectionMap, - usedPorts2: Map[Int, Connection] + usedPorts2: UsedPortMap ): State = { + // Compute the used port numbers + val usedPortNumbers = usedPorts1.keys.toSet ++ usedPorts2.keys.toSet State( t, pi1, map1, pi2, map2, - PortNumberingState.initial( - usedPorts1.keys.toSet ++ usedPorts2.keys.toSet, + MatchedPortNumberingState.initial( + usedPortNumbers, usedPorts1, usedPorts2 ) @@ -206,7 +212,7 @@ object MatchedPortNumbering { portMatching: Component.PortMatching ) = { // Map remote components to connections at pi - def constructMap(pi: PortInstance) = { + def computeConnectionMap(pi: PortInstance): Result.Result[ConnectionMap] = { val empty: ConnectionMap = Map() val pii = PortInstanceIdentifier(ci, pi) val cs = t.getConnectionsAt(pii).toList.sorted @@ -230,11 +236,12 @@ object MatchedPortNumbering { }) } - // Computes the set of used ports for all connections at a specific port instance - def computeUsedPortNumbers(pi: PortInstance): Result.Result[Map[Int, Connection]] = { + // Map port numbers to connections at pi + def computeUsedPortMap(pi: PortInstance): Result.Result[UsedPortMap] = { val pii = PortInstanceIdentifier(ci, pi) val cs = t.getConnectionsAt(pii).toList.sorted - Result.foldLeft (cs) (Map[Int, Connection]()) ((m, c) => { + val empty: UsedPortMap = Map() + Result.foldLeft (cs) (empty) ((m, c) => { val piiRemote = c.getOtherEndpoint(pi).port t.getPortNumber(pi, c) match { case Some(n) => @@ -262,10 +269,10 @@ object MatchedPortNumbering { val pi2 = portMatching.instance2 val loc = portMatching.getLoc for { - map1 <- constructMap(pi1) - map2 <- constructMap(pi2) - usedPorts1 <- computeUsedPortNumbers(pi1) - usedPorts2 <- computeUsedPortNumbers(pi2) + map1 <- computeConnectionMap(pi1) + map2 <- computeConnectionMap(pi2) + usedPorts1 <- computeUsedPortMap(pi1) + usedPorts2 <- computeUsedPortMap(pi2) _ <- checkForMissingConnections(loc, map1, map2) state <- { val state = State.initial(t, pi1, map1, usedPorts1, pi2, map2, usedPorts2) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala new file mode 100644 index 000000000..42d496d92 --- /dev/null +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala @@ -0,0 +1,75 @@ +package fpp.compiler.analysis + +import fpp.compiler.ast._ +import fpp.compiler.util._ + +/** Matched port numbering state */ +case class MatchedPortNumberingState private ( + /** The used port numbers */ + usedPortNumbers: Set[Int], + /** The next port number */ + nextPortNumber: Int, + /** Map from port numbers to connections for port instance 1 */ + usedPorts1: MatchedPortNumberingState.UsedPortMap = Map(), + /** Map from port numbers to connections for port instance 2 */ + usedPorts2: MatchedPortNumberingState.UsedPortMap = Map() +) { + + /** Marks the next port number as used and generates + * a new one */ + def usePortNumber: MatchedPortNumberingState = { + val s = usedPortNumbers + nextPortNumber + val n = MatchedPortNumberingState.getNextNumber( + nextPortNumber, + s + ) + MatchedPortNumberingState(s, n, usedPorts1, usedPorts2) + } + + /** Gets the next port number and updates the state */ + def getPortNumber: (MatchedPortNumberingState, Int) = { + val s = usePortNumber + (s, nextPortNumber) + } + + // Takes in the updated sets, updated the usedPortNumbers set + // (ie: union of usedPorts1 and usedPorts2) and figure out the new next port number + def setUsedPorts( + u1: MatchedPortNumberingState.UsedPortMap, + u2: MatchedPortNumberingState.UsedPortMap + ): MatchedPortNumberingState = { + val updatedUsedPortNumbers = u1.keys.toSet ++ u2.keys.toSet + val updatedNextPortNumber = MatchedPortNumberingState.getNextNumber( + nextPortNumber, + updatedUsedPortNumbers + ) + MatchedPortNumberingState(updatedUsedPortNumbers, updatedNextPortNumber, u1, u2) + } + +} + +object MatchedPortNumberingState { + + /** A mapping from port numbers to connections **/ + type UsedPortMap = Map[Int, Connection] + + /** Construct an initial state */ + def initial( + usedPortNumbers: Set[Int], + usedPorts1: UsedPortMap = Map(), + usedPorts2: UsedPortMap = Map() + ): MatchedPortNumberingState = { + val nextPortNumber = getNextNumber(0, usedPortNumbers) + MatchedPortNumberingState(usedPortNumbers, nextPortNumber, usedPorts1, usedPorts2) + } + + /** Gets the next available port number */ + def getNextNumber(from: Int, used: Set[Int]): Int = { + def helper(n: Int): Int = + if (!used.contains(n)) + n + else helper(n + 1) + helper(from) + } + +} diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala index 2e2263259..2d3f606b4 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala @@ -8,11 +8,7 @@ case class PortNumberingState private ( /** The used port numbers */ usedPortNumbers: Set[Int], /** The next port number */ - nextPortNumber: Int, - /** First map of used ports for port instance 1 */ - usedPorts1: Map[Int, Connection] = Map(), - /** Second map of used ports for port instance 2 */ - usedPorts2: Map[Int, Connection] = Map() + nextPortNumber: Int ) { /** Marks the next port number as used and generates @@ -23,7 +19,7 @@ case class PortNumberingState private ( nextPortNumber, s ) - PortNumberingState(s, n, usedPorts1, usedPorts2) + PortNumberingState(s, n) } /** Gets the next port number and updates the state */ @@ -32,34 +28,19 @@ case class PortNumberingState private ( (s, nextPortNumber) } - // Takes in the updated sets, updated the usedPortNumbers set - // (ie: union of usedPorts1 and usedPorts2) and figure out the new next port number - def setUsedPorts(u1: Map[Int, Connection], u2: Map[Int, Connection]): PortNumberingState = { - val updatedUsedPortNumbers = u1.keys.toSet ++ u2.keys.toSet - val updatedNextPortNumber = PortNumberingState.getNextNumber( - nextPortNumber, - updatedUsedPortNumbers - ) - PortNumberingState(updatedUsedPortNumbers, updatedNextPortNumber, u1, u2) - } - } object PortNumberingState { /** Construct an initial state */ - def initial( - usedPortNumbers: Set[Int], - usedPorts1: Map[Int, Connection] = Map(), - usedPorts2: Map[Int, Connection] = Map() - ): PortNumberingState = { + def initial(usedPortNumbers: Set[Int]): PortNumberingState = { val nextPortNumber = getNextNumber(0, usedPortNumbers) - PortNumberingState(usedPortNumbers, nextPortNumber, usedPorts1, usedPorts2) + PortNumberingState(usedPortNumbers, nextPortNumber) } /** Gets the next available port number */ def getNextNumber(from: Int, used: Set[Int]): Int = { - def helper(n: Int): Int = + def helper(n: Int): Int = if (!used.contains(n)) n else helper(n + 1) From 74a327358d4af0c002988ba940773a9c22e9b5d4 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 29 Oct 2024 14:43:59 -0700 Subject: [PATCH 44/73] Refactor matched numbering --- .../MatchedPortNumbering.scala | 8 +----- .../MatchedPortNumberingState.scala | 28 ++++++------------- 2 files changed, 9 insertions(+), 27 deletions(-) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala index 0ce7c4fa6..292134693 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala @@ -154,19 +154,13 @@ object MatchedPortNumbering { map2: ConnectionMap, usedPorts2: UsedPortMap ): State = { - // Compute the used port numbers - val usedPortNumbers = usedPorts1.keys.toSet ++ usedPorts2.keys.toSet State( t, pi1, map1, pi2, map2, - MatchedPortNumberingState.initial( - usedPortNumbers, - usedPorts1, - usedPorts2 - ) + MatchedPortNumberingState.initial(usedPorts1, usedPorts2) ) } diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala index 42d496d92..a2b705cd3 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala @@ -5,7 +5,7 @@ import fpp.compiler.util._ /** Matched port numbering state */ case class MatchedPortNumberingState private ( - /** The used port numbers */ + /** The port numbering state */ usedPortNumbers: Set[Int], /** The next port number */ nextPortNumber: Int, @@ -19,7 +19,7 @@ case class MatchedPortNumberingState private ( * a new one */ def usePortNumber: MatchedPortNumberingState = { val s = usedPortNumbers + nextPortNumber - val n = MatchedPortNumberingState.getNextNumber( + val n = PortNumberingState.getNextNumber( nextPortNumber, s ) @@ -39,7 +39,7 @@ case class MatchedPortNumberingState private ( u2: MatchedPortNumberingState.UsedPortMap ): MatchedPortNumberingState = { val updatedUsedPortNumbers = u1.keys.toSet ++ u2.keys.toSet - val updatedNextPortNumber = MatchedPortNumberingState.getNextNumber( + val updatedNextPortNumber = PortNumberingState.getNextNumber( nextPortNumber, updatedUsedPortNumbers ) @@ -50,26 +50,14 @@ case class MatchedPortNumberingState private ( object MatchedPortNumberingState { - /** A mapping from port numbers to connections **/ + /** A mapping from used port numbers to connections **/ type UsedPortMap = Map[Int, Connection] /** Construct an initial state */ - def initial( - usedPortNumbers: Set[Int], - usedPorts1: UsedPortMap = Map(), - usedPorts2: UsedPortMap = Map() - ): MatchedPortNumberingState = { - val nextPortNumber = getNextNumber(0, usedPortNumbers) - MatchedPortNumberingState(usedPortNumbers, nextPortNumber, usedPorts1, usedPorts2) - } - - /** Gets the next available port number */ - def getNextNumber(from: Int, used: Set[Int]): Int = { - def helper(n: Int): Int = - if (!used.contains(n)) - n - else helper(n + 1) - helper(from) + def initial(upm1: UsedPortMap, upm2: UsedPortMap): MatchedPortNumberingState = { + val usedPortNumbers = upm1.keys.toSet ++ upm2.keys.toSet + val nextPortNumber = PortNumberingState.getNextNumber(0, usedPortNumbers) + MatchedPortNumberingState(usedPortNumbers, nextPortNumber, upm1, upm2) } } From d0d154cde1934ba48cca33127168e096e941c424 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 29 Oct 2024 15:05:23 -0700 Subject: [PATCH 45/73] Refactor matched numbering --- .../ResolveTopology/MatchedPortNumberingState.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala index a2b705cd3..7a9e7ea9b 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala @@ -54,10 +54,10 @@ object MatchedPortNumberingState { type UsedPortMap = Map[Int, Connection] /** Construct an initial state */ - def initial(upm1: UsedPortMap, upm2: UsedPortMap): MatchedPortNumberingState = { - val usedPortNumbers = upm1.keys.toSet ++ upm2.keys.toSet + def initial(map1: UsedPortMap, map2: UsedPortMap): MatchedPortNumberingState = { + val usedPortNumbers = map1.keys.toSet ++ map2.keys.toSet val nextPortNumber = PortNumberingState.getNextNumber(0, usedPortNumbers) - MatchedPortNumberingState(usedPortNumbers, nextPortNumber, upm1, upm2) + MatchedPortNumberingState(usedPortNumbers, nextPortNumber, map1, map2) } } From 7d026a4103d01bb4532e2c5bdb9cf47bcd9d9b71 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 29 Oct 2024 16:28:18 -0700 Subject: [PATCH 46/73] Refactor matched numbering --- .../MatchedPortNumbering.scala | 3 +- .../MatchedPortNumberingState.scala | 47 ++++++++++++++++--- .../ResolveTopology/PortNumberingState.scala | 17 ++++--- 3 files changed, 54 insertions(+), 13 deletions(-) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala index 292134693..c7a76a1ef 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala @@ -102,7 +102,8 @@ object MatchedPortNumbering { case None => val t1 = t.assignPortNumber(pi1, c1, n2) // Update the set of used ports so that the new port number is tracked - val numbering = state.numbering.setUsedPorts(u1 + (n2 -> c1), u2) + //val numbering = state.numbering.setUsedPorts(u1 + (n2 -> c1), u2) + val numbering = state.numbering.updateUsedPorts1(n2, c1) Right(state.copy(t = t1, numbering = numbering)) } case (None, None) => diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala index 7a9e7ea9b..b21913af5 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala @@ -15,20 +15,25 @@ case class MatchedPortNumberingState private ( usedPorts2: MatchedPortNumberingState.UsedPortMap = Map() ) { - /** Marks the next port number as used and generates + /** Marks the specified port number as used and generates * a new one */ - def usePortNumber: MatchedPortNumberingState = { - val s = usedPortNumbers + nextPortNumber - val n = PortNumberingState.getNextNumber( + def usePortNumber(n: Int): MatchedPortNumberingState = { + val s = usedPortNumbers + n + val n1 = PortNumberingState.getNextNumber( nextPortNumber, s ) - MatchedPortNumberingState(s, n, usedPorts1, usedPorts2) + MatchedPortNumberingState(s, n1, usedPorts1, usedPorts2) } + /** Marks the next port number as used and generates + * a new one */ + def useNextPortNumber: MatchedPortNumberingState = + usePortNumber(nextPortNumber) + /** Gets the next port number and updates the state */ def getPortNumber: (MatchedPortNumberingState, Int) = { - val s = usePortNumber + val s = useNextPortNumber (s, nextPortNumber) } @@ -46,6 +51,36 @@ case class MatchedPortNumberingState private ( MatchedPortNumberingState(updatedUsedPortNumbers, updatedNextPortNumber, u1, u2) } + /** Adds a mapping to usedPorts1 */ + def updateUsedPorts1(n: Int, c: Connection): MatchedPortNumberingState = { + val usedPortNumbers = this.usedPortNumbers + n + val nextPortNumber = PortNumberingState.getNextNumber( + this.nextPortNumber, + usedPortNumbers + ) + val usedPorts1 = this.usedPorts1 + (n -> c) + this.copy( + usedPortNumbers = usedPortNumbers, + nextPortNumber = nextPortNumber, + usedPorts1 = usedPorts1 + ) + } + + /** Adds a mapping to usedPorts2 */ + def updateUsedPorts2(n: Int, c: Connection): MatchedPortNumberingState = { + val usedPortNumbers = this.usedPortNumbers + n + val nextPortNumber = PortNumberingState.getNextNumber( + this.nextPortNumber, + usedPortNumbers + ) + val usedPorts2 = this.usedPorts2 + (n -> c) + this.copy( + usedPortNumbers = usedPortNumbers, + nextPortNumber = nextPortNumber, + usedPorts2 = usedPorts2 + ) + } + } object MatchedPortNumberingState { diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala index 2d3f606b4..7de4c5a88 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala @@ -11,20 +11,25 @@ case class PortNumberingState private ( nextPortNumber: Int ) { - /** Marks the next port number as used and generates + /** Marks the specified port number as used and generates * a new one */ - def usePortNumber: PortNumberingState = { - val s = usedPortNumbers + nextPortNumber - val n = PortNumberingState.getNextNumber( + def usePortNumber(n: Int): PortNumberingState = { + val s = usedPortNumbers + n + val n1 = PortNumberingState.getNextNumber( nextPortNumber, s ) - PortNumberingState(s, n) + PortNumberingState(s, n1) } + /** Marks the next port number as used and generates + * a new one */ + def useNextPortNumber: PortNumberingState = + usePortNumber(nextPortNumber) + /** Gets the next port number and updates the state */ def getPortNumber: (PortNumberingState, Int) = { - val s = usePortNumber + val s = useNextPortNumber (s, nextPortNumber) } From 626fc970d69b2aac79b2b8c6d5f3193dd28aa1a7 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 29 Oct 2024 16:33:06 -0700 Subject: [PATCH 47/73] Refactor matched port numbering --- .../MatchedPortNumberingState.scala | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala index b21913af5..0bce70b7c 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala @@ -52,19 +52,22 @@ case class MatchedPortNumberingState private ( } /** Adds a mapping to usedPorts1 */ - def updateUsedPorts1(n: Int, c: Connection): MatchedPortNumberingState = { - val usedPortNumbers = this.usedPortNumbers + n - val nextPortNumber = PortNumberingState.getNextNumber( - this.nextPortNumber, - usedPortNumbers - ) - val usedPorts1 = this.usedPorts1 + (n -> c) - this.copy( - usedPortNumbers = usedPortNumbers, - nextPortNumber = nextPortNumber, - usedPorts1 = usedPorts1 - ) - } + def updateUsedPorts1(n: Int, c: Connection): MatchedPortNumberingState = + usePortNumber(n).copy(usedPorts1 = this.usedPorts1 + (n -> c)) + +// { +// val usedPortNumbers = this.usedPortNumbers + n +// val nextPortNumber = PortNumberingState.getNextNumber( +// this.nextPortNumber, +// usedPortNumbers +// ) +// val usedPorts1 = this.usedPorts1 + (n -> c) +// this.copy( +// usedPortNumbers = usedPortNumbers, +// nextPortNumber = nextPortNumber, +// usedPorts1 = usedPorts1 +// ) +// } /** Adds a mapping to usedPorts2 */ def updateUsedPorts2(n: Int, c: Connection): MatchedPortNumberingState = { From d2ad2c789dd980b5de25a2e6e9dead90809c10b1 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 29 Oct 2024 16:38:33 -0700 Subject: [PATCH 48/73] Refactor matched port numbering --- .../MatchedPortNumbering.scala | 4 +-- .../MatchedPortNumberingState.scala | 29 ++----------------- 2 files changed, 4 insertions(+), 29 deletions(-) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala index c7a76a1ef..e56c42e2b 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala @@ -81,7 +81,8 @@ object MatchedPortNumbering { case None => val t1 = t.assignPortNumber(pi2, c2, n1) // Update the set of used ports so that the new port number is tracked - val numbering = state.numbering.setUsedPorts(u1, u2 + (n1 -> c2)) + //val numbering = state.numbering.setUsedPorts(u1, u2 + (n1 -> c2)) + val numbering = state.numbering.updateUsedPorts2(n1, c2) Right(state.copy(t = t1, numbering = numbering)) } case (None, Some(n2)) => @@ -102,7 +103,6 @@ object MatchedPortNumbering { case None => val t1 = t.assignPortNumber(pi1, c1, n2) // Update the set of used ports so that the new port number is tracked - //val numbering = state.numbering.setUsedPorts(u1 + (n2 -> c1), u2) val numbering = state.numbering.updateUsedPorts1(n2, c1) Right(state.copy(t = t1, numbering = numbering)) } diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala index 0bce70b7c..5de09287a 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala @@ -55,34 +55,9 @@ case class MatchedPortNumberingState private ( def updateUsedPorts1(n: Int, c: Connection): MatchedPortNumberingState = usePortNumber(n).copy(usedPorts1 = this.usedPorts1 + (n -> c)) -// { -// val usedPortNumbers = this.usedPortNumbers + n -// val nextPortNumber = PortNumberingState.getNextNumber( -// this.nextPortNumber, -// usedPortNumbers -// ) -// val usedPorts1 = this.usedPorts1 + (n -> c) -// this.copy( -// usedPortNumbers = usedPortNumbers, -// nextPortNumber = nextPortNumber, -// usedPorts1 = usedPorts1 -// ) -// } - /** Adds a mapping to usedPorts2 */ - def updateUsedPorts2(n: Int, c: Connection): MatchedPortNumberingState = { - val usedPortNumbers = this.usedPortNumbers + n - val nextPortNumber = PortNumberingState.getNextNumber( - this.nextPortNumber, - usedPortNumbers - ) - val usedPorts2 = this.usedPorts2 + (n -> c) - this.copy( - usedPortNumbers = usedPortNumbers, - nextPortNumber = nextPortNumber, - usedPorts2 = usedPorts2 - ) - } + def updateUsedPorts2(n: Int, c: Connection): MatchedPortNumberingState = + usePortNumber(n).copy(usedPorts2 = this.usedPorts2 + (n -> c)) } From 50ad9163687d4aa9523391a94a71f9393ed3f43e Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 29 Oct 2024 16:44:13 -0700 Subject: [PATCH 49/73] Refactor matched port numbering --- .../ResolveTopology/MatchedPortNumbering.scala | 3 ++- .../MatchedPortNumberingState.scala | 14 -------------- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala index e56c42e2b..76a17fe48 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala @@ -121,7 +121,8 @@ object MatchedPortNumbering { else { val t1 = t.assignPortNumber(pi1, c1, n).assignPortNumber(pi2, c2, n) // Update the set of used ports so that the new port number is tracked - val numbering = state.numbering.setUsedPorts(u1 + (n -> c1), u2 + (n -> c2)) + //val numbering = state.numbering.setUsedPorts(u1 + (n -> c1), u2 + (n -> c2)) + val numbering = state.numbering.updateUsedPorts1(n, c1).updateUsedPorts2(n, c2) Right(state.copy(t = t1, numbering = numbering)) } } diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala index 5de09287a..1e0804a99 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala @@ -37,20 +37,6 @@ case class MatchedPortNumberingState private ( (s, nextPortNumber) } - // Takes in the updated sets, updated the usedPortNumbers set - // (ie: union of usedPorts1 and usedPorts2) and figure out the new next port number - def setUsedPorts( - u1: MatchedPortNumberingState.UsedPortMap, - u2: MatchedPortNumberingState.UsedPortMap - ): MatchedPortNumberingState = { - val updatedUsedPortNumbers = u1.keys.toSet ++ u2.keys.toSet - val updatedNextPortNumber = PortNumberingState.getNextNumber( - nextPortNumber, - updatedUsedPortNumbers - ) - MatchedPortNumberingState(updatedUsedPortNumbers, updatedNextPortNumber, u1, u2) - } - /** Adds a mapping to usedPorts1 */ def updateUsedPorts1(n: Int, c: Connection): MatchedPortNumberingState = usePortNumber(n).copy(usedPorts1 = this.usedPorts1 + (n -> c)) From 3aaf786fb82e4d8c2c9318816db09d0ac4fdd5f1 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 29 Oct 2024 16:51:04 -0700 Subject: [PATCH 50/73] Refactor matched port numbering --- .../ResolveTopology/MatchedPortNumbering.scala | 1 - .../MatchedPortNumberingState.scala | 14 ++++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala index 76a17fe48..4e64e9ad3 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala @@ -121,7 +121,6 @@ object MatchedPortNumbering { else { val t1 = t.assignPortNumber(pi1, c1, n).assignPortNumber(pi2, c2, n) // Update the set of used ports so that the new port number is tracked - //val numbering = state.numbering.setUsedPorts(u1 + (n -> c1), u2 + (n -> c2)) val numbering = state.numbering.updateUsedPorts1(n, c1).updateUsedPorts2(n, c2) Right(state.copy(t = t1, numbering = numbering)) } diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala index 1e0804a99..bfb9ea65d 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala @@ -6,13 +6,15 @@ import fpp.compiler.util._ /** Matched port numbering state */ case class MatchedPortNumberingState private ( /** The port numbering state */ + portNumberingState: PortNumberingState, + /** The used port numbers */ usedPortNumbers: Set[Int], /** The next port number */ nextPortNumber: Int, /** Map from port numbers to connections for port instance 1 */ - usedPorts1: MatchedPortNumberingState.UsedPortMap = Map(), + usedPorts1: MatchedPortNumberingState.UsedPortMap, /** Map from port numbers to connections for port instance 2 */ - usedPorts2: MatchedPortNumberingState.UsedPortMap = Map() + usedPorts2: MatchedPortNumberingState.UsedPortMap ) { /** Marks the specified port number as used and generates @@ -23,7 +25,10 @@ case class MatchedPortNumberingState private ( nextPortNumber, s ) - MatchedPortNumberingState(s, n1, usedPorts1, usedPorts2) + MatchedPortNumberingState( + portNumberingState.usePortNumber(n), + s, n1, usedPorts1, usedPorts2 + ) } /** Marks the next port number as used and generates @@ -55,8 +60,9 @@ object MatchedPortNumberingState { /** Construct an initial state */ def initial(map1: UsedPortMap, map2: UsedPortMap): MatchedPortNumberingState = { val usedPortNumbers = map1.keys.toSet ++ map2.keys.toSet + val portNumberingState = PortNumberingState.initial(usedPortNumbers) val nextPortNumber = PortNumberingState.getNextNumber(0, usedPortNumbers) - MatchedPortNumberingState(usedPortNumbers, nextPortNumber, map1, map2) + MatchedPortNumberingState(portNumberingState, usedPortNumbers, nextPortNumber, map1, map2) } } From 202ea974f964d792fcd03ad64e3ca450d04a1ae8 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 29 Oct 2024 17:01:48 -0700 Subject: [PATCH 51/73] Refactor matched port numbering --- .../MatchedPortNumberingState.scala | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala index bfb9ea65d..5b6174dcf 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala @@ -20,26 +20,21 @@ case class MatchedPortNumberingState private ( /** Marks the specified port number as used and generates * a new one */ def usePortNumber(n: Int): MatchedPortNumberingState = { - val s = usedPortNumbers + n - val n1 = PortNumberingState.getNextNumber( - nextPortNumber, - s - ) MatchedPortNumberingState( portNumberingState.usePortNumber(n), - s, n1, usedPorts1, usedPorts2 + Set(), 0, usedPorts1, usedPorts2 ) } /** Marks the next port number as used and generates * a new one */ def useNextPortNumber: MatchedPortNumberingState = - usePortNumber(nextPortNumber) + this.copy(portNumberingState = portNumberingState.useNextPortNumber) /** Gets the next port number and updates the state */ def getPortNumber: (MatchedPortNumberingState, Int) = { - val s = useNextPortNumber - (s, nextPortNumber) + val (pns, pn) = portNumberingState.getPortNumber + (this.copy(portNumberingState = pns), pn) } /** Adds a mapping to usedPorts1 */ @@ -61,8 +56,8 @@ object MatchedPortNumberingState { def initial(map1: UsedPortMap, map2: UsedPortMap): MatchedPortNumberingState = { val usedPortNumbers = map1.keys.toSet ++ map2.keys.toSet val portNumberingState = PortNumberingState.initial(usedPortNumbers) - val nextPortNumber = PortNumberingState.getNextNumber(0, usedPortNumbers) - MatchedPortNumberingState(portNumberingState, usedPortNumbers, nextPortNumber, map1, map2) + //val nextPortNumber = PortNumberingState.getNextNumber(0, usedPortNumbers) + MatchedPortNumberingState(portNumberingState, Set(), 0, map1, map2) } } From 9dae02f11eb54045f207a97b4616f8f96588b6ed Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 29 Oct 2024 17:17:58 -0700 Subject: [PATCH 52/73] Refactor matched numbering --- .../MatchedPortNumbering.scala | 3 +- .../MatchedPortNumberingState.scala | 29 ++++++------------- 2 files changed, 10 insertions(+), 22 deletions(-) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala index 4e64e9ad3..4b0471f20 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala @@ -12,7 +12,7 @@ object MatchedPortNumbering { // A mapping from port numbers to connections type UsedPortMap = Map[Int, Connection] - // State for matched numbering + // State for matched port numbering private case class State private( // The topology t: Topology, @@ -81,7 +81,6 @@ object MatchedPortNumbering { case None => val t1 = t.assignPortNumber(pi2, c2, n1) // Update the set of used ports so that the new port number is tracked - //val numbering = state.numbering.setUsedPorts(u1, u2 + (n1 -> c2)) val numbering = state.numbering.updateUsedPorts2(n1, c2) Right(state.copy(t = t1, numbering = numbering)) } diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala index 5b6174dcf..9f5217b66 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala @@ -3,31 +3,21 @@ package fpp.compiler.analysis import fpp.compiler.ast._ import fpp.compiler.util._ -/** Matched port numbering state */ +/** Port numbering state with used-port maps for matching */ case class MatchedPortNumberingState private ( /** The port numbering state */ portNumberingState: PortNumberingState, - /** The used port numbers */ - usedPortNumbers: Set[Int], - /** The next port number */ - nextPortNumber: Int, /** Map from port numbers to connections for port instance 1 */ usedPorts1: MatchedPortNumberingState.UsedPortMap, /** Map from port numbers to connections for port instance 2 */ usedPorts2: MatchedPortNumberingState.UsedPortMap ) { - /** Marks the specified port number as used and generates - * a new one */ - def usePortNumber(n: Int): MatchedPortNumberingState = { - MatchedPortNumberingState( - portNumberingState.usePortNumber(n), - Set(), 0, usedPorts1, usedPorts2 - ) - } + /** Marks the specified port number as used and generates a new one */ + def usePortNumber(n: Int): MatchedPortNumberingState = + this.copy(portNumberingState = portNumberingState.usePortNumber(n)) - /** Marks the next port number as used and generates - * a new one */ + /** Marks the next port number as used and generates a new one */ def useNextPortNumber: MatchedPortNumberingState = this.copy(portNumberingState = portNumberingState.useNextPortNumber) @@ -52,12 +42,11 @@ object MatchedPortNumberingState { /** A mapping from used port numbers to connections **/ type UsedPortMap = Map[Int, Connection] - /** Construct an initial state */ - def initial(map1: UsedPortMap, map2: UsedPortMap): MatchedPortNumberingState = { - val usedPortNumbers = map1.keys.toSet ++ map2.keys.toSet + /** Construct an initial state from a pair of used port maps */ + def initial(up1: UsedPortMap, up2: UsedPortMap): MatchedPortNumberingState = { + val usedPortNumbers = up1.keys.toSet ++ up2.keys.toSet val portNumberingState = PortNumberingState.initial(usedPortNumbers) - //val nextPortNumber = PortNumberingState.getNextNumber(0, usedPortNumbers) - MatchedPortNumberingState(portNumberingState, Set(), 0, map1, map2) + MatchedPortNumberingState(portNumberingState, up1, up2) } } From e0e3c8da6dfeb2470c8e4ddf1774d77d1990d646 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 29 Oct 2024 19:13:06 -0700 Subject: [PATCH 53/73] Refactor matched port numbering --- .../MatchedPortNumbering.scala | 47 ++++++++++++++++--- 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala index 4b0471f20..f4ef3e41c 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala @@ -10,7 +10,7 @@ object MatchedPortNumbering { private type ConnectionMap = Map[ComponentInstance, Connection] // A mapping from port numbers to connections - type UsedPortMap = Map[Int, Connection] + private type UsedPortMap = Map[Int, Connection] // State for matched port numbering private case class State private( @@ -25,8 +25,38 @@ object MatchedPortNumbering { // The map from component instances to connections for port 2 map2: ConnectionMap, // Port numbering state - numbering: MatchedPortNumberingState - ) + numbering: MatchedPortNumberingState, + numbering1: PortNumberingState, + // Map from port numbers to connections for port instance 1 + upm1: UsedPortMap, + // Map from port numbers to connections for port instance 2 + upm2: UsedPortMap + ) { + + // Marks the specified port number as used and generates a new one + def usePortNumber(n: Int): State = + this.copy(numbering = numbering.usePortNumber(n)) + + // Marks the next port number as used and generates a new one + def useNextPortNumber: State = + this.copy(numbering = numbering.useNextPortNumber) + + // Gets the next port number and updates the state + def getPortNumber: (State, Int) = { + val (s, n) = numbering.getPortNumber + (this.copy(numbering = s), n) + } + + // Adds a mapping to usedPorts1 + def updateUsedPorts1(n: Int, c: Connection): State = + usePortNumber(n).copy(upm1 = this.upm1 + (n -> c)) + + + // Adds a mapping to usedPorts2 + def updateUsedPorts2(n: Int, c: Connection): State = + usePortNumber(n).copy(upm2 = this.upm2 + (n -> c)) + + } private object State { @@ -149,18 +179,23 @@ object MatchedPortNumbering { t: Topology, pi1: PortInstance, map1: ConnectionMap, - usedPorts1: UsedPortMap, + up1: UsedPortMap, pi2: PortInstance, map2: ConnectionMap, - usedPorts2: UsedPortMap + up2: UsedPortMap ): State = { + // Compute used port numbers + val usedPortNumbers = up1.keys.toSet ++ up2.keys.toSet State( t, pi1, map1, pi2, map2, - MatchedPortNumberingState.initial(usedPorts1, usedPorts2) + MatchedPortNumberingState.initial(up1, up2), + PortNumberingState.initial(usedPortNumbers), + up1, + up2 ) } From b6a41df22d7a779c03ced1aa2c83dd73c7390224 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 29 Oct 2024 19:32:15 -0700 Subject: [PATCH 54/73] Refactor matched port numbering --- .../MatchedPortNumbering.scala | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala index f4ef3e41c..866307ad3 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala @@ -25,8 +25,8 @@ object MatchedPortNumbering { // The map from component instances to connections for port 2 map2: ConnectionMap, // Port numbering state - numbering: MatchedPortNumberingState, - numbering1: PortNumberingState, + //numbering: MatchedPortNumberingState, + numbering: PortNumberingState, // Map from port numbers to connections for port instance 1 upm1: UsedPortMap, // Map from port numbers to connections for port instance 2 @@ -72,8 +72,8 @@ object MatchedPortNumbering { val n1Opt = t.getPortNumber(pi1, c1) val pi2 = state.pi2 val n2Opt = t.getPortNumber(pi2, c2) - val u1 = state.numbering.usedPorts1 - val u2 = state.numbering.usedPorts2 + //val upm1 = state.upm1 //state.numbering.usedPorts1 + //val upm2 = state.upm2 //state.numbering.usedPorts2 (n1Opt, n2Opt) match { case (Some(n1), Some(n2)) => // Both ports have a number: check that they match @@ -96,7 +96,7 @@ object MatchedPortNumbering { case (Some(n1), None) => // Only pi1 has a number: assign it to pi2 // Check to see if the port number is already assigned - u2.get(n1) match { + state.upm2.get(n1) match { case Some(prevC) => Left( SemanticError.ImplicitDuplicateConnectionAtMatchedPort( @@ -111,13 +111,13 @@ object MatchedPortNumbering { case None => val t1 = t.assignPortNumber(pi2, c2, n1) // Update the set of used ports so that the new port number is tracked - val numbering = state.numbering.updateUsedPorts2(n1, c2) - Right(state.copy(t = t1, numbering = numbering)) + //state.numbering.updateUsedPorts2(n1, c2) + Right(state.updateUsedPorts2(n1, c2).copy(t = t1)) } case (None, Some(n2)) => // Only pi2 has a number: assign it to pi1 // Check to see if the port number is already in use - state.numbering.usedPorts1.get(n2) match { + state.upm1.get(n2) match { case Some(prevC) => Left( SemanticError.ImplicitDuplicateConnectionAtMatchedPort( @@ -132,12 +132,13 @@ object MatchedPortNumbering { case None => val t1 = t.assignPortNumber(pi1, c1, n2) // Update the set of used ports so that the new port number is tracked - val numbering = state.numbering.updateUsedPorts1(n2, c1) - Right(state.copy(t = t1, numbering = numbering)) + //val numbering = state.updateUsedPorts1(n2, c1) //state.numbering.updateUsedPorts1(n2, c1) + //Right(state.copy(t = t1, numbering = numbering)) + Right(state.updateUsedPorts1(n2, c1).copy(t = t1)) } case (None, None) => // Neither port has a number: assign a new one - val (numbering, n) = state.numbering.getPortNumber + val (state1, n) = state.getPortNumber //state.numbering.getPortNumber // Return an error if the port number is out of range if(n >= pi1.getArraySize) Left( @@ -150,8 +151,9 @@ object MatchedPortNumbering { else { val t1 = t.assignPortNumber(pi1, c1, n).assignPortNumber(pi2, c2, n) // Update the set of used ports so that the new port number is tracked - val numbering = state.numbering.updateUsedPorts1(n, c1).updateUsedPorts2(n, c2) - Right(state.copy(t = t1, numbering = numbering)) + //val numbering = state.updateUsedPorts(n, c1).updateUsedPorts(n, c2) + //state.numbering.updateUsedPorts1(n, c1).updateUsedPorts2(n, c2) + Right(state1.updateUsedPorts1(n, c1).updateUsedPorts2(n, c2).copy(t = t1)) } } } @@ -192,7 +194,7 @@ object MatchedPortNumbering { map1, pi2, map2, - MatchedPortNumberingState.initial(up1, up2), + //MatchedPortNumberingState.initial(up1, up2), PortNumberingState.initial(usedPortNumbers), up1, up2 From 6e1eb5f391bcc26a0a660b0de94070d9c4e617c3 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 29 Oct 2024 19:43:02 -0700 Subject: [PATCH 55/73] Refactor matched numbering --- .../MatchedPortNumbering.scala | 46 ++++++++----------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala index 866307ad3..5babfe1fc 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala @@ -20,17 +20,16 @@ object MatchedPortNumbering { pi1: PortInstance, // The map from component instances to connections for port 1 map1: ConnectionMap, + // The map from port numbers to connections for port instance 1 + upm1: UsedPortMap, // The port instance for port 2 pi2: PortInstance, // The map from component instances to connections for port 2 map2: ConnectionMap, - // Port numbering state - //numbering: MatchedPortNumberingState, - numbering: PortNumberingState, - // Map from port numbers to connections for port instance 1 - upm1: UsedPortMap, // Map from port numbers to connections for port instance 2 - upm2: UsedPortMap + upm2: UsedPortMap, + // Port numbering state + numbering: PortNumberingState ) { // Marks the specified port number as used and generates a new one @@ -72,8 +71,6 @@ object MatchedPortNumbering { val n1Opt = t.getPortNumber(pi1, c1) val pi2 = state.pi2 val n2Opt = t.getPortNumber(pi2, c2) - //val upm1 = state.upm1 //state.numbering.usedPorts1 - //val upm2 = state.upm2 //state.numbering.usedPorts2 (n1Opt, n2Opt) match { case (Some(n1), Some(n2)) => // Both ports have a number: check that they match @@ -110,9 +107,9 @@ object MatchedPortNumbering { ) case None => val t1 = t.assignPortNumber(pi2, c2, n1) - // Update the set of used ports so that the new port number is tracked - //state.numbering.updateUsedPorts2(n1, c2) - Right(state.updateUsedPorts2(n1, c2).copy(t = t1)) + // Add n1 -> c2 to the port connection map + val state1 = state.updateUsedPorts2(n1, c2) + Right(state1.copy(t = t1)) } case (None, Some(n2)) => // Only pi2 has a number: assign it to pi1 @@ -131,10 +128,9 @@ object MatchedPortNumbering { ) case None => val t1 = t.assignPortNumber(pi1, c1, n2) - // Update the set of used ports so that the new port number is tracked - //val numbering = state.updateUsedPorts1(n2, c1) //state.numbering.updateUsedPorts1(n2, c1) - //Right(state.copy(t = t1, numbering = numbering)) - Right(state.updateUsedPorts1(n2, c1).copy(t = t1)) + // Add n2 -> c1 to the port connection map + val state1 = state.updateUsedPorts1(n2, c1) + Right(state1.copy(t = t1)) } case (None, None) => // Neither port has a number: assign a new one @@ -151,9 +147,8 @@ object MatchedPortNumbering { else { val t1 = t.assignPortNumber(pi1, c1, n).assignPortNumber(pi2, c2, n) // Update the set of used ports so that the new port number is tracked - //val numbering = state.updateUsedPorts(n, c1).updateUsedPorts(n, c2) - //state.numbering.updateUsedPorts1(n, c1).updateUsedPorts2(n, c2) - Right(state1.updateUsedPorts1(n, c1).updateUsedPorts2(n, c2).copy(t = t1)) + val state2 = state1.updateUsedPorts1(n, c1).updateUsedPorts2(n, c2) + Right(state2.copy(t = t1)) } } } @@ -181,23 +176,22 @@ object MatchedPortNumbering { t: Topology, pi1: PortInstance, map1: ConnectionMap, - up1: UsedPortMap, + upm1: UsedPortMap, pi2: PortInstance, map2: ConnectionMap, - up2: UsedPortMap + upm2: UsedPortMap ): State = { - // Compute used port numbers - val usedPortNumbers = up1.keys.toSet ++ up2.keys.toSet + // Compute the used port numbers + val usedPortNumbers = upm1.keys.toSet ++ upm2.keys.toSet State( t, pi1, map1, + upm1, pi2, map2, - //MatchedPortNumberingState.initial(up1, up2), - PortNumberingState.initial(usedPortNumbers), - up1, - up2 + upm2, + PortNumberingState.initial(usedPortNumbers) ) } From 613ccd11aade84daee850a2e9a10c58aa0bc1491 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 29 Oct 2024 20:08:49 -0700 Subject: [PATCH 56/73] Refactor matched port numbering --- .../MatchedPortNumbering.scala | 114 +++++++++--------- .../ResolveTopology/PortNumberingState.scala | 5 +- 2 files changed, 57 insertions(+), 62 deletions(-) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala index 5babfe1fc..0a9250b7c 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala @@ -6,11 +6,13 @@ import fpp.compiler.util._ /** Apply matched port numbering */ object MatchedPortNumbering { - // A mapping from component instances to connections - private type ConnectionMap = Map[ComponentInstance, Connection] + // A map from component instances to connections for tracking + // matching pairs of connections + private type InstanceConnectionMap = Map[ComponentInstance, Connection] - // A mapping from port numbers to connections - private type UsedPortMap = Map[Int, Connection] + // A map from port numbers to connections for tracking port + // assignments + private type PortConnectionMap = Map[Int, Connection] // State for matched port numbering private case class State private( @@ -19,15 +21,15 @@ object MatchedPortNumbering { // The port instance for port 1 pi1: PortInstance, // The map from component instances to connections for port 1 - map1: ConnectionMap, - // The map from port numbers to connections for port instance 1 - upm1: UsedPortMap, + icm1: InstanceConnectionMap, + // The map from port numbers to connections for port 1 + pcm1: PortConnectionMap, // The port instance for port 2 pi2: PortInstance, // The map from component instances to connections for port 2 - map2: ConnectionMap, - // Map from port numbers to connections for port instance 2 - upm2: UsedPortMap, + icm2: InstanceConnectionMap, + // The map from port numbers to connections for port 2 + pcm2: PortConnectionMap, // Port numbering state numbering: PortNumberingState ) { @@ -40,20 +42,19 @@ object MatchedPortNumbering { def useNextPortNumber: State = this.copy(numbering = numbering.useNextPortNumber) - // Gets the next port number and updates the state + // Gets the next port number and updates the port numbring state def getPortNumber: (State, Int) = { val (s, n) = numbering.getPortNumber (this.copy(numbering = s), n) } - // Adds a mapping to usedPorts1 - def updateUsedPorts1(n: Int, c: Connection): State = - usePortNumber(n).copy(upm1 = this.upm1 + (n -> c)) + // Adds a mapping to pcm1 and updates the port numbering state + def updatePortConnectionMap1(n: Int, c: Connection): State = + usePortNumber(n).copy(pcm1 = this.pcm1 + (n -> c)) - - // Adds a mapping to usedPorts2 - def updateUsedPorts2(n: Int, c: Connection): State = - usePortNumber(n).copy(upm2 = this.upm2 + (n -> c)) + // Adds a mapping to pcm2 and updates the port numbering state + def updatePortConnectionMap2(n: Int, c: Connection): State = + usePortNumber(n).copy(pcm2 = this.pcm2 + (n -> c)) } @@ -93,7 +94,7 @@ object MatchedPortNumbering { case (Some(n1), None) => // Only pi1 has a number: assign it to pi2 // Check to see if the port number is already assigned - state.upm2.get(n1) match { + state.pcm2.get(n1) match { case Some(prevC) => Left( SemanticError.ImplicitDuplicateConnectionAtMatchedPort( @@ -107,14 +108,13 @@ object MatchedPortNumbering { ) case None => val t1 = t.assignPortNumber(pi2, c2, n1) - // Add n1 -> c2 to the port connection map - val state1 = state.updateUsedPorts2(n1, c2) + val state1 = state.updatePortConnectionMap2(n1, c2) Right(state1.copy(t = t1)) } case (None, Some(n2)) => // Only pi2 has a number: assign it to pi1 // Check to see if the port number is already in use - state.upm1.get(n2) match { + state.pcm1.get(n2) match { case Some(prevC) => Left( SemanticError.ImplicitDuplicateConnectionAtMatchedPort( @@ -128,13 +128,12 @@ object MatchedPortNumbering { ) case None => val t1 = t.assignPortNumber(pi1, c1, n2) - // Add n2 -> c1 to the port connection map - val state1 = state.updateUsedPorts1(n2, c1) + val state1 = state.updatePortConnectionMap1(n2, c1) Right(state1.copy(t = t1)) } case (None, None) => // Neither port has a number: assign a new one - val (state1, n) = state.getPortNumber //state.numbering.getPortNumber + val (state1, n) = state.getPortNumber // Return an error if the port number is out of range if(n >= pi1.getArraySize) Left( @@ -146,8 +145,7 @@ object MatchedPortNumbering { ) else { val t1 = t.assignPortNumber(pi1, c1, n).assignPortNumber(pi2, c2, n) - // Update the set of used ports so that the new port number is tracked - val state2 = state1.updateUsedPorts1(n, c1).updateUsedPorts2(n, c2) + val state2 = state1.updatePortConnectionMap1(n, c1).updatePortConnectionMap2(n, c2) Right(state2.copy(t = t1)) } } @@ -159,12 +157,12 @@ object MatchedPortNumbering { matchingLoc: Location, state: State ): Result.Result[State] = { - val (map1, map2) = (state.map1, state.map2) - val list1 = map1.toList.sortWith(_._2 < _._2) + val (icm1, icm2) = (state.icm1, state.icm2) + val list1 = icm1.toList.sortWith(_._2 < _._2) for { result <- Result.foldLeft (list1) (state) ({ case (s, (ci, c1)) => { - val c2 = map2(ci) + val c2 = icm2(ci) numberConnectionPair(matchingLoc, s, c1, c2) } }) @@ -175,22 +173,22 @@ object MatchedPortNumbering { def initial( t: Topology, pi1: PortInstance, - map1: ConnectionMap, - upm1: UsedPortMap, + icm1: InstanceConnectionMap, + pcm1: PortConnectionMap, pi2: PortInstance, - map2: ConnectionMap, - upm2: UsedPortMap + icm2: InstanceConnectionMap, + pcm2: PortConnectionMap ): State = { // Compute the used port numbers - val usedPortNumbers = upm1.keys.toSet ++ upm2.keys.toSet + val usedPortNumbers = pcm1.keys.toSet ++ pcm2.keys.toSet State( t, pi1, - map1, - upm1, + icm1, + pcm1, pi2, - map2, - upm2, + icm2, + pcm2, PortNumberingState.initial(usedPortNumbers) ) } @@ -210,13 +208,13 @@ object MatchedPortNumbering { // Check for missing connections private def checkForMissingConnections( matchingLoc: Location, - map1: ConnectionMap, - map2: ConnectionMap + icm1: InstanceConnectionMap, + icm2: InstanceConnectionMap ): Result.Result[Unit] = { - // Ensure that map2 contains everything in map1 - def helper(map1: ConnectionMap, map2: ConnectionMap) = - Result.foldLeft (map1.toList) (()) ({ case (u, (ci, c)) => - if (map2.contains(ci)) + // Ensure that icm2 contains everything in icm1 + def helper(icm1: InstanceConnectionMap, icm2: InstanceConnectionMap) = + Result.foldLeft (icm1.toList) (()) ({ case (u, (ci, c)) => + if (icm2.contains(ci)) Right(()) else { val loc = c.getLoc @@ -224,10 +222,10 @@ object MatchedPortNumbering { } }) // Ensure that the two sets of keys match - if (map1.size >= map2.size) - helper(map1, map2) + if (icm1.size >= icm2.size) + helper(icm1, icm2) else - helper(map2, map1) + helper(icm2, icm1) } // Handle one port matching @@ -237,8 +235,8 @@ object MatchedPortNumbering { portMatching: Component.PortMatching ) = { // Map remote components to connections at pi - def computeConnectionMap(pi: PortInstance): Result.Result[ConnectionMap] = { - val empty: ConnectionMap = Map() + def computeInstanceConnectionMap(pi: PortInstance): Result.Result[InstanceConnectionMap] = { + val empty: InstanceConnectionMap = Map() val pii = PortInstanceIdentifier(ci, pi) val cs = t.getConnectionsAt(pii).toList.sorted Result.foldLeft (cs) (empty) ((m, c) => { @@ -262,10 +260,10 @@ object MatchedPortNumbering { } // Map port numbers to connections at pi - def computeUsedPortMap(pi: PortInstance): Result.Result[UsedPortMap] = { + def computePortConnectionMap(pi: PortInstance): Result.Result[PortConnectionMap] = { val pii = PortInstanceIdentifier(ci, pi) val cs = t.getConnectionsAt(pii).toList.sorted - val empty: UsedPortMap = Map() + val empty: PortConnectionMap = Map() Result.foldLeft (cs) (empty) ((m, c) => { val piiRemote = c.getOtherEndpoint(pi).port t.getPortNumber(pi, c) match { @@ -294,13 +292,13 @@ object MatchedPortNumbering { val pi2 = portMatching.instance2 val loc = portMatching.getLoc for { - map1 <- computeConnectionMap(pi1) - map2 <- computeConnectionMap(pi2) - usedPorts1 <- computeUsedPortMap(pi1) - usedPorts2 <- computeUsedPortMap(pi2) - _ <- checkForMissingConnections(loc, map1, map2) + icm1 <- computeInstanceConnectionMap(pi1) + icm2 <- computeInstanceConnectionMap(pi2) + pcm1 <- computePortConnectionMap(pi1) + pcm2 <- computePortConnectionMap(pi2) + _ <- checkForMissingConnections(loc, icm1, icm2) state <- { - val state = State.initial(t, pi1, map1, usedPorts1, pi2, map2, usedPorts2) + val state = State.initial(t, pi1, icm1, pcm1, pi2, icm2, pcm2) State.assignNumbers(loc, state) } } diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala index 7de4c5a88..42c1ad5c2 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala @@ -15,10 +15,7 @@ case class PortNumberingState private ( * a new one */ def usePortNumber(n: Int): PortNumberingState = { val s = usedPortNumbers + n - val n1 = PortNumberingState.getNextNumber( - nextPortNumber, - s - ) + val n1 = PortNumberingState.getNextNumber(nextPortNumber, s) PortNumberingState(s, n1) } From 1e2c797b8128644ba1f5edad12c6a22f0c38f66b Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 29 Oct 2024 20:09:11 -0700 Subject: [PATCH 57/73] Delete unused file --- .../MatchedPortNumberingState.scala | 52 ------------------- 1 file changed, 52 deletions(-) delete mode 100644 compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala deleted file mode 100644 index 9f5217b66..000000000 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumberingState.scala +++ /dev/null @@ -1,52 +0,0 @@ -package fpp.compiler.analysis - -import fpp.compiler.ast._ -import fpp.compiler.util._ - -/** Port numbering state with used-port maps for matching */ -case class MatchedPortNumberingState private ( - /** The port numbering state */ - portNumberingState: PortNumberingState, - /** Map from port numbers to connections for port instance 1 */ - usedPorts1: MatchedPortNumberingState.UsedPortMap, - /** Map from port numbers to connections for port instance 2 */ - usedPorts2: MatchedPortNumberingState.UsedPortMap -) { - - /** Marks the specified port number as used and generates a new one */ - def usePortNumber(n: Int): MatchedPortNumberingState = - this.copy(portNumberingState = portNumberingState.usePortNumber(n)) - - /** Marks the next port number as used and generates a new one */ - def useNextPortNumber: MatchedPortNumberingState = - this.copy(portNumberingState = portNumberingState.useNextPortNumber) - - /** Gets the next port number and updates the state */ - def getPortNumber: (MatchedPortNumberingState, Int) = { - val (pns, pn) = portNumberingState.getPortNumber - (this.copy(portNumberingState = pns), pn) - } - - /** Adds a mapping to usedPorts1 */ - def updateUsedPorts1(n: Int, c: Connection): MatchedPortNumberingState = - usePortNumber(n).copy(usedPorts1 = this.usedPorts1 + (n -> c)) - - /** Adds a mapping to usedPorts2 */ - def updateUsedPorts2(n: Int, c: Connection): MatchedPortNumberingState = - usePortNumber(n).copy(usedPorts2 = this.usedPorts2 + (n -> c)) - -} - -object MatchedPortNumberingState { - - /** A mapping from used port numbers to connections **/ - type UsedPortMap = Map[Int, Connection] - - /** Construct an initial state from a pair of used port maps */ - def initial(up1: UsedPortMap, up2: UsedPortMap): MatchedPortNumberingState = { - val usedPortNumbers = up1.keys.toSet ++ up2.keys.toSet - val portNumberingState = PortNumberingState.initial(usedPortNumbers) - MatchedPortNumberingState(portNumberingState, up1, up2) - } - -} From 175e691456c739cfdbd2f43100a62c85210bd229 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 29 Oct 2024 20:29:05 -0700 Subject: [PATCH 58/73] Refactor matched port numbering --- .../MatchedPortNumbering.scala | 44 +++++++++++-------- .../ResolveTopology/PortNumberingState.scala | 3 +- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala index 0a9250b7c..17fbc356a 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala @@ -74,11 +74,12 @@ object MatchedPortNumbering { val n2Opt = t.getPortNumber(pi2, c2) (n1Opt, n2Opt) match { case (Some(n1), Some(n2)) => - // Both ports have a number: check that they match + // Both ports have a number if (n1 == n2) + // Numbers match: OK, nothing to do Right(state) else { - // Error: numbers don't match + // Numbers don't match: error val p1Loc = c1.getThisEndpoint(pi1).loc val p2Loc = c2.getThisEndpoint(pi2).loc Left( @@ -91,51 +92,53 @@ object MatchedPortNumbering { ) ) } - case (Some(n1), None) => - // Only pi1 has a number: assign it to pi2 - // Check to see if the port number is already assigned - state.pcm2.get(n1) match { + case (Some(n), None) => + // Only pi1 has a number + state.pcm2.get(n) match { case Some(prevC) => + // Number is already assigned at pi2: error Left( SemanticError.ImplicitDuplicateConnectionAtMatchedPort( c2.getLoc, pi2.toString, - n1, + n, c1.getLoc, matchingLoc, prevC.getLoc, ) ) case None => - val t1 = t.assignPortNumber(pi2, c2, n1) - val state1 = state.updatePortConnectionMap2(n1, c2) + // Assign the number to c2 at pi2 and update the state + val t1 = t.assignPortNumber(pi2, c2, n) + val state1 = state.updatePortConnectionMap2(n, c2) Right(state1.copy(t = t1)) } - case (None, Some(n2)) => - // Only pi2 has a number: assign it to pi1 - // Check to see if the port number is already in use - state.pcm1.get(n2) match { + case (None, Some(n)) => + // Only pi2 has a number + state.pcm1.get(n) match { case Some(prevC) => + // Number is already assigned at pi1: error Left( SemanticError.ImplicitDuplicateConnectionAtMatchedPort( c1.getLoc, pi1.toString, - n2, + n, c2.getLoc, matchingLoc, prevC.getLoc ) ) case None => - val t1 = t.assignPortNumber(pi1, c1, n2) - val state1 = state.updatePortConnectionMap1(n2, c1) + // Assign the number to c1 at pi1 and update the state + val t1 = t.assignPortNumber(pi1, c1, n) + val state1 = state.updatePortConnectionMap1(n, c1) Right(state1.copy(t = t1)) } case (None, None) => - // Neither port has a number: assign a new one + // Neither port has a number; get a new one val (state1, n) = state.getPortNumber - // Return an error if the port number is out of range if(n >= pi1.getArraySize) + // Port number is out of range: error Left( SemanticError.NoPortAvailableForMatchedNumbering( c1.getLoc, @@ -144,8 +147,10 @@ object MatchedPortNumbering { ) ) else { + // Assign the number to both sides and update the state val t1 = t.assignPortNumber(pi1, c1, n).assignPortNumber(pi2, c2, n) - val state2 = state1.updatePortConnectionMap1(n, c1).updatePortConnectionMap2(n, c2) + val state2 = state1.updatePortConnectionMap1(n, c1). + updatePortConnectionMap2(n, c2) Right(state2.copy(t = t1)) } } @@ -260,6 +265,7 @@ object MatchedPortNumbering { } // Map port numbers to connections at pi + // While computing the map, enforce the rule against duplicate connections def computePortConnectionMap(pi: PortInstance): Result.Result[PortConnectionMap] = { val pii = PortInstanceIdentifier(ci, pi) val cs = t.getConnectionsAt(pii).toList.sorted diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala index 42c1ad5c2..c16c7441b 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/PortNumberingState.scala @@ -19,8 +19,7 @@ case class PortNumberingState private ( PortNumberingState(s, n1) } - /** Marks the next port number as used and generates - * a new one */ + /** Marks the next port number as used and generates a new one */ def useNextPortNumber: PortNumberingState = usePortNumber(nextPortNumber) From 96bfb6e692ebc683e56cff5908eeac70f3e43b45 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 29 Oct 2024 20:38:39 -0700 Subject: [PATCH 59/73] Revise comment --- compiler/lib/src/main/scala/analysis/Semantics/Connection.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/Connection.scala b/compiler/lib/src/main/scala/analysis/Semantics/Connection.scala index 1fc891cbb..a844a62b4 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/Connection.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/Connection.scala @@ -104,7 +104,7 @@ case class Connection( } } - /** Checks to see if a connection is match constrained */ + /** Checks whether a connection is match constrained */ def isMatchConstrained: Boolean = { def portMatchingExists(pml: List[Component.PortMatching], pi: PortInstance): Boolean = pml.exists(pm => pi.equals(pm.instance1) || pi.equals(pm.instance2)) From 893f3a8f7716458188cd5d349fba5783154cbb52 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 29 Oct 2024 21:23:58 -0700 Subject: [PATCH 60/73] Refactor matched port numbering --- .../Semantics/ResolveTopology/MatchedPortNumbering.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala index 17fbc356a..c689af208 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/ResolveTopology/MatchedPortNumbering.scala @@ -239,7 +239,7 @@ object MatchedPortNumbering { ci: ComponentInstance, portMatching: Component.PortMatching ) = { - // Map remote components to connections at pi + // Map remote component instances to connections at pi def computeInstanceConnectionMap(pi: PortInstance): Result.Result[InstanceConnectionMap] = { val empty: InstanceConnectionMap = Map() val pii = PortInstanceIdentifier(ci, pi) @@ -298,10 +298,10 @@ object MatchedPortNumbering { val pi2 = portMatching.instance2 val loc = portMatching.getLoc for { - icm1 <- computeInstanceConnectionMap(pi1) - icm2 <- computeInstanceConnectionMap(pi2) pcm1 <- computePortConnectionMap(pi1) pcm2 <- computePortConnectionMap(pi2) + icm1 <- computeInstanceConnectionMap(pi1) + icm2 <- computeInstanceConnectionMap(pi2) _ <- checkForMissingConnections(loc, icm1, icm2) state <- { val state = State.initial(t, pi1, icm1, pcm1, pi2, icm2, pcm2) From ef8b76dcb05ea2bdfe6d146cae79e5a883cb77ea Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Wed, 30 Oct 2024 08:22:49 -0700 Subject: [PATCH 61/73] Revise tests --- .../fpp-check/test/connection_direct/ok.fpp | 2 +- ...o_port_available_for_matched_numbering.fpp | 25 +++++++++++-------- ...rt_available_for_matched_numbering.ref.txt | 8 +++--- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/compiler/tools/fpp-check/test/connection_direct/ok.fpp b/compiler/tools/fpp-check/test/connection_direct/ok.fpp index 0ae1443b0..9c1d4240d 100644 --- a/compiler/tools/fpp-check/test/connection_direct/ok.fpp +++ b/compiler/tools/fpp-check/test/connection_direct/ok.fpp @@ -12,7 +12,7 @@ passive component C2 { passive component C3 { output port pOut: [5] P2 - sync input port pIn: [5] P2 + sync input port pIn: [5] P2 match pOut with pIn } diff --git a/compiler/tools/fpp-check/test/port_numbering/no_port_available_for_matched_numbering.fpp b/compiler/tools/fpp-check/test/port_numbering/no_port_available_for_matched_numbering.fpp index c7e12a1a8..f40154919 100644 --- a/compiler/tools/fpp-check/test/port_numbering/no_port_available_for_matched_numbering.fpp +++ b/compiler/tools/fpp-check/test/port_numbering/no_port_available_for_matched_numbering.fpp @@ -4,8 +4,8 @@ module M { passive component C1 { - output port pOut: [4] P - sync input port pIn: [4] P + output port pOut: [2] P + sync input port pIn: [2] P match pOut with pIn @@ -13,16 +13,21 @@ module M { passive component C2 { - output port pOut: [4] P - sync input port pIn: [4] P + output port pOut: [2] P + sync input port pIn: [2] P - match pOut with pIn + } + + passive component C3 { + + output port pOut: P + sync input port pIn: P } instance c1: C1 base id 0x100 - instance c2: C1 base id 0x200 - instance c3: C1 base id 0x300 + instance c2: C2 base id 0x200 + instance c3: C2 base id 0x300 topology T { @@ -32,10 +37,8 @@ module M { connections P { - unmatched c1.pOut -> c2.pIn[0] - unmatched c1.pOut -> c2.pIn[1] - unmatched c1.pOut -> c2.pIn[2] - unmatched c2.pOut -> c2.pIn[3] + unmatched c1.pOut[0] -> c3.pIn + unmatched c3.pOut -> c1.pIn[1] c1.pOut -> c2.pIn c2.pOut -> c1.pIn diff --git a/compiler/tools/fpp-check/test/port_numbering/no_port_available_for_matched_numbering.ref.txt b/compiler/tools/fpp-check/test/port_numbering/no_port_available_for_matched_numbering.ref.txt index 600622501..fb7289e8c 100644 --- a/compiler/tools/fpp-check/test/port_numbering/no_port_available_for_matched_numbering.ref.txt +++ b/compiler/tools/fpp-check/test/port_numbering/no_port_available_for_matched_numbering.ref.txt @@ -1,12 +1,12 @@ fpp-check error: no port available for matched numbering matched connections are specified here: -[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/no_port_available_for_matched_numbering.fpp:41.7 - c2.pOut -> c1.pIn - ^ -[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/no_port_available_for_matched_numbering.fpp:40.7 +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/no_port_available_for_matched_numbering.fpp:43.7 c1.pOut -> c2.pIn ^ +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/no_port_available_for_matched_numbering.fpp:44.7 + c2.pOut -> c1.pIn + ^ port matching is specified here: [ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/no_port_available_for_matched_numbering.fpp:10.5 match pOut with pIn From 3bb23aa8c218c0dbf6f5f2951ba837a242629efd Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Wed, 30 Oct 2024 08:28:27 -0700 Subject: [PATCH 62/73] Revise tests --- .../fpp-check/test/connection_direct/ok.fpp | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/compiler/tools/fpp-check/test/connection_direct/ok.fpp b/compiler/tools/fpp-check/test/connection_direct/ok.fpp index 9c1d4240d..c2a4e90eb 100644 --- a/compiler/tools/fpp-check/test/connection_direct/ok.fpp +++ b/compiler/tools/fpp-check/test/connection_direct/ok.fpp @@ -1,5 +1,4 @@ port P -port P2 passive component C1 { output port pOut: [2] P @@ -11,28 +10,48 @@ passive component C2 { } passive component C3 { - output port pOut: [5] P2 - sync input port pIn: [5] P2 + output port pOut: [4] P + sync input port pIn: [4] P match pOut with pIn } +passive component C4 { + output port pOut: [4] P + sync input port pIn: [4] P +} + +passive component C5 { + output port pOut: [4] P + sync input port pIn: [4] P +} + instance c1: C1 base id 0x100 instance c2: C2 base id 0x200 instance c3: C3 base id 0x300 -instance c4: C3 base id 0x400 +instance c4: C4 base id 0x400 +instance c5: C5 base id 0x500 topology T { instance c1 instance c2 instance c3 instance c4 + instance c5 + connections C { + c1.pOut -> c2.pIn c1.serialOut -> c2.pIn c1.pOut -> c2.serialIn c1.serialOut -> c2.serialIn + + # Matched connections to matched ports (c3.pOut, c3.pIn) + c3.pOut -> c5.pIn + c5.pOut -> c3.pIn + # Unmatched connections to matched ports (c3.pOut, c3.pIn) unmatched c3.pOut[0] -> c4.pIn[0] unmatched c3.pOut -> c4.pIn + } } From 153e7c62ce048de0f83e2fa8adbc103d261b0c49 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Wed, 30 Oct 2024 08:30:51 -0700 Subject: [PATCH 63/73] Revise tests --- .../invalid_unmatched_connection.fpp | 24 +++++++++---------- .../invalid_unmatched_connection.ref.txt | 4 ++-- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/compiler/tools/fpp-check/test/connection_direct/invalid_unmatched_connection.fpp b/compiler/tools/fpp-check/test/connection_direct/invalid_unmatched_connection.fpp index a099472f6..1f672fac6 100644 --- a/compiler/tools/fpp-check/test/connection_direct/invalid_unmatched_connection.fpp +++ b/compiler/tools/fpp-check/test/connection_direct/invalid_unmatched_connection.fpp @@ -1,31 +1,29 @@ -port P1 -port P2 +port P passive component C1 { - output port p1Out: [5] P1 - sync input port p1In: [5] P1 + output port pOut: P - output port p2Out: P2 - sync input port p2In: P2 +} + +passive component C2 { + + sync input port pIn: P } instance c1: C1 base id 0x100 -instance c2: C1 base id 0x200 +instance c2: C2 base id 0x200 topology T { instance c1 instance c2 - connections P1 { - unmatched c1.p1Out[0] -> c2.p1In[0] - unmatched c1.p1Out -> c2.p1In - } + connections C { + + unmatched c1.pOut -> c2.pIn - connections P2 { - c1.p2Out -> c2.p2In } } diff --git a/compiler/tools/fpp-check/test/connection_direct/invalid_unmatched_connection.ref.txt b/compiler/tools/fpp-check/test/connection_direct/invalid_unmatched_connection.ref.txt index 0fcf6e1d7..95053c603 100644 --- a/compiler/tools/fpp-check/test/connection_direct/invalid_unmatched_connection.ref.txt +++ b/compiler/tools/fpp-check/test/connection_direct/invalid_unmatched_connection.ref.txt @@ -1,5 +1,5 @@ fpp-check -[ local path prefix ]/compiler/tools/fpp-check/test/connection_direct/invalid_unmatched_connection.fpp:23.15 - unmatched c1.p1Out[0] -> c2.p1In[0] +[ local path prefix ]/compiler/tools/fpp-check/test/connection_direct/invalid_unmatched_connection.fpp:25.15 + unmatched c1.pOut -> c2.pIn ^ error: unmatched connection must go from or to a matched port From 19bab67f4895cc9c97cfc6af2947982fd9a6fc6b Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Wed, 30 Oct 2024 08:35:50 -0700 Subject: [PATCH 64/73] Revise error message --- compiler/lib/src/main/scala/util/Error.scala | 2 +- .../no_port_available_for_matched_numbering.ref.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/lib/src/main/scala/util/Error.scala b/compiler/lib/src/main/scala/util/Error.scala index fb415ab69..2f84bd5f5 100644 --- a/compiler/lib/src/main/scala/util/Error.scala +++ b/compiler/lib/src/main/scala/util/Error.scala @@ -225,7 +225,7 @@ sealed trait Error { System.err.println(loc2) printMatchingLoc(matchingLoc) System.err.println("note: to be available, a port number must be in bounds and " ++ - "unassigned at both of the matched ports") + "unassigned at each of the matched ports") case SemanticError.OverlappingIdRanges( maxId1, name1, loc1, baseId2, name2, loc2 ) => diff --git a/compiler/tools/fpp-check/test/port_numbering/no_port_available_for_matched_numbering.ref.txt b/compiler/tools/fpp-check/test/port_numbering/no_port_available_for_matched_numbering.ref.txt index fb7289e8c..79359f241 100644 --- a/compiler/tools/fpp-check/test/port_numbering/no_port_available_for_matched_numbering.ref.txt +++ b/compiler/tools/fpp-check/test/port_numbering/no_port_available_for_matched_numbering.ref.txt @@ -11,4 +11,4 @@ port matching is specified here: [ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/no_port_available_for_matched_numbering.fpp:10.5 match pOut with pIn ^ -note: to be available, a port number must be in bounds and unassigned at both of the matched ports +note: to be available, a port number must be in bounds and unassigned at each of the matched ports From e8f3ce5fbb354581cb8e7f6e307117fbc7ce15c5 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Wed, 30 Oct 2024 08:53:37 -0700 Subject: [PATCH 65/73] Revise tests --- .../unmatched/C1ComponentAi.ref.xml | 4 ++-- .../unmatched/C2ComponentAi.ref.xml | 16 ---------------- .../unmatched/TTopologyAppAi.ref.xml | 4 ---- ...d_connections.fpp => numbering_unmatched.fpp} | 1 + ...tions.ref.txt => numbering_unmatched.ref.txt} | 0 .../test/top_numbering/unmatched/run.sh | 6 +++--- .../test/top_numbering/unmatched/tests.sh | 2 +- .../test/top_numbering/unmatched/update-ref.sh | 6 +++--- 8 files changed, 10 insertions(+), 29 deletions(-) delete mode 100644 compiler/tools/fpp-to-xml/test/top_numbering/unmatched/C2ComponentAi.ref.xml rename compiler/tools/fpp-to-xml/test/top_numbering/unmatched/{unmatched_connections.fpp => numbering_unmatched.fpp} (99%) rename compiler/tools/fpp-to-xml/test/top_numbering/unmatched/{unmatched_connections.ref.txt => numbering_unmatched.ref.txt} (100%) diff --git a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/C1ComponentAi.ref.xml b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/C1ComponentAi.ref.xml index 8a186df23..a3b25ec0a 100644 --- a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/C1ComponentAi.ref.xml +++ b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/C1ComponentAi.ref.xml @@ -9,8 +9,8 @@ Generated by fpp-to-xml PPortAi.xml - - + + diff --git a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/C2ComponentAi.ref.xml b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/C2ComponentAi.ref.xml deleted file mode 100644 index b875e5dc6..000000000 --- a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/C2ComponentAi.ref.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - PPortAi.xml - - - - - - - diff --git a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/TTopologyAppAi.ref.xml b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/TTopologyAppAi.ref.xml index ed4d71c1b..302711c44 100644 --- a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/TTopologyAppAi.ref.xml +++ b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/TTopologyAppAi.ref.xml @@ -70,10 +70,6 @@ Generated by fpp-to-xml - - - - diff --git a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/unmatched_connections.fpp b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/numbering_unmatched.fpp similarity index 99% rename from compiler/tools/fpp-to-xml/test/top_numbering/unmatched/unmatched_connections.fpp rename to compiler/tools/fpp-to-xml/test/top_numbering/unmatched/numbering_unmatched.fpp index caa74787c..ad82bae07 100644 --- a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/unmatched_connections.fpp +++ b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/numbering_unmatched.fpp @@ -73,6 +73,7 @@ module M { c8.pOut[3] -> c8.pIn[3] } + } } diff --git a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/unmatched_connections.ref.txt b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/numbering_unmatched.ref.txt similarity index 100% rename from compiler/tools/fpp-to-xml/test/top_numbering/unmatched/unmatched_connections.ref.txt rename to compiler/tools/fpp-to-xml/test/top_numbering/unmatched/numbering_unmatched.ref.txt diff --git a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/run.sh b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/run.sh index a38d9a73d..2f4ee5036 100644 --- a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/run.sh +++ b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/run.sh @@ -1,5 +1,5 @@ -numbering_matched() +numbering_unmatched() { - run_test "-p $PWD" unmatched_connections && \ - diff_xml PPort C1Component C2Component TTopologyApp + run_test "-p $PWD" numbering_unmatched && \ + diff_xml PPort C1Component TTopologyApp } diff --git a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/tests.sh b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/tests.sh index bdd8decc1..551560222 100644 --- a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/tests.sh +++ b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/tests.sh @@ -1,3 +1,3 @@ tests=" -unmatched_connections +numbering_unmatched " diff --git a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/update-ref.sh b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/update-ref.sh index ad8ab30d7..e49d6d4e0 100644 --- a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/update-ref.sh +++ b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/update-ref.sh @@ -1,5 +1,5 @@ -numbering_matched() +numbering_unmatched() { - update "-p $PWD" unmatched_connections - move_xml PPort C1Component C2Component TTopologyApp + update "-p $PWD" numbering_unmatched + move_xml PPort C1Component TTopologyApp } From c1a64494817e1c836ecb1e4a53f65eac950f29c6 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Wed, 30 Oct 2024 10:02:09 -0700 Subject: [PATCH 66/73] Revise tests --- .../test/top_numbering/unmatched/.gitignore | 4 + .../unmatched/TTopologyAppAi.ref.xml | 116 ++++++---------- .../test/top_numbering/unmatched/clean | 4 + .../test/top_numbering/unmatched/gen-layout | 16 +++ .../unmatched/numbering_unmatched.fpp | 129 +++++++++--------- .../test/top_numbering/unmatched/run.sh | 2 +- .../top_numbering/unmatched/update-ref.sh | 2 +- 7 files changed, 138 insertions(+), 135 deletions(-) create mode 100644 compiler/tools/fpp-to-xml/test/top_numbering/unmatched/.gitignore create mode 100755 compiler/tools/fpp-to-xml/test/top_numbering/unmatched/gen-layout diff --git a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/.gitignore b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/.gitignore new file mode 100644 index 000000000..4dd6f6e38 --- /dev/null +++ b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/.gitignore @@ -0,0 +1,4 @@ +*.eps +*.pdf +Case*.txt +Case*.xml diff --git a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/TTopologyAppAi.ref.xml b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/TTopologyAppAi.ref.xml index 302711c44..c9ccb5087 100644 --- a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/TTopologyAppAi.ref.xml +++ b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/TTopologyAppAi.ref.xml @@ -6,101 +6,73 @@ Generated by fpp-to-xml ====================================================================== --> - C1ComponentAi.xml + SourceComponentAi.xml + TargetComponentAi.xml - - - - - - - - + + + + + + + + + + - + - - + + - - + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - - + + - - + + - - + + + + + - - + + - - + + + + + - - + + - - + + diff --git a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/clean b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/clean index 8d322fe40..4632eae13 100755 --- a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/clean +++ b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/clean @@ -3,3 +3,7 @@ export COMPILER_ROOT=../../../../.. sh ../../scripts/clean.sh +for file in `find . -name 'Case*.txt' -or -name '*.eps' -or -name '*.pdf'` +do + rm $file +done diff --git a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/gen-layout b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/gen-layout new file mode 100755 index 000000000..b5bd543b6 --- /dev/null +++ b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/gen-layout @@ -0,0 +1,16 @@ +#!/bin/sh -e + +cases=" +Case1 +Case2 +Case3 +Case4 +" + +fpl-extract-xml TTopologyAppAi.ref.xml +for case_name in $cases +do + fpl-convert-xml $case_name.xml > $case_name.txt + fpl-write-eps < $case_name.txt > $case_name.eps + epspdf $case_name.eps +done diff --git a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/numbering_unmatched.fpp b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/numbering_unmatched.fpp index ad82bae07..3bf7e900f 100644 --- a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/numbering_unmatched.fpp +++ b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/numbering_unmatched.fpp @@ -1,77 +1,84 @@ module M { + constant numPorts = 4 + port P - passive component C1 { + passive component Source { - output port pOut: [4] P - sync input port pIn: [4] P + output port pOut: [numPorts] P + sync input port pIn: [numPorts] P match pOut with pIn + + } + + passive component Target { + + output port pOut: [numPorts] P + sync input port pIn: [numPorts] P + } - instance c1: C1 base id 0x100 - instance c2: C1 base id 0x200 - instance c3: C1 base id 0x300 - instance c4: C1 base id 0x400 - instance c5: C1 base id 0x500 - instance c6: C1 base id 0x600 - instance c7: C1 base id 0x700 - instance c8: C1 base id 0x800 + instance source1: Source base id 0x0100 + instance target11: Target base id 0x1100 + + instance source2: Source base id 0x0200 + instance target21: Target base id 0x2100 + + instance source3: Source base id 0x300 + instance target31: Source base id 0x3100 + instance target32: Source base id 0x3200 + + instance source4: Source base id 0x400 + instance target41: Source base id 0x4100 + instance target42: Source base id 0x4200 topology T { - instance c1 - instance c2 - instance c3 - instance c4 - instance c5 - instance c6 - instance c7 - instance c8 - - connections P { - # Case 1: 2 ports that go to the same component instance - # unmatched connections - unmatched c1.pOut -> c1.pIn - unmatched c2.pOut -> c1.pIn - # implicit matched connections - c1.pOut -> c1.pIn - c2.pOut -> c1.pIn - # explicit matched connection - c1.pOut[1] -> c2.pIn[1] - - # Case 2: Have a connection out of A at some index i and - # some connection at B at same index i but they go to different component instances - unmatched c3.pOut[0] -> c3.pIn[0] - unmatched c4.pOut[0] -> c4.pIn[0] - # implicit matched connections - c3.pOut -> c4.pIn - c4.pOut -> c3.pIn - # explicit matched connections - c3.pOut[1] -> c3.pIn[1] - c4.pOut[1] -> c4.pIn[1] - - # Case 3: Have a connection out of A at index i and - # some connection at B index at j not equal to i going to same component instance - unmatched c5.pOut[0] -> c5.pIn[0] - unmatched c6.pOut[1] -> c5.pIn[1] - # implicit matched connection - c6.pOut -> c5.pIn - # explicit matched connection - c5.pOut[2] -> c6.pIn[2] - - # Case 4: Have a connection out of A at index i and - # some connection at B index at j not equal to i going to different component instances - unmatched c7.pOut[0] -> c7.pIn[0] - unmatched c8.pOut[1] -> c8.pIn[1] - # implicit matched connections - c7.pOut -> c8.pIn - c8.pOut -> c7.pIn - # explicit matched connections - c7.pOut[2] -> c7.pIn[2] - c8.pOut[3] -> c8.pIn[3] + # Case 1: Matching connections to the same target + + instance source1 + instance target11 + + connections Case1 { + unmatched source1.pOut[0] -> target11.pIn[0] + unmatched target11.pOut[0] -> source1.pIn[0] + unmatched source1.pOut[1] -> target11.pIn[1] + unmatched target11.pOut[1] -> source1.pIn[1] + } + + # Case 2: Non-matching connections to the same target + + instance source2 + instance target21 + + connections Case2 { + unmatched source2.pOut[0] -> target21.pIn[0] + unmatched target21.pOut[0] -> source2.pIn[0] + unmatched source2.pOut[1] -> target21.pIn[1] + } + + # Case 3: Matching connections to different targets + + instance source3 + instance target31 + instance target32 + + connections Case3 { + unmatched source3.pOut[0] -> target31.pIn[0] + unmatched target32.pOut[0] -> source3.pIn[0] + } + + # Case 4: Non-matching connections to the same target + instance source4 + instance target41 + instance target42 + + connections Case4 { + unmatched source4.pOut[0] -> target41.pIn[0] + unmatched target42.pOut[1] -> source4.pIn[1] } } diff --git a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/run.sh b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/run.sh index 2f4ee5036..c33c1e04a 100644 --- a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/run.sh +++ b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/run.sh @@ -1,5 +1,5 @@ numbering_unmatched() { run_test "-p $PWD" numbering_unmatched && \ - diff_xml PPort C1Component TTopologyApp + diff_xml TTopologyApp } diff --git a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/update-ref.sh b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/update-ref.sh index e49d6d4e0..6410a79cc 100644 --- a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/update-ref.sh +++ b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/update-ref.sh @@ -1,5 +1,5 @@ numbering_unmatched() { update "-p $PWD" numbering_unmatched - move_xml PPort C1Component TTopologyApp + move_xml TTopologyApp } From 09d467ca8f5825e1a25d49a1997a2c99bdf1f3a6 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Wed, 30 Oct 2024 10:17:22 -0700 Subject: [PATCH 67/73] Revise tests --- .../unmatched/TTopologyAppAi.ref.xml | 45 +++++++++++++++++++ .../test/top_numbering/unmatched/gen-layout | 2 + .../unmatched/numbering_unmatched.fpp | 35 ++++++++++++++- 3 files changed, 81 insertions(+), 1 deletion(-) diff --git a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/TTopologyAppAi.ref.xml b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/TTopologyAppAi.ref.xml index c9ccb5087..a0e3fe21a 100644 --- a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/TTopologyAppAi.ref.xml +++ b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/TTopologyAppAi.ref.xml @@ -13,12 +13,18 @@ Generated by fpp-to-xml + + + + + + @@ -76,4 +82,43 @@ Generated by fpp-to-xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/gen-layout b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/gen-layout index b5bd543b6..511cfd6c8 100755 --- a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/gen-layout +++ b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/gen-layout @@ -5,11 +5,13 @@ Case1 Case2 Case3 Case4 +Case5 " fpl-extract-xml TTopologyAppAi.ref.xml for case_name in $cases do + echo "[ $case_name ]" fpl-convert-xml $case_name.xml > $case_name.txt fpl-write-eps < $case_name.txt > $case_name.eps epspdf $case_name.eps diff --git a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/numbering_unmatched.fpp b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/numbering_unmatched.fpp index 3bf7e900f..4a8a05735 100644 --- a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/numbering_unmatched.fpp +++ b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/numbering_unmatched.fpp @@ -1,6 +1,6 @@ module M { - constant numPorts = 4 + constant numPorts = 5 port P @@ -34,6 +34,13 @@ module M { instance target41: Source base id 0x4100 instance target42: Source base id 0x4200 + instance source5: Source base id 0x500 + instance target51: Source base id 0x5100 + instance target52: Source base id 0x5200 + instance target53: Source base id 0x5300 + instance target54: Source base id 0x5400 + instance target55: Source base id 0x5500 + topology T { # Case 1: Matching connections to the same target @@ -81,6 +88,32 @@ module M { unmatched target42.pOut[1] -> source4.pIn[1] } + # Case 5: Mixed matched and unmatched connections + + instance source5 + instance target51 + instance target52 + instance target53 + instance target54 + instance target55 + + connections Case5 { + # Matched connections with explicit numbering + source5.pOut[0] -> target51.pIn + target51.pOut -> source5.pIn[0] + # Matched connections with implicit numbering at pOut + source5.pOut -> target52.pIn + target52.pOut -> source5.pIn[1] + # Matched connections with implicit numbering at pIn + source5.pOut[2] -> target53.pIn + target53.pOut -> source5.pIn + # Matched connections with implicit numbering on both sides + source5.pOut -> target54.pIn + target54.pOut -> source5.pIn + # Unmatched connection + unmatched source5.pOut -> target55.pIn + } + } } From 829f17bc9624e57562cc0ed16685f7823ab24046 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Wed, 30 Oct 2024 10:26:53 -0700 Subject: [PATCH 68/73] Revise tests --- .../duplicate_connection_at_matched_port.fpp | 16 ++++++++++------ .../duplicate_connection_at_matched_port.ref.txt | 6 +++--- compiler/tools/fpp-check/test/update-ref | 9 +++++++++ compiler/tools/fpp-to-dict/test/.gitignore | 2 ++ 4 files changed, 24 insertions(+), 9 deletions(-) create mode 100755 compiler/tools/fpp-check/test/update-ref diff --git a/compiler/tools/fpp-check/test/port_numbering/duplicate_connection_at_matched_port.fpp b/compiler/tools/fpp-check/test/port_numbering/duplicate_connection_at_matched_port.fpp index c40355646..504b81372 100644 --- a/compiler/tools/fpp-check/test/port_numbering/duplicate_connection_at_matched_port.fpp +++ b/compiler/tools/fpp-check/test/port_numbering/duplicate_connection_at_matched_port.fpp @@ -4,28 +4,32 @@ module M { passive component C1 { - output port pOut: [4] P - sync input port pIn: [4] P + output port pOut: [2] P + sync input port pIn: [2] P match pOut with pIn } + passive component C2 { + + output port pOut: [2] P + sync input port pIn: [2] P + + } + instance c1: C1 base id 0x100 instance c2: C1 base id 0x200 - instance c3: C1 base id 0x300 topology T1 { instance c1 instance c2 - instance c3 connections P { - c1.pOut -> c2.pIn c2.pOut -> c1.pIn[0] - c3.pOut -> c1.pIn[0] + c2.pOut -> c1.pIn[0] } diff --git a/compiler/tools/fpp-check/test/port_numbering/duplicate_connection_at_matched_port.ref.txt b/compiler/tools/fpp-check/test/port_numbering/duplicate_connection_at_matched_port.ref.txt index 4156de2cf..87a473409 100644 --- a/compiler/tools/fpp-check/test/port_numbering/duplicate_connection_at_matched_port.ref.txt +++ b/compiler/tools/fpp-check/test/port_numbering/duplicate_connection_at_matched_port.ref.txt @@ -1,10 +1,10 @@ fpp-check -[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/duplicate_connection_at_matched_port.fpp:28.7 - c3.pOut -> c1.pIn[0] +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/duplicate_connection_at_matched_port.fpp:32.7 + c2.pOut -> c1.pIn[0] ^ error: duplicate connection at matched port pIn[0] previous occurrence is here: -[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/duplicate_connection_at_matched_port.fpp:27.7 +[ local path prefix ]/compiler/tools/fpp-check/test/port_numbering/duplicate_connection_at_matched_port.fpp:31.7 c2.pOut -> c1.pIn[0] ^ port matching is specified here: diff --git a/compiler/tools/fpp-check/test/update-ref b/compiler/tools/fpp-check/test/update-ref new file mode 100755 index 000000000..31b3d6c88 --- /dev/null +++ b/compiler/tools/fpp-check/test/update-ref @@ -0,0 +1,9 @@ +#!/bin/sh -e + +for file in `find . -mindepth 2 -name update-ref` +do + dir=`dirname $file` + base=`basename $file` + echo "[ $dir ]" + (cd $dir; ./$base) +done diff --git a/compiler/tools/fpp-to-dict/test/.gitignore b/compiler/tools/fpp-to-dict/test/.gitignore index a38478347..6df5a7bbd 100644 --- a/compiler/tools/fpp-to-dict/test/.gitignore +++ b/compiler/tools/fpp-to-dict/test/.gitignore @@ -1,3 +1,5 @@ +*.diff.txt +*.out.txt *Dictionary.json default-tests.sh default-update-ref.sh From 6a0a1396a303a08ac22832ff8ef677138aef3425 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Wed, 30 Oct 2024 10:28:38 -0700 Subject: [PATCH 69/73] Remove trailing spaces --- compiler/tools/fpp-syntax/test/syntax.fpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/tools/fpp-syntax/test/syntax.fpp b/compiler/tools/fpp-syntax/test/syntax.fpp index d487002d8..4870d6d9e 100644 --- a/compiler/tools/fpp-syntax/test/syntax.fpp +++ b/compiler/tools/fpp-syntax/test/syntax.fpp @@ -36,7 +36,7 @@ module DefinitionsAndSpecifiers { @ Parameter specifier param P: U32 default 0 id 0x00 set opcode 0x01 save opcode 0x02 @< Parameter specifier - + @ General port instance specifier sync input port p1: [10] P priority 10 assert @< General port instance specifier @@ -108,12 +108,12 @@ module DefinitionsAndSpecifiers { @< Constant definition @ Enum definition - enum E : I32 { + enum E : I32 { @ X X = 1 @< X @ Y - Y = 2 + Y = 2 @< Y } @< Enum definition @@ -135,12 +135,12 @@ module DefinitionsAndSpecifiers { @< Port definition @ Struct definition - struct S { + struct S { @ x x: U32 format "{} s" @< x @ y - y: F32 format "{} m/s" + y: F32 format "{} m/s" @< y } @< Struct definition @@ -157,7 +157,7 @@ module DefinitionsAndSpecifiers { @< Private instance specifier @ Direct connection graph specifier - connections C { + connections C { i1.p[0] -> i2.p[1] unmatched i1.p1[0] -> i2.p2[0] unmatched i1.p1 -> i2.p2 From 4cf870cda488fdfa96f3f6b13bc42bd1be02b019 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Wed, 30 Oct 2024 10:38:04 -0700 Subject: [PATCH 70/73] Remove unneeded ref files --- .../unmatched/C1ComponentAi.ref.xml | 16 ---------------- .../test/top_numbering/unmatched/PPortAi.ref.xml | 8 -------- 2 files changed, 24 deletions(-) delete mode 100644 compiler/tools/fpp-to-xml/test/top_numbering/unmatched/C1ComponentAi.ref.xml delete mode 100644 compiler/tools/fpp-to-xml/test/top_numbering/unmatched/PPortAi.ref.xml diff --git a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/C1ComponentAi.ref.xml b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/C1ComponentAi.ref.xml deleted file mode 100644 index a3b25ec0a..000000000 --- a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/C1ComponentAi.ref.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - PPortAi.xml - - - - - - - diff --git a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/PPortAi.ref.xml b/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/PPortAi.ref.xml deleted file mode 100644 index 64b132daf..000000000 --- a/compiler/tools/fpp-to-xml/test/top_numbering/unmatched/PPortAi.ref.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - From 23647d60a0e3724a7a149d0269af00cf18a097be Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Wed, 30 Oct 2024 10:45:06 -0700 Subject: [PATCH 71/73] Revise User's Guide --- docs/fpp-users-guide.html | 5 +---- docs/users-guide/Defining-Components.adoc | 3 --- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/docs/fpp-users-guide.html b/docs/fpp-users-guide.html index 0a3fbcd62..3a85355a0 100644 --- a/docs/fpp-users-guide.html +++ b/docs/fpp-users-guide.html @@ -6644,9 +6644,6 @@

    10.13. Matched Ports

    The matched pairs in item 2 must be connected to the same port numbers at p1 and p2.

    -
  • -

    Multiple connections can not use the same port number even if the port is an input port.

    -
  • @@ -12684,7 +12681,7 @@

    diff --git a/docs/users-guide/Defining-Components.adoc b/docs/users-guide/Defining-Components.adoc index f499d7b55..e0625131d 100644 --- a/docs/users-guide/Defining-Components.adoc +++ b/docs/users-guide/Defining-Components.adoc @@ -2677,9 +2677,6 @@ component instance and `p2`. . The matched pairs in item 2 must be connected to the same port numbers at `p1` and `p2`. -. Multiple connections can not use the same port number even if the port is an input port. - - In this case we call `p1` and `p2` a pair of *matched ports*. For example: From bcc11c0932a24eff47c013b41255328cf1ca3523 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Wed, 30 Oct 2024 11:41:51 -0700 Subject: [PATCH 72/73] Revise User's Guide --- docs/fpp-users-guide.html | 186 ++++++++++++---------- docs/users-guide/Defining-Topologies.adoc | 165 ++++++++++--------- 2 files changed, 194 insertions(+), 157 deletions(-) diff --git a/docs/fpp-users-guide.html b/docs/fpp-users-guide.html index 3a85355a0..46e8ad4e3 100644 --- a/docs/fpp-users-guide.html +++ b/docs/fpp-users-guide.html @@ -8469,11 +8469,8 @@

    12.3.2. Matched Nu
    1. -

      Multiple connections can not use the same port number even if the port is an input port.

      -
    2. -
    3. When a component has the matching specifier -match p1 with p2, for every matched connection between p1 +match p1 with p2, for every connection between p1 and another component, there must be a corresponding connection between that other component and p2.

    4. @@ -8485,20 +8482,118 @@

      12.3.2. Matched Nu and p2[1] to the same component, because this connection forces a mismatch.

      +
    5. +

      Duplicate connections at the same port number of p1 or +p2 are not allowed, even if p1 or p2 are input ports.

      +

    If you violate these rules, you will get an error during -analysis.

    +analysis. +You can relax these rules by writing unmatched connections, +as described below.

    +
    +
    +

    Unmatched connections: +Occasionally you may need to relax the rules for using matched ports. +For example, you may need to match pairs of connections that use +the F Prime hub pattern to cross a network boundary. +In this case, although the connections are logically matched +at the endpoints, they all go through a single hub instance +on the side of the boundary that has the matched ports, and so they do not obey the +simple rules for matching given here.

    +
    +
    +

    When a connection goes to or from a matched port, +we say that it is match constrained. +Ordinarily a match constrained connection must obey the +rules for matching stated above. +To relax the rules, you can write an unmatched connection. +To do this, write the keyword unmatched at the start of the connection +specifier. +Here is an example:

    +
    +
    +
    +
    Port P
    +
    +passive component Source {
    +  sync input port pIn: [2] P
    +  output port pOut: [2] P
    +
    +  match pOut with pIn
    +}
    +
    +passive component Target {
    +  sync input port pIn: [2] P
    +  output port pOut: [2] P
    +}
    +
    +instance source: Source base id 0x100
    +instance target: Target base id 0x200
    +
    +topology T {
    +
    +  instance source
    +  instance target
    +
    +  connections C {
    +    unmatched source.pOut[0] -> target.pIn[0]
    +    unmatched target.pOut[0] -> source.pIn[0]
    +    unmatched source.pOut[1] -> target.pIn[1]
    +    unmatched target.pOut[1] -> source.pIn[1]
    +  }
    +
    +}
    +
    +
    +
    +

    In this example, there are two pairs of connections between the +pIn and pOut connections of the instances source and target. +The ports of source are match constrained, so ordinarily +the connections would need to obey the matching rules. +The connections do partially obey the rules: for example, +there are no duplicate numbers, and the numbers match. +However, both pairs of connections go to and from the same +instance target; ordinarily this is not allowed for +match constrained connections. +To allow it, we need to use unmatched ports as shown.

    +
    +
    +

    Note the following about using unmatched ports:

    +
    +
    +
      +
    1. +

      When connections are marked unmatched, the analyzer cannot check that the +port numbers assigned to the connections conform to any particular pattern. +If you need the port numbers to follow a pattern, as in the example shown +above, then you must use explicit numbering. +For a suggestion on how to do this, see the discussion of manual matching +below.

      +
    2. +
    3. +

      Unmatched ports must still obey the rule that distinct +connections at a matched port must have distinct port numbers.

      +
    4. +
    5. +

      The unmatched keyword is allowed only for connections that +are match constrained, i.e., that go to or from a matched port. +If you try to write an unmatched connection and the connection +is not match constrained, then you will get an error.

      +
    6. +

    Manual matching: -Automatic matched numbering works when each matched pair of connections +Port matching specifiers work well when each matched pair of connections goes between the same two components, one of which has a matched pair of ports. If the matching does not follow this pattern, then automatic matched -numbering will not work, and you will need to use explicit port -numbers to express the matching. +numbering will not work, and it is usually better not to +use a port matching specifier at all. +Instead, you can use explicit port numbers to express the matching. For example, the Ref topology contains these connections:

    @@ -8519,79 +8614,6 @@

    12.3.2. Matched Nu Instead we define a symbolic constant Ports.StaticMemory.uplink and use that twice to do the matching by hand.

    -
    -

    Unmatched connections: -Unmatched connections can be used in a topology to bypass match -constraints that are specified in component definitions. Doing so -allows you to skip port matching requirements without receiving an -error if a match constraint is violated.

    -
    -
    -

    To specify that a connection is unmatched, start the connection -with the unmatched keyword.

    -
    -
    -
    -
    unmatched c1.pOut -> c2.pIn
    -
    -
    -
    -

    Note that unmatched connections are only allowed when a match -constraint has been specified. In the below example, unmatched -connections would not be valid since neither ports pIn or pOut -are match constrained.

    -
    -
    -
    -
    Port P
    -
    -passive component C {
    -  sync input port pIn: [3] P
    -  output port pOut: [3] P
    -}
    -
    -
    -
    -

    Below is a valid example for using unmatched connections:

    -
    -
    -
    -
    Port P
    -
    -passive component C {
    -  sync input port pIn: [3] P
    -  output port pOut: [3] P
    -
    -  match pOut with pIn
    -}
    -
    -instance c1: C base id 0x100
    -instance c2: C base id 0x200
    -
    -topology T {
    -
    -  @ This specifier says that instance c1 is part of the topology
    -  instance c1
    -  @ This specifier says that instance c2 is part of the topology
    -  instance c2
    -
    -  @ This code specifies a connection graph C1
    -  connections C1 {
    -    unmatched c1.pOut[0] -> c2.pIn[0]
    -    unmatched c1.pOut[1] -> c2.pIn[1]
    -  }
    -
    -}
    -
    -
    -
    -

    This example consists of a component C with ports pOut and pIn -that are match constrained by the matching specifier match pOut with pIn. -In addition, The topology T contains two unmatched connections that go -from c1.pOut[0] to c2.pIn[0] and from c1.pOut[1] to c2.pIn[1]. -Since pOut and pIn are match constrained, the unmatched keyword can be used -to mark the connection as unmatched and bypass the port matching requirement.

    -

    12.3.3. General Numbering

    @@ -12681,7 +12703,7 @@

    diff --git a/docs/users-guide/Defining-Topologies.adoc b/docs/users-guide/Defining-Topologies.adoc index d72cfc6eb..a6d4e4459 100644 --- a/docs/users-guide/Defining-Topologies.adoc +++ b/docs/users-guide/Defining-Topologies.adoc @@ -698,10 +698,8 @@ Sequencer component. When you use matched numbering with direct graph specifiers, you must obey the following rules: -. Multiple connections can not use the same port number even if the port is an input port. - . When a component has the matching specifier -`match p1 with p2`, for every matched connection between `p1` +`match p1 with p2`, for every connection between `p1` and another component, there must be a corresponding connection between that other component and `p2`. @@ -712,16 +710,102 @@ For example, you may not connect `p1[0]` to another component and `p2[1]` to the same component, because this connection forces a mismatch. +. Duplicate connections at the same port number of `p1` or +`p2` are not allowed, even if `p1` or `p2` are input ports. + If you violate these rules, you will get an error during analysis. +You can relax these rules by writing unmatched connections, +as described below. + +*Unmatched connections:* +Occasionally you may need to relax the rules for using matched ports. +For example, you may need to match pairs of connections that use +the F Prime hub pattern to cross a network boundary. +In this case, although the connections are logically matched +at the endpoints, they all go through a single hub instance +on the side of the boundary that has the matched ports, and so they do not obey the +simple rules for matching given here. + +When a connection goes to or from a matched port, +we say that it is *match constrained*. +Ordinarily a match constrained connection must obey the +rules for matching stated above. +To relax the rules, you can write an *unmatched* connection. +To do this, write the keyword `unmatched` at the start of the connection +specifier. +Here is an example: + +[source,fpp] +-------- +Port P + +passive component Source { + sync input port pIn: [2] P + output port pOut: [2] P + + match pOut with pIn +} + +passive component Target { + sync input port pIn: [2] P + output port pOut: [2] P +} + +instance source: Source base id 0x100 +instance target: Target base id 0x200 + +topology T { + + instance source + instance target + + connections C { + unmatched source.pOut[0] -> target.pIn[0] + unmatched target.pOut[0] -> source.pIn[0] + unmatched source.pOut[1] -> target.pIn[1] + unmatched target.pOut[1] -> source.pIn[1] + } + +} +-------- + +In this example, there are two pairs of connections between the +`pIn` and `pOut` connections of the instances `source` and `target`. +The ports of `source` are match constrained, so ordinarily +the connections would need to obey the matching rules. +The connections do partially obey the rules: for example, +there are no duplicate numbers, and the numbers match. +However, both pairs of connections go to and from the same +instance `target`; ordinarily this is not allowed for +match constrained connections. +To allow it, we need to use unmatched ports as shown. + +Note the following about using unmatched ports: + +. When connections are marked `unmatched`, the analyzer cannot check that the +port numbers assigned to the connections conform to any particular pattern. +If you need the port numbers to follow a pattern, as in the example shown +above, then you must use explicit numbering. +For a suggestion on how to do this, see the discussion of manual matching +below. + +. Unmatched ports must still obey the rule that distinct +connections at a matched port must have distinct port numbers. + +. The `unmatched` keyword is allowed only for connections that +are match constrained, i.e., that go to or from a matched port. +If you try to write an unmatched connection and the connection +is not match constrained, then you will get an error. *Manual matching:* -Automatic matched numbering works when each matched pair of connections +Port matching specifiers work well when each matched pair of connections goes between the same two components, one of which has a matched pair of ports. If the matching does not follow this pattern, then automatic matched -numbering will not work, and you will need to use explicit port -numbers to express the matching. +numbering will not work, and it is usually better not to +use a port matching specifier at all. +Instead, you can use explicit port numbers to express the matching. For example, the Ref topology contains these connections: [source,fpp] @@ -741,75 +825,6 @@ component instances, we can't used automatic matched numbering. Instead we define a symbolic constant `Ports.StaticMemory.uplink` and use that twice to do the matching by hand. -*Unmatched connections:* -Unmatched connections can be used in a topology to bypass match -constraints that are specified in component definitions. Doing so -allows you to skip port matching requirements without receiving an -error if a match constraint is violated. - -To specify that a connection is unmatched, start the connection -with the `unmatched` keyword. - -[source,fpp] --------- -unmatched c1.pOut -> c2.pIn --------- - -Note that unmatched connections are only allowed when a match -constraint has been specified. In the below example, unmatched -connections would not be valid since neither ports `pIn` or `pOut` -are match constrained. - -[source,fpp] --------- -Port P - -passive component C { - sync input port pIn: [3] P - output port pOut: [3] P -} --------- - -Below is a valid example for using unmatched connections: - -[source,fpp] --------- -Port P - -passive component C { - sync input port pIn: [3] P - output port pOut: [3] P - - match pOut with pIn -} - -instance c1: C base id 0x100 -instance c2: C base id 0x200 - -topology T { - - @ This specifier says that instance c1 is part of the topology - instance c1 - @ This specifier says that instance c2 is part of the topology - instance c2 - - @ This code specifies a connection graph C1 - connections C1 { - unmatched c1.pOut[0] -> c2.pIn[0] - unmatched c1.pOut[1] -> c2.pIn[1] - } - -} --------- - -This example consists of a component `C` with ports `pOut` and `pIn` -that are match constrained by the matching specifier `match pOut with pIn`. -In addition, The topology `T` contains two unmatched connections that go -from `c1.pOut[0]` to `c2.pIn[0]` and from `c1.pOut[1]` to `c2.pIn[1]`. -Since `pOut` and `pIn` are match constrained, the unmatched keyword can be used -to mark the connection as unmatched and bypass the port matching requirement. - - ==== General Numbering After resolving From b1f68c85e6e7d60579ec5ffa7194146e9c69dc09 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Wed, 30 Oct 2024 13:29:03 -0700 Subject: [PATCH 73/73] Update spec (#525) --- docs/fpp-spec.html | 5 ++++- docs/spec/Specifiers/Connection-Graph-Specifiers.adoc | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/fpp-spec.html b/docs/fpp-spec.html index c5e4c04de..11f9486f9 100644 --- a/docs/fpp-spec.html +++ b/docs/fpp-spec.html @@ -5237,6 +5237,9 @@

    7.3.1. Syntax

    telemetry

  • +

    text event

    +
  • +
  • time

  • @@ -10577,7 +10580,7 @@

    22.4. Translation Tools

    diff --git a/docs/spec/Specifiers/Connection-Graph-Specifiers.adoc b/docs/spec/Specifiers/Connection-Graph-Specifiers.adoc index 42473fd0d..75bb71b8a 100644 --- a/docs/spec/Specifiers/Connection-Graph-Specifiers.adoc +++ b/docs/spec/Specifiers/Connection-Graph-Specifiers.adoc @@ -63,6 +63,8 @@ _pattern-kind_ is one of the following: . `telemetry` +. `text` `event` + . `time` _instance-sequence_ is an