diff --git a/compiler/lib/src/main/scala/analysis/Analysis.scala b/compiler/lib/src/main/scala/analysis/Analysis.scala index 506775030f..7f681fe52f 100644 --- a/compiler/lib/src/main/scala/analysis/Analysis.scala +++ b/compiler/lib/src/main/scala/analysis/Analysis.scala @@ -88,14 +88,14 @@ case class Analysis( tlmPacketSet: Option[TlmPacketSet] = None, /** The mapping from nodes to implied uses */ impliedUseMap: Map[AstNode.Id, ImpliedUse.Uses] = Map(), - /** Node ID of the template expansion currently */ - template: Option[AstNode.Id] = None, - /** Maps template expansion AST nodes to their */ - templateExpansionMap: Map[AstNode.Id, TemplateExpansion] = Map(), - /** Tracks the current expansion we are analyzing inside of */ + /** Node ID of the current template definition */ + templateDefId: Option[AstNode.Id] = None, + /** The current template expansion */ templateExpansion: Option[TemplateExpansion] = None, - /** Node ID of the template definition we are currently cloning inside of */ - templateDefinition: Option[AstNode.Id] = None, + /** Node ID of the current template expansion */ + templateExpansionId: Option[AstNode.Id] = None, + /** Mapping from template expansion nodes to their expansions */ + templateExpansionMap: Map[AstNode.Id, TemplateExpansion] = Map(), /** The set of symbols defined with a dictionary specifier */ dictionarySymbolSet: Set[Symbol] = Set(), /** The mapping from system symbols to systems */ diff --git a/compiler/lib/src/main/scala/analysis/Analyzers/ModuleAnalyzer.scala b/compiler/lib/src/main/scala/analysis/Analyzers/ModuleAnalyzer.scala index 10604d50f0..77d40738e8 100644 --- a/compiler/lib/src/main/scala/analysis/Analyzers/ModuleAnalyzer.scala +++ b/compiler/lib/src/main/scala/analysis/Analyzers/ModuleAnalyzer.scala @@ -17,20 +17,24 @@ trait ModuleAnalyzer extends Analyzer { yield a2.copy(scopeNameList = a.scopeNameList) } - override def specTemplateExpandAnnotatedNode( + override def specTemplateExpandAnnotatedNodeExpanded( a: Analysis, - aNode: Ast.Annotated[AstNode[Ast.SpecTemplateExpand]] + aNode: Ast.Annotated[AstNode[Ast.SpecTemplateExpand]], + members: List[Ast.ModuleMember] ) = { val (_, node, _) = aNode - // Check if this template has been expanded - node.data.members match { - case Some(members) => { - // Mark the analysis with the proper expansion - val a1 = a.copy(templateExpansion = Some(a.templateExpansionMap(node.id))) + a.templateExpansionMap.get(node.id) match { + case Some(expansion) => + // This node has been expanded by analysis. + // Mark the analysis with the proper expansion. + val a1 = a.copy(templateExpansion = Some(expansion)) for { a2 <- visitList(a1, members, matchModuleMember) } yield a2.copy(templateExpansion = a.templateExpansion) - } - case None => Right(a) + case None => + // This node has not yet been expanded by analysis. + // The expansion is provided in the source model, in the form + // expand T { ... }. + Right(a) } } diff --git a/compiler/lib/src/main/scala/analysis/CheckSemantics/CheckTemplateDefs.scala b/compiler/lib/src/main/scala/analysis/CheckSemantics/CheckTemplateDefs.scala new file mode 100644 index 0000000000..09777f515a --- /dev/null +++ b/compiler/lib/src/main/scala/analysis/CheckSemantics/CheckTemplateDefs.scala @@ -0,0 +1,53 @@ +package fpp.compiler.analysis + +import fpp.compiler.ast._ +import fpp.compiler.util._ + +/** Check template definitions */ +object CheckTemplateDefs + extends Analyzer + with ModuleAnalyzer +{ + + override def defModuleTemplateAnnotatedNode( + a: Analysis, + aNode: Ast.Annotated[AstNode[Ast.DefModuleTemplate]] + ) = { + val (_, node, _) = aNode + val data = node.data + for { + _ <- a.templateDefId match { + case Some(defId) => Left( + SemanticError.TemplateDefError( + Locations.get(node.id), + "module template definitions cannot be nested", + Locations.get(defId) + ) + ) + case None => Right(()) + } + a <- Right(a.copy(templateDefId = Some(node.id))) + a <- visitList(a, data.members, matchModuleMember) + a <- Right(a.copy(templateDefId = None)) + } yield a + } + + override def specTemplateExpandAnnotatedNode( + a: Analysis, + aNode: Ast.Annotated[AstNode[Ast.SpecTemplateExpand]] + ) = { + val (_, node, _) = aNode + val data = node.data + a.templateDefId match { + case Some(defId) => Left( + SemanticError.TemplateDefError( + Locations.get(node.id), + "template expansion specifiers cannot appear inside a module template", + Locations.get(defId) + ) + ) + case None => Right(a) + } + } + +} diff --git a/compiler/lib/src/main/scala/analysis/CheckSemantics/CheckTemplateExpansions.scala b/compiler/lib/src/main/scala/analysis/CheckSemantics/CheckTemplateExpansions.scala new file mode 100644 index 0000000000..132bc4fada --- /dev/null +++ b/compiler/lib/src/main/scala/analysis/CheckSemantics/CheckTemplateExpansions.scala @@ -0,0 +1,54 @@ +package fpp.compiler.analysis + +import fpp.compiler.ast._ +import fpp.compiler.util._ + +/** Check template expansions */ +object CheckTemplateExpansions + extends Analyzer + with ModuleAnalyzer +{ + + override def defModuleTemplateAnnotatedNode( + a: Analysis, + aNode: Ast.Annotated[AstNode[Ast.DefModuleTemplate]] + ) = + a.templateExpansionId match { + case Some(expandId) => Left( + SemanticError.TemplateExpandError( + Locations.get(aNode._2.id), + "module template definitions cannot appear inside a template expansion", + Locations.get(expandId) + ) + ) + case None => Right(a) + } + + override def specTemplateExpandAnnotatedNodeExpanded( + a: Analysis, + aNode: Ast.Annotated[AstNode[Ast.SpecTemplateExpand]], + members: List[Ast.ModuleMember] + ) = + for { + a <- specTemplateExpandAnnotatedNodeUnexpanded(a, aNode) + a <- Right(a.copy(templateExpansionId = Some(aNode._2.id))) + a <- visitList(a, members, matchModuleMember) + a <- Right(a.copy(templateExpansionId = None)) + } yield a + + override def specTemplateExpandAnnotatedNodeUnexpanded( + a: Analysis, + aNode: Ast.Annotated[AstNode[Ast.SpecTemplateExpand]], + ) = + a.templateExpansionId match { + case Some(defId) => Left( + SemanticError.TemplateExpandError( + Locations.get(aNode._2.id), + "template expansions cannot be nested", + Locations.get(defId) + ) + ) + case None => Right(a) + } + +} diff --git a/compiler/lib/src/main/scala/analysis/CheckSemantics/ExpandSyntaxAndEnterSymbols.scala b/compiler/lib/src/main/scala/analysis/CheckSemantics/ExpandSyntaxAndEnterSymbols.scala index b2351b7b96..5fe3c2f5ad 100644 --- a/compiler/lib/src/main/scala/analysis/CheckSemantics/ExpandSyntaxAndEnterSymbols.scala +++ b/compiler/lib/src/main/scala/analysis/CheckSemantics/ExpandSyntaxAndEnterSymbols.scala @@ -16,8 +16,10 @@ object ExpandSyntaxAndEnterSymbols { (a, tul) <- ResolveSpecInclude.transUnitList(a, tul) tul <- AddStateEnums.transUnitList(tul) a <- EnterSymbols.visitList(a, tul, EnterSymbols.transUnit) + a <- CheckTemplateDefs.visitList(a, tul, CheckTemplateDefs.transUnit) + a <- CheckTemplateExpansions.visitList(a, tul, CheckTemplateExpansions.transUnit) a <- CheckTemplateUses.visitList(a, tul, CheckTemplateUses.transUnit) - (_, tul) <- ExpandTemplates.transformList(a, tul, ExpandTemplates.transUnit) + tul <- ExpandTemplates.transformList(a, tul, ExpandTemplates.transUnit) a <- EnterTemplateExpansionSymbols.visitList(a, tul, EnterTemplateExpansionSymbols.transUnit) } yield (a, tul) } diff --git a/compiler/lib/src/main/scala/analysis/Semantics/TemplateExpansion.scala b/compiler/lib/src/main/scala/analysis/Semantics/TemplateExpansion.scala index a806ae441c..dd90af846f 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/TemplateExpansion.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/TemplateExpansion.scala @@ -3,7 +3,7 @@ package fpp.compiler.analysis import fpp.compiler.ast._ import fpp.compiler.util._ -/** An FPP template */ +/** An FPP template expansion */ case class TemplateExpansion( /** The AST node defining the template */ defNode: Ast.Annotated[AstNode[Ast.DefModuleTemplate]], diff --git a/compiler/lib/src/main/scala/ast/AstStateTransformer.scala b/compiler/lib/src/main/scala/ast/AstStateTransformer.scala index b92cfcd4f2..d2be4f9682 100644 --- a/compiler/lib/src/main/scala/ast/AstStateTransformer.scala +++ b/compiler/lib/src/main/scala/ast/AstStateTransformer.scala @@ -35,6 +35,15 @@ trait AstStateTransformer extends AstTransformer { yield (pair._1, pair._2.reverse) } + /** Transform a list and flatten the result */ + def transformFlatList[A, B]( + s: State, + list: List[A], + transform: (In, A) => Result[List[B]] + ): Result[List[B]] = + for ((s, bs) <- transformList(s, list, transform)) + yield (s, bs.flatten) + def tuMember(s: State, member: Ast.TUMember): Result[List[Ast.TUMember]] = matchModuleMember(s, member) diff --git a/compiler/lib/src/main/scala/ast/AstTransformer.scala b/compiler/lib/src/main/scala/ast/AstTransformer.scala index dd4499b4bf..c3f6c66498 100644 --- a/compiler/lib/src/main/scala/ast/AstTransformer.scala +++ b/compiler/lib/src/main/scala/ast/AstTransformer.scala @@ -288,6 +288,22 @@ trait AstTransformer { def specTemplateExpandAnnotatedNode( in: In, node: Ast.Annotated[AstNode[Ast.SpecTemplateExpand]] + ): ResultAnnotatedNode[Ast.SpecTemplateExpand] = + node._2.data.members match { + case Some(members) => specTemplateExpandAnnotatedNodeExpanded(in, node, members) + case None => specTemplateExpandAnnotatedNodeUnexpanded(in, node) + } + + def specTemplateExpandAnnotatedNodeUnexpanded( + in: In, + node: Ast.Annotated[AstNode[Ast.SpecTemplateExpand]] + ): ResultAnnotatedNode[Ast.SpecTemplateExpand] = + defaultAnnotatedNode(in, node) + + def specTemplateExpandAnnotatedNodeExpanded( + in: In, + node: Ast.Annotated[AstNode[Ast.SpecTemplateExpand]], + members: List[Ast.ModuleMember] ): ResultAnnotatedNode[Ast.SpecTemplateExpand] = defaultAnnotatedNode(in, node) diff --git a/compiler/lib/src/main/scala/ast/AstUnitTransformer.scala b/compiler/lib/src/main/scala/ast/AstUnitTransformer.scala new file mode 100644 index 0000000000..b4d2f51e43 --- /dev/null +++ b/compiler/lib/src/main/scala/ast/AstUnitTransformer.scala @@ -0,0 +1,42 @@ +package fpp.compiler.transform + +import fpp.compiler.analysis._ +import fpp.compiler.ast._ +import fpp.compiler.util._ + +/** Transform an AST, producing a unit Out value */ +trait AstUnitTransformer extends AstTransformer +{ + + type Out = Unit + + /** Transform a list in sequence */ + def transformList[A, B]( + in: In, + list: List[A], + transform: (In, A) => Result[B] + ): Result.Result[List[B]] = { + def helper(inList: List[A], outList: List[B]): Result.Result[List[B]] = { + inList match { + case Nil => Right(outList) + case head :: tail => transform(in, head) match { + case Left(e) => Left(e) + case Right((_, list)) => helper(tail, list :: outList) + } + } + } + helper(list, Nil).map(_.reverse) + } + + /** Transform a list and flatten the result */ + def transformFlatList[A, B]( + in: In, + list: List[A], + transform: (In, A) => Result[List[B]] + ): Result.Result[List[B]] = transformList(in, list, transform).map(_.flatten) + + /** Adapt a simple result function to the form of the visitor functions */ + def resultAdapter[A,B](f: (A, B) => Result.Result[B]) = + (a: A, b: B) => for (c <- f(a, b)) yield ((), c) + +} diff --git a/compiler/lib/src/main/scala/ast/ModuleStateTransformer.scala b/compiler/lib/src/main/scala/ast/ModuleStateTransformer.scala index 1b09561e49..e372f9f1f2 100644 --- a/compiler/lib/src/main/scala/ast/ModuleStateTransformer.scala +++ b/compiler/lib/src/main/scala/ast/ModuleStateTransformer.scala @@ -11,15 +11,29 @@ trait ModuleStateTransformer extends AstStateTransformer { ) = { val (pre, node, post) = aNode val Ast.DefModule(name, members) = node.data - for { result <- transformList(s, members, moduleMember) } + for ((s1, members1) <- transformFlatList(s, members, moduleMember)) yield { - val (s1, members1) = result - val defModule = Ast.DefModule(name, members1.flatten) + val defModule = Ast.DefModule(name, members1) val node1 = AstNode.create(defModule, node.id) (s1, (pre, node1, post)) } } + override def specTemplateExpandAnnotatedNodeExpanded( + s: State, + aNode: Ast.Annotated[AstNode[Ast.SpecTemplateExpand]], + members: List[Ast.ModuleMember] + ) = { + val (pre, node, post) = aNode + val Ast.SpecTemplateExpand(template, args, _) = node.data + for ((s1, members1) <- transformFlatList(s, members, moduleMember)) + yield { + val specTemplateExpand = Ast.SpecTemplateExpand(template, args, Some(members1)) + val node1 = AstNode.create(specTemplateExpand, node.id) + (s1, (pre, node1, post)) + } + } + def moduleMember(s: State, member: Ast.ModuleMember): Result[List[Ast.ModuleMember]] = matchModuleMember(s, member) diff --git a/compiler/lib/src/main/scala/codegen/AstWriter.scala b/compiler/lib/src/main/scala/codegen/AstWriter.scala index 8d5b30ec1c..a03e01c92b 100644 --- a/compiler/lib/src/main/scala/codegen/AstWriter.scala +++ b/compiler/lib/src/main/scala/codegen/AstWriter.scala @@ -186,23 +186,9 @@ object AstWriter extends AstVisitor with LineUtils { ).map(indentIn) } - override def specTemplateExpandAnnotatedNodeUnexpanded( + override def specTemplateExpandAnnotatedNode( in: In, aNode: Ast.Annotated[AstNode[Ast.SpecTemplateExpand]] - ) = { - val (_, node, _) = aNode - val data = node.data - lines("expand") ++ - List.concat( - qualIdent(data.template.data), - templateArgList(data.args) - ).map(indentIn) - } - - override def specTemplateExpandAnnotatedNodeExpanded( - in: In, - aNode: Ast.Annotated[AstNode[Ast.SpecTemplateExpand]], - members: List[Ast.ModuleMember] ) = { val (_, node, _) = aNode val data = node.data @@ -210,7 +196,7 @@ object AstWriter extends AstVisitor with LineUtils { List.concat( qualIdent(data.template.data), templateArgList(data.args), - members.flatMap(moduleMember) + data.members.getOrElse(Nil).flatMap(moduleMember) ).map(indentIn) } diff --git a/compiler/lib/src/main/scala/codegen/DictionaryJsonWriter/DictionaryJsonEncoder.scala b/compiler/lib/src/main/scala/codegen/DictionaryJsonWriter/DictionaryJsonEncoder.scala index 7a625e7f38..e5beed02f2 100644 --- a/compiler/lib/src/main/scala/codegen/DictionaryJsonWriter/DictionaryJsonEncoder.scala +++ b/compiler/lib/src/main/scala/codegen/DictionaryJsonWriter/DictionaryJsonEncoder.scala @@ -568,10 +568,12 @@ case class DictionaryJsonEncoder( /** JSON Encoding for Telemetry Packet Sets */ private implicit def tlmPacketSetEncoder: Encoder[(Name.Unqualified, TlmPacketSet)] = new Encoder[(Name.Unqualified, TlmPacketSet)] { override def apply(entry: (Name.Unqualified, TlmPacketSet)): Json = { - Json.obj( + val (setPreA, _, setPostA) = entry._2.aNode + val json = Json.obj( "name" -> entry._1.toString.asJson, "members" -> entry._2.packetMap.map((id, packet) => { - Json.obj( + val (preA, _, postA) = packet.aNode + val packetJson = Json.obj( "name" -> packet.getName.asJson, "id" -> id.asJson, "group" -> packet.group.asJson, @@ -580,12 +582,14 @@ case class DictionaryJsonEncoder( s"${e.instance.toString}.${e.tlmChannel.getName}" }).asJson ) + jsonWithOptionalValues(packetJson, Map("annotation" -> concatAnnotations(preA, postA))) }).asJson, "omitted" -> entry._2.omittedIdSet.map(tlmId => { val e = dictionary.tlmChannelEntryMap(tlmId) s"${e.instance.toString}.${e.tlmChannel.getName}" }).toList.sorted.asJson ) + jsonWithOptionalValues(json, Map("annotation" -> concatAnnotations(setPreA, setPostA))) } } diff --git a/compiler/lib/src/main/scala/syntax/Parser.scala b/compiler/lib/src/main/scala/syntax/Parser.scala index 0a4daadb35..3d721b5825 100644 --- a/compiler/lib/src/main/scala/syntax/Parser.scala +++ b/compiler/lib/src/main/scala/syntax/Parser.scala @@ -1096,8 +1096,10 @@ object Parser extends Parsers { val templateArgList = argList(templateArg) def specTemplateExpand: Parser[Ast.SpecTemplateExpand] = { - (expand ~>! node(qualIdent)) ~! templateArgList ^^ { - case id ~ args => Ast.SpecTemplateExpand(id, args, None) + (expand ~>! node(qualIdent)) ~! templateArgList ~! opt( + lbrace ~>! moduleMembers <~! rbrace + ) ^^ { + case id ~ args ~ membersOpt => Ast.SpecTemplateExpand(id, args, membersOpt) } } diff --git a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala index e0244a0787..bfd50e6c22 100644 --- a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala +++ b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala @@ -5,444 +5,273 @@ import fpp.compiler.ast._ import fpp.compiler.util._ /** Expand any template expansion specifiers that have not yet been expanded */ -object ExpandTemplates extends AstTransformer +object ExpandTemplates extends AstUnitTransformer { - type State = Analysis - - type In = State - - type Out = Unit + type In = Analysis def default(a: Analysis) = - throw new InternalError("ExpandTemplates: Transformer not implemented") - - /** Transform a list in sequence, threading state */ - def transformList[A, B]( - s: State, - list: List[A], - transform: (State, A) => Result[B] - ): Result[List[B]] = { - def helper(in: List[A], out: List[B]): Result[List[B]] = { - in match { - case Nil => Right(((), out)) - case head :: tail => transform(s, head) match { - case Left(e) => Left(e) - case Right((_, list)) => helper(tail, list :: out) - } - } - } - for { pair <- helper(list, Nil) } - yield ((), pair._2.reverse) - } + throw InternalError("ExpandTemplates: Transformer not implemented") override def transUnit( a: Analysis, tu: Ast.TransUnit - ): Result[Ast.TransUnit] = { - for { - members <- transformList(a, tu.members, matchModuleMember) - } yield (members._1, Ast.TransUnit(members._2.flatten)) + ) = { + for (members <- transformFlatList(a, tu.members, matchModuleMember)) + yield ((), Ast.TransUnit(members)) } // Duplicate every node inside a template definition override def defaultNode[T]( a: Analysis, node: AstNode[T] - ) = - a.template match { - case None => Right((), node) - case Some(expansionNode) => { - val out = AstNode.create(node.data) - val inLoc = Locations.get(node.id) - Locations.put(out.id, Location( - inLoc.file, - inLoc.pos, - inLoc.includingLoc, - Some(Locations.get(expansionNode)) - )) - Right((), out) - } - } - - def defaultNodeOpt[T]( - a: Analysis, - node: Option[AstNode[T]] - ): Result[Option[AstNode[T]]] = - node match { - case None => Right(((), None)) - case Some(node) => - for (result <- defaultNode(a, node)) - yield (result._1, Some(result._2)) - } + ) = Right((), cloneNode(a, node, node.data)) override def defaultAnnotatedNode[T]( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[T]] ) = { - a.template match { - // We are not currently in a template, leave the node alone - case None => Right((), aNode) - case Some(_) => - val (pre, node, post) = aNode - for (inter <- defaultNode(a, node)) - yield (inter._1, (pre, inter._2, post)) - } + val (pre, node, post) = aNode + val node1 = cloneNode(a, node, node.data) + Right((), (pre, node1, post)) } - inline def cloneNode[T]( + override def exprArrayNode( a: Analysis, - node: AstNode[T], - data: T + node: AstNode[Ast.Expr], + e: Ast.ExprArray ) = - a.template match { - case None => AstNode.create(data, node.id) - case Some(expansionNode) => { - val out = AstNode.create(data) - val inLoc = Locations.get(node.id) - Locations.put(out.id, Location( - inLoc.file, - inLoc.pos, - inLoc.includingLoc, - Some(Locations.get(expansionNode)) - )) - out - } - } + for (result <- transformList(a, e.elts, matchExprNode)) + yield ((), cloneNode(a, node, Ast.ExprArray(result))) - inline def cloneAnnotatedNode[T]( + override def exprArraySubscriptNode( a: Analysis, - aNode: Ast.Annotated[AstNode[T]], - data: T - ) = { - val (pre, node, post) = aNode - (pre, cloneNode(a, node, data), post) - } - - override def exprArrayNode(a: In, node: AstNode[Ast.Expr], e: Ast.ExprArray): ResultNode[Ast.Expr] = - for { result <- transformList(a, e.elts, matchExprNode) } - yield { - val (a1, elts1) = result - (a1, cloneNode(a, node, Ast.ExprArray(elts1))) - } - - override def exprArraySubscriptNode(a: In, node: AstNode[Ast.Expr], e: Ast.ExprArraySubscript): ResultNode[Ast.Expr] = + node: AstNode[Ast.Expr], + e: Ast.ExprArraySubscript + ) = for { - e1 <- matchExprNode(a, e.e1) - e2 <- matchExprNode(a, e.e2) - } - yield { - val (_, e1_) = e1 - val (_, e2_) = e2 - ((), cloneNode(a, node, Ast.ExprArraySubscript(e1_, e2_))) + (_, e1) <- matchExprNode(a, e.e1) + (_, e2) <- matchExprNode(a, e.e2) } + yield ((), cloneNode(a, node, Ast.ExprArraySubscript(e1, e2))) - override def exprBinopNode(a: In, node: AstNode[Ast.Expr], e: Ast.ExprBinop): ResultNode[Ast.Expr] = + override def exprBinopNode( + a: Analysis, node: AstNode[Ast.Expr], + e: Ast.ExprBinop + ) = for { - e1 <- matchExprNode(a, e.e1) - e2 <- matchExprNode(a, e.e2) - } - yield { - val (_, e1_) = e1 - val (_, e2_) = e2 - ((), cloneNode(a, node, Ast.ExprBinop(e1_, e.op, e2_))) - } - - override def exprDotNode(a: In, node: AstNode[Ast.Expr], e: Ast.ExprDot): ResultNode[Ast.Expr] = - for (result <- matchExprNode(a, e.e)) - yield { - val (a1, left) = result - (a1, cloneNode(a, node, Ast.ExprDot(left, cloneNode(a, e.id, e.id.data)))) - } - - override def exprParenNode(a: In, node: AstNode[Ast.Expr], e: Ast.ExprParen): ResultNode[Ast.Expr] = - for (result <- matchExprNode(a, e.e)) - yield { - val (a1, value) = result - (a1, cloneNode(a, node, Ast.ExprParen(value))) + (_, e1) <- matchExprNode(a, e.e1) + (_, e2) <- matchExprNode(a, e.e2) } + yield ((), cloneNode(a, node, Ast.ExprBinop(e1, e.op, e2))) - def structMember( + override def exprDotNode( a: Analysis, - node: AstNode[Ast.StructMember] - ) = { - for (result <- matchExprNode(a, node.data.value)) - yield { - val (a1, value) = result - (a1, cloneNode(a, node, Ast.StructMember( - node.data.name, - value - ))) - } - } - - def cloneQualIdentNode( - a: In, - node: AstNode[Ast.QualIdent] - ): AstNode[Ast.QualIdent] = { - node.data match { - case Ast.QualIdent.Qualified(qualifier, name) => - cloneNode(a, node, Ast.QualIdent.Qualified( - cloneQualIdentNode(a, qualifier), - cloneNode(a, name, name.data) - )) - case Ast.QualIdent.Unqualified(name, isAbsolute) => - cloneNode(a, node, Ast.QualIdent.Unqualified(name, isAbsolute)) - } - } + node: AstNode[Ast.Expr], + e: Ast.ExprDot + ) = + for ((_, left) <- matchExprNode(a, e.e)) + yield ((), cloneNode(a, node, Ast.ExprDot(left, cloneNode(a, e.id, e.id.data)))) - def qualIdentNode( - a: In, - node: AstNode[Ast.QualIdent] - ): ResultNode[Ast.QualIdent] = - Right(((), cloneQualIdentNode(a, node))) + override def exprParenNode( + a: Analysis, + node: AstNode[Ast.Expr], + e: Ast.ExprParen + ) = + for ((_, value) <- matchExprNode(a, e.e)) + yield ((), cloneNode(a, node, Ast.ExprParen(value))) override def exprStructNode( a: Analysis, node: AstNode[Ast.Expr], e: Ast.ExprStruct ) = - for { result <- transformList(a, e.members, structMember) } - yield { - val (a1, members1) = result - (a1, cloneNode(a, node, Ast.ExprStruct(members1))) - } + for (result <- transformList(a, e.members, resultAdapter(structMember))) + yield ((), cloneNode(a, node, Ast.ExprStruct(result))) - override def exprUnopNode(a: In, node: AstNode[Ast.Expr], e: Ast.ExprUnop) = - for (ec <- matchExprNode(a, e.e)) - yield (ec._1, cloneNode(a, node, Ast.ExprUnop(e.op, ec._2))) + override def exprUnopNode( + a: Analysis, + node: AstNode[Ast.Expr], + e: Ast.ExprUnop + ) = + for ((_, ec) <- matchExprNode(a, e.e)) + yield ((), cloneNode(a, node, Ast.ExprUnop(e.op, ec))) - override def exprSizeOfNode(a: In, node: AstNode[Ast.Expr], e: Ast.ExprSizeOf): ResultNode[Ast.Expr] = - for (result <- matchTypeName(a, e.typeName)) - yield (result._1, cloneNode(a, node, Ast.ExprSizeOf(result._2))) + override def exprSizeOfNode( + a: Analysis, + node: AstNode[Ast.Expr], + e: Ast.ExprSizeOf + ) = + for ((_, result) <- matchTypeName(a, e.typeName)) + yield ((), cloneNode(a, node, Ast.ExprSizeOf(result))) override def typeNameQualIdentNode( - a: In, + a: Analysis, node: AstNode[Ast.TypeName], tn: Ast.TypeNameQualIdent - ): ResultNode[Ast.TypeName] = { - Right(((), cloneNode(a, node, Ast.TypeNameQualIdent( - cloneQualIdentNode(a, tn.name) - )))) + ) = { + val qidNode = cloneQualIdentNode(a, tn.name) + Right((), cloneNode(a, node, Ast.TypeNameQualIdent(qidNode))) } - def exprNodeOpt( - a: In, - node: Option[AstNode[Ast.Expr]] - ): Result[Option[AstNode[Ast.Expr]]] = - node match { - case None => Right(((), None)) - case Some(value) => - for (result <- matchExprNode(a, value)) - yield { - val (a1, v1) = result - (a1, Some(v1)) - } - } - override def typeNameStringNode( - a: In, + a: Analysis, node: AstNode[Ast.TypeName], tn: Ast.TypeNameString - ): ResultNode[Ast.TypeName] = { - tn.size match { - case None => - Right(((), cloneNode(a, node, Ast.TypeNameString(None)))) - case Some(size) => - for (result <- matchExprNode(a, size)) - yield { - val (a1, value) = result - (a1, cloneNode(a, node, Ast.TypeNameString(Some(value)))) - } - } - } - - def typeNameNodeOpt( - a: In, - node: Option[AstNode[Ast.TypeName]] - ): Result[Option[AstNode[Ast.TypeName]]] = - node match { - case None => Right(((), None)) - case Some(tn) => - for (result <- matchTypeName(a, tn)) - yield ((), Some(result._2)) + ) = + for { + valueOpt <- tn.size match { + case None => Right(None) + case Some(size) => matchExprNode(a, size).map(_._2).map(Some(_)) + } } + yield ((), cloneNode(a, node, Ast.TypeNameString(valueOpt))) override def defAliasTypeAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefAliasType]] ): ResultAnnotatedNode[Ast.DefAliasType] = val data = aNode._2.data - for (result <- matchTypeName(a, data.typeName)) - yield { - val (a1, ty) = result - (a1, cloneAnnotatedNode( - a, aNode, data.copy(typeName = ty) - )) - } - - def cloneStringNodeOpt( - a: In, - node: Option[AstNode[String]] - ): Option[AstNode[String]] = - node match { - case None => None - case Some(value) => Some(cloneNode(a, value, value.data)) - } + for ((_, ty) <- matchTypeName(a, data.typeName)) + yield ((), cloneAnnotatedNode(a, aNode, data.copy(typeName = ty))) - override def defArrayAnnotatedNode(a: In, aNode: Ast.Annotated[AstNode[Ast.DefArray]]): ResultAnnotatedNode[Ast.DefArray] = + override def defArrayAnnotatedNode( + a: Analysis, + aNode: Ast.Annotated[AstNode[Ast.DefArray]] + ) = { val data = aNode._2.data for { - size <- matchExprNode(a, data.size) - eltType <- matchTypeName(a, data.eltType) + (_, size) <- matchExprNode(a, data.size) + (_, eltType) <- matchTypeName(a, data.eltType) default <- exprNodeOpt(a, data.default) } yield { - ( - (), - cloneAnnotatedNode( - a, aNode, - data.copy( - size = size._2, - eltType = eltType._2, - default = default._2, - format = cloneStringNodeOpt(a, data.format) - ) - ) + val dataCopy = data.copy( + size = size, + eltType = eltType, + default = default, + format = cloneStringNodeOpt(a, data.format) ) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) } + } - override def defComponentAnnotatedNode(a: In, aNode: Ast.Annotated[AstNode[Ast.DefComponent]]): ResultAnnotatedNode[Ast.DefComponent] = + override def defComponentAnnotatedNode( + a: Analysis, + aNode: Ast.Annotated[AstNode[Ast.DefComponent]] + ) = { val data = aNode._2.data - for (result <- transformList(a, data.members, matchComponentMember)) - yield { - val (a1, members1) = result - (a1, cloneAnnotatedNode(a, aNode, data.copy(members = members1.flatten))) - } + for (members <- transformFlatList(a, data.members, matchComponentMember)) + yield ((), cloneAnnotatedNode(a, aNode, data.copy(members = members))) + } override def defComponentInstanceAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefComponentInstance]] - ): ResultAnnotatedNode[Ast.DefComponentInstance] = + ) = { val data = aNode._2.data for { component <- Right(cloneQualIdentNode(a, data.component)) - baseId <- matchExprNode(a, data.baseId) + (_, baseId) <- matchExprNode(a, data.baseId) queueSize <- exprNodeOpt(a, data.queueSize) stackSize <- exprNodeOpt(a, data.stackSize) priority <- exprNodeOpt(a, data.priority) cpu <- exprNodeOpt(a, data.cpu) initSpecs <- transformList(a, data.initSpecs, specInitAnnotatedNode) } yield { - ( - (), - cloneAnnotatedNode( - a, aNode, - data.copy( - component=component, - baseId=baseId._2, - implType=cloneStringNodeOpt(a, data.implType), - file=cloneStringNodeOpt(a, data.file), - queueSize=queueSize._2, - stackSize=stackSize._2, - priority=priority._2, - cpu=cpu._2, - initSpecs=initSpecs._2 - ) - ) + val dataCopy = data.copy( + component=component, + baseId=baseId, + implType=cloneStringNodeOpt(a, data.implType), + file=cloneStringNodeOpt(a, data.file), + queueSize=queueSize, + stackSize=stackSize, + priority=priority, + cpu=cpu, + initSpecs=initSpecs ) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) } + } - override def defInterfaceAnnotatedNode(a: In, aNode: Ast.Annotated[AstNode[Ast.DefInterface]]): ResultAnnotatedNode[Ast.DefInterface] = + override def defInterfaceAnnotatedNode( + a: Analysis, + aNode: Ast.Annotated[AstNode[Ast.DefInterface]] + ) = { val data = aNode._2.data for (result <- transformList(a, data.members, matchInterfaceMember)) - yield { - val (a1, members1) = result - (a1, cloneAnnotatedNode(a, aNode, data.copy(members=members1))) - } + yield ((), cloneAnnotatedNode(a, aNode, data.copy(members=result))) + } override def defConstantAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefConstant]] - ): ResultAnnotatedNode[Ast.DefConstant] = - val data = aNode._2.data - for (value <- matchExprNode(a, data.value)) - yield { - ((), - cloneAnnotatedNode( - a, aNode, - data.copy(value = value._2))) - } - - def defEnumConstantAnnotatedNode( - a: In, - aNode: Ast.Annotated[AstNode[Ast.DefEnumConstant]] - ): ResultAnnotatedNode[Ast.DefEnumConstant] = + ) = val data = aNode._2.data - for (value <- exprNodeOpt(a, data.value)) - yield { - ((), cloneAnnotatedNode(a, aNode, data.copy(value = value._2))) - } + for ((_, value) <- matchExprNode(a, data.value)) + yield { + val dataCopy = data.copy(value = value) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) + } override def defEnumAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefEnum]] - ): ResultAnnotatedNode[Ast.DefEnum] = + ) = val data = aNode._2.data for { typeName <- typeNameNodeOpt(a, data.typeName) - constants <- transformList(a, data.constants, defEnumConstantAnnotatedNode) + constants <- transformList( + a, + data.constants, + resultAdapter(defEnumConstantAnnotatedNode) + ) default <- exprNodeOpt(a, data.default) - } yield ((), cloneAnnotatedNode(a, aNode, data.copy( - typeName = typeName._2, - constants = constants._2, - default = default._2 - ))) - - def formalAnnotatatedParam( - a: In, - aNode: Ast.Annotated[AstNode[Ast.FormalParam]] - ) = - val data = aNode._2.data - for (ty <- matchTypeName(a, data.typeName)) - yield ((), cloneAnnotatedNode(a, aNode, data.copy(typeName = ty._2))) - - def formalParamList( - a: In, - aNode: Ast.FormalParamList - ) = transformList(a, aNode, formalAnnotatatedParam) + } yield { + val dataCopy = data.copy( + typeName = typeName, + constants = constants, + default = default + ) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) + } override def defPortAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefPort]] - ): ResultAnnotatedNode[Ast.DefPort] = + ) = val data = aNode._2.data for { params <- formalParamList(a, data.params) returnType <- typeNameNodeOpt(a, data.returnType) - } yield ((), cloneAnnotatedNode(a, aNode, data.copy( - params = params._2, - returnType = returnType._2 - ))) + } yield { + val dataCopy = data.copy(params = params, returnType = returnType) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) + } override def defStateMachineAnnotatedNodeExternal( in: In, node: Ast.Annotated[AstNode[Ast.DefStateMachine]] - ): ResultAnnotatedNode[Ast.DefStateMachine] = + ) = defaultAnnotatedNode(in, node) override def defStateMachineAnnotatedNodeInternal( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefStateMachine]], members: List[Ast.StateMachineMember] - ): ResultAnnotatedNode[Ast.DefStateMachine] = - val data = aNode._2.data - for (result <- transformList(a, members, matchStateMachineMember)) - yield (result._1, cloneAnnotatedNode(a, aNode, data.copy(members = Some(result._2.flatten)))) + ) = + val data = aNode._2.data + for (members <- transformFlatList(a, members, matchStateMachineMember)) + yield ((), cloneAnnotatedNode(a, aNode, data.copy(members = Some(members)))) override def defStateMachineAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefStateMachine]] - ): ResultAnnotatedNode[Ast.DefStateMachine] = + ) = val data = aNode._2.data data.members match { case None => defStateMachineAnnotatedNodeExternal(a, aNode) @@ -450,201 +279,144 @@ object ExpandTemplates extends AstTransformer } override def defActionAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefAction]] - ): ResultAnnotatedNode[Ast.DefAction] = + ) = val data = aNode._2.data for { typeName <- typeNameNodeOpt(a, data.typeName) - } yield { - ((), cloneAnnotatedNode(a, aNode, data.copy(typeName = typeName._2))) - } - - def transitionExpr( - a: In, - node: AstNode[Ast.TransitionExpr] - ): ResultNode[Ast.TransitionExpr] = - for { - actions <- transformList(a, node.data.actions, defaultNode) - target <- qualIdentNode(a, node.data.target) - } yield ((), cloneNode(a, node, node.data.copy( - actions = actions._2, - target = target._2, - ))) + } yield ((), cloneAnnotatedNode(a, aNode, data.copy(typeName = typeName))) override def defChoiceAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefChoice]] - ): ResultAnnotatedNode[Ast.DefChoice] = + ) = val data = aNode._2.data for { - guard <- defaultNode(a, data.guard) + (_, guard) <- defaultNode(a, data.guard) ifTransition <- transitionExpr(a, data.ifTransition) elseTransition <- transitionExpr(a, data.elseTransition) } yield { - ((), cloneAnnotatedNode(a, aNode, data.copy( - guard = guard._2, - ifTransition = ifTransition._2, - elseTransition = elseTransition._2, - ))) + val dataCopy = data.copy( + guard = guard, + ifTransition = ifTransition, + elseTransition = elseTransition + ) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) } override def defGuardAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefGuard]] - ): ResultAnnotatedNode[Ast.DefGuard] = + ) = val data = aNode._2.data - for { - typeName <- typeNameNodeOpt(a, data.typeName) - } yield { - ((), cloneAnnotatedNode(a, aNode, data.copy(typeName = typeName._2))) - } + for (typeName <- typeNameNodeOpt(a, data.typeName)) + yield ((), cloneAnnotatedNode(a, aNode, data.copy(typeName = typeName))) override def defSignalAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefSignal]] - ): ResultAnnotatedNode[Ast.DefSignal] = + ) = val data = aNode._2.data - for { - typeName <- typeNameNodeOpt(a, data.typeName) - } yield { - ((), cloneAnnotatedNode(a, aNode, data.copy(typeName = typeName._2))) - } + for (typeName <- typeNameNodeOpt(a, data.typeName)) + yield ((), cloneAnnotatedNode(a, aNode, data.copy(typeName = typeName))) override def defStateAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefState]] - ): ResultAnnotatedNode[Ast.DefState] = + ) = val data = aNode._2.data - for (members <- transformList(a, data.members, matchStateMember)) - yield ((), cloneAnnotatedNode(a, aNode, data.copy(members = members._2.flatten))) + for (members <- transformFlatList(a, data.members, matchStateMember)) + yield ((), cloneAnnotatedNode(a, aNode, data.copy(members = members))) override def specInitialTransitionAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecInitialTransition]] - ): ResultAnnotatedNode[Ast.SpecInitialTransition] = + ) = val data = aNode._2.data - for { - transition <- transitionExpr(a, data.transition) - } yield { - ((), cloneAnnotatedNode(a, aNode, data.copy(transition = transition._2))) - } + for (transition <- transitionExpr(a, data.transition)) + yield ((), cloneAnnotatedNode(a, aNode, data.copy(transition = transition))) override def specStateEntryAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecStateEntry]] - ): ResultAnnotatedNode[Ast.SpecStateEntry] = + ) = val data = aNode._2.data - for { - actions <- transformList(a, data.actions, defaultNode) - } yield { - ((), cloneAnnotatedNode(a, aNode, data.copy(actions = actions._2))) - } + for (actions <- transformList(a, data.actions, defaultNode)) + yield ((), cloneAnnotatedNode(a, aNode, data.copy(actions = actions))) override def specStateExitAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecStateExit]] - ): ResultAnnotatedNode[Ast.SpecStateExit] = - val data = aNode._2.data - for { - actions <- transformList(a, data.actions, defaultNode) - } yield { - ((), cloneAnnotatedNode(a, aNode, data.copy(actions = actions._2))) - } - - def transitionOrDo( - a: In, - transitionOrDo: Ast.TransitionOrDo ) = - transitionOrDo match - case Ast.TransitionOrDo.Transition(transition) => - for (result <- transitionExpr(a, transition)) - yield (result._1, Ast.TransitionOrDo.Transition(result._2)) - case Ast.TransitionOrDo.Do(actions) => - for (result <- transformList(a, actions, defaultNode)) - yield (result._1, Ast.TransitionOrDo.Do(result._2)) - + val data = aNode._2.data + for (actions <- transformList(a, data.actions, defaultNode)) + yield ((), cloneAnnotatedNode(a, aNode, data.copy(actions = actions))) override def specStateTransitionAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecStateTransition]] - ): ResultAnnotatedNode[Ast.SpecStateTransition] = + ) = val data = aNode._2.data for { - signal <- defaultNode(a, data.signal) + (_, signal) <- defaultNode(a, data.signal) guard <- defaultNodeOpt(a, data.guard) transitionOrDo <- transitionOrDo(a, data.transitionOrDo) } yield { - ((), cloneAnnotatedNode(a, aNode, data.copy( - signal = signal._2, - guard = guard._2, - transitionOrDo = transitionOrDo._2 - ))) - } - - def structTypeMemberAnnotatedNode( - a: In, - aNode: Ast.Annotated[AstNode[Ast.StructTypeMember]] - ) = - val data = aNode._2.data - for { - size <- exprNodeOpt(a, data.size) - typeName <- matchTypeName(a, data.typeName) - } yield { - ((), cloneAnnotatedNode(a, aNode, data.copy( - size = size._2, - typeName = typeName._2, - format = cloneStringNodeOpt(a, data.format) - ))) + val dataCopy = data.copy( + signal = signal, + guard = guard, + transitionOrDo = transitionOrDo + ) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) } override def defStructAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefStruct]] - ): ResultAnnotatedNode[Ast.DefStruct] = + ) = val data = aNode._2.data for { - members <- transformList(a, data.members, structTypeMemberAnnotatedNode) + members <- transformList(a, data.members, resultAdapter(structTypeMemberAnnotatedNode)) default <- exprNodeOpt(a, data.default) } yield { - ((), cloneAnnotatedNode(a, aNode, data.copy( - members = members._2, - default = default._2 - ))) + val dataCopy = data.copy(members = members, default = default) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) } override def defTopologyAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefTopology]] - ): ResultAnnotatedNode[Ast.DefTopology] = + ) = val data = aNode._2.data for { - members <- transformList(a, data.members, matchTopologyMember) + members <- transformFlatList(a, data.members, matchTopologyMember) implements <- transformList(a, data.implements, (a, q) => Right(((), cloneQualIdentNode(a, q)))) } yield { - ((), cloneAnnotatedNode(a, aNode, data.copy( - members = members._2.flatten, - implements = implements._2 - ))) + val dataCopy = data.copy(members = members, implements = implements) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) } override def defSystemAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefSystem]] - ): ResultAnnotatedNode[Ast.DefSystem] = + ) = val data = aNode._2.data - for { - topology <- qualIdentNode(a, data.topology) - } yield { - ((), cloneAnnotatedNode(a, aNode, data.copy( - topology = topology._2 - ))) - } + for (topology <- qualIdentNode(a, data.topology)) + yield { + val dataCopy = data.copy(topology = topology) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) + } override def specCommandAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecCommand]] - ): ResultAnnotatedNode[Ast.SpecCommand] = + ) = val data = aNode._2.data for { params <- formalParamList(a, data.params) @@ -652,48 +424,37 @@ object ExpandTemplates extends AstTransformer priority <- exprNodeOpt(a, data.priority) queueFull <- defaultNodeOpt(a, data.queueFull) } yield { - ((), cloneAnnotatedNode(a, aNode, data.copy( - params = params._2, - opcode = opcode._2, - priority = priority._2, - queueFull = queueFull._2, - ))) + val dataCopy = data.copy( + params = params, + opcode = opcode, + priority = priority, + queueFull = queueFull, + ) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) } override def specInstanceAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecInstance]] - ): ResultAnnotatedNode[Ast.SpecInstance] = + ) = val data = aNode._2.data for { instance <- qualIdentNode(a, data.instance) } yield { - ((), cloneAnnotatedNode(a, aNode, data.copy( - instance = instance._2, - ))) + val dataCopy = data.copy(instance = instance) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) } - def portInstanceIdentifierNode( - a: In, - pii: AstNode[Ast.PortInstanceIdentifier] - ): ResultNode[Ast.PortInstanceIdentifier] = { - for { - interfaceInstance <- qualIdentNode(a, pii.data.interfaceInstance) - portName <- defaultNode(a, pii.data.portName) - } yield ((), cloneNode(a, pii, pii.data.copy( - interfaceInstance = interfaceInstance._2, - portName = portName._2, - ))) - } - override def specConnectionGraphAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecConnectionGraph]] - ): ResultAnnotatedNode[Ast.SpecConnectionGraph] = + ) = { val data = aNode._2.data def connection( - a: In, + a: Analysis, connection: Ast.SpecConnectionGraph.Connection ): Result[Ast.SpecConnectionGraph.Connection] = { for { @@ -702,390 +463,395 @@ object ExpandTemplates extends AstTransformer toPort <- portInstanceIdentifierNode(a, connection.toPort) toIndex <- exprNodeOpt(a, connection.toIndex) } yield { - ((), connection.copy( - fromPort = fromPort._2, - fromIndex = fromIndex._2, - toPort = toPort._2, - toIndex = toIndex._2, - )) + val connectionCopy = connection.copy( + fromPort = fromPort, + fromIndex = fromIndex, + toPort = toPort, + toIndex = toIndex + ) + ((), connectionCopy) } } data match { case data @ Ast.SpecConnectionGraph.Direct(_, connections) => - for { - connections <- transformList(a, connections, connection) - } yield ((), cloneAnnotatedNode(a, aNode, data.copy( - connections = connections._2 - ))) + for (connections <- transformList(a, connections, connection)) + yield { + val dataCopy = data.copy(connections = connections) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) + } case data @ Ast.SpecConnectionGraph.Pattern(_, source, targets) => for { source <- qualIdentNode(a, source) - targets <- transformList(a, targets, qualIdentNode) - } yield ((), cloneAnnotatedNode(a, aNode, data.copy( - source = source._2, - targets = targets._2 - ))) + targets <- transformList(a, targets, resultAdapter(qualIdentNode)) + } yield { + val dataCopy = data.copy(source = source, targets = targets) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) + } } + } + override def specContainerAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecContainer]] - ): ResultAnnotatedNode[Ast.SpecContainer] = + ) = val data = aNode._2.data for { id <- exprNodeOpt(a, data.id) defaultPriority <- exprNodeOpt(a, data.defaultPriority) } yield { - ((), cloneAnnotatedNode(a, aNode, data.copy( - id = id._2, - defaultPriority = defaultPriority._2, - ))) + val dataCopy = data.copy(id = id, defaultPriority = defaultPriority) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) } override def specEventAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecEvent]] - ): ResultAnnotatedNode[Ast.SpecEvent] = + ) = val data = aNode._2.data for { params <- formalParamList(a, data.params) id <- exprNodeOpt(a, data.id) - format <- defaultNode(a, data.format) - throttle <- { - data.throttle match { - case None => Right(((), None)) - case Some(throttle) => - for { - count <- matchExprNode(a, throttle.data.count) - every <- exprNodeOpt(a, throttle.data.every) - } yield ((), Some(cloneNode( - a, throttle, throttle.data.copy( - every = every._2, - count = count._2, - ) - ))) - } + (_, format) <- defaultNode(a, data.format) + throttle <- data.throttle match { + case None => Right(None) + case Some(throttle) => + for { + (_, count) <- matchExprNode(a, throttle.data.count) + every <- exprNodeOpt(a, throttle.data.every) + } yield { + val dataCopy = throttle.data.copy(every = every, count = count) + val node = cloneNode(a, throttle, dataCopy) + Some(node) + } } } yield { - ((), cloneAnnotatedNode(a, aNode, data.copy( - params = params._2, - id = id._2, - format = format._2, - throttle = throttle._2, - ))) + val dataCopy = data.copy( + params = params, + id = id, + format = format, + throttle = throttle + ) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) } override def specIncludeAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecInclude]] - ): ResultAnnotatedNode[Ast.SpecInclude] = + ) = val data = aNode._2.data for { - file <- defaultNode(a, data.file) - } yield (file._1, cloneAnnotatedNode(a, aNode, data.copy( - file = file._2, - ))) + (_, file) <- defaultNode(a, data.file) + } yield ((), cloneAnnotatedNode(a, aNode, data.copy(file = file))) override def specInitAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecInit]] - ): ResultAnnotatedNode[Ast.SpecInit] = + ) = val data = aNode._2.data - for (result <- matchExprNode(a, data.phase)) - yield { - val (a1, phase1) = result - (a1, cloneAnnotatedNode(a, aNode, data.copy(phase=phase1))) - } + for ((_, phase) <- matchExprNode(a, data.phase)) + yield ((), cloneAnnotatedNode(a, aNode, data.copy(phase=phase))) override def specInternalPortAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecInternalPort]] - ): ResultAnnotatedNode[Ast.SpecInternalPort] = + ) = val data = aNode._2.data for { params <- formalParamList(a, data.params) priority <- exprNodeOpt(a, data.priority) - } yield ((), cloneAnnotatedNode(a, aNode, data.copy( - params = params._2, - priority = priority._2, - ))) + } yield { + val dataCopy = data.copy(params = params, priority = priority) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) + } override def specLocAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecLoc]] - ): ResultAnnotatedNode[Ast.SpecLoc] = + ) = val data = aNode._2.data for { symbol <- qualIdentNode(a, data.symbol) - file <- defaultNode(a, data.file) - } yield ((), cloneAnnotatedNode(a, aNode, data.copy( - symbol = symbol._2, - file = file._2, - ))) + (_, file) <- defaultNode(a, data.file) + } yield { + val dataCopy = data.copy(symbol = symbol, file = file) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) + } override def specParamAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecParam]] - ): ResultAnnotatedNode[Ast.SpecParam] = + ) = val data = aNode._2.data for { - typeName <- matchTypeName(a, data.typeName) + (_, typeName) <- matchTypeName(a, data.typeName) default <- exprNodeOpt(a, data.default) id <- exprNodeOpt(a, data.id) setOpcode <- exprNodeOpt(a, data.setOpcode) saveOpcode <- exprNodeOpt(a, data.saveOpcode) - } yield ((), cloneAnnotatedNode(a, aNode, data.copy( - typeName = typeName._2, - default = default._2, - id = id._2, - setOpcode = setOpcode._2, - saveOpcode = saveOpcode._2, - ))) - - def qualIdentNodeOpt( - a: In, - qi: Option[AstNode[Ast.QualIdent]] - ): Result[Option[AstNode[Ast.QualIdent]]] = { - qi match { - case None => Right(((), None)) - case Some(value) => - for (result <- qualIdentNode(a, value)) - yield (((), Some(result._2))) + } yield { + val dataCopy = data.copy( + typeName = typeName, + default = default, + id = id, + setOpcode = setOpcode, + saveOpcode = saveOpcode + ) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) } - } override def specPortInstanceAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecPortInstance]] - ): ResultAnnotatedNode[Ast.SpecPortInstance] = + ) = val data = aNode._2.data data match { - case data @ Ast.SpecPortInstance.General(_, _, _, _, _, _) => + case data : Ast.SpecPortInstance.General => for { size <- exprNodeOpt(a, data.size) port <- qualIdentNodeOpt(a, data.port) priority <- exprNodeOpt(a, data.priority) queueFull <- defaultNodeOpt(a, data.queueFull) } yield { - ((), cloneAnnotatedNode(a, aNode, data.copy( - size = size._2, - port = port._2, - priority = priority._2, - queueFull = queueFull._2 - ))) + val dataCopy = data.copy( + size = size, + port = port, + priority = priority, + queueFull = queueFull + ) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) } - case data @ Ast.SpecPortInstance.Special(_, _, _, _, _) => + case data : Ast.SpecPortInstance.Special => for { priority <- exprNodeOpt(a, data.priority) queueFull <- defaultNodeOpt(a, data.queueFull) } yield { - ((), cloneAnnotatedNode(a, aNode, data.copy( - priority = priority._2, - queueFull = queueFull._2 - ))) + val dataCopy = data.copy(priority = priority, queueFull = queueFull) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) } } override def specPortMatchingAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecPortMatching]] - ): ResultAnnotatedNode[Ast.SpecPortMatching] = + ) = val data = aNode._2.data for { - port1 <- defaultNode(a, data.port1) - port2 <- defaultNode(a, data.port2) - } yield (((), cloneAnnotatedNode(a, aNode, data.copy( - port1 = port1._2, - port2 = port2._2 - )))) + (_, port1) <- defaultNode(a, data.port1) + (_, port2) <- defaultNode(a, data.port2) + } yield { + val dataCopy = data.copy(port1 = port1, port2 = port2) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) + } override def specRecordAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecRecord]] - ): ResultAnnotatedNode[Ast.SpecRecord] = + ) = val data = aNode._2.data for { - recordType <- matchTypeName(a, data.recordType) + (_, recordType) <- matchTypeName(a, data.recordType) id <- exprNodeOpt(a, data.id) - } yield (((), cloneAnnotatedNode(a, aNode, data.copy( - recordType = recordType._2, - id = id._2 - )))) + } yield { + val dataCopy = data.copy(recordType = recordType, id = id) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) + } override def specStateMachineInstanceAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecStateMachineInstance]] - ): ResultAnnotatedNode[Ast.SpecStateMachineInstance] = + ) = val data = aNode._2.data for { stateMachine <- qualIdentNode(a, data.stateMachine) priority <- exprNodeOpt(a, data.priority) - } yield (((), cloneAnnotatedNode(a, aNode, data.copy( - stateMachine = stateMachine._2, - priority = priority._2 - )))) + } yield { + val dataCopy = data.copy(stateMachine = stateMachine, priority = priority) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) + } override def specTlmChannelAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecTlmChannel]] - ): ResultAnnotatedNode[Ast.SpecTlmChannel] = + ) = val data = aNode._2.data def limit( - a: In, + a: Analysis, limit: Ast.SpecTlmChannel.Limit ): Result[Ast.SpecTlmChannel.Limit] = { val (kind, value) = limit for { - kind <- defaultNode(a, kind) - value <- matchExprNode(a, value) - } yield (((), (kind._2, value._2))) + (_, kind) <- defaultNode(a, kind) + (_, value) <- matchExprNode(a, value) + } yield ((), (kind, value)) } for { - typeName <- matchTypeName(a, data.typeName) + (_, typeName) <- matchTypeName(a, data.typeName) id <- exprNodeOpt(a, data.id) low <- transformList(a, data.low, limit) high <- transformList(a, data.high, limit) - } yield (((), cloneAnnotatedNode(a, aNode, data.copy( - typeName = typeName._2, - id = id._2, - format = cloneStringNodeOpt(a, data.format), - low = low._2, - high = high._2 - )))) + } yield { + val dataCopy = data.copy( + typeName = typeName, + id = id, + format = cloneStringNodeOpt(a, data.format), + low = low, + high = high + ) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) + } override def specTlmPacketAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecTlmPacket]] - ): ResultAnnotatedNode[Ast.SpecTlmPacket] = + ) = val data = aNode._2.data def tlmPacketMember( - a: In, + a: Analysis, member: Ast.TlmPacketMember ): Result[Ast.TlmPacketMember] = { member match { case Ast.TlmPacketMember.SpecInclude(node) => - for (file <- defaultNode(a, node.data.file)) - yield ((), Ast.TlmPacketMember.SpecInclude( - cloneNode(a, node, node.data.copy(file = file._2)) - )) + for ((_, file) <- defaultNode(a, node.data.file)) + yield { + val nodeCopy = cloneNode(a, node, node.data.copy(file = file)) + val specIncludeCopy = Ast.TlmPacketMember.SpecInclude(nodeCopy) + ((), specIncludeCopy) + } case Ast.TlmPacketMember.TlmChannelIdentifier(node) => for { componentInstance <- qualIdentNode(a, node.data.componentInstance) - channelName <- defaultNode(a, node.data.channelName) - } yield ((), Ast.TlmPacketMember.TlmChannelIdentifier( - cloneNode(a, node, node.data.copy( - componentInstance = componentInstance._2, - channelName = channelName._2 - )) - )) + (_, channelName) <- defaultNode(a, node.data.channelName) + } yield { + val dataCopy = node.data.copy( + componentInstance = componentInstance, + channelName = channelName + ) + val nodeCopy = cloneNode(a, node, dataCopy) + val channelIdCopy = Ast.TlmPacketMember.TlmChannelIdentifier(nodeCopy) + ((), channelIdCopy) + } } } for { id <- exprNodeOpt(a, data.id) - group <- matchExprNode(a, data.group) + (_, group) <- matchExprNode(a, data.group) members <- transformList(a, data.members, tlmPacketMember) - } yield (((), cloneAnnotatedNode(a, aNode, data.copy( - id = id._2, - group = group._2, - members = members._2, - )))) + } yield { + val dataCopy = data.copy( + id = id, + group = group, + members = members + ) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) + } override def specTopPortAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecTopPort]] - ): ResultAnnotatedNode[Ast.SpecTopPort] = + ) = val data = aNode._2.data - for { - underlyingPort <- portInstanceIdentifierNode(a, data.underlyingPort) - } yield ((), cloneAnnotatedNode(a, aNode, data.copy( - underlyingPort = underlyingPort._2, - ))) + for (underlyingPort <- portInstanceIdentifierNode(a, data.underlyingPort)) + yield { + val dataCopy = data.copy(underlyingPort = underlyingPort) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) + } override def specTlmPacketSetAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecTlmPacketSet]] - ): ResultAnnotatedNode[Ast.SpecTlmPacketSet] = + ) = val data = aNode._2.data def tlmChannelIdentifier( - a: In, + a: Analysis, node: AstNode[Ast.TlmChannelIdentifier] ): ResultNode[Ast.TlmChannelIdentifier] = val data = node.data for { componentInstance <- qualIdentNode(a, data.componentInstance) - channelName <- defaultNode(a, data.channelName) - } yield ((), cloneNode(a, node, data.copy( - componentInstance = componentInstance._2, - channelName = channelName._2 - ))) + (_, channelName) <- defaultNode(a, data.channelName) + } yield { + val dataCopy = data.copy( + componentInstance = componentInstance, + channelName = channelName + ) + val nodeCopy = cloneNode(a, node, dataCopy) + ((), nodeCopy) + } for { - members <- transformList(a, data.members, matchTlmPacketSetMember) + members <- transformFlatList(a, data.members, matchTlmPacketSetMember) omitted <- transformList(a, data.omitted, tlmChannelIdentifier) - } yield ((), cloneAnnotatedNode(a, aNode, data.copy( - members = members._2.flatten, - omitted = omitted._2, - ))) + } yield { + val dataCopy = data.copy(members = members, omitted = omitted) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) + } override def specInterfaceImportAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecImport]] - ): ResultAnnotatedNode[Ast.SpecImport] = + ) = val data = aNode._2.data for { sym <- qualIdentNode(a, data.sym) - } yield ((), cloneAnnotatedNode(a, aNode, data.copy( - sym = sym._2, - ))) + } yield { + val dataCopy = data.copy(sym = sym) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) + } override def defModuleTemplateAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefModuleTemplate]] - ): ResultAnnotatedNode[Ast.DefModuleTemplate] = + ) = val (_, node, _) = aNode val data = node.data def templateParam( - a: In, + a: Analysis, param: Ast.Annotated[AstNode[Ast.TemplateParam]] ): ResultAnnotatedNode[Ast.TemplateParam] = { val (_, node, _) = param - node.data match { - case data @ Ast.TemplateParam.Constant(_, tn) => - for (tn <- matchTypeName(a, tn)) - yield ((), cloneAnnotatedNode(a, param, data.copy(typeName = tn._2))) - case data @ Ast.TemplateParam.Type(_) => - Right(((), cloneAnnotatedNode(a, param, data))) - case data @ Ast.TemplateParam.Interface(_, interface) => - for (interface <- qualIdentNode(a, interface)) - yield ((), cloneAnnotatedNode(a, param, data.copy(interface = interface._2))) - } + for { + data <- node.data match { + case data @ Ast.TemplateParam.Constant(_, tn) => + for ((_, tn) <- matchTypeName(a, tn)) + yield data.copy(typeName = tn) + case data @ Ast.TemplateParam.Type(_) => Right(data) + case data @ Ast.TemplateParam.Interface(_, interface) => + for (interface <- qualIdentNode(a, interface)) + yield data.copy(interface = interface) + } + } yield ((), cloneAnnotatedNode(a, param, data)) } for { - // Validate no nested template - _ <- a.templateDefinition match { - case Some(parent) => Left(SemanticError.NestedTemplateDefinition( - Locations.get(aNode._2.id), - Locations.get(parent) - )) - case None => Right(()) - } - a <- Right(a.copy(templateDefinition = Some(node.id))) params <- transformList(a, data.params, templateParam) - members <- transformList(a, data.members, matchModuleMember) - a <- Right(a.copy(templateDefinition = None)) + members <- transformFlatList(a, data.members, matchModuleMember) } yield { - val (_, params1) = params - val (_, members1) = members - ((), cloneAnnotatedNode(a, aNode, data.copy( - params = params1, - members = members1.flatten - ))) + val dataCopy = data.copy(params = params, members = members) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) } override def defModuleAnnotatedNode( @@ -1094,52 +860,244 @@ object ExpandTemplates extends AstTransformer ) = { val (_, node, _) = aNode val data = node.data - for { result <- transformList(a, data.members, matchModuleMember) } - yield { - val (a1, members1) = result - (a1, cloneAnnotatedNode(a, aNode, data.copy(members = members1.flatten))) - } + for (members <- transformFlatList(a, data.members, matchModuleMember)) + yield ((), cloneAnnotatedNode(a, aNode, data.copy(members = members))) } override def specTemplateExpandAnnotatedNode( a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecTemplateExpand]] - ): ResultAnnotatedNode[Ast.SpecTemplateExpand] = { + ) = { + val (_, node, _) = aNode + val data = node.data + data.members match { + // Members are already there; nothing to do + case Some(members) => Right((), aNode) + // Members are not there; expand + case None => (resultAdapter(expandTemplate))(a, aNode) + } + } + + private inline def cloneNode[T]( + a: Analysis, + node: AstNode[T], + data: T + ) = + a.templateExpansionId match { + case None => AstNode.create(data, node.id) + case Some(expansionNode) => { + val out = AstNode.create(data) + val inLoc = Locations.get(node.id) + val outLoc = Location( + inLoc.file, + inLoc.pos, + inLoc.includingLoc, + Some(Locations.get(expansionNode)) + ) + Locations.put(out.id, outLoc) + out + } + } + + private inline def cloneAnnotatedNode[T]( + a: Analysis, + aNode: Ast.Annotated[AstNode[T]], + data: T + ) = { + val (pre, node, post) = aNode + (pre, cloneNode(a, node, data), post) + } + + private def cloneQualIdentNode( + a: Analysis, + node: AstNode[Ast.QualIdent] + ): AstNode[Ast.QualIdent] = { + node.data match { + case Ast.QualIdent.Qualified(qualifier, name) => + val qualIdent = Ast.QualIdent.Qualified( + cloneQualIdentNode(a, qualifier), + cloneNode(a, name, name.data) + ) + cloneNode(a, node, qualIdent) + case Ast.QualIdent.Unqualified(name, isAbsolute) => + cloneNode(a, node, Ast.QualIdent.Unqualified(name, isAbsolute)) + } + } + + private def cloneStringNodeOpt( + a: Analysis, + node: Option[AstNode[String]] + ): Option[AstNode[String]] = + node match { + case None => None + case Some(value) => Some(cloneNode(a, value, value.data)) + } + + private def defaultNodeOpt[T]( + a: Analysis, + node: Option[AstNode[T]] + ): Result.Result[Option[AstNode[T]]] = + node match { + case None => Right(None) + case Some(node) => + for ((_, node) <- defaultNode(a, node)) + yield Some(node) + } + + private def defEnumConstantAnnotatedNode( + a: Analysis, + aNode: Ast.Annotated[AstNode[Ast.DefEnumConstant]] + ): Result.Result[Ast.Annotated[AstNode[Ast.DefEnumConstant]]] = + val data = aNode._2.data + for (value <- exprNodeOpt(a, data.value)) + yield cloneAnnotatedNode(a, aNode, data.copy(value = value)) + + /** Expand a template */ + private def expandTemplate( + a: Analysis, + aNode: Ast.Annotated[AstNode[Ast.SpecTemplateExpand]] + ): Result.Result[Ast.Annotated[AstNode[Ast.SpecTemplateExpand]]] = { val (pre, node, post) = aNode val data = node.data + for { + // Look up the template def + tmpl <- a.getTemplateSymbol(data.template.id) + // Clone the template body, recording the expansion node so that + // cloned nodes point back at the expansion site. + members <- transformFlatList( + a.copy(templateExpansionId = Some(node.id)), + tmpl.node._2.data.members, + matchModuleMember + ) + } yield { + // Paste the expanded template body into the expansion specifier + val dataCopy = data.copy(members = Some(members)) + val nodeCopy = AstNode.create(dataCopy, node.id) + (pre, nodeCopy, post) + } + } - (a.template, a.templateDefinition) match { - case (None, None) => - // Not inside a template: expand it - for { - // Look up the template def - tmpl <- a.getTemplateSymbol(data.template.id) - - // Clone the template body, recording the expansion node so that any - // nested expansion specifier is rejected and so that cloned nodes - // point back at the expansion site. - // Record the template definition too for diagnostics. - members <- transformList( - a.copy( - template = Some(node.id), - templateDefinition = Some(tmpl.node._2.id) - ), - tmpl.node._2.data.members, - matchModuleMember - ) - } yield { - // Paste the expanded template body into the expansion specifier - ((), (pre, AstNode.create(data.copy(members = Some(members._2.flatten)), node.id), post)) - } - case (_, Some(templateDefinition)) => - // The expansion specifier is nested inside a template body - Left(SemanticError.TemplateExpansionInTemplate( - Locations.get(node.id), - Locations.get(templateDefinition) - )) - case (Some(_), None) => throw new InternalError( - "ExpandTemplates: expanding a template with no template definition" + private def exprNodeOpt( + a: Analysis, + node: Option[AstNode[Ast.Expr]] + ): Result.Result[Option[AstNode[Ast.Expr]]] = + node match { + case None => Right(None) + case Some(value) => + for ((_, result) <- matchExprNode(a, value)) + yield Some(result) + } + + private def formalAnnotatatedParam( + a: Analysis, + aNode: Ast.Annotated[AstNode[Ast.FormalParam]] + ) = + val data = aNode._2.data + for ((_, ty) <- matchTypeName(a, data.typeName)) + yield cloneAnnotatedNode(a, aNode, data.copy(typeName = ty)) + + private def formalParamList( + a: Analysis, + aNode: Ast.FormalParamList + ) = for (node <- transformList(a, aNode, resultAdapter(formalAnnotatatedParam))) + yield node + + private def portInstanceIdentifierNode( + a: Analysis, + pii: AstNode[Ast.PortInstanceIdentifier] + ): Result.Result[AstNode[Ast.PortInstanceIdentifier]] = { + for { + interfaceInstance <- qualIdentNode(a, pii.data.interfaceInstance) + (_, portName) <- defaultNode(a, pii.data.portName) + } yield { + val dataCopy = pii.data.copy( + interfaceInstance = interfaceInstance, + portName = portName ) + cloneNode(a, pii, dataCopy) + } + } + + private def qualIdentNode( + a: Analysis, + node: AstNode[Ast.QualIdent] + ): Result.Result[AstNode[Ast.QualIdent]] = + Right(cloneQualIdentNode(a, node)) + + private def qualIdentNodeOpt( + a: Analysis, + qi: Option[AstNode[Ast.QualIdent]] + ): Result.Result[Option[AstNode[Ast.QualIdent]]] = { + qi match { + case None => Right(None) + case Some(value) => + for (result <- qualIdentNode(a, value)) + yield Some(result) } } + + private def structMember( + a: Analysis, + node: AstNode[Ast.StructMember] + ) = { + for ((_, value) <- matchExprNode(a, node.data.value)) + yield cloneNode( + a, + node, + Ast.StructMember(node.data.name, value) + ) + } + + private def structTypeMemberAnnotatedNode( + a: Analysis, + aNode: Ast.Annotated[AstNode[Ast.StructTypeMember]] + ) = + val data = aNode._2.data + for { + size <- exprNodeOpt(a, data.size) + (_, typeName) <- matchTypeName(a, data.typeName) + } yield { + val dataCopy = data.copy( + size = size, + typeName = typeName, + format = cloneStringNodeOpt(a, data.format) + ) + cloneAnnotatedNode(a, aNode, dataCopy) + } + + private def transitionExpr( + a: Analysis, + node: AstNode[Ast.TransitionExpr] + ): Result.Result[AstNode[Ast.TransitionExpr]] = + for { + actions <- transformList(a, node.data.actions, defaultNode) + target <- qualIdentNode(a, node.data.target) + } yield { + val dataCopy = node.data.copy(actions = actions, target = target) + cloneNode(a, node, dataCopy) + } + + private def transitionOrDo( + a: Analysis, + transitionOrDo: Ast.TransitionOrDo + ) = + transitionOrDo match + case Ast.TransitionOrDo.Transition(transition) => + for (result <- transitionExpr(a, transition)) + yield Ast.TransitionOrDo.Transition(result) + case Ast.TransitionOrDo.Do(actions) => + for (result <- transformList(a, actions, defaultNode)) + yield Ast.TransitionOrDo.Do(result) + + private def typeNameNodeOpt( + a: Analysis, + node: Option[AstNode[Ast.TypeName]] + ): Result.Result[Option[AstNode[Ast.TypeName]]] = + node match { + case None => Right(None) + case Some(tn) => + for ((_, tn) <- matchTypeName(a, tn)) + yield Some(tn) + } + } diff --git a/compiler/lib/src/main/scala/util/Error.scala b/compiler/lib/src/main/scala/util/Error.scala index 0d66e72172..01f2858e31 100644 --- a/compiler/lib/src/main/scala/util/Error.scala +++ b/compiler/lib/src/main/scala/util/Error.scala @@ -270,18 +270,18 @@ sealed trait Error { System.err.println("conflicting port number is here:") System.err.println(p2Loc) printMatchingLoc(matchingLoc) - case SemanticError.WrongNumberOfTemplateArguments( - expandLoc: Location, - defLoc: Location, - expandLength: Number, - defLength: Number, + case SemanticError.InterfaceImplements( + loc, + err ) => - val parameters = if defLength == 1 then "argument" else "arguments" - Error.print (Some(expandLoc)) ( - s"expected $defLength template $parameters, got $expandLength" - ) - System.err.println("template defined here:") - System.err.println(defLoc) + Error.print (Some(loc)) ("port interface not implemented") + err.print + case SemanticError.InterfaceImport( + importLoc, + err + ) => + Error.print (Some(importLoc)) (s"failed to import interface") + err.print case SemanticError.InvalidTemplateArg( paramName: String, argLoc: Location, @@ -291,30 +291,6 @@ sealed trait Error { Error.print (Some(argLoc)) (s"invalid argument for template parameter $paramName: $msg") System.err.println("template parameter is defined here:") System.err.println(paramLoc) - case SemanticError.TemplateParameterConflict( - paramName: String, - paramLoc: Location, - defLoc: Location, - ) => - Error.print (Some(paramLoc)) ( - s"template parameter $paramName conflicts with a definition in the template body" - ) - System.err.println("conflicting definition is here:") - System.err.println(defLoc) - case SemanticError.NestedTemplateDefinition( - nestedLoc: Location, - parentLoc: Location - ) => - Error.print (Some(nestedLoc)) ("module template definitions cannot be nested") - System.err.println("parent template defined here:") - System.err.println(parentLoc) - case SemanticError.TemplateExpansionInTemplate( - expandLoc: Location, - templateLoc: Location - ) => - Error.print (Some(expandLoc)) ("template expansion specifiers cannot appear inside a module template") - System.err.println("enclosing template defined here:") - System.err.println(templateLoc) case SemanticError.MissingAsync(kind, loc) => Error.print (Some(loc)) (s"$kind component must have async input") case SemanticError.MissingConnection(loc, matchingLoc) => @@ -349,6 +325,16 @@ sealed trait Error { } case SemanticError.PassiveStateMachine(loc) => Error.print (Some(loc)) ("passive component may not have a state machine instance") + case SemanticError.PortInterfaceMissingPort( + loc + ) => + Error.print (Some(loc)) ("port instance missing") + case SemanticError.PortInterfaceInvalidPort( + loc, + defLoc + ) => + Error.print (Some(loc)) ("port instance does not match definition in interface:") + System.err.println(defLoc) case SemanticError.RedefinedSymbol(name, loc, prevLoc) => Error.print (Some(loc)) (s"redefinition of symbol ${name}") System.err.println("previous definition is here:") @@ -387,6 +373,32 @@ sealed trait Error { Error.print (Some(loc)) (s"state machine has too many leaf states") case SemanticError.StateMachine.UnreachableNode(name, loc) => Error.print (Some(loc)) (s"$name is unreachable") + case SemanticError.TemplateParameterConflict( + paramName: String, + paramLoc: Location, + defLoc: Location, + ) => + Error.print (Some(paramLoc)) ( + s"template parameter $paramName conflicts with a definition in the template body" + ) + System.err.println("conflicting definition is here:") + System.err.println(defLoc) + case SemanticError.TemplateDefError( + loc: Location, + msg: String, + defLoc: Location + ) => + Error.print (Some(loc)) (msg) + System.err.println("enclosing template is defined here:") + System.err.println(defLoc) + case SemanticError.TemplateExpandError( + loc: Location, + msg: String, + expandLoc: Location + ) => + Error.print (Some(loc)) (msg) + System.err.println("enclosing template expansion is here:") + System.err.println(expandLoc) case SemanticError.TooManyOutputPorts(loc, numPorts, arraySize, instanceLoc) => Error.print (Some(loc)) (s"too many ports connected here (found $numPorts, max is $arraySize)") System.err.println("for this component instance:") @@ -395,29 +407,19 @@ sealed trait Error { case SemanticError.UndefinedSymbol(name, symbolKind, loc) => Error.print (Some(loc)) (s"symbol ${name} is not defined") printNote(s"looking for a $symbolKind here") - case SemanticError.InterfaceImport( - importLoc, - err - ) => - Error.print (Some(importLoc)) (s"failed to import interface") - err.print - case SemanticError.PortInterfaceMissingPort( - loc - ) => - Error.print (Some(loc)) ("port instance missing") - case SemanticError.PortInterfaceInvalidPort( - loc, - defLoc + case SemanticError.UseDefCycle(loc, msg) => Error.print (Some(loc)) (msg) + case SemanticError.WrongNumberOfTemplateArguments( + expandLoc: Location, + defLoc: Location, + expandLength: Number, + defLength: Number, ) => - Error.print (Some(loc)) ("port instance does not match definition in interface:") + val parameters = if defLength == 1 then "argument" else "arguments" + Error.print (Some(expandLoc)) ( + s"expected $defLength template $parameters, got $expandLength" + ) + System.err.println("template defined here:") System.err.println(defLoc) - case SemanticError.InterfaceImplements( - loc, - err - ) => - Error.print (Some(loc)) ("port interface not implemented") - err.print - case SemanticError.UseDefCycle(loc, msg) => Error.print (Some(loc)) (msg) case XmlError.ParseError(file, msg) => Error.printXml (file) (msg) case XmlError.SemanticError(file, msg) => Error.printXml (file) (msg) case AnnotatedError(error, notes) => @@ -627,6 +629,16 @@ object SemanticError { specifiedPath: String, actualLoc: Location ) extends Error + /** Error while importing an interface */ + final case class InterfaceImport( + importLoc: Location, + err: Error + ) extends Error + /** Error while checking if instance implements interface */ + final case class InterfaceImplements( + loc: Location, + err: Error + ) extends Error /** No member in anonymous struct type */ final case class InvalidAnonStructMember( memberName: String, @@ -748,6 +760,13 @@ object SemanticError { msg: String, defLoc: Location ) extends Error + /** Template argument of the wrong kind */ + final case class InvalidTemplateArg( + paramName: String, + argLoc: Location, + paramLoc: Location, + msg: String, + ) extends Error /** Invalid telemetry channel identifier name */ final case class InvalidTlmChannelName( loc: Location, @@ -770,36 +789,6 @@ object SemanticError { p2Number: Int, matchingLoc: Location ) extends Error - /** Wrong number of template arguments */ - final case class WrongNumberOfTemplateArguments( - expandLoc: Location, - defLoc: Location, - expandLength: Number, - defLength: Number, - ) extends Error - /** Template argument of the wrong kind */ - final case class InvalidTemplateArg( - paramName: String, - argLoc: Location, - paramLoc: Location, - msg: String, - ) extends Error - /** Template parameter conflicts with a definition in the template body */ - final case class TemplateParameterConflict( - paramName: String, - paramLoc: Location, - defLoc: Location, - ) extends Error - /** Nested template definition */ - final case class NestedTemplateDefinition( - nestedLoc: Location, - parentLoc: Location, - ) extends Error - /** Template expansion specifier nested inside a template */ - final case class TemplateExpansionInTemplate( - expandLoc: Location, - templateLoc: Location, - ) extends Error /** Missing async input */ final case class MissingAsync(kind: String, loc: Location) extends Error /** Missing connection */ @@ -832,11 +821,9 @@ object SemanticError { name2: String, loc2: Location ) extends Error - /** Error while importing an interface */ - final case class InterfaceImport( - importLoc: Location, - err: Error - ) extends Error + /** Passive async input */ + final case class PassiveAsync(loc: Location, importLocs: List[Location]) extends Error + final case class PassiveStateMachine(loc: Location) extends Error /** A port is missing from a port interface */ final case class PortInterfaceMissingPort( loc: Location @@ -846,14 +833,6 @@ object SemanticError { loc: Location, defLoc: Location ) extends Error - /** Error while checking if instance implements interface */ - final case class InterfaceImplements( - loc: Location, - err: Error - ) extends Error - /** Passive async input */ - final case class PassiveAsync(loc: Location, importLocs: List[Location]) extends Error - final case class PassiveStateMachine(loc: Location) extends Error /** Redefined symbol */ final case class RedefinedSymbol( name: String, @@ -906,6 +885,24 @@ object SemanticError { loc: Location ) extends Error } + /** Error in template definition */ + final case class TemplateDefError( + loc: Location, + msg: String, + defLoc: Location + ) extends Error + /** Error in template expansion */ + final case class TemplateExpandError( + loc: Location, + msg: String, + expandLoc: Location + ) extends Error + /** Template parameter conflicts with a definition in the template body */ + final case class TemplateParameterConflict( + paramName: String, + paramLoc: Location, + defLoc: Location, + ) extends Error /** Too many output ports */ final case class TooManyOutputPorts( loc: Location, @@ -919,6 +916,13 @@ object SemanticError { final case class UndefinedSymbol(name: String, symbolKind: String, loc: Location) extends Error /** Use-def cycle */ final case class UseDefCycle(loc: Location, msg: String) extends Error + /** Wrong number of template arguments */ + final case class WrongNumberOfTemplateArguments( + expandLoc: Location, + defLoc: Location, + expandLength: Number, + defLength: Number, + ) extends Error } /** An F Prime XML error */ diff --git a/compiler/lib/src/test/scala/syntax/Parser.scala b/compiler/lib/src/test/scala/syntax/Parser.scala index 534ef5b510..b1c5d76576 100644 --- a/compiler/lib/src/test/scala/syntax/Parser.scala +++ b/compiler/lib/src/test/scala/syntax/Parser.scala @@ -542,13 +542,21 @@ class ParserSpec extends AnyWordSpec { Parser.specTemplateExpand, List( "expand T", + "expand T { constant a = 0 }", "expand M.T()", + "expand M.T() { constant a = 0 }", "expand M.T(constant 1)", + "expand M.T(constant 1) { constant a = 0 }", "expand M.T(constant 1, constant 2)", + "expand M.T(constant 1, constant 2) { constant a = 0 }", "expand M.T(constant 1, constant 2, instance mod.$instance)", + "expand M.T(constant 1, constant 2, instance mod.$instance) { constant a = 0 }", "expand M.T(constant 1, constant 2, instance .mod.$instance, type Type.Name)", + "expand M.T(constant 1, constant 2, instance .mod.$instance, type Type.Name) { constant a = 0 }", "expand M.T(constant 1, instance .inst1, type U32)", + "expand M.T(constant 1, instance .inst1, type U32) { constant a = 0 }", "expand M.T(constant 1, constant 2, constant {member=1}, constant [1, 2])", + "expand M.T(constant 1, constant 2, constant {member=1}, constant [1, 2]) { constant a = 0 }", ) ) } diff --git a/compiler/tools/fpp-check/test/template/composition_invalid.fpp b/compiler/tools/fpp-check/test/template/composition_invalid.fpp deleted file mode 100644 index a5c9e08cd7..0000000000 --- a/compiler/tools/fpp-check/test/template/composition_invalid.fpp +++ /dev/null @@ -1,11 +0,0 @@ -module template T1( - constant p: U32 -) { - constant c = p -} - -module template T2( - constant p: U32 -) { - expand T1(constant p) -} diff --git a/compiler/tools/fpp-check/test/template/composition_invalid.ref.txt b/compiler/tools/fpp-check/test/template/composition_invalid.ref.txt deleted file mode 100644 index 1ebb3e4975..0000000000 --- a/compiler/tools/fpp-check/test/template/composition_invalid.ref.txt +++ /dev/null @@ -1,9 +0,0 @@ -fpp-check -[ local path prefix ]/compiler/tools/fpp-check/test/template/composition_invalid.fpp:10.5 - expand T1(constant p) - ^ -error: template expansion specifiers cannot appear inside a module template -enclosing template defined here: -[ local path prefix ]/compiler/tools/fpp-check/test/template/composition_invalid.fpp:7.1 -module template T2( -^ diff --git a/compiler/tools/fpp-check/test/template/expand_in_template_def.fpp b/compiler/tools/fpp-check/test/template/expand_in_template_def.fpp new file mode 100644 index 0000000000..54621c4d93 --- /dev/null +++ b/compiler/tools/fpp-check/test/template/expand_in_template_def.fpp @@ -0,0 +1,9 @@ +module template T1 { + +} + +module template T2 { + + expand T1 + +} diff --git a/compiler/tools/fpp-check/test/template/expand_in_template_def.ref.txt b/compiler/tools/fpp-check/test/template/expand_in_template_def.ref.txt new file mode 100644 index 0000000000..469ffdc576 --- /dev/null +++ b/compiler/tools/fpp-check/test/template/expand_in_template_def.ref.txt @@ -0,0 +1,9 @@ +fpp-check +[ local path prefix ]/compiler/tools/fpp-check/test/template/expand_in_template_def.fpp:7.3 + expand T1 + ^ +error: template expansion specifiers cannot appear inside a module template +enclosing template is defined here: +[ local path prefix ]/compiler/tools/fpp-check/test/template/expand_in_template_def.fpp:5.1 +module template T2 { +^ diff --git a/compiler/tools/fpp-check/test/template/invalid_nested.fpp b/compiler/tools/fpp-check/test/template/invalid_nested.fpp deleted file mode 100644 index e52774a663..0000000000 --- a/compiler/tools/fpp-check/test/template/invalid_nested.fpp +++ /dev/null @@ -1,22 +0,0 @@ -module template Outer(constant c1: U32) { - module template Inner(constant c2: U32) { - constant k1 = c2 * 2 - } - - module M1 { - expand Inner(constant 10) - constant k2 = k1 * 3 - } - - module M2 { - expand Inner(constant 20) - constant k2 = k1 * 3 - } - - expand Inner(constant 30) - - constant j1 = M1.k1 + M2.k2 - constant j2 = k1 + M1.k1 + M2.k1 -} - -expand Outer(constant 10) diff --git a/compiler/tools/fpp-check/test/template/invalid_nested.ref.txt b/compiler/tools/fpp-check/test/template/invalid_nested.ref.txt deleted file mode 100644 index ec320733a7..0000000000 --- a/compiler/tools/fpp-check/test/template/invalid_nested.ref.txt +++ /dev/null @@ -1,9 +0,0 @@ -fpp-check -[ local path prefix ]/compiler/tools/fpp-check/test/template/invalid_nested.fpp:2.5 - module template Inner(constant c2: U32) { - ^ -error: module template definitions cannot be nested -parent template defined here: -[ local path prefix ]/compiler/tools/fpp-check/test/template/invalid_nested.fpp:1.1 -module template Outer(constant c1: U32) { -^ diff --git a/compiler/tools/fpp-check/test/template/nested_expand.fpp b/compiler/tools/fpp-check/test/template/nested_expand.fpp new file mode 100644 index 0000000000..a9e989c18f --- /dev/null +++ b/compiler/tools/fpp-check/test/template/nested_expand.fpp @@ -0,0 +1,9 @@ +module template T1 { + +} + +expand T1 { + + expand T1 + +} diff --git a/compiler/tools/fpp-check/test/template/nested_expand.ref.txt b/compiler/tools/fpp-check/test/template/nested_expand.ref.txt new file mode 100644 index 0000000000..5db5a806b4 --- /dev/null +++ b/compiler/tools/fpp-check/test/template/nested_expand.ref.txt @@ -0,0 +1,9 @@ +fpp-check +[ local path prefix ]/compiler/tools/fpp-check/test/template/nested_expand.fpp:7.3 + expand T1 + ^ +error: template expansions cannot be nested +enclosing template expansion is here: +[ local path prefix ]/compiler/tools/fpp-check/test/template/nested_expand.fpp:5.1 +expand T1 { +^ diff --git a/compiler/tools/fpp-check/test/template/nested_template_def.fpp b/compiler/tools/fpp-check/test/template/nested_template_def.fpp new file mode 100644 index 0000000000..0b47b127ce --- /dev/null +++ b/compiler/tools/fpp-check/test/template/nested_template_def.fpp @@ -0,0 +1,7 @@ +module template T1 { + + module template T2 { + + } + +} diff --git a/compiler/tools/fpp-check/test/template/nested_template_def.ref.txt b/compiler/tools/fpp-check/test/template/nested_template_def.ref.txt new file mode 100644 index 0000000000..f3c2f25428 --- /dev/null +++ b/compiler/tools/fpp-check/test/template/nested_template_def.ref.txt @@ -0,0 +1,9 @@ +fpp-check +[ local path prefix ]/compiler/tools/fpp-check/test/template/nested_template_def.fpp:3.5 + module template T2 { + ^ +error: module template definitions cannot be nested +enclosing template is defined here: +[ local path prefix ]/compiler/tools/fpp-check/test/template/nested_template_def.fpp:1.1 +module template T1 { +^ diff --git a/compiler/tools/fpp-check/test/template/source_expand_bad_args.fpp b/compiler/tools/fpp-check/test/template/source_expand_bad_args.fpp new file mode 100644 index 0000000000..796116e62a --- /dev/null +++ b/compiler/tools/fpp-check/test/template/source_expand_bad_args.fpp @@ -0,0 +1,9 @@ +module template T { + +} + +expand T(constant 10) { + + constant a = 0 + +} diff --git a/compiler/tools/fpp-check/test/template/source_expand_bad_args.ref.txt b/compiler/tools/fpp-check/test/template/source_expand_bad_args.ref.txt new file mode 100644 index 0000000000..1c04c9f7b7 --- /dev/null +++ b/compiler/tools/fpp-check/test/template/source_expand_bad_args.ref.txt @@ -0,0 +1,9 @@ +fpp-check +[ local path prefix ]/compiler/tools/fpp-check/test/template/source_expand_bad_args.fpp:5.1 +expand T(constant 10) { +^ +error: expected 0 template arguments, got 1 +template defined here: +[ local path prefix ]/compiler/tools/fpp-check/test/template/source_expand_bad_args.fpp:1.1 +module template T { +^ diff --git a/compiler/tools/fpp-check/test/template/source_expand_ok.fpp b/compiler/tools/fpp-check/test/template/source_expand_ok.fpp new file mode 100644 index 0000000000..b0de9cc16c --- /dev/null +++ b/compiler/tools/fpp-check/test/template/source_expand_ok.fpp @@ -0,0 +1,9 @@ +module template T { + +} + +expand T { + + constant a = 0 + +} diff --git a/compiler/tools/fpp-check/test/template/source_expand_ok.ref.txt b/compiler/tools/fpp-check/test/template/source_expand_ok.ref.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/compiler/tools/fpp-check/test/template/source_expand_undefined_symbol.fpp b/compiler/tools/fpp-check/test/template/source_expand_undefined_symbol.fpp new file mode 100644 index 0000000000..76a128ddc2 --- /dev/null +++ b/compiler/tools/fpp-check/test/template/source_expand_undefined_symbol.fpp @@ -0,0 +1,9 @@ +module template T { + +} + +expand T { + + constant a = b + +} diff --git a/compiler/tools/fpp-check/test/template/source_expand_undefined_symbol.ref.txt b/compiler/tools/fpp-check/test/template/source_expand_undefined_symbol.ref.txt new file mode 100644 index 0000000000..1aa8df51b4 --- /dev/null +++ b/compiler/tools/fpp-check/test/template/source_expand_undefined_symbol.ref.txt @@ -0,0 +1,6 @@ +fpp-check +[ local path prefix ]/compiler/tools/fpp-check/test/template/source_expand_undefined_symbol.fpp:7.16 + constant a = b + ^ +error: symbol b is not defined +note: looking for a constant here diff --git a/compiler/tools/fpp-check/test/template/template_def_in_expand.fpp b/compiler/tools/fpp-check/test/template/template_def_in_expand.fpp new file mode 100644 index 0000000000..ecdf65e966 --- /dev/null +++ b/compiler/tools/fpp-check/test/template/template_def_in_expand.fpp @@ -0,0 +1,11 @@ +module template T1 { + +} + +expand T1 { + + module template T2 { + + } + +} diff --git a/compiler/tools/fpp-check/test/template/template_def_in_expand.ref.txt b/compiler/tools/fpp-check/test/template/template_def_in_expand.ref.txt new file mode 100644 index 0000000000..ae9b5a94e9 --- /dev/null +++ b/compiler/tools/fpp-check/test/template/template_def_in_expand.ref.txt @@ -0,0 +1,9 @@ +fpp-check +[ local path prefix ]/compiler/tools/fpp-check/test/template/template_def_in_expand.fpp:7.3 + module template T2 { + ^ +error: module template definitions cannot appear inside a template expansion +enclosing template expansion is here: +[ local path prefix ]/compiler/tools/fpp-check/test/template/template_def_in_expand.fpp:5.1 +expand T1 { +^ diff --git a/compiler/tools/fpp-check/test/template/tests.sh b/compiler/tools/fpp-check/test/template/tests.sh index 711ed0c514..a065b37a7c 100644 --- a/compiler/tools/fpp-check/test/template/tests.sh +++ b/compiler/tools/fpp-check/test/template/tests.sh @@ -13,13 +13,13 @@ basic_constant bound_param_capture bound_param_capture_ok chained_constants -composition_invalid constant_param_array_promote constant_param_array_promote_bad_subscript constant_with_default definition_point_scoping definition_point_scoping_ok duplicate_def +expand_in_template_def import_two_expansions_ok interfaces interfaces_arg_bad_signature @@ -35,16 +35,20 @@ interfaces_topology_arg_deployment interfaces_topology_arg_ok interfaces_topology_arg_order_ok interfaces_valid_port_instance_name_aliased -invalid_nested module_merge_ok +nested_expand nested_scope_resolution nested_scope_resolution_ok +nested_template_def param_body_def_different_group_ok param_conflict_body_def param_conflict_same_name_group param_same_name_different_groups_ok parameter_shadow_error parameter_shadow_ok +source_expand_bad_args +source_expand_ok +source_expand_undefined_symbol struct_parameter_alias_default_ok struct_parameter_anon_array_promote struct_parameter_array_member_default_ok @@ -55,6 +59,7 @@ struct_parameter_nested_default_bad_arg struct_parameter_nested_default_ok struct_parameter_ok struct_parameter_omitted_member_ok +template_def_in_expand type_arg_string type_param_implied_use types diff --git a/compiler/tools/fpp-syntax/test/include-module-template-expand.fpp b/compiler/tools/fpp-syntax/test/include-module-template-expand.fpp new file mode 100644 index 0000000000..8e05a24cf9 --- /dev/null +++ b/compiler/tools/fpp-syntax/test/include-module-template-expand.fpp @@ -0,0 +1,9 @@ +module template T { + +} + +expand T { + + include "constant.fppi" + +} diff --git a/compiler/tools/fpp-syntax/test/include-module-template-expand.ref.txt b/compiler/tools/fpp-syntax/test/include-module-template-expand.ref.txt new file mode 100644 index 0000000000..eff5fbd184 --- /dev/null +++ b/compiler/tools/fpp-syntax/test/include-module-template-expand.ref.txt @@ -0,0 +1,9 @@ +def module template + ident T +expand + qual ident T + @ Included constant + def constant + ident x + literal int 0 + @< Included constant diff --git a/compiler/tools/fpp-syntax/test/include-module-template.fpp b/compiler/tools/fpp-syntax/test/include-module-template.fpp new file mode 100644 index 0000000000..b1d2ecf330 --- /dev/null +++ b/compiler/tools/fpp-syntax/test/include-module-template.fpp @@ -0,0 +1,5 @@ +module template T { + + include "constant.fppi" + +} diff --git a/compiler/tools/fpp-syntax/test/include-module-template.ref.txt b/compiler/tools/fpp-syntax/test/include-module-template.ref.txt new file mode 100644 index 0000000000..7f8e14b51f --- /dev/null +++ b/compiler/tools/fpp-syntax/test/include-module-template.ref.txt @@ -0,0 +1,7 @@ +def module template + ident T + @ Included constant + def constant + ident x + literal int 0 + @< Included constant diff --git a/compiler/tools/fpp-syntax/test/template.fpp b/compiler/tools/fpp-syntax/test/module-template.fpp similarity index 52% rename from compiler/tools/fpp-syntax/test/template.fpp rename to compiler/tools/fpp-syntax/test/module-template.fpp index 74a9c4b6e9..0748e77c0d 100644 --- a/compiler/tools/fpp-syntax/test/template.fpp +++ b/compiler/tools/fpp-syntax/test/module-template.fpp @@ -15,6 +15,18 @@ module template Tmpl( } } -@ Expansion specifier -expand Tmpl(constant 10, type Type, instance .instance1) -@< Expansion specifier +module Unexpanded { + + @ Unexpanded expansion specifier + expand Tmpl(constant 10, type Type, instance .instance1) + @< Unexpanded expansion specifier + +} + +module Expanded { + + @ Expanded expansion specifier + expand Tmpl(constant 10, type Type, instance .instance1) { constant a = 0 } + @< Expanded expansion specifier + +} diff --git a/compiler/tools/fpp-syntax/test/module-template.ref.txt b/compiler/tools/fpp-syntax/test/module-template.ref.txt new file mode 100644 index 0000000000..cecd64f59d --- /dev/null +++ b/compiler/tools/fpp-syntax/test/module-template.ref.txt @@ -0,0 +1,59 @@ +def module template + ident Tmpl + @ Constant template parameter + constant template param + ident c + type name qual ident SomeType + @< Constant parameter + @ Type template parameter + type template param + ident TypeParam + @< Type parameter + @ Interface instance template parameter + instance template param + ident inst + qual ident InterfaceDef + @< Instance parameter + def array + ident Arr + size literal int 3 + type name qual ident TypeParam + def topology + ident Top + spec interface instance + qual ident inst +def module + ident Unexpanded + @ Unexpanded expansion specifier + expand + qual ident Tmpl + constant template arg + literal int 10 + type template arg + type name qual ident Type + instance template arg + qual ident .instance1 + def array + ident Arr + size literal int 3 + type name qual ident TypeParam + def topology + ident Top + spec interface instance + qual ident inst + @< Unexpanded expansion specifier +def module + ident Expanded + @ Expanded expansion specifier + expand + qual ident Tmpl + constant template arg + literal int 10 + type template arg + type name qual ident Type + instance template arg + qual ident .instance1 + def constant + ident a + literal int 0 + @< Expanded expansion specifier diff --git a/compiler/tools/fpp-syntax/test/run b/compiler/tools/fpp-syntax/test/run index 5283847ce5..99f75df8ff 100755 --- a/compiler/tools/fpp-syntax/test/run +++ b/compiler/tools/fpp-syntax/test/run @@ -23,6 +23,11 @@ comments() run_test "" comments } +dictionary_specifier() +{ + run_test -a dictionary-specifier +} + embedded_tab() { run_test "" embedded-tab @@ -73,9 +78,14 @@ include_module() run_test -ia include-module } -include_parse_error() +include_module_template() { - run_test -i include-parse-error + run_test -ia include-module-template +} + +include_module_template_expand() +{ + run_test -ia include-module-template-expand } include_parent_dir() @@ -83,14 +93,14 @@ include_parent_dir() run_test -ia subdir/include-parent-dir } -include_state_machine() +include_parse_error() { - run_test -ia include-state-machine + run_test -i include-parse-error } -include_subdir() +include_state_machine() { - run_test -ia include-subdir + run_test -ia include-state-machine } include_state_machine() @@ -98,11 +108,26 @@ include_state_machine() run_test -ia include-state-machine } +include_subdir() +{ + run_test -ia include-subdir +} + include_topology() { run_test -ia include-topology } +module_template() +{ + run_test -iea module-template +} + +numeric_shift() +{ + run_test "" numeric-shift +} + parse_error() { run_test "" parse-error @@ -118,11 +143,6 @@ syntax() run_test "" syntax } -syntax_kwd_names() -{ - run_test "" syntax-kwd-names -} - syntax_ast() { run_test -a syntax syntax-ast @@ -133,15 +153,15 @@ syntax_include_ast() run_test -ia syntax syntax-include-ast } -syntax_stdin() +syntax_kwd_names() { - cat syntax.fpp | $fpp_syntax -ia > syntax-stdin.out.txt - diff -u syntax-stdin.ref.txt syntax-stdin.out.txt > syntax-stdin.diff.txt 2>&1 + run_test "" syntax-kwd-names } -template() +syntax_stdin() { - run_test -iea template + cat syntax.fpp | $fpp_syntax -ia > syntax-stdin.out.txt + diff -u syntax-stdin.ref.txt syntax-stdin.out.txt > syntax-stdin.diff.txt 2>&1 } topology_ports() @@ -155,18 +175,9 @@ two_input_files() diff -u two-input-files.ref.txt two-input-files.out.txt > two-input-files.diff.txt 2>&1 } -dictionary_specifier() -{ - run_test -a dictionary-specifier -} - -numeric_shift() -{ - run_test "" numeric-shift -} - tests=" comments +dictionary_specifier embedded_tab empty escaped_strings @@ -177,11 +188,15 @@ include_cycle_1 include_cycle_2 include_missing_file include_module +include_module_template +include_module_template_expand include_parent_dir include_parse_error include_state_machine include_subdir include_topology +module_template +numeric_shift parse_error state_machine syntax @@ -189,11 +204,8 @@ syntax_ast syntax_include_ast syntax_kwd_names syntax_stdin -template topology_ports two_input_files -dictionary_specifier -numeric_shift " run_suite $tests diff --git a/compiler/tools/fpp-syntax/test/template.ref.txt b/compiler/tools/fpp-syntax/test/template.ref.txt deleted file mode 100644 index faa0858fe9..0000000000 --- a/compiler/tools/fpp-syntax/test/template.ref.txt +++ /dev/null @@ -1,42 +0,0 @@ -def module template - ident Tmpl - @ Constant template parameter - constant template param - ident c - type name qual ident SomeType - @< Constant parameter - @ Type template parameter - type template param - ident TypeParam - @< Type parameter - @ Interface instance template parameter - instance template param - ident inst - qual ident InterfaceDef - @< Instance parameter - def array - ident Arr - size literal int 3 - type name qual ident TypeParam - def topology - ident Top - spec interface instance - qual ident inst -@ Expansion specifier -expand - qual ident Tmpl - constant template arg - literal int 10 - type template arg - type name qual ident Type - instance template arg - qual ident .instance1 - def array - ident Arr - size literal int 3 - type name qual ident TypeParam - def topology - ident Top - spec interface instance - qual ident inst -@< Expansion specifier diff --git a/compiler/tools/fpp-syntax/test/update-ref b/compiler/tools/fpp-syntax/test/update-ref index 2f21c6bffa..38bc1642ea 100755 --- a/compiler/tools/fpp-syntax/test/update-ref +++ b/compiler/tools/fpp-syntax/test/update-ref @@ -26,15 +26,15 @@ done update "" comments update "" embedded-tab update "" illegal-character +update "" numeric-shift update "" parse-error update "" syntax update "" syntax-kwd-names -update -a state-machine -update -ia topology-ports update -a dictionary-specifier update -a empty update -a escaped-strings update -a state-machine +update -a state-machine update -a syntax syntax-ast update -i cycle-1 include-cycle-1 update -i cycle-2 include-cycle-2 @@ -43,15 +43,17 @@ update -i include-parse-error update -ia include-component update -ia include-constant-1 include-constant-1 update -ia include-module +update -ia include-module-template +update -ia include-module-template-expand update -ia include-state-machine update -ia include-state-machine update -ia include-subdir update -ia include-topology -update -ia topology-ports -update -ita template update -ia subdir/include-parent-dir update -ia syntax syntax-include-ast -update "" numeric-shift +update -ia topology-ports +update -ia topology-ports +update -iea module-template cat syntax.fpp | $fpp_syntax -ia 2>&1 > syntax-stdin.ref.txt diff --git a/compiler/tools/fpp-to-dict/test/dictionary.schema.json b/compiler/tools/fpp-to-dict/test/dictionary.schema.json index f9335794bb..a0d82cb72c 100644 --- a/compiler/tools/fpp-to-dict/test/dictionary.schema.json +++ b/compiler/tools/fpp-to-dict/test/dictionary.schema.json @@ -114,6 +114,9 @@ "items": { "type": "string" } + }, + "annotation": { + "type": "string" } }, "required": [ @@ -577,6 +580,9 @@ "items": { "type": "string" } + }, + "annotation": { + "type": "string" } }, "required": [ diff --git a/compiler/tools/fpp-to-dict/test/top/FirstTopTopologyDictionary.ref.json b/compiler/tools/fpp-to-dict/test/top/FirstTopTopologyDictionary.ref.json index c0f8226ee4..35e2facc8a 100644 --- a/compiler/tools/fpp-to-dict/test/top/FirstTopTopologyDictionary.ref.json +++ b/compiler/tools/fpp-to-dict/test/top/FirstTopTopologyDictionary.ref.json @@ -1252,7 +1252,8 @@ "members" : [ "Module1.myFirstC1.TlmChannel1", "Module1.myFirstC1.TlmChannel2" - ] + ], + "annotation" : "Pre annotation for MyTlmPacket1" }, { "name" : "MyTlmPacket2", @@ -1260,14 +1261,16 @@ "group" : 1, "members" : [ "Module1.myFirstC2.TlmChannel1" - ] + ], + "annotation" : "Pre annotation for MyTlmPacket2" } ], "omitted" : [ "Module1.myFirstC1.TlmChannel3", "Module1.myFirstC2.TlmChannel2", "Module1.myFirstC2.TlmChannel3" - ] + ], + "annotation" : "Pre annotation for Packets" } ] } diff --git a/compiler/tools/fpp-to-dict/test/top/multipleTops.fpp b/compiler/tools/fpp-to-dict/test/top/multipleTops.fpp index 62f693e48a..670cfd3c84 100644 --- a/compiler/tools/fpp-to-dict/test/top/multipleTops.fpp +++ b/compiler/tools/fpp-to-dict/test/top/multipleTops.fpp @@ -300,12 +300,15 @@ module Module1 { myFirstC1.pOut -> myFirstC2.pIn } + @ Pre annotation for Packets telemetry packets Packets { + @ Pre annotation for MyTlmPacket1 packet MyTlmPacket1 id 0 group 0 { Module1.myFirstC1.TlmChannel1 Module1.myFirstC1.TlmChannel2 } + @ Pre annotation for MyTlmPacket2 packet MyTlmPacket2 id 1 group 1 { Module1.myFirstC2.TlmChannel1 } diff --git a/compiler/tools/fpp-to-fpp/test/run b/compiler/tools/fpp-to-fpp/test/run index a86099346f..b7486f2919 100755 --- a/compiler/tools/fpp-to-fpp/test/run +++ b/compiler/tools/fpp-to-fpp/test/run @@ -69,16 +69,16 @@ dictionary_specifier() $fpp_syntax dictionary_specifier.out.txt } -# Note: the expanded output uses the `expand ... { ... }` form, which is not -# (yet) valid FPP surface syntax, so we do not round-trip it through fpp-syntax. template_expand() { - run_test '-e' template_expand + run_test '-e' template_expand && \ + $fpp_syntax template_expand.out.txt } template_include() { - run_test '-e' template_include + run_test '-e' template_include && \ + $fpp_syntax template_include.out.txt } run_suite $tests diff --git a/docs/fpp-spec.html b/docs/fpp-spec.html index 56a2dd78e3..8303493df9 100644 --- a/docs/fpp-spec.html +++ b/docs/fpp-spec.html @@ -1003,7 +1003,12 @@
A template expansion specifier names a -template +module template definition and specifies arguments for the parameters of the template. During template expansion, it generates the definitions specified by the template and the arguments.
@@ -9265,6 +9270,9 @@( template-arg-list )
+]
+[
+{ module-member-sequence }
]
module-member-sequence is the same as for a +module definition.
+The optional module member list represents the result of +expanding the template. +If a template expansion specifier has a module member +list, then it is called an expanded template. +Otherwise it is called an unexpanded template.
+If module-member-sequence is present, then
+module-member-sequence must not transitively contain any +module +template definitions or template expansion specifiers. +This rule ensures that the syntax of module-member-sequence could +be produced by expanding some template.
+module-member-sequence is not required to conform to the syntax produced +by expanding the template referred to in the specifier.
+All the definitions and uses inside module-member-sequence are +semantically analyzed in the same way as if module-member-sequence had been +produced by template expansion.
+Expansion of templates performs partial analysis and syntactic expansion. -It produces a new model in which each -template -expansion specifier S is transformed into an -expanded template \$E = S { X }\$, where X -is a copy of the syntax provided +It produces a new model according to the following rules:
+For each unexpanded
+template
+expansion specifier S in the source model,
+transform S into an
+expanded template expansion specifier E = S { X }, where X
+is a copy of the module member list provided
by the template definition to which S refers.
-The expanded template E is not expressible in the syntax
-of the source language, but it is expressible in the internal
-representation of the model.
The syntax X behaves as if it were literally included in
the model at the point of E, except that there are
-special rules for resolving
+special rules for
resolving names that appear inside E.
For each expanded template expansion specifier E = S { X }
+in the source model, leave E unchanged.
Note in particular that applying template expansion twice +(or, more generally, any number of times greater than one) +is equivalent to applying template expansion once.
For each template expansion specifier S in M, -do the following:
+For each unexpanded template expansion specifier S in M, do the +following:
Let X be a copy of the syntax specified in the body of T.
Replace S with \$S { X }\$.
+Replace S with S { X }.
Model M:
Let model M be the same as model M' from the previous section. +Then the template expansion specifier is expanded, so template +expansion leaves the model unchanged (\$M' = M\$).
+