This commit is contained in:
jawest 2024-09-16 08:55:59 -07:00
parent d3c3de33a8
commit ed4e051a19
9 changed files with 33 additions and 76 deletions

View File

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

View File

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

View File

@ -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](

View File

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

View File

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

View File

@ -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",

View File

@ -129,7 +129,7 @@ object TopologyXmlFppWriter extends LineUtils {
}
yield {
Ast.SpecConnectionGraph.Connection(
Ast.ConnectionMatching.PossiblyMatched,
false,
from._1,
from._2,
to._1,

View File

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

View File

@ -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.