diff --git a/compiler/install b/compiler/install index 88e272216..0ca968e22 100755 --- a/compiler/install +++ b/compiler/install @@ -25,6 +25,8 @@ fi wd=`dirname $0` cd $wd +top=`pwd` +meta=$top/lib/src/main/resources/META-INF/native-image dir=`dirname $dest` dir=`cd $dir; pwd` @@ -67,7 +69,8 @@ do echo " $jar" cp $jar $dest/$tool.jar echo '#!/bin/sh - - java -jar '$dest'/'$tool'.jar "$@"' > $dest/$tool + # See https://www.graalvm.org/22.1/reference-manual/native-image/Agent/ + #java -agentlib:native-image-agent=config-merge-dir='$meta' -jar '$dest'/'$tool'.jar "$@"' > $dest/$tool + java -jar "`dirname $0`/'$tool'.jar" "$@"' > $dest/$tool chmod +x $dest/$tool done diff --git a/compiler/lib/src/main/resources/META-INF/native-image/reflect-config.json b/compiler/lib/src/main/resources/META-INF/native-image/reflect-config.json index f5d93467b..6404a8b36 100644 --- a/compiler/lib/src/main/resources/META-INF/native-image/reflect-config.json +++ b/compiler/lib/src/main/resources/META-INF/native-image/reflect-config.json @@ -1,4 +1,29 @@ [ +{ + "name":"com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"fpp.compiler.analysis.ComponentInstance[]" +}, +{ + "name":"fpp.compiler.analysis.Connection[]" +}, +{ + "name":"fpp.compiler.analysis.Format$Parser$", + "fields":[{"name":"0bitmap$1", "allowUnsafeAccess":true}] +}, +{ + "name":"fpp.compiler.codegen.CppDocCppWriter$", + "fields":[{"name":"0bitmap$1", "allowUnsafeAccess":true}] +}, +{ + "name":"fpp.compiler.codegen.CppDocHppWriter$", + "fields":[{"name":"0bitmap$1", "allowUnsafeAccess":true}] +}, +{ + "name":"fpp.compiler.codegen.Line[]" +}, { "name":"fpp.compiler.syntax.Lexer$", "fields":[{"name":"0bitmap$2", "allowUnsafeAccess":true}] @@ -14,6 +39,9 @@ { "name":"java.lang.ClassValue" }, +{ + "name":"java.lang.String[]" +}, { "name":"java.lang.invoke.VarHandle", "methods":[{"name":"releaseFence","parameterTypes":[] }] @@ -26,6 +54,14 @@ "name":"scala.util.parsing.input.OffsetPosition$", "fields":[{"name":"0bitmap$2", "allowUnsafeAccess":true}] }, +{ + "name":"scala.xml.XML$", + "fields":[{"name":"0bitmap$2", "allowUnsafeAccess":true}] +}, +{ + "name":"scala.xml.parsing.FactoryAdapter", + "fields":[{"name":"0bitmap$1", "allowUnsafeAccess":true}] +}, { "name":"scopt.OParser$", "fields":[{"name":"0bitmap$1", "allowUnsafeAccess":true}] diff --git a/compiler/lib/src/main/resources/META-INF/native-image/resource-config.json b/compiler/lib/src/main/resources/META-INF/native-image/resource-config.json index 791ea0f4c..8d7333115 100644 --- a/compiler/lib/src/main/resources/META-INF/native-image/resource-config.json +++ b/compiler/lib/src/main/resources/META-INF/native-image/resource-config.json @@ -1,5 +1,5 @@ { "resources":{ "includes":[]}, - "bundles":[] + "bundles":[{"name":"com.sun.org.apache.xerces.internal.impl.msg.XMLMessages"}] } diff --git a/compiler/lib/src/main/scala/ast/Ast.scala b/compiler/lib/src/main/scala/ast/Ast.scala index abce40491..430578357 100644 --- a/compiler/lib/src/main/scala/ast/Ast.scala +++ b/compiler/lib/src/main/scala/ast/Ast.scala @@ -90,6 +90,7 @@ object Ast { name: Ident, component: AstNode[QualIdent], baseId: AstNode[Expr], + implType: Option[AstNode[String]], file: Option[AstNode[String]], queueSize: Option[AstNode[Expr]], stackSize: Option[AstNode[Expr]], diff --git a/compiler/lib/src/main/scala/codegen/AstWriter.scala b/compiler/lib/src/main/scala/codegen/AstWriter.scala index c7843c101..c69971ac7 100644 --- a/compiler/lib/src/main/scala/codegen/AstWriter.scala +++ b/compiler/lib/src/main/scala/codegen/AstWriter.scala @@ -62,6 +62,7 @@ object AstWriter extends AstVisitor with LineUtils { ident(data.name), addPrefix("component", qualIdent) (data.component.data), addPrefix("base id", exprNode) (data.baseId), + linesOpt(addPrefix("type", applyToData(string)), data.implType), linesOpt(applyToData(fileString), data.file), linesOpt(addPrefix("queue size", exprNode), data.queueSize), linesOpt(addPrefix("stack size", exprNode), data.stackSize), diff --git a/compiler/lib/src/main/scala/codegen/CppWriter/TopologyCppWriter/TopComponentInstances.scala b/compiler/lib/src/main/scala/codegen/CppWriter/TopologyCppWriter/TopComponentInstances.scala index eae205e1d..7256e12f5 100644 --- a/compiler/lib/src/main/scala/codegen/CppWriter/TopologyCppWriter/TopComponentInstances.scala +++ b/compiler/lib/src/main/scala/codegen/CppWriter/TopologyCppWriter/TopComponentInstances.scala @@ -10,26 +10,47 @@ case class TopComponentInstances( aNode: Ast.Annotated[AstNode[Ast.DefTopology]] ) extends TopologyCppWriterUtils(s, aNode) { - def getLines: List[Line] = { - addBannerComment( - "Component instances", - getComponentInstanceLines - ) + private val bannerComment = "Component instances" + + def getHppLines: List[Line] = addBannerComment( + bannerComment, + getDeclLines + ) + + def getCppLines: List[Line] = addBannerComment( + bannerComment, + getDefLines + ) + + private def getDeclLines = { + def getCode(ci: ComponentInstance): List[Line] = { + val implType = getImplType(ci) + val instanceName = getNameAsIdent(ci.qualifiedName) + Line.addPrefixLine (line(s"//! $instanceName")) ( + lines( + s"extern $implType $instanceName;" + ) + ) + } + flattenWithBlankPrefix(instances.map(getCode)) } - private def getComponentInstanceLines: List[Line] = { + private def getDefLines = { def getCode(ci: ComponentInstance): List[Line] = { - val componentName = getComponentNameAsQualIdent(ci) + val implType = getImplType(ci) val instanceName = getNameAsIdent(ci.qualifiedName) - Line.addPrefixLine (line(s"// $instanceName")) ( - getCodeLinesForPhase (CppWriter.Phases.instances) (ci).getOrElse( - lines( - s"$componentName $instanceName(FW_OPTIONAL_NAME($q$instanceName$q));" - ) + getCodeLinesForPhase (CppWriter.Phases.instances) (ci).getOrElse( + lines( + s"$implType $instanceName(FW_OPTIONAL_NAME($q$instanceName$q));" ) ) } flattenWithBlankPrefix(instances.map(getCode)) } + private def getImplType(ci: ComponentInstance) = { + val implType = ci.aNode._2.data.implType.map(_.data) + implType.getOrElse(getComponentNameAsQualIdent(ci)) + } + } diff --git a/compiler/lib/src/main/scala/codegen/CppWriter/TopologyCppWriter/TopConfigObjects.scala b/compiler/lib/src/main/scala/codegen/CppWriter/TopologyCppWriter/TopConfigObjects.scala index 6ab4f4aa4..1dff3f100 100644 --- a/compiler/lib/src/main/scala/codegen/CppWriter/TopologyCppWriter/TopConfigObjects.scala +++ b/compiler/lib/src/main/scala/codegen/CppWriter/TopologyCppWriter/TopConfigObjects.scala @@ -102,7 +102,7 @@ case class TopConfigObjects( } val (map, maxNum) = mapAndMaxNum wrapInScope( - "Svc::HealthImpl::PingEntry pingEntries[] = {", + "Svc::Health::PingEntry pingEntries[] = {", // Loop over all ports in the range 0..maxNum. // Entries are positional, so we must generate code // for any unconnected entries in this range. diff --git a/compiler/lib/src/main/scala/codegen/CppWriter/TopologyCppWriter/TopPrivateFunctions.scala b/compiler/lib/src/main/scala/codegen/CppWriter/TopologyCppWriter/TopHelperFns.scala similarity index 59% rename from compiler/lib/src/main/scala/codegen/CppWriter/TopologyCppWriter/TopPrivateFunctions.scala rename to compiler/lib/src/main/scala/codegen/CppWriter/TopologyCppWriter/TopHelperFns.scala index 7e7c58c0a..c327b186e 100644 --- a/compiler/lib/src/main/scala/codegen/CppWriter/TopologyCppWriter/TopPrivateFunctions.scala +++ b/compiler/lib/src/main/scala/codegen/CppWriter/TopologyCppWriter/TopHelperFns.scala @@ -4,43 +4,52 @@ import fpp.compiler.analysis._ import fpp.compiler.ast._ import fpp.compiler.util._ -/** Writes out C++ for topology private functions */ -case class TopPrivateFunctions( +/** Writes out C++ for topology helper functions */ +case class TopHelperFns( s: CppWriterState, aNode: Ast.Annotated[AstNode[Ast.DefTopology]] ) extends TopologyCppWriterUtils(s, aNode) { /** Compute the set of defined function names and the list - * of lines defining the functions */ - def getLines: (Set[String], List[Line]) = { - // Get pairs of (function name, function lines) + * of CppDoc members defining the functions */ + def getMembers: (Set[String], List[CppDoc.Member]) = { + // Get pairs of (function name, function member) val pairs = List( - getInitComponentsLines, - getConfigComponentsLines, - getSetBaseIdsLines, - getConnectComponentsLines, - getRegCommandsLines, - getReadParametersLines, - getLoadParametersLines, - getStartTasksLines, - getStopTasksLines, - getFreeThreadsLines, - getTearDownComponentsLines, + getInitComponentsFn, + getConfigComponentsFn, + getSetBaseIdsFn, + getConnectComponentsFn, + getRegCommandsFn, + getReadParametersFn, + getLoadParametersFn, + getStartTasksFn, + getStopTasksFn, + getFreeThreadsFn, + getTearDownComponentsFn, ) // Compute the set of names with nonempty lines - val fns = pairs.foldLeft (Set[String]()) { - case (set, (_, Nil)) => set + val fnNames = pairs.foldLeft (Set[String]()) { + case (set, (_, None)) => set case (set, (name, _)) => set + name } - // Extract the lines - val ll = addBannerComment( - "Private functions", - pairs.map(_._2).flatten - ) - (fns, ll) + // Add the banner comment + val fnMembers = pairs.map(_._2).filter(_.isDefined).map(_.get) + val members = fnMembers match { + case Nil => Nil + case _ => getBannerComment :: fnMembers + } + (fnNames, members) } - private def getInitComponentsLines: (String, List[Line]) = { + private val stateParams = List( + CppDoc.Function.Param( + CppDoc.Type("const TopologyState&"), + "state", + Some("The topology state") + ) + ) + + private def getInitComponentsFn = { def getCode(ci: ComponentInstance): List[Line] = { val name = getNameAsIdent(ci.qualifiedName) getCodeLinesForPhase (CppWriter.Phases.initComponents) (ci).getOrElse( @@ -53,51 +62,46 @@ case class TopPrivateFunctions( ) } val name = "initComponents" - val ll = addComment( + val memberOpt = getFnMemberOpt( "Initialize components", - wrapInScope( - s"void $name(const TopologyState& state) {", - instances.flatMap(getCode), - "}" - ) + name, + stateParams, + instances.flatMap(getCode) ) - (name, ll) + (name, memberOpt) } - private def getConfigComponentsLines: (String, List[Line]) = { + private def getConfigComponentsFn = { def getCode(ci: ComponentInstance): List[Line] = { val name = getNameAsIdent(ci.qualifiedName) getCodeLinesForPhase (CppWriter.Phases.configComponents) (ci).getOrElse(Nil) } val name = "configComponents" - val ll = addComment( + val memberOpt = getFnMemberOpt( "Configure components", - wrapInScope( - s"void $name(const TopologyState& state) {", - instances.flatMap(getCode), - "}" - ) + name, + stateParams, + instances.flatMap(getCode) ) - (name, ll) + (name, memberOpt) } - private def getSetBaseIdsLines: (String, List[Line]) = { + private def getSetBaseIdsFn = { val name = "setBaseIds" - val ll = addComment( + val body = instancesByBaseId.map(ci => { + val name = getNameAsIdent(ci.qualifiedName) + line(s"$name.setIdBase(BaseIds::$name);") + }) + val memberOpt = getFnMemberOpt( "Set component base Ids", - wrapInScope( - s"void $name() {", - instancesByBaseId.map(ci => { - val name = getNameAsIdent(ci.qualifiedName) - line(s"$name.setIdBase(BaseIds::$name);") - }), - "}" - ) + name, + Nil, + body ) - (name, ll) + (name, memberOpt) } - private def getConnectComponentsLines: (String, List[Line]) = { + private def getConnectComponentsFn = { def getPortInfo(pii: PortInstanceIdentifier, c: Connection) = { val instanceName = getNameAsIdent(pii.componentInstance.qualifiedName) val portName = pii.portInstance.getUnqualifiedName @@ -117,25 +121,22 @@ case class TopPrivateFunctions( ) } val name = "connectComponents" - val ll = addComment( - "Connect components", - wrapInScope( - s"void $name() {", - addBlankPostfix( - t.connectionMap.toList.sortWith(_._1 < _._1).flatMap { - case (name, cs) => addComment( - name, - t.sortConnections(cs).flatMap(writeConnection).toList - ) - } - ), - "}" + val body = t.connectionMap.toList.sortWith(_._1 < _._1).flatMap { + case (name, cs) => addComment( + name, + t.sortConnections(cs).flatMap(writeConnection).toList ) + } + val memberOpt = getFnMemberOpt( + "Connect components", + name, + Nil, + body ) - (name, ll) + (name, memberOpt) } - private def getRegCommandsLines: (String, List[Line]) = { + private def getRegCommandsFn = { def getCode(ci: ComponentInstance): List[Line] = { getCodeLinesForPhase (CppWriter.Phases.regCommands) (ci).getOrElse( if (hasCommands(ci)) { @@ -146,33 +147,29 @@ case class TopPrivateFunctions( ) } val name = "regCommands" - val ll = addComment( + val memberOpt = getFnMemberOpt( "Register commands", - wrapInScope( - s"void $name() {", - instances.flatMap(getCode), - "}" - ) + name, + Nil, + instances.flatMap(getCode) ) - (name, ll) + (name, memberOpt) } - private def getReadParametersLines: (String, List[Line]) = { + private def getReadParametersFn = { def getCode(ci: ComponentInstance): List[Line] = getCodeLinesForPhase (CppWriter.Phases.readParameters) (ci).getOrElse(Nil) val name = "readParameters" - val ll = addComment( + val memberOpt = getFnMemberOpt( "Read parameters", - wrapInScope( - s"void $name() {", - instances.flatMap(getCode), - "}" - ) + name, + Nil, + instances.flatMap(getCode) ) - (name, ll) + (name, memberOpt) } - private def getLoadParametersLines: (String, List[Line]) = { + private def getLoadParametersFn = { def getCode(ci: ComponentInstance): List[Line] = { getCodeLinesForPhase (CppWriter.Phases.loadParameters) (ci).getOrElse( if (hasParams(ci)) { @@ -183,18 +180,16 @@ case class TopPrivateFunctions( ) } val name = "loadParameters" - val ll = addComment( + val memberOpt = getFnMemberOpt( "Load parameters", - wrapInScope( - s"void $name() {", - instances.flatMap(getCode), - "}" - ) + name, + Nil, + instances.flatMap(getCode) ) - (name, ll) + (name, memberOpt) } - private def getStartTasksLines: (String, List[Line]) = { + private def getStartTasksFn = { def getCode(ci: ComponentInstance): List[Line] = getCodeLinesForPhase (CppWriter.Phases.startTasks) (ci).getOrElse { if (isActive(ci)) { @@ -227,18 +222,16 @@ case class TopPrivateFunctions( else Nil } val name = "startTasks" - val ll = addComment( + val memberOpt = getFnMemberOpt( "Start tasks", - wrapInScope( - s"void $name(const TopologyState& state) {", - instances.flatMap(getCode), - "}" - ) + name, + stateParams, + instances.flatMap(getCode) ) - (name, ll) + (name, memberOpt) } - private def getStopTasksLines: (String, List[Line]) = { + private def getStopTasksFn = { def getCode(ci: ComponentInstance): List[Line] = getCodeLinesForPhase (CppWriter.Phases.stopTasks) (ci).getOrElse { if (isActive(ci)) { @@ -248,18 +241,16 @@ case class TopPrivateFunctions( else Nil } val name = "stopTasks" - val ll = addComment( + val memberOpt = getFnMemberOpt( "Stop tasks", - wrapInScope( - "void stopTasks(const TopologyState& state) {", - instances.flatMap(getCode), - "}" - ) + name, + stateParams, + instances.flatMap(getCode) ) - (name, ll) + (name, memberOpt) } - private def getFreeThreadsLines: (String, List[Line]) = { + private def getFreeThreadsFn = { def getCode(ci: ComponentInstance): List[Line] = getCodeLinesForPhase (CppWriter.Phases.freeThreads) (ci).getOrElse { if (isActive(ci)) { @@ -269,32 +260,55 @@ case class TopPrivateFunctions( else Nil } val name = "freeThreads" - val ll = addComment( + val memberOpt = getFnMemberOpt( "Free threads", - wrapInScope( - s"void $name(const TopologyState& state) {", - instances.flatMap(getCode), - "}" - ) + name, + stateParams, + instances.flatMap(getCode) ) - (name, ll) + (name, memberOpt) } - private def getTearDownComponentsLines: (String, List[Line]) = { + private def getTearDownComponentsFn = { def getCode(ci: ComponentInstance): List[Line] = { val name = getNameAsIdent(ci.qualifiedName) getCodeLinesForPhase (CppWriter.Phases.tearDownComponents) (ci).getOrElse(Nil) } val name = "tearDownComponents" - val ll = addComment( + val memberOpt = getFnMemberOpt( "Tear down components", - wrapInScope( - s"void $name(const TopologyState& state) {", - instances.flatMap(getCode), - "}" + name, + stateParams, + instances.flatMap(getCode) + ) + (name, memberOpt) + } + + private def getFnMemberOpt( + comment: String, + name: String, + params: List[CppDoc.Function.Param], + body: List[Line] + ) = body match { + case Nil => None + case ll => Some( + CppDoc.Member.Function( + CppDoc.Function( + Some(comment), + name, + params, + CppDoc.Type("void"), + ll + ) ) ) - (name, ll) } + private def getBannerComment = CppDoc.Member.Lines( + CppDoc.Lines( + CppDocWriter.writeBannerComment("Helper functions"), + CppDoc.Lines.Both + ) + ) + } diff --git a/compiler/lib/src/main/scala/codegen/CppWriter/TopologyCppWriter/TopPublicFunctions.scala b/compiler/lib/src/main/scala/codegen/CppWriter/TopologyCppWriter/TopSetupTeardownFns.scala similarity index 85% rename from compiler/lib/src/main/scala/codegen/CppWriter/TopologyCppWriter/TopPublicFunctions.scala rename to compiler/lib/src/main/scala/codegen/CppWriter/TopologyCppWriter/TopSetupTeardownFns.scala index ea4029b35..38fee5a6e 100644 --- a/compiler/lib/src/main/scala/codegen/CppWriter/TopologyCppWriter/TopPublicFunctions.scala +++ b/compiler/lib/src/main/scala/codegen/CppWriter/TopologyCppWriter/TopSetupTeardownFns.scala @@ -4,11 +4,11 @@ import fpp.compiler.analysis._ import fpp.compiler.ast._ import fpp.compiler.util._ -/** Writes out C++ for topology public functions */ -case class TopPublicFunctions( +/** Writes out C++ for setup and teardown functions */ +case class TopSetupTeardownFns( s: CppWriterState, aNode: Ast.Annotated[AstNode[Ast.DefTopology]], - privateFns: Set[String] + helperFnNames: Set[String] /** The names of the generated helper functions */ ) extends TopologyCppWriterUtils(s, aNode) { def getMembers: List[CppDoc.Member] = List( @@ -27,14 +27,14 @@ case class TopPublicFunctions( private def getBannerComment = CppDoc.Member.Lines( CppDoc.Lines( - CppDocWriter.writeBannerComment("Public interface functions"), + CppDocWriter.writeBannerComment("Setup and teardown functions"), CppDoc.Lines.Both ) ) private def writeFnCall(pair: (String, String)): List[Line] = { val (name, argument) = pair - if (privateFns.contains(name)) + if (helperFnNames.contains(name)) lines(s"$name($argument);") else Nil } diff --git a/compiler/lib/src/main/scala/codegen/CppWriter/TopologyCppWriter/TopologyCppWriter.scala b/compiler/lib/src/main/scala/codegen/CppWriter/TopologyCppWriter/TopologyCppWriter.scala index 78a8a7537..79514a9e6 100644 --- a/compiler/lib/src/main/scala/codegen/CppWriter/TopologyCppWriter/TopologyCppWriter.scala +++ b/compiler/lib/src/main/scala/codegen/CppWriter/TopologyCppWriter/TopologyCppWriter.scala @@ -34,7 +34,8 @@ case class TopologyCppWriter( CppWriter.linesMember(Line.blank :: strings.map(line)) } val hppLines = CppWriter.linesMember( - TopConstants(s, aNode).getLines + TopConstants(s, aNode).getLines ++ + TopComponentInstances(s, aNode).getHppLines ) val cppIncludes = { val fileName = s"${ComputeCppFiles.FileNames.getTopology(name)}.hpp" @@ -46,22 +47,22 @@ case class TopologyCppWriter( CppDoc.Lines.Cpp ) } - val (privateFns, privateFnLines) = TopPrivateFunctions(s, aNode).getLines val cppLines = CppWriter.linesMember( Line.blank :: - wrapInAnonymousNamespace( - addBlankPostfix( - List( + List( + wrapInAnonymousNamespace( + addBlankPostfix( TopConfigObjects(s, aNode).getLines, - TopComponentInstances(s, aNode).getLines, - privateFnLines - ).flatten - ) - ), + ) + ), + TopComponentInstances(s, aNode).getCppLines + ).flatten, CppDoc.Lines.Cpp ) - val publicFunctions = TopPublicFunctions(s, aNode, privateFns).getMembers - val defs = hppLines :: cppLines :: publicFunctions + val (helperFnNames, helperFns) = TopHelperFns(s, aNode).getMembers + val setupTeardownFns = TopSetupTeardownFns(s, aNode, helperFnNames). + getMembers + val defs = hppLines :: cppLines :: (helperFns ++ setupTeardownFns) List( List(hppIncludes, cppIncludes), CppWriter.wrapInNamespaces(namespaceIdentList, defs) diff --git a/compiler/lib/src/main/scala/codegen/CppWriter/TopologyCppWriter/TopologyCppWriterUtils.scala b/compiler/lib/src/main/scala/codegen/CppWriter/TopologyCppWriter/TopologyCppWriterUtils.scala index 94f370836..e13a86d71 100644 --- a/compiler/lib/src/main/scala/codegen/CppWriter/TopologyCppWriter/TopologyCppWriterUtils.scala +++ b/compiler/lib/src/main/scala/codegen/CppWriter/TopologyCppWriter/TopologyCppWriterUtils.scala @@ -14,7 +14,7 @@ abstract class TopologyCppWriterUtils( val namespaceIdentList: List[String] = s.getNamespaceIdentList(symbol) - val name = aNode._2.data.name + val name: String = aNode._2.data.name val t: Topology = s.a.topologyMap(symbol) @@ -84,10 +84,12 @@ abstract class TopologyCppWriterUtils( def getSpecifierForPhase (phase: Int) (ci: ComponentInstance): Option[InitSpecifier] = ci.initSpecifierMap.get(phase) - def getCodeForPhase (phase: Int)(ci: ComponentInstance): Option[String] = + def getCodeForPhase (phase: Int)(ci: ComponentInstance): + Option[String] = getSpecifierForPhase(phase)(ci).map(is => is.aNode._2.data.code) - def getCodeLinesForPhase (phase: Int) (ci: ComponentInstance): Option[List[Line]] = ( + def getCodeLinesForPhase (phase: Int) (ci: ComponentInstance): + Option[List[Line]] = ( getCodeForPhase (phase) (ci) ).map(lines) diff --git a/compiler/lib/src/main/scala/codegen/FppWriter.scala b/compiler/lib/src/main/scala/codegen/FppWriter.scala index 004ddcde7..9a6608c95 100644 --- a/compiler/lib/src/main/scala/codegen/FppWriter.scala +++ b/compiler/lib/src/main/scala/codegen/FppWriter.scala @@ -113,6 +113,7 @@ object FppWriter extends AstVisitor with LineUtils { lines(s"instance ${ident(data.name)}"). join (": ") (qualIdent(data.component.data)). join (" base id ") (exprNode(data.baseId)). + joinOptWithBreak (data.implType) ("type ") (applyToData(string)). joinOptWithBreak (data.file) ("at ") (applyToData(string)). joinOptWithBreak (data.queueSize) ("queue size ") (exprNode). joinOptWithBreak (data.stackSize) ("stack size ") (exprNode). diff --git a/compiler/lib/src/main/scala/codegen/XmlFppWriter/TopologyXmlFppWriter.scala b/compiler/lib/src/main/scala/codegen/XmlFppWriter/TopologyXmlFppWriter.scala index e0089c933..fa6843ef1 100644 --- a/compiler/lib/src/main/scala/codegen/XmlFppWriter/TopologyXmlFppWriter.scala +++ b/compiler/lib/src/main/scala/codegen/XmlFppWriter/TopologyXmlFppWriter.scala @@ -56,6 +56,7 @@ object TopologyXmlFppWriter extends LineUtils { None, None, None, + None, Nil ), Nil diff --git a/compiler/lib/src/main/scala/syntax/Parser.scala b/compiler/lib/src/main/scala/syntax/Parser.scala index 5b3b273c3..46d49d627 100644 --- a/compiler/lib/src/main/scala/syntax/Parser.scala +++ b/compiler/lib/src/main/scala/syntax/Parser.scala @@ -39,7 +39,7 @@ object Parser extends Parsers { failure("component member expected") } - def componentMembers: Parser[List[Ast.ComponentMember]] = + def componentMembers: Parser[List[Ast.ComponentMember]] = annotatedElementSequence(componentMemberNode, semi, Ast.ComponentMember(_)) def connection: Parser[Ast.SpecConnectionGraph.Connection] = { @@ -48,7 +48,7 @@ object Parser extends Parsers { case (fromPort ~ fromIndex) ~ (toPort ~ toIndex) => { Ast.SpecConnectionGraph.Connection( fromPort, - fromIndex, + fromIndex, toPort, toIndex ) @@ -84,17 +84,19 @@ object Parser extends Parsers { } } (instance ~>! ident) ~! (colon ~>! node(qualIdent)) ~! (base ~! id ~>! exprNode) ~! + opt(typeToken ~>! node(literalString)) ~! opt(at ~>! node(literalString)) ~! opt(queue ~! size ~>! exprNode) ~! opt(stack ~! size ~>! exprNode) ~! opt(priority ~>! exprNode) ~! opt(cpu ~>! exprNode) ~! initSpecSequence ^^ { - case name ~ typeName ~ baseId ~ file ~ queueSize ~ stackSize ~ priority ~ cpu ~ initSpecSequence => + case name ~ typeName ~ baseId ~ implType ~ file ~ queueSize ~ stackSize ~ priority ~ cpu ~ initSpecSequence => Ast.DefComponentInstance( name, typeName, baseId, + implType, file, queueSize, stackSize, @@ -115,7 +117,7 @@ object Parser extends Parsers { def id(x: Ast.Annotated[AstNode[Ast.DefEnumConstant]]) = x def constants = annotatedElementSequence(node(defEnumConstant), comma, id) (enumeration ~>! ident) ~! - opt(colon ~>! node(typeName)) ~! + opt(colon ~>! node(typeName)) ~! (lbrace ~>! constants <~! rbrace) ~! opt(default ~>! exprNode) ^^ { case name ~ typeName ~ constants ~ default => Ast.DefEnum(name, typeName, constants, default) @@ -123,7 +125,7 @@ object Parser extends Parsers { } def defEnumConstant: Parser[Ast.DefEnumConstant] = { - ident ~! opt(equals ~>! exprNode) ^^ { + ident ~! opt(equals ~>! exprNode) ^^ { case id ~ e => Ast.DefEnumConstant(id, e) } } @@ -147,7 +149,7 @@ object Parser extends Parsers { case name ~ members ~ default => Ast.DefStruct(name, members, default) } } - + def defTopology: Parser[Ast.DefTopology] = { (topology ~>! ident) ~! (lbrace ~>! topologyMembers <~! rbrace) ^^ { case name ~ members => Ast.DefTopology(name, members) @@ -173,8 +175,8 @@ object Parser extends Parsers { es.foldLeft(e)(f) } def dotOperand = node { - def arrayExpr = - lbracket ~>! elementSequence(exprNode, comma) <~! rbracket ^^ { + def arrayExpr = + lbracket ~>! elementSequence(exprNode, comma) <~! rbracket ^^ { case es => Ast.ExprArray(es) } def falseExpr = falseToken ^^ { case _ => Ast.ExprLiteralBool(Ast.LiteralBool.False) } @@ -186,7 +188,7 @@ object Parser extends Parsers { def structMember = ident ~! (equals ~>! exprNode) ^^ { case id ~ e => Ast.StructMember(id, e) } - def structExpr = + def structExpr = lbrace ~>! elementSequence(node(structMember), comma) <~! rbrace ^^ { case es => Ast.ExprStruct(es) } @@ -202,7 +204,7 @@ object Parser extends Parsers { trueExpr | failure("expression expected") } - def unaryMinus = node { + def unaryMinus = node { minus ~>! unaryMinusOperand ^^ { case e => Ast.ExprUnop(Ast.Unop.Minus, e) } } def unaryMinusOperand = { @@ -229,7 +231,7 @@ object Parser extends Parsers { def formalParam: Parser[Ast.FormalParam] = { def kind = { - opt(ref) ^^ { + opt(ref) ^^ { case Some(_) => Ast.FormalParam.Ref case None => Ast.FormalParam.Value } @@ -283,7 +285,7 @@ object Parser extends Parsers { def positionedT: Parser[Positioned] = positioned { p ^^ { case x => Positioned(x) } } - positionedT ^^ { + positionedT ^^ { case pt @ Positioned(t) => { val n = AstNode.create(t) val loc = Location(ParserState.file, pt.pos, ParserState.includingLoc) @@ -295,7 +297,7 @@ object Parser extends Parsers { def parseAllInput[T](p: Parser[T]): Parser[T] = new Parser[T] { def apply(in: Input) = { - val r = p(in) + val r = p(in) r match { case s @ Success(out, in1) => error match { @@ -327,7 +329,7 @@ object Parser extends Parsers { } def portInstanceIdentifier: Parser[Ast.PortInstanceIdentifier] = - node(ident) ~! (dot ~>! qualIdentNodeList) ^^ { + node(ident) ~! (dot ~>! qualIdentNodeList) ^^ { case id ~ qid => { val portName :: tail = qid.reverse val componentInstance = id :: tail.reverse @@ -336,7 +338,7 @@ object Parser extends Parsers { } } - def qualIdent: Parser[Ast.QualIdent] = + def qualIdent: Parser[Ast.QualIdent] = qualIdentNodeList ^^ { case qid => Ast.QualIdent.fromNodeList(qid) } def qualIdentNodeList: Parser[Ast.QualIdent.NodeList] = rep1sep(node(ident), dot) @@ -357,21 +359,21 @@ object Parser extends Parsers { } kind ~ (command ~>! ident) ~! formalParamList ~! opt(opcode ~>! exprNode) ~! opt(priority ~>! exprNode) ~! opt(node(queueFull)) ^^ { - case kind ~ name ~ params ~ opcode ~ priority ~ queueFull => + case kind ~ name ~ params ~ opcode ~ priority ~ queueFull => Ast.SpecCommand(kind, name, params, opcode, priority, queueFull) } } def specCompInstance: Parser[Ast.SpecCompInstance] = { - visibility ~ (instance ~>! node(qualIdent)) ^^ { - case visibility ~ instance => Ast.SpecCompInstance(visibility, instance) + visibility ~ (instance ~>! node(qualIdent)) ^^ { + case visibility ~ instance => Ast.SpecCompInstance(visibility, instance) } } def specConnectionGraph: Parser[Ast.SpecConnectionGraph] = { def directGraph = { - (connections ~> ident) ~! (lbrace ~>! elementSequence(connection, comma) <~! rbrace) ^^ { - case ident ~ connections => Ast.SpecConnectionGraph.Direct(ident, connections) + (connections ~> ident) ~! (lbrace ~>! elementSequence(connection, comma) <~! rbrace) ^^ { + case ident ~ connections => Ast.SpecConnectionGraph.Direct(ident, connections) } } def patternGraph = { @@ -416,7 +418,7 @@ object Parser extends Parsers { opt(id ~>! exprNode) ~! (format ~>! node(literalString)) ~! opt(throttle ~>! exprNode) ^^ { - case name ~ params ~ severity ~ id ~ format ~ throttle => + case name ~ params ~ severity ~ id ~ format ~ throttle => Ast.SpecEvent(name, params, severity, id, format, throttle) } } @@ -435,7 +437,7 @@ object Parser extends Parsers { (internal ~! port ~>! ident) ~! formalParamList ~! opt(priority ~>! exprNode) ~! opt(queueFull) ^^ { - case name ~ params ~ priority ~ queueFull => + case name ~ params ~ priority ~ queueFull => Ast.SpecInternalPort(name, params, priority, queueFull) } } @@ -568,7 +570,7 @@ object Parser extends Parsers { failure("topology member expected") } - def topologyMembers: Parser[List[Ast.TopologyMember]] = + def topologyMembers: Parser[List[Ast.TopologyMember]] = annotatedElementSequence(topologyMemberNode, semi, Ast.TopologyMember(_)) def transUnit: Parser[Ast.TransUnit] = { @@ -613,7 +615,7 @@ object Parser extends Parsers { } e } - val r = p(in) + val r = p(in) r match{ case s @ Success(_, _) => s case e : Error => setError(e) @@ -686,7 +688,7 @@ object Parser extends Parsers { private def default = accept("default", { case t : Token.DEFAULT => t }) private def diagnostic = accept("diagnostic", { case t : Token.DIAGNOSTIC => t }) - + private def event = accept("event", { case t : Token.EVENT => t }) private def dot = accept(".", { case t : Token.DOT => t }) @@ -721,14 +723,14 @@ object Parser extends Parsers { private def high = accept("high", { case t : Token.HIGH => t }) private def id = accept("id", { case t : Token.ID => t }) - + private def ident: Parser[Ast.Ident] = accept("identifier", { case Token.IDENTIFIER(s) => s }) private def importToken = accept("import", { case t : Token.IMPORT => t }) private def include = accept("include", { case t : Token.INCLUDE => t }) - + private def input = accept("input", { case t : Token.INPUT => t }) private def instance = accept("instance", { case t : Token.INSTANCE => t }) @@ -742,7 +744,7 @@ object Parser extends Parsers { private def literalFloat: Parser[String] = accept("floating-point literal", { case Token.LITERAL_FLOAT(s) => s }) - private def literalInt: Parser[String] = + private def literalInt: Parser[String] = accept("integer literal", { case Token.LITERAL_INT(s) => s }) private def literalString: Parser[String] = @@ -787,7 +789,7 @@ object Parser extends Parsers { private def queue = accept("queue", { case t : Token.QUEUE => t }) private def queued = accept("queued", { case t : Token.QUEUED => t }) - + private def rarrow = accept("->", { case t : Token.RARROW => t }) private def rbrace = accept("}", { case t : Token.RBRACE => t }) diff --git a/compiler/lib/src/test/scala/syntax/Parser.scala b/compiler/lib/src/test/scala/syntax/Parser.scala index fa05a637d..bdb3fa6a7 100644 --- a/compiler/lib/src/test/scala/syntax/Parser.scala +++ b/compiler/lib/src/test/scala/syntax/Parser.scala @@ -103,11 +103,13 @@ class ParserSpec extends AnyWordSpec { Parser.defComponentInstance, List( "instance i: C base id 0x100", - "instance i: C base id 0x100 queue size 10", - "instance i: C base id 0x100 queue size 10 stack size 1024 ", - "instance i: C base id 0x100 queue size 10 stack size 1024 priority 3", - "instance i: C base id 0x100 queue size 10 stack size 1024 priority 3 { phase 0 \"code\" }", - "instance i: C base id 0x100 queue size 10 stack size 1024 priority 3 cpu 0 { phase 0 \"code\" }", + "instance i: C base id 0x100 type \"T\"", + "instance i: C base id 0x100 type \"T\" at \"file.hpp\"", + "instance i: C base id 0x100 type \"T\" at \"file.hpp\" queue size 10", + "instance i: C base id 0x100 type \"T\" at \"file.hpp\" queue size 10 stack size 1024", + "instance i: C base id 0x100 type \"T\" at \"file.hpp\" queue size 10 stack size 1024 priority 3", + "instance i: C base id 0x100 type \"T\" at \"file.hpp\" queue size 10 stack size 1024 priority 3 cpu 0", + "instance i: C base id 0x100 type \"T\" at \"file.hpp\" queue size 10 stack size 1024 priority 3 cpu 0 { phase 0 \"code\" }", ) ) } diff --git a/compiler/tools/fpp-format/test/include.ref.txt b/compiler/tools/fpp-format/test/include.ref.txt index 1122c99cf..2d0183fd9 100644 --- a/compiler/tools/fpp-format/test/include.ref.txt +++ b/compiler/tools/fpp-format/test/include.ref.txt @@ -92,6 +92,7 @@ module DefinitionsAndSpecifiers { @ Component instance definition instance c2: C2 base id 0x200 \ + type "T" \ at "C2.hpp" \ queue size 100 \ stack size 1024 \ diff --git a/compiler/tools/fpp-format/test/no_include.ref.txt b/compiler/tools/fpp-format/test/no_include.ref.txt index 62791770c..b207007e3 100644 --- a/compiler/tools/fpp-format/test/no_include.ref.txt +++ b/compiler/tools/fpp-format/test/no_include.ref.txt @@ -92,6 +92,7 @@ module DefinitionsAndSpecifiers { @ Component instance definition instance c2: C2 base id 0x200 \ + type "T" \ at "C2.hpp" \ queue size 100 \ stack size 1024 \ diff --git a/compiler/tools/fpp-format/test/run b/compiler/tools/fpp-format/test/run index aa454a957..28e34a609 100755 --- a/compiler/tools/fpp-format/test/run +++ b/compiler/tools/fpp-format/test/run @@ -3,6 +3,7 @@ . ../../../scripts/test-utils.sh fpp_format=../../../bin/fpp-format +fpp_syntax=../../../bin/fpp-syntax compare() { @@ -40,19 +41,19 @@ done > default-tests.sh include() { run_test '-i' syntax include && \ - fpp-syntax include.out.txt + $fpp_syntax include.out.txt } kwd_names() { run_test '' kwd_names && \ - fpp-syntax kwd_names.out.txt + $fpp_syntax kwd_names.out.txt } no_include() { run_test '' syntax no_include && \ - fpp-syntax no_include.out.txt + $fpp_syntax no_include.out.txt } run_suite $tests diff --git a/compiler/tools/fpp-format/test/syntax.fpp b/compiler/tools/fpp-format/test/syntax.fpp index e4775ba5c..ee9e8f603 100644 --- a/compiler/tools/fpp-format/test/syntax.fpp +++ b/compiler/tools/fpp-format/test/syntax.fpp @@ -60,7 +60,7 @@ module DefinitionsAndSpecifiers { @< Simple component instance definition @ Component instance definition - instance c2: C2 base id 0x200 at "C2.hpp" queue size 100 stack size 1024 priority 10 cpu 0 { + instance c2: C2 base id 0x200 type "T" at "C2.hpp" queue size 100 stack size 1024 priority 10 cpu 0 { @ Init specifier phase CONSTRUCTION """ line 1 diff --git a/compiler/tools/fpp-syntax/test/syntax-ast.ref.txt b/compiler/tools/fpp-syntax/test/syntax-ast.ref.txt index 1f675da2b..319d61f8c 100644 --- a/compiler/tools/fpp-syntax/test/syntax-ast.ref.txt +++ b/compiler/tools/fpp-syntax/test/syntax-ast.ref.txt @@ -160,6 +160,7 @@ def module ident c2 component qual ident C2 base id literal int 0x200 + type T file C2.hpp queue size literal int 100 stack size literal int 1024 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 c358adfe3..b57e5a737 100644 --- a/compiler/tools/fpp-syntax/test/syntax-include-ast.ref.txt +++ b/compiler/tools/fpp-syntax/test/syntax-include-ast.ref.txt @@ -160,6 +160,7 @@ def module ident c2 component qual ident C2 base id literal int 0x200 + type T file C2.hpp queue size literal int 100 stack size literal int 1024 diff --git a/compiler/tools/fpp-syntax/test/syntax-stdin.ref.txt b/compiler/tools/fpp-syntax/test/syntax-stdin.ref.txt index c358adfe3..b57e5a737 100644 --- a/compiler/tools/fpp-syntax/test/syntax-stdin.ref.txt +++ b/compiler/tools/fpp-syntax/test/syntax-stdin.ref.txt @@ -160,6 +160,7 @@ def module ident c2 component qual ident C2 base id literal int 0x200 + type T file C2.hpp queue size literal int 100 stack size literal int 1024 diff --git a/compiler/tools/fpp-syntax/test/syntax.fpp b/compiler/tools/fpp-syntax/test/syntax.fpp index e4775ba5c..ee9e8f603 100644 --- a/compiler/tools/fpp-syntax/test/syntax.fpp +++ b/compiler/tools/fpp-syntax/test/syntax.fpp @@ -60,7 +60,7 @@ module DefinitionsAndSpecifiers { @< Simple component instance definition @ Component instance definition - instance c2: C2 base id 0x200 at "C2.hpp" queue size 100 stack size 1024 priority 10 cpu 0 { + instance c2: C2 base id 0x200 type "T" at "C2.hpp" queue size 100 stack size 1024 priority 10 cpu 0 { @ Init specifier phase CONSTRUCTION """ line 1 diff --git a/compiler/tools/fpp-to-cpp/test/top/BasicTopologyAc.ref.cpp b/compiler/tools/fpp-to-cpp/test/top/BasicTopologyAc.ref.cpp index 5b63ca47c..eb61f0bf1 100644 --- a/compiler/tools/fpp-to-cpp/test/top/BasicTopologyAc.ref.cpp +++ b/compiler/tools/fpp-to-cpp/test/top/BasicTopologyAc.ref.cpp @@ -22,109 +22,95 @@ namespace M { } - // ---------------------------------------------------------------------- - // Component instances - // ---------------------------------------------------------------------- + } - // active1 - Active active1(FW_OPTIONAL_NAME("active1")); + // ---------------------------------------------------------------------- + // Component instances + // ---------------------------------------------------------------------- - // active2 - Active active2; + Active active1(FW_OPTIONAL_NAME("active1")); - // active3 - Active active3(FW_OPTIONAL_NAME("active3")); + Active active2; - // passive1 - Passive passive1(FW_OPTIONAL_NAME("passive1")); + Active active3(FW_OPTIONAL_NAME("active3")); - // passive2 - Passive passive2(FW_OPTIONAL_NAME("passive2")); + Passive passive1(FW_OPTIONAL_NAME("passive1")); - // ---------------------------------------------------------------------- - // Private functions - // ---------------------------------------------------------------------- + ConcretePassive passive2(FW_OPTIONAL_NAME("passive2")); - // Initialize components - void initComponents(const TopologyState& state) { - active1.init(QueueSizes::active1, InstanceIds::active1); - active2.initSpecial(); - active3.init(QueueSizes::active3, InstanceIds::active3); - passive1.init(InstanceIds::passive1); - passive2.init(InstanceIds::passive2); - } - - // Configure components - void configComponents(const TopologyState& state) { - active2.config(); - } + // ---------------------------------------------------------------------- + // Helper functions + // ---------------------------------------------------------------------- - // Set component base Ids - void setBaseIds() { - active1.setIdBase(BaseIds::active1); - active2.setIdBase(BaseIds::active2); - active3.setIdBase(BaseIds::active3); - passive1.setIdBase(BaseIds::passive1); - passive2.setIdBase(BaseIds::passive2); - } + void initComponents(const TopologyState& state) { + active1.init(QueueSizes::active1, InstanceIds::active1); + active2.initSpecial(); + active3.init(QueueSizes::active3, InstanceIds::active3); + passive1.init(InstanceIds::passive1); + passive2.init(InstanceIds::passive2); + } - // Connect components - void connectComponents() { + void configComponents(const TopologyState& state) { + active2.config(); + } - // C1 - passive1.set_p_OutputPort( - 0, - active1.get_p_InputPort(0) - ); + void setBaseIds() { + active1.setIdBase(BaseIds::active1); + active2.setIdBase(BaseIds::active2); + active3.setIdBase(BaseIds::active3); + passive1.setIdBase(BaseIds::passive1); + passive2.setIdBase(BaseIds::passive2); + } - // C2 - passive2.set_p_OutputPort( - 0, - active2.get_p_InputPort(0) - ); + void connectComponents() { - } + // C1 + passive1.set_p_OutputPort( + 0, + active1.get_p_InputPort(0) + ); - // Start tasks - void startTasks(const TopologyState& state) { - active1.start( - static_cast(Priorities::active1), - static_cast(StackSizes::active1), - static_cast(CPUs::active1), - static_cast(TaskIds::active1) - ); - active2.startSpecial(); - active3.start( - Os::Task::TASK_DEFAULT, // Default priority - Os::Task::TASK_DEFAULT, // Default stack size - Os::Task::TASK_DEFAULT, // Default CPU - static_cast(TaskIds::active3) - ); - } + // C2 + passive2.set_p_OutputPort( + 0, + active2.get_p_InputPort(0) + ); + } - // Stop tasks - void stopTasks(const TopologyState& state) { - active1.exit(); - active2.stopSpecial(); - active3.exit(); - } + void startTasks(const TopologyState& state) { + active1.start( + static_cast(Priorities::active1), + static_cast(StackSizes::active1), + static_cast(CPUs::active1), + static_cast(TaskIds::active1) + ); + active2.startSpecial(); + active3.start( + Os::Task::TASK_DEFAULT, // Default priority + Os::Task::TASK_DEFAULT, // Default stack size + Os::Task::TASK_DEFAULT, // Default CPU + static_cast(TaskIds::active3) + ); + } - // Free threads - void freeThreads(const TopologyState& state) { - (void) active1.ActiveComponentBase::join(nullptr); - active2.freeSpecial(); - (void) active3.ActiveComponentBase::join(nullptr); - } + void stopTasks(const TopologyState& state) { + active1.exit(); + active2.stopSpecial(); + active3.exit(); + } - // Tear down components - void tearDownComponents(const TopologyState& state) { - active2.tearDown(); - } + void freeThreads(const TopologyState& state) { + (void) active1.ActiveComponentBase::join(nullptr); + active2.freeSpecial(); + (void) active3.ActiveComponentBase::join(nullptr); + } + void tearDownComponents(const TopologyState& state) { + active2.tearDown(); } // ---------------------------------------------------------------------- - // Public interface functions + // Setup and teardown functions // ---------------------------------------------------------------------- void setup(const TopologyState& state) { diff --git a/compiler/tools/fpp-to-cpp/test/top/BasicTopologyAc.ref.hpp b/compiler/tools/fpp-to-cpp/test/top/BasicTopologyAc.ref.hpp index 8d8acd37a..1e32e63b5 100644 --- a/compiler/tools/fpp-to-cpp/test/top/BasicTopologyAc.ref.hpp +++ b/compiler/tools/fpp-to-cpp/test/top/BasicTopologyAc.ref.hpp @@ -81,7 +81,66 @@ namespace M { } // ---------------------------------------------------------------------- - // Public interface functions + // Component instances + // ---------------------------------------------------------------------- + + //! active1 + extern Active active1; + + //! active2 + extern Active active2; + + //! active3 + extern Active active3; + + //! passive1 + extern Passive passive1; + + //! passive2 + extern ConcretePassive passive2; + + // ---------------------------------------------------------------------- + // Helper functions + // ---------------------------------------------------------------------- + + //! Initialize components + void initComponents( + const TopologyState& state //!< The topology state + ); + + //! Configure components + void configComponents( + const TopologyState& state //!< The topology state + ); + + //! Set component base Ids + void setBaseIds(); + + //! Connect components + void connectComponents(); + + //! Start tasks + void startTasks( + const TopologyState& state //!< The topology state + ); + + //! Stop tasks + void stopTasks( + const TopologyState& state //!< The topology state + ); + + //! Free threads + void freeThreads( + const TopologyState& state //!< The topology state + ); + + //! Tear down components + void tearDownComponents( + const TopologyState& state //!< The topology state + ); + + // ---------------------------------------------------------------------- + // Setup and teardown functions // ---------------------------------------------------------------------- //! Set up the topology diff --git a/compiler/tools/fpp-to-cpp/test/top/CommandsTopologyAc.ref.cpp b/compiler/tools/fpp-to-cpp/test/top/CommandsTopologyAc.ref.cpp index 32af51e97..3d7e3f0f4 100644 --- a/compiler/tools/fpp-to-cpp/test/top/CommandsTopologyAc.ref.cpp +++ b/compiler/tools/fpp-to-cpp/test/top/CommandsTopologyAc.ref.cpp @@ -8,44 +8,36 @@ namespace M { - namespace { - // ---------------------------------------------------------------------- - // Component instances - // ---------------------------------------------------------------------- - - // c1 - C c1(FW_OPTIONAL_NAME("c1")); + // ---------------------------------------------------------------------- + // Component instances + // ---------------------------------------------------------------------- - // c2 - C c2(FW_OPTIONAL_NAME("c2")); + C c1(FW_OPTIONAL_NAME("c1")); - // ---------------------------------------------------------------------- - // Private functions - // ---------------------------------------------------------------------- + C c2(FW_OPTIONAL_NAME("c2")); - // Initialize components - void initComponents(const TopologyState& state) { - c1.init(InstanceIds::c1); - c2.init(InstanceIds::c2); - } + // ---------------------------------------------------------------------- + // Helper functions + // ---------------------------------------------------------------------- - // Set component base Ids - void setBaseIds() { - c1.setIdBase(BaseIds::c1); - c2.setIdBase(BaseIds::c2); - } + void initComponents(const TopologyState& state) { + c1.init(InstanceIds::c1); + c2.init(InstanceIds::c2); + } - // Register commands - void regCommands() { - c1.regCommandsSpecial(); - c2.regCommands(); - } + void setBaseIds() { + c1.setIdBase(BaseIds::c1); + c2.setIdBase(BaseIds::c2); + } + void regCommands() { + c1.regCommandsSpecial(); + c2.regCommands(); } // ---------------------------------------------------------------------- - // Public interface functions + // Setup and teardown functions // ---------------------------------------------------------------------- void setup(const TopologyState& state) { diff --git a/compiler/tools/fpp-to-cpp/test/top/CommandsTopologyAc.ref.hpp b/compiler/tools/fpp-to-cpp/test/top/CommandsTopologyAc.ref.hpp index e685f678a..e8d779a24 100644 --- a/compiler/tools/fpp-to-cpp/test/top/CommandsTopologyAc.ref.hpp +++ b/compiler/tools/fpp-to-cpp/test/top/CommandsTopologyAc.ref.hpp @@ -31,7 +31,32 @@ namespace M { } // ---------------------------------------------------------------------- - // Public interface functions + // Component instances + // ---------------------------------------------------------------------- + + //! c1 + extern C c1; + + //! c2 + extern C c2; + + // ---------------------------------------------------------------------- + // Helper functions + // ---------------------------------------------------------------------- + + //! Initialize components + void initComponents( + const TopologyState& state //!< The topology state + ); + + //! Set component base Ids + void setBaseIds(); + + //! Register commands + void regCommands(); + + // ---------------------------------------------------------------------- + // Setup and teardown functions // ---------------------------------------------------------------------- //! Set up the topology diff --git a/compiler/tools/fpp-to-cpp/test/top/HealthTopologyAc.ref.cpp b/compiler/tools/fpp-to-cpp/test/top/HealthTopologyAc.ref.cpp index 4d430e102..4e3c60648 100644 --- a/compiler/tools/fpp-to-cpp/test/top/HealthTopologyAc.ref.cpp +++ b/compiler/tools/fpp-to-cpp/test/top/HealthTopologyAc.ref.cpp @@ -17,7 +17,7 @@ namespace M { namespace ConfigObjects { namespace health { - Svc::HealthImpl::PingEntry pingEntries[] = { + Svc::Health::PingEntry pingEntries[] = { { PingEntries::c1::WARN, PingEntries::c1::FATAL, @@ -33,64 +33,57 @@ namespace M { } - // ---------------------------------------------------------------------- - // Component instances - // ---------------------------------------------------------------------- + } - // c1 - C c1(FW_OPTIONAL_NAME("c1")); + // ---------------------------------------------------------------------- + // Component instances + // ---------------------------------------------------------------------- - // c2 - C c2(FW_OPTIONAL_NAME("c2")); + C c1(FW_OPTIONAL_NAME("c1")); - // health - Svc::HealthImpl health(FW_OPTIONAL_NAME("health")); + C c2(FW_OPTIONAL_NAME("c2")); - // ---------------------------------------------------------------------- - // Private functions - // ---------------------------------------------------------------------- + Svc::Health health(FW_OPTIONAL_NAME("health")); - // Initialize components - void initComponents(const TopologyState& state) { - c1.init(InstanceIds::c1); - c2.init(InstanceIds::c2); - health.init(InstanceIds::health); - } - - // Set component base Ids - void setBaseIds() { - health.setIdBase(BaseIds::health); - c1.setIdBase(BaseIds::c1); - c2.setIdBase(BaseIds::c2); - } + // ---------------------------------------------------------------------- + // Helper functions + // ---------------------------------------------------------------------- - // Connect components - void connectComponents() { - - // Health - c1.set_pingOut_OutputPort( - 0, - health.get_pingIn_InputPort(0) - ); - c2.set_pingOut_OutputPort( - 0, - health.get_pingIn_InputPort(1) - ); - health.set_pingOut_OutputPort( - 0, - c1.get_pingIn_InputPort(0) - ); - health.set_pingOut_OutputPort( - 1, - c2.get_pingIn_InputPort(0) - ); + void initComponents(const TopologyState& state) { + c1.init(InstanceIds::c1); + c2.init(InstanceIds::c2); + health.init(InstanceIds::health); + } - } + void setBaseIds() { + health.setIdBase(BaseIds::health); + c1.setIdBase(BaseIds::c1); + c2.setIdBase(BaseIds::c2); + } + void connectComponents() { + + // Health + c1.set_pingOut_OutputPort( + 0, + health.get_pingIn_InputPort(0) + ); + c2.set_pingOut_OutputPort( + 0, + health.get_pingIn_InputPort(1) + ); + health.set_pingOut_OutputPort( + 0, + c1.get_pingIn_InputPort(0) + ); + health.set_pingOut_OutputPort( + 1, + c2.get_pingIn_InputPort(0) + ); } // ---------------------------------------------------------------------- - // Public interface functions + // Setup and teardown functions // ---------------------------------------------------------------------- void setup(const TopologyState& state) { diff --git a/compiler/tools/fpp-to-cpp/test/top/HealthTopologyAc.ref.hpp b/compiler/tools/fpp-to-cpp/test/top/HealthTopologyAc.ref.hpp index 151686fd8..19dce13e7 100644 --- a/compiler/tools/fpp-to-cpp/test/top/HealthTopologyAc.ref.hpp +++ b/compiler/tools/fpp-to-cpp/test/top/HealthTopologyAc.ref.hpp @@ -8,7 +8,7 @@ #define M_HealthTopologyAc_HPP #include "C.hpp" -#include "HealthImpl.hpp" +#include "Health.hpp" #include "HealthTopologyDefs.hpp" namespace M { @@ -34,7 +34,35 @@ namespace M { } // ---------------------------------------------------------------------- - // Public interface functions + // Component instances + // ---------------------------------------------------------------------- + + //! c1 + extern C c1; + + //! c2 + extern C c2; + + //! health + extern Svc::Health health; + + // ---------------------------------------------------------------------- + // Helper functions + // ---------------------------------------------------------------------- + + //! Initialize components + void initComponents( + const TopologyState& state //!< The topology state + ); + + //! Set component base Ids + void setBaseIds(); + + //! Connect components + void connectComponents(); + + // ---------------------------------------------------------------------- + // Setup and teardown functions // ---------------------------------------------------------------------- //! Set up the topology diff --git a/compiler/tools/fpp-to-cpp/test/top/NestedNamespacesTopologyAc.ref.cpp b/compiler/tools/fpp-to-cpp/test/top/NestedNamespacesTopologyAc.ref.cpp index 40535b66f..46f609a06 100644 --- a/compiler/tools/fpp-to-cpp/test/top/NestedNamespacesTopologyAc.ref.cpp +++ b/compiler/tools/fpp-to-cpp/test/top/NestedNamespacesTopologyAc.ref.cpp @@ -12,7 +12,7 @@ namespace A { // ---------------------------------------------------------------------- - // Public interface functions + // Setup and teardown functions // ---------------------------------------------------------------------- void setup(const TopologyState& state) { diff --git a/compiler/tools/fpp-to-cpp/test/top/NestedNamespacesTopologyAc.ref.hpp b/compiler/tools/fpp-to-cpp/test/top/NestedNamespacesTopologyAc.ref.hpp index cc3ffd38f..9bd25e0c2 100644 --- a/compiler/tools/fpp-to-cpp/test/top/NestedNamespacesTopologyAc.ref.hpp +++ b/compiler/tools/fpp-to-cpp/test/top/NestedNamespacesTopologyAc.ref.hpp @@ -14,7 +14,7 @@ namespace A { namespace B { // ---------------------------------------------------------------------- - // Public interface functions + // Setup and teardown functions // ---------------------------------------------------------------------- //! Set up the topology diff --git a/compiler/tools/fpp-to-cpp/test/top/NoNamespaceTopologyAc.ref.cpp b/compiler/tools/fpp-to-cpp/test/top/NoNamespaceTopologyAc.ref.cpp index 02542e5a5..7453d300d 100644 --- a/compiler/tools/fpp-to-cpp/test/top/NoNamespaceTopologyAc.ref.cpp +++ b/compiler/tools/fpp-to-cpp/test/top/NoNamespaceTopologyAc.ref.cpp @@ -8,7 +8,7 @@ // ---------------------------------------------------------------------- -// Public interface functions +// Setup and teardown functions // ---------------------------------------------------------------------- void setup(const TopologyState& state) { diff --git a/compiler/tools/fpp-to-cpp/test/top/NoNamespaceTopologyAc.ref.hpp b/compiler/tools/fpp-to-cpp/test/top/NoNamespaceTopologyAc.ref.hpp index 650bfbd4d..99b88f332 100644 --- a/compiler/tools/fpp-to-cpp/test/top/NoNamespaceTopologyAc.ref.hpp +++ b/compiler/tools/fpp-to-cpp/test/top/NoNamespaceTopologyAc.ref.hpp @@ -10,7 +10,7 @@ #include "NoNamespaceTopologyDefs.hpp" // ---------------------------------------------------------------------- -// Public interface functions +// Setup and teardown functions // ---------------------------------------------------------------------- //! Set up the topology diff --git a/compiler/tools/fpp-to-cpp/test/top/ParamsTopologyAc.ref.cpp b/compiler/tools/fpp-to-cpp/test/top/ParamsTopologyAc.ref.cpp index fb1a80bca..bfae9fce7 100644 --- a/compiler/tools/fpp-to-cpp/test/top/ParamsTopologyAc.ref.cpp +++ b/compiler/tools/fpp-to-cpp/test/top/ParamsTopologyAc.ref.cpp @@ -8,55 +8,45 @@ namespace M { - namespace { - - // ---------------------------------------------------------------------- - // Component instances - // ---------------------------------------------------------------------- - - // c1 - C c1(FW_OPTIONAL_NAME("c1")); - - // c2 - C c2(FW_OPTIONAL_NAME("c2")); - - // ---------------------------------------------------------------------- - // Private functions - // ---------------------------------------------------------------------- - - // Initialize components - void initComponents(const TopologyState& state) { - c1.init(InstanceIds::c1); - c2.init(InstanceIds::c2); - } - - // Set component base Ids - void setBaseIds() { - c1.setIdBase(BaseIds::c1); - c2.setIdBase(BaseIds::c2); - } - - // Register commands - void regCommands() { - c1.regCommands(); - c2.regCommands(); - } - - // Read parameters - void readParameters() { - c1.readParamFile(); - } - - // Load parameters - void loadParameters() { - c1.loadParamsSpecial(); - c2.loadParameters(); - } + // ---------------------------------------------------------------------- + // Component instances + // ---------------------------------------------------------------------- + + C c1(FW_OPTIONAL_NAME("c1")); + + C c2(FW_OPTIONAL_NAME("c2")); + + // ---------------------------------------------------------------------- + // Helper functions + // ---------------------------------------------------------------------- + + void initComponents(const TopologyState& state) { + c1.init(InstanceIds::c1); + c2.init(InstanceIds::c2); + } + + void setBaseIds() { + c1.setIdBase(BaseIds::c1); + c2.setIdBase(BaseIds::c2); + } + + void regCommands() { + c1.regCommands(); + c2.regCommands(); + } + + void readParameters() { + c1.readParamFile(); + } + + void loadParameters() { + c1.loadParamsSpecial(); + c2.loadParameters(); } // ---------------------------------------------------------------------- - // Public interface functions + // Setup and teardown functions // ---------------------------------------------------------------------- void setup(const TopologyState& state) { diff --git a/compiler/tools/fpp-to-cpp/test/top/ParamsTopologyAc.ref.hpp b/compiler/tools/fpp-to-cpp/test/top/ParamsTopologyAc.ref.hpp index b2dc0c59b..4e8465052 100644 --- a/compiler/tools/fpp-to-cpp/test/top/ParamsTopologyAc.ref.hpp +++ b/compiler/tools/fpp-to-cpp/test/top/ParamsTopologyAc.ref.hpp @@ -31,7 +31,38 @@ namespace M { } // ---------------------------------------------------------------------- - // Public interface functions + // Component instances + // ---------------------------------------------------------------------- + + //! c1 + extern C c1; + + //! c2 + extern C c2; + + // ---------------------------------------------------------------------- + // Helper functions + // ---------------------------------------------------------------------- + + //! Initialize components + void initComponents( + const TopologyState& state //!< The topology state + ); + + //! Set component base Ids + void setBaseIds(); + + //! Register commands + void regCommands(); + + //! Read parameters + void readParameters(); + + //! Load parameters + void loadParameters(); + + // ---------------------------------------------------------------------- + // Setup and teardown functions // ---------------------------------------------------------------------- //! Set up the topology diff --git a/compiler/tools/fpp-to-cpp/test/top/basic.fpp b/compiler/tools/fpp-to-cpp/test/top/basic.fpp index 1eebe2f38..64a08f6c2 100644 --- a/compiler/tools/fpp-to-cpp/test/top/basic.fpp +++ b/compiler/tools/fpp-to-cpp/test/top/basic.fpp @@ -66,7 +66,7 @@ module M { queue size 10 instance passive1: Passive base id 0x300 - instance passive2: Passive base id 0x400 + instance passive2: Passive base id 0x400 type "ConcretePassive" topology Basic { diff --git a/compiler/tools/fpp-to-cpp/test/top/check-cpp-dir/Basic/Passive.hpp b/compiler/tools/fpp-to-cpp/test/top/check-cpp-dir/Basic/Passive.hpp index 8a94331d5..880d1918d 100644 --- a/compiler/tools/fpp-to-cpp/test/top/check-cpp-dir/Basic/Passive.hpp +++ b/compiler/tools/fpp-to-cpp/test/top/check-cpp-dir/Basic/Passive.hpp @@ -21,6 +21,9 @@ namespace M { }; + // Simulate a concrete implementation + typedef Passive ConcretePassive; + } #endif diff --git a/compiler/tools/fpp-to-cpp/test/top/check-cpp-dir/Health/HealthImpl.hpp b/compiler/tools/fpp-to-cpp/test/top/check-cpp-dir/Health/Health.hpp similarity index 75% rename from compiler/tools/fpp-to-cpp/test/top/check-cpp-dir/Health/HealthImpl.hpp rename to compiler/tools/fpp-to-cpp/test/top/check-cpp-dir/Health/Health.hpp index 151fdcab5..f7fea1673 100644 --- a/compiler/tools/fpp-to-cpp/test/top/check-cpp-dir/Health/HealthImpl.hpp +++ b/compiler/tools/fpp-to-cpp/test/top/check-cpp-dir/Health/Health.hpp @@ -1,11 +1,11 @@ -#ifndef M_HealthImpl_HPP -#define M_HealthImpl_HPP +#ifndef M_Health_HPP +#define M_Health_HPP #include "HealthComponentAc.hpp" namespace Svc { - class HealthImpl : + class Health : public HealthComponentBase { @@ -17,7 +17,7 @@ namespace Svc { const char* c; } PingEntry; - HealthImpl(const char* name) { + Health(const char* name) { } diff --git a/compiler/tools/fpp-to-cpp/test/top/health.fpp b/compiler/tools/fpp-to-cpp/test/top/health.fpp index d77df98b9..718a9fb07 100644 --- a/compiler/tools/fpp-to-cpp/test/top/health.fpp +++ b/compiler/tools/fpp-to-cpp/test/top/health.fpp @@ -15,14 +15,7 @@ module M { output port pingOut: Svc.Ping } - instance $health: Svc.Health base id 0x100 \ - at "HealthImpl.hpp" { - - phase Phases.instances """ - Svc::HealthImpl health(FW_OPTIONAL_NAME("health")); - """ - - } + instance $health: Svc.Health base id 0x100 instance c1: C base id 0x200 instance c2: C base id 0x300 diff --git a/compiler/tools/fpp-to-xml/test/port/run.sh b/compiler/tools/fpp-to-xml/test/port/run.sh index a37afb21d..8f79ffb03 100644 --- a/compiler/tools/fpp-to-xml/test/port/run.sh +++ b/compiler/tools/fpp-to-xml/test/port/run.sh @@ -1,5 +1,7 @@ #!/bin/sh +fpp_depend=../../../../bin/fpp-depend + port_kwd_name() { run_test "-p $PWD" port_kwd_name && \ @@ -10,7 +12,7 @@ port_ok() { files="" for i in `seq 1 4`; do files="$files PortOK${i}Port"; done - run_test "-i `fpp-depend port_ok.fpp | tr '\n' ','` -p $PWD" port_ok && \ + run_test "-i `$fpp_depend port_ok.fpp | tr '\n' ','` -p $PWD" port_ok && \ diff_xml $files } diff --git a/docs/fpp-spec.html b/docs/fpp-spec.html index 3a12a40f1..141b3b3bc 100644 --- a/docs/fpp-spec.html +++ b/docs/fpp-spec.html @@ -1849,6 +1849,9 @@

5.4.1. Syntax

qual-ident base id expression [ +type string-literal +] +[ at string-literal ] [ @@ -1887,8 +1890,9 @@

5.4.2. Semanticsrefer to a component definition D. -This component definition is called the component definition -associated with the component instance.

+This component definition D is called the component definition +associated with the component instance I. +We also say that I is an instance of D.

  • The expression following the keywords base id must have a @@ -1922,11 +1926,41 @@

    5.4.2. Semantics

  • +

    If present, the string literal following the keyword type +names the implementation type of the instance. +The type must be a valid type in the target language (e.g., a type name +in C++). +If the implementation type is not present, then the code generator +infers the name of the implementation type from the component name when +generating the constructor for the instance. +For example:

    +
    +
      +
    1. +

      Suppose an FPP model has a component C defined in module M. +Suppose I is an instance of component M.C. +By default, the implementation type associated with I is M::C.

      +
    2. +
    3. +

      Specifying type "M::D" causes FPP to generate a +constructor for I with name "M::D" instead of "M::C".

      +
    4. +
    +
    +
    +

    Specifying an implementation type is useful in cases where the name +of the component implementation does not match the component +name, e.g., because there are several implementations of the +same FPP component.

    +
    +
  • +
  • If present, the string literal following the keyword at must specify a file path, relative to the location of the component instance definition. -The file path must name a file in the target language (e.g., a C++ header file) +The file path must name a file in the target language (e.g., a C++ +header file) that provides the implementation associated with the instance. If no such path is given, then the translator uses the location of the component instance and the name of the component to generate @@ -8159,7 +8193,7 @@

    20.4. Translation Tools

    diff --git a/docs/fpp-users-guide.html b/docs/fpp-users-guide.html index 34514e8ae..5c8c3ab24 100644 --- a/docs/fpp-users-guide.html +++ b/docs/fpp-users-guide.html @@ -591,7 +591,7 @@

    The F Prime Prime (FPP) User’s Guide, Unreleased, after v1.0.1

  • 10.1.3. Active Components
  • -
  • 10.2. Specifying Header Files
  • +
  • 10.2. Specifying the Implementation
  • 10.3. Init Specifiers @@ -6492,18 +6493,62 @@

    -

    10.2. Specifying Header Files

    +

    10.2. Specifying the Implementation

    When you define a component instance I, the FPP translator needs -to locate the header file for the C++ -implementation associated with I. -This location can occur automatically in many cases. -In other cases, you have to specify the location manually.

    +to know the following information about the C++ implementation of I:

    +
    +
    +
      +
    1. +

      The type (i.e., the name of the C++ class) that defines the +implementation.

      +
    2. +
    3. +

      The location of the C++ header file that declares the implementation +class.

      +
    4. +
    +
    +
    +

    In most cases, the translator can infer this information. +However, in some cases you must specify it manually.

    +
    +
    +

    The implementation type: +The FPP translator can automatically infer the implementation +type if its qualified C++ class name matches the qualified +name of the FPP component. +For example, the C++ class name A::B matches the FPP component +name A.B.

    +
    +
    +

    If the names do not match, then you must provide the type +associated with the implementation. +You do this by writing the keyword type after the base identifier, +followed by a string +specifying the implementation type.

    -

    Automatic location: -The FPP translator can automatically locate the header file if it -conforms to the following rules:

    +

    For example, suppose we have a C++ class Utils::SpecialDataCompressor, +which is a specialized implementation of the FPP component +Utils.DataCompressor. +By default, when we specify Utils.DataCompressor as the component name, the +translator infers Utils::DataCompressor as the implementation type. +Here is how we specify the implementation type Utils::SpecialDataCompressor:

    +
    +
    +
    +
    instance dataCompressor: Utils.DataCompressor base id 0x100 \
    +  type "Utils::SpecialDataCompressor" \
    +  queue size Default.queueSize \
    +  cpu 0
    +
    +
    +
    +

    The header file: +The FPP translator can automatically locate the header file for I +if it conforms to the following rules:

      @@ -6513,8 +6558,7 @@

      10.2. Specifying H any module qualifiers.

    1. -

      The header -file is located in the same directory as the FPP +

      The header file is located in the same directory as the FPP source file that defines the component.

    @@ -6534,27 +6578,26 @@

    10.2. Specifying H

    The FPP component Ref.SignalGen is defined in the directory Ref/SignalGen/SignalGen.fpp, -and the implementation header file is -Ref/SignalGen/SignalGen.hpp. +and the implementation class Ref::SignalGen is declared in +the header file Ref/SignalGen/SignalGen.hpp. In this case, the header file follows rules (1) and (2) stated above, so the FPP translator can automatically locate the file.

    -

    Manual specification: -If the implementation header file does not follow +

    If the implementation header file does not follow rules (1) and (2) stated above, then you must specify the name and location of the header file by hand. -You do that by writing the keyword at followed by the -header file path enclosed in quotation marks. +You do that by writing the keyword at followed by +a string +specifying the header file path. The header file path is relative to the directory containing the source file that defines the component instance.

    For example, the F Prime repository has a directory -Svc/Time that contains an FPP model for a component -Svc.Time. +Svc/Time that contains an FPP model for a component Svc.Time. Because the C++ implementation for this component is platform-specific, the directory Svc/Time doesn’t contain any implementation. @@ -6566,17 +6609,19 @@

    10.2. Specifying H

    The F Prime repository also provides a Linux-specific implementation of the Time component in the directory Svc/LinuxTime. The file Ref/Top/instances.fpp contains an instance definition -linuxTime that reads in part as follows:

    +linuxTime that reads as follows:

    instance linuxTime: Svc.Time base id 0x4500 \
    +  type "Svc::LinuxTime" \
       at "../../Svc/LinuxTime/LinuxTime.hpp"
    -

    This definition says to use implementation header file -Svc/LinuxTime/LinuxTime.hpp.

    +

    This definition says to use the implementation of the component +Svc.Time with C++ type name Svc::LinuxTime defined in the header +file ../../Svc/LinuxTime/LinuxTime.hpp.

    @@ -9521,7 +9566,7 @@

    13.2. Generating XMLF provided as arguments are translated.

    -

    Tool behavior: When you run fpp-check, the following occurs:

    +

    Tool behavior: When you run fpp-to-xml, the following occurs:

      @@ -10651,7 +10696,7 @@

      14.1. I

      An implementation of the function

      -
      Fw::SerializeStatus T::serialize(Fw::SerializeBufferBase&)
      +
      Fw::SerializeStatus T::deserialize(Fw::SerializeBufferBase&)
      @@ -10945,37 +10990,11 @@

      -

      For example, Ref/Top/RefTopologyAc.hpp declares the following -variables:

      -

      -
      -
        -
      1. -

        A variable Ref::Allocation::mallocator of type Fw::MallocAllocator. +

        For example, Ref/Top/RefTopologyAc.hpp declares +a variable Ref::Allocation::mallocator of type Fw::MallocAllocator. It provides an allocator used in the setup and teardown -of several component instances.

        -
      2. -
      3. -

        A component instance blockDrv of type Drv::BlockDriver. -This is one of the component instances in the Ref topology. -It is declared here, instead of being declared in RefTopologyAc.cpp, -so that it is visible in the main function. -In the instances phase, the init specifier for this instance -overrides the standard instance declaration with a comment:

        -
        -
        -
        init blockDrv phase Fpp.ToCpp.Phases.instances """
        -// Declared in RefTopologyDefs.cpp
        -"""
        -
        -
        -
      4. -
      -
      -
      -

      Both of these declarations refer to link-time symbols; the -corresponding link-time symbols are defined in -RefTopologyDefs.cpp.

      +of several component instances. +The corresponding link-time symbol is defined in RefTopologyDefs.cpp.

    @@ -11062,13 +11081,75 @@

    +

    14.2.3. Public Symbols

    +
    +

    The header file T TopologyAc.hpp declares several public +symbols that you can use when writing your main function.

    +
    +
    +

    Instance variables: +Each component instance used in the topology is declared as +an extern variable, so you can refer to any component instance +in the main function. +For example, the main function in the Ref topology +calls the method callIsr of the blockDrv (block driver) +component instance, in order to simulate an interrupt service +routine (ISR) call triggered by a hardware interrupt.

    +
    +
    +

    Helper functions: +The auto-generated setup function calls the following auto-generated +helper functions:

    +
    +
    +
    +
    void initComponents(const TopologyState& state);
    +void configComponents(const TopologyState& state);
    +void setBaseIds();
    +void connectComponents();
    +void regCommands();
    +void readParameters();
    +void loadParameters();
    +void startTasks(const TopologyState& state);
    +
    +
    +
    +

    The auto-generated teardown function calls the following +auto-generated helper functions:

    +
    +
    +
    +
    void stopTasks(const TopologyState& state);
    +void freeThreads(const TopologyState& state);
    +void tearDownComponents(const TopologyState& state);
    +
    +
    +
    +

    The helper functions are declared as public symbols in T +TopologyAc.hpp, so if you wish, you may write your own versions +of setup and teardown that call these functions directly. +The FPP modeling is designed so that you don’t have to do this; +you can put any custom C++ code for setup or teardown into +init specifiers +and let the FPP translator generate complete setup and teardown +functions that you simply call, as described above. +Using init specifiers generally produces cleaner integration between +the model and the C++ code: you write the custom +C++ code once, any topology T that uses an instance I will pick +up the custom C++ code for I, and the FPP translator will automatically +put the code for I into the correct place in T TopologyAc.cpp. +However, if you wish to write the custom code directly into your main +function, you may.

    +
    +
    diff --git a/docs/spec/Definitions/Component-Instance-Definitions.adoc b/docs/spec/Definitions/Component-Instance-Definitions.adoc index 4568dda39..0e09d49a6 100644 --- a/docs/spec/Definitions/Component-Instance-Definitions.adoc +++ b/docs/spec/Definitions/Component-Instance-Definitions.adoc @@ -14,6 +14,9 @@ that you can refer to in a <> `base` `id` <> _[_ +`type` <> +_]_ +_[_ `at` <> _]_ _[_ @@ -33,7 +36,7 @@ _[_ _]_ _init-specifier-sequence_ is an -<> in +<> in which each element is an <>, and the terminating punctuation is a semicolon. @@ -46,8 +49,9 @@ and the terminating punctuation is a semicolon. <> a <>. -This component definition is called the component definition -*associated with* the component instance. +This component definition _D_ is called the component definition +*associated with* the component instance _I_. +We also say that _I_ is an instance of _D_. . The expression following the keywords `base` `id` must have a <>. @@ -59,7 +63,7 @@ It associates a base identifier with the component instance. .. For each component instance, for each command, event, telemetry, or parameter identifier, the identifier associated with the instance -is computed by adding the base identifier specified here to the relative +is computed by adding the base identifier specified here to the relative identifier specified in the component. For this purpose, command opcodes are identifiers. @@ -71,17 +75,40 @@ If the component has no identifiers, then this range is empty. .. No instance may have a base identifier that lies within the identifier range of another instance. +. If present, the string literal following the keyword `type` +names the implementation type of the instance. +The type must be a valid type in the target language (e.g., a type name +in {cpp}). +If the implementation type is not present, then the code generator +infers the name of the implementation type from the component name when +generating the constructor for the instance. +For example: + +.. Suppose an FPP model has a component `C` defined in module `M`. +Suppose _I_ is an instance of component `M.C`. +By default, the implementation type associated with _I_ is `M::C`. + +.. Specifying `type "M::D"` causes FPP to generate a +constructor for _I_ with name `"M::D"` instead of `"M::C"`. + ++ +Specifying an implementation type is useful in cases where the name +of the component implementation does not match the component +name, e.g., because there are several implementations of the +same FPP component. + . If present, the string literal following the keyword `at` must specify a file path, relative to the <> of the component instance definition. -The file path must name a file in the target language (e.g., a C++ header file) +The file path must name a file in the target language (e.g., a {cpp} +header file) that provides the implementation associated with the instance. If no such path is given, then the translator uses the location of the component instance and the name of the component to generate a default implementation path. -. If present, the expression following the keywords `queue` `size` must +. If present, the expression following the keywords `queue` `size` must have a <> and must evaluate to a nonnegative integer after <>. @@ -111,7 +138,7 @@ for queued or passive components. . If present, the init specifiers govern {cpp} code generation for the component instance being defined. -See the section on +See the section on <> for further information. @@ -139,6 +166,6 @@ instance timer: Svc.Timer at "../../Timers/HardwareTimer.hpp" This example defines an instance `timer` of component `Svc.Timer`. It specifies that the component implementation is located at -path `../../Timers/HardwareTimer.hpp` instead of in the default location for the +path `../../Timers/HardwareTimer.hpp` instead of in the default location for the component. The path is resolved relative to the location of the instance definition. diff --git a/docs/users-guide/Analyzing-and-Translating-Models.adoc b/docs/users-guide/Analyzing-and-Translating-Models.adoc index d22543295..a03b93c87 100644 --- a/docs/users-guide/Analyzing-and-Translating-Models.adoc +++ b/docs/users-guide/Analyzing-and-Translating-Models.adoc @@ -223,7 +223,7 @@ This option tells the tool that you want to read the files in _D_ for their symb but you don't want to translate them. Only the files _F_ provided as arguments are translated. -*Tool behavior:* When you run `fpp-check`, the following occurs: +*Tool behavior:* When you run `fpp-to-xml`, the following occurs: . The tool runs the same analysis <>. diff --git a/docs/users-guide/Defining-Component-Instances.adoc b/docs/users-guide/Defining-Component-Instances.adoc index 57d45ab6c..619fb78c7 100644 --- a/docs/users-guide/Defining-Component-Instances.adoc +++ b/docs/users-guide/Defining-Component-Instances.adoc @@ -313,24 +313,57 @@ instance dataCompressor: Utils.DataCompressor base id 0x100 \ cpu 0 -------- -=== Specifying Header Files +=== Specifying the Implementation When you define a component instance _I_, the FPP translator needs -to locate the header file for the {cpp} -implementation associated with _I_. -This location can occur automatically in many cases. -In other cases, you have to specify the location manually. +to know the following information about the {cpp} implementation of _I_: -*Automatic location:* -The FPP translator can automatically locate the header file if it -conforms to the following rules: +. The type (i.e., the name of the {cpp} class) that defines the +implementation. + +. The location of the {cpp} header file that declares the implementation +class. + +In most cases, the translator can infer this information. +However, in some cases you must specify it manually. + +*The implementation type:* +The FPP translator can automatically infer the implementation +type if its qualified {cpp} class name matches the qualified +name of the FPP component. +For example, the {cpp} class name `A::B` matches the FPP component +name `A.B`. + +If the names do not match, then you must provide the type +associated with the implementation. +You do this by writing the keyword `type` after the base identifier, +followed by a <> +specifying the implementation type. + +For example, suppose we have a {cpp} class `Utils::SpecialDataCompressor`, +which is a specialized implementation of the FPP component +`Utils.DataCompressor`. +By default, when we specify `Utils.DataCompressor` as the component name, the +translator infers `Utils::DataCompressor` as the implementation type. +Here is how we specify the implementation type `Utils::SpecialDataCompressor`: + +[source,fpp] +-------- +instance dataCompressor: Utils.DataCompressor base id 0x100 \ + type "Utils::SpecialDataCompressor" \ + queue size Default.queueSize \ + cpu 0 +-------- + +*The header file:* +The FPP translator can automatically locate the header file for _I_ +if it conforms to the following rules: . The name of the header file is `Name.hpp`, where `Name` is the name of the component in the FPP model, without any module qualifiers. -. The header -file is located in the same directory as the FPP +. The header file is located in the same directory as the FPP source file that defines the component. For example, the F Prime repository contains a reference FSW implementation @@ -346,25 +379,24 @@ instance SG1: Ref.SignalGen base id 0x2100 \ The FPP component `Ref.SignalGen` is defined in the directory `Ref/SignalGen/SignalGen.fpp`, -and the implementation header file is -`Ref/SignalGen/SignalGen.hpp`. +and the implementation class `Ref::SignalGen` is declared in +the header file `Ref/SignalGen/SignalGen.hpp`. In this case, the header file follows rules (1) and (2) stated above, so the FPP translator can automatically locate the file. -*Manual specification:* If the implementation header file does not follow rules (1) and (2) stated above, then you must specify the name and location of the header file by hand. -You do that by writing the keyword `at` followed by the -header file path enclosed in quotation marks. +You do that by writing the keyword `at` followed by +a <> +specifying the header file path. The header file path is relative to the directory containing the source file that defines the component instance. For example, the F Prime repository has a directory -`Svc/Time` that contains an FPP model for a component -`Svc.Time`. +`Svc/Time` that contains an FPP model for a component `Svc.Time`. Because the {cpp} implementation for this component is platform-specific, the directory `Svc/Time` doesn't contain any implementation. @@ -375,16 +407,18 @@ in a different directory. The F Prime repository also provides a Linux-specific implementation of the `Time` component in the directory `Svc/LinuxTime`. The file `Ref/Top/instances.fpp` contains an instance definition -`linuxTime` that reads in part as follows: +`linuxTime` that reads as follows: [source,fpp] ---- instance linuxTime: Svc.Time base id 0x4500 \ + type "Svc::LinuxTime" \ at "../../Svc/LinuxTime/LinuxTime.hpp" ---- -This definition says to use implementation header file -`Svc/LinuxTime/LinuxTime.hpp`. +This definition says to use the implementation of the component +`Svc.Time` with {cpp} type name `Svc::LinuxTime` defined in the header +file `../../Svc/LinuxTime/LinuxTime.hpp`. === Init Specifiers diff --git a/docs/users-guide/Writing-C-Plus-Plus-Implementations.adoc b/docs/users-guide/Writing-C-Plus-Plus-Implementations.adoc index d34742b87..1d9f20993 100644 --- a/docs/users-guide/Writing-C-Plus-Plus-Implementations.adoc +++ b/docs/users-guide/Writing-C-Plus-Plus-Implementations.adoc @@ -8,7 +8,7 @@ four kinds of implementations you have to write: These are types that are named in the FPP model but are defined directly in {cpp}. -. Implementations of +. Implementations of <>. . Implementations of any libraries used by the component implementations, @@ -31,9 +31,9 @@ and implementing deployments. Except for a few built-in types (see below), when translating to XML and then {cpp}, an <> represents a {cpp} class that you write directly in {cpp}. -When you use an abstract type _T_ in an FPP definition _D_ (for example, as the +When you use an abstract type _T_ in an FPP definition _D_ (for example, as the member type of an array definition) -and you translate _D_ to XML, then the generated XML node for _D_ contains an +and you translate _D_ to XML, then the generated XML node for _D_ contains an `include_header` node that includes a header file for _T_. @@ -77,13 +77,13 @@ Your class definition must include the following: Fw::SerializeStatus T::serialize(Fw::SerializeBufferBase&) const ---- + -that specifies how to *serialize* a class instance (i.e., convert a class +that specifies how to *serialize* a class instance (i.e., convert a class instance to a byte string). * An implementation of the function + ---- -Fw::SerializeStatus T::serialize(Fw::SerializeBufferBase&) +Fw::SerializeStatus T::deserialize(Fw::SerializeBufferBase&) ---- + that specifies how to *deserialize* a class instance (i.e., reconstruct a class @@ -177,7 +177,7 @@ You don't have to define header files for these types. At the highest level of an F Prime implementation, you write two units of {cpp} code: -. Application-specific definitions visible +. Application-specific definitions visible both to the `main` function and to the auto-generated topology code. @@ -192,7 +192,7 @@ As discussed in the section on generating {cpp} topology definitions>>, when you translate an FPP topology _T_ to {cpp}, the result goes into files _T_ `TopologyAc.hpp` and _T_ `TopologyAc.cpp`. -The generated file _T_ `TopologyAc.hpp` includes a file +The generated file _T_ `TopologyAc.hpp` includes a file _T_ `TopologyDefs.hpp`. The purpose of this file inclusion is as follows: @@ -218,7 +218,7 @@ follow the description given below. *Topology state:* _T_ `TopologyDefs.hpp` must define a type -`TopologyState` in the {cpp} namespace +`TopologyState` in the {cpp} namespace corresponding to the FPP module where the topology _T_ is defined. For example, in `Ref/Top/topology.fpp` in the F Prime repository, the FPP topology `Ref` is defined in the FPP @@ -227,7 +227,7 @@ is defined in the namespace `Ref`. `TopologyState` may be any type. Usually it is a struct or class. -The {cpp} code generated by FPP passes a value `state` of type `TopologyState` into +The {cpp} code generated by FPP passes a value `state` of type `TopologyState` into each of the functions for setting up and tearing down topologies. You can read this value in the code associated with your <> +and let the FPP translator generate complete `setup` and `teardown` +functions that you simply call, as described above. +Using init specifiers generally produces cleaner integration between +the model and the {cpp} code: you write the custom +{cpp} code once, any topology _T_ that uses an instance _I_ will pick +up the custom {cpp} code for _I_, and the FPP translator will automatically +put the code for _I_ into the correct place in _T_ `TopologyAc.cpp`. +However, if you wish to write the custom code directly into your main +function, you may.