From 6f09d40309aa83be45a218f35d6aad0c0f303143 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Mon, 12 Oct 2026 16:05:58 -0700 Subject: [PATCH 01/51] Revise spec --- docs/fpp-spec.html | 81 +++++++++++++++---- docs/fpp-users-guide.html | 2 +- docs/spec/Expansion-of-Templates.adoc | 45 +++++++---- .../Template-Expansion-Specifiers.adoc | 14 +++- 4 files changed, 109 insertions(+), 33 deletions(-) diff --git a/docs/fpp-spec.html b/docs/fpp-spec.html index 56a2dd78e..73899fa0e 100644 --- a/docs/fpp-spec.html +++ b/docs/fpp-spec.html @@ -1003,7 +1003,12 @@

The F Prime Prime (FPP) Language Specification, Unreleased, after v3.4.0

18. Expansion of Templates
  • 19. Types @@ -9253,7 +9258,7 @@

    7.18.3. Examples

    7.19. Template Expansion Specifiers

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

    7.19.1. Syntax

    qual-ident [ ( template-arg-list ) +] +[ +{ module-member-sequence } ]

    @@ -9290,6 +9298,17 @@

    7.19.1. Syntax

  • +
    +

    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 is called an expanded template. +Otherwise it is called an unexpanded template.

    +

    7.19.2. Semantics

    @@ -12172,19 +12191,33 @@

    18. Expansion of Templates

    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:

    +
    +
    +
      +
    1. +

      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.

      +
    2. +
    3. +

      For each expanded template expansion specifier \$E = S { X +}\$ in the source model, leave E unchanged.

      +
    4. +
    +
    +
    +

    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.

    18.1. Algorithm

    @@ -12201,8 +12234,8 @@

    18.1. Algorithm

    match all template expansion specifiers with the template definitions to which they refer.

  • -

    For each template expansion specifier S in M, -do the following:

    +

    For each unexpanded template expansion specifier S in M, do the +following:

    1. @@ -12221,7 +12254,9 @@

      18.1. Algorithm

  • -

    18.2. Example

    +

    18.2. Examples

    +
    +

    18.2.1. Example 1

    Model M:

    @@ -12265,13 +12300,25 @@

    18.2. Example

    module N { - # The expanded template is expand M.T(constant 1) { constant c = a + b } - expand M.T(constant 1) + expand M.T(constant 1) { + + constant c = a + b + + } }
    +
    +

    18.2.2. Example 2

    +
    +

    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\$).

    +
    +
    +
    @@ -14526,7 +14573,7 @@

    25.4. Translation Tools

    diff --git a/docs/fpp-users-guide.html b/docs/fpp-users-guide.html index 17a587b60..f8c184f24 100644 --- a/docs/fpp-users-guide.html +++ b/docs/fpp-users-guide.html @@ -18571,7 +18571,7 @@

    19.4. S diff --git a/docs/spec/Expansion-of-Templates.adoc b/docs/spec/Expansion-of-Templates.adoc index e5400b340..9450b7ef4 100644 --- a/docs/spec/Expansion-of-Templates.adoc +++ b/docs/spec/Expansion-of-Templates.adoc @@ -2,21 +2,28 @@ Expansion of templates performs partial analysis and syntactic expansion. -It produces a new model in which each -<> _S_ is transformed into an -*expanded template* stem:[E = S { X }], where _X_ -is a copy of the syntax provided +It produces a new model according to the following rules: + +. For each <> _S_ in the source model, +transform _S_ into an +expanded template expansion specifier stem:[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 <> that appear inside _E_. +. For each expanded template expansion specifier stem:[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. + === Algorithm Let _M_ be the model initially presented to the analyzer, @@ -27,8 +34,8 @@ Construct the output model _M'_ as follows: <> and to match all template expansion specifiers with the template definitions to which they refer. -. For each template expansion specifier _S_ in _M_, - do the following: +. For each unexpanded template expansion specifier _S_ in _M_, do the + following: .. Let _T_ be the template definition referred to in _S_. @@ -36,7 +43,9 @@ Construct the output model _M'_ as follows: .. Replace _S_ with stem:[S { X }]. -=== Example +=== Examples + +==== Example 1 *Model _M_:* @@ -79,9 +88,17 @@ module M { module N { - # The expanded template is expand M.T(constant 1) { constant c = a + b } - expand M.T(constant 1) + expand M.T(constant 1) { + + constant c = a + b + + } } ---- +==== Example 2 + +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 (stem:[M' = M]). diff --git a/docs/spec/Specifiers/Template-Expansion-Specifiers.adoc b/docs/spec/Specifiers/Template-Expansion-Specifiers.adoc index 30f6ac3dc..49b27b09c 100644 --- a/docs/spec/Specifiers/Template-Expansion-Specifiers.adoc +++ b/docs/spec/Specifiers/Template-Expansion-Specifiers.adoc @@ -1,7 +1,7 @@ === Template Expansion Specifiers A *template expansion specifier* names a -<> +<> and specifies arguments for the parameters of the template. During <>, it generates the definitions specified by the template and the arguments. @@ -13,6 +13,9 @@ by the template and the arguments. _[_ `(` _template-arg-list_ `)` _]_ +_[_ +`{` _module-member-sequence_ `}` +_]_ _template-arg-list_ is an <> in @@ -28,6 +31,15 @@ Each template argument is one of the following: . A *type template argument* `type` <> +_module-member-sequence_ is the same as for a +<>. + +The optional module member list represents the result of +<>. +If a template expansion specifier has a module member +list, then is called an *expanded template*. +Otherwise it is called an *unexpanded template*. + ==== Semantics . The qualified identifier must From 8ab7f5e9908bf7b18030b8e0b6b08350e5359e9c Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Mon, 12 Oct 2026 16:23:25 -0700 Subject: [PATCH 02/51] Revise spec; revise syntax --- compiler/lib/src/main/scala/syntax/Parser.scala | 6 ++++-- compiler/lib/src/test/scala/syntax/Parser.scala | 8 ++++++++ docs/fpp-spec.html | 14 +++++++------- docs/spec/Expansion-of-Templates.adoc | 10 +++++----- .../Specifiers/Template-Expansion-Specifiers.adoc | 2 +- 5 files changed, 25 insertions(+), 15 deletions(-) diff --git a/compiler/lib/src/main/scala/syntax/Parser.scala b/compiler/lib/src/main/scala/syntax/Parser.scala index 0a4daadb3..c88e5bf1b 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( + module ~>! lbrace ~>! moduleMembers <~! rbrace + ) ^^ { + case id ~ args ~ membersOpt => Ast.SpecTemplateExpand(id, args, membersOpt) } } diff --git a/compiler/lib/src/test/scala/syntax/Parser.scala b/compiler/lib/src/test/scala/syntax/Parser.scala index 534ef5b51..7e0829a6e 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 module { constant a = 0 }", "expand M.T()", + "expand M.T() module { constant a = 0 }", "expand M.T(constant 1)", + "expand M.T(constant 1) module { constant a = 0 }", "expand M.T(constant 1, constant 2)", + "expand M.T(constant 1, constant 2) module { constant a = 0 }", "expand M.T(constant 1, constant 2, instance mod.$instance)", + "expand M.T(constant 1, constant 2, instance mod.$instance) module { 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) module { constant a = 0 }", "expand M.T(constant 1, instance .inst1, type U32)", + "expand M.T(constant 1, instance .inst1, type U32) module { 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]) module { constant a = 0 }", ) ) } diff --git a/docs/fpp-spec.html b/docs/fpp-spec.html index 73899fa0e..41fe5c33a 100644 --- a/docs/fpp-spec.html +++ b/docs/fpp-spec.html @@ -9272,7 +9272,7 @@

    7.19.1. Syntax

    ( template-arg-list ) ] [ -{ module-member-sequence } +module { module-member-sequence } ]

    @@ -12200,7 +12200,7 @@

    18. Expansion of Templates

    template expansion specifier S in the source model, transform S into an -expanded template expansion specifier \$E = S { X }\$, where X +expanded template expansion specifier E = S module { X }, where X is a copy of the module member list provided by the template definition to which S refers. The syntax X behaves as if it were literally included in @@ -12209,8 +12209,8 @@

    18. Expansion of Templates

    resolving names that appear inside E.

  • -

    For each expanded template expansion specifier \$E = S { X -}\$ in the source model, leave E unchanged.

    +

    For each expanded template expansion specifier E = S module { X } +in the source model, leave E unchanged.

  • @@ -12245,7 +12245,7 @@

    18.1. Algorithm

    Let X be a copy of the syntax specified in the body of T.

  • -

    Replace S with \$S { X }\$.

    +

    Replace S with S module { X }.

  • @@ -12300,7 +12300,7 @@

    18.2.1. Example 1

    module N { - expand M.T(constant 1) { + expand M.T(constant 1) module { constant c = a + b @@ -14573,7 +14573,7 @@

    25.4. Translation Tools

    diff --git a/docs/spec/Expansion-of-Templates.adoc b/docs/spec/Expansion-of-Templates.adoc index 9450b7ef4..c583ba3a2 100644 --- a/docs/spec/Expansion-of-Templates.adoc +++ b/docs/spec/Expansion-of-Templates.adoc @@ -8,7 +8,7 @@ It produces a new model according to the following rules: template expansion specifier>> _S_ in the source model, transform _S_ into an -expanded template expansion specifier stem:[E = S { X }], where _X_ +expanded template expansion specifier _E_ = _S_ `module` `{` _X_ `}`, where _X_ is a copy of the module member list provided by the template definition to which _S_ refers. The syntax _X_ behaves as if it were literally included in @@ -17,8 +17,8 @@ special rules for <> that appear inside _E_. -. For each expanded template expansion specifier stem:[E = S { X -}] in the source model, leave _E_ unchanged. +. For each expanded template expansion specifier _E_ = _S_ `module` `{` _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) @@ -41,7 +41,7 @@ Construct the output model _M'_ as follows: .. Let _X_ be a copy of the syntax specified in the body of _T_. -.. Replace _S_ with stem:[S { X }]. +.. Replace _S_ with _S_ `module` `{` _X_ `}`. === Examples @@ -88,7 +88,7 @@ module M { module N { - expand M.T(constant 1) { + expand M.T(constant 1) module { constant c = a + b diff --git a/docs/spec/Specifiers/Template-Expansion-Specifiers.adoc b/docs/spec/Specifiers/Template-Expansion-Specifiers.adoc index 49b27b09c..664ad9a71 100644 --- a/docs/spec/Specifiers/Template-Expansion-Specifiers.adoc +++ b/docs/spec/Specifiers/Template-Expansion-Specifiers.adoc @@ -14,7 +14,7 @@ _[_ `(` _template-arg-list_ `)` _]_ _[_ -`{` _module-member-sequence_ `}` +`module` `{` _module-member-sequence_ `}` _]_ _template-arg-list_ is an From cfde476885dbf20e7c2491e1a5b3907110bf3158 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Mon, 12 Oct 2026 16:35:22 -0700 Subject: [PATCH 03/51] Refactor AstWriter --- .../lib/src/main/scala/codegen/AstWriter.scala | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/compiler/lib/src/main/scala/codegen/AstWriter.scala b/compiler/lib/src/main/scala/codegen/AstWriter.scala index 8d5b30ec1..a03e01c92 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) } From 5bd18ab7bdb219811018b920b502a18586f3cc6e Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Mon, 12 Oct 2026 17:11:24 -0700 Subject: [PATCH 04/51] Revise spec, syntax, and tests --- .../lib/src/main/scala/syntax/Parser.scala | 2 +- .../lib/src/test/scala/syntax/Parser.scala | 16 ++++---- compiler/tools/fpp-syntax/test/template.fpp | 18 +++++++-- .../tools/fpp-syntax/test/template.ref.txt | 38 ++++++++++--------- compiler/tools/fpp-syntax/test/update-ref | 2 +- compiler/tools/fpp-to-fpp/test/run | 8 ++-- docs/fpp-spec.html | 12 +++--- docs/spec/Expansion-of-Templates.adoc | 8 ++-- .../Template-Expansion-Specifiers.adoc | 2 +- 9 files changed, 60 insertions(+), 46 deletions(-) diff --git a/compiler/lib/src/main/scala/syntax/Parser.scala b/compiler/lib/src/main/scala/syntax/Parser.scala index c88e5bf1b..3d721b582 100644 --- a/compiler/lib/src/main/scala/syntax/Parser.scala +++ b/compiler/lib/src/main/scala/syntax/Parser.scala @@ -1097,7 +1097,7 @@ object Parser extends Parsers { def specTemplateExpand: Parser[Ast.SpecTemplateExpand] = { (expand ~>! node(qualIdent)) ~! templateArgList ~! opt( - module ~>! lbrace ~>! moduleMembers <~! rbrace + lbrace ~>! moduleMembers <~! rbrace ) ^^ { case id ~ args ~ membersOpt => Ast.SpecTemplateExpand(id, args, membersOpt) } diff --git a/compiler/lib/src/test/scala/syntax/Parser.scala b/compiler/lib/src/test/scala/syntax/Parser.scala index 7e0829a6e..b1c5d7657 100644 --- a/compiler/lib/src/test/scala/syntax/Parser.scala +++ b/compiler/lib/src/test/scala/syntax/Parser.scala @@ -542,21 +542,21 @@ class ParserSpec extends AnyWordSpec { Parser.specTemplateExpand, List( "expand T", - "expand T module { constant a = 0 }", + "expand T { constant a = 0 }", "expand M.T()", - "expand M.T() module { constant a = 0 }", + "expand M.T() { constant a = 0 }", "expand M.T(constant 1)", - "expand M.T(constant 1) module { constant a = 0 }", + "expand M.T(constant 1) { constant a = 0 }", "expand M.T(constant 1, constant 2)", - "expand M.T(constant 1, constant 2) module { constant a = 0 }", + "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) module { constant a = 0 }", + "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) module { constant a = 0 }", + "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) module { constant a = 0 }", + "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]) module { constant a = 0 }", + "expand M.T(constant 1, constant 2, constant {member=1}, constant [1, 2]) { constant a = 0 }", ) ) } diff --git a/compiler/tools/fpp-syntax/test/template.fpp b/compiler/tools/fpp-syntax/test/template.fpp index 74a9c4b6e..21bf40104 100644 --- a/compiler/tools/fpp-syntax/test/template.fpp +++ b/compiler/tools/fpp-syntax/test/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/template.ref.txt b/compiler/tools/fpp-syntax/test/template.ref.txt index faa0858fe..92987959c 100644 --- a/compiler/tools/fpp-syntax/test/template.ref.txt +++ b/compiler/tools/fpp-syntax/test/template.ref.txt @@ -22,21 +22,23 @@ def module template 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 +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 diff --git a/compiler/tools/fpp-syntax/test/update-ref b/compiler/tools/fpp-syntax/test/update-ref index 2f21c6bff..d036a8739 100755 --- a/compiler/tools/fpp-syntax/test/update-ref +++ b/compiler/tools/fpp-syntax/test/update-ref @@ -48,7 +48,7 @@ update -ia include-state-machine update -ia include-subdir update -ia include-topology update -ia topology-ports -update -ita template +update -iea template update -ia subdir/include-parent-dir update -ia syntax syntax-include-ast update "" numeric-shift diff --git a/compiler/tools/fpp-to-fpp/test/run b/compiler/tools/fpp-to-fpp/test/run index a86099346..b7486f291 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 41fe5c33a..fcb52cc52 100644 --- a/docs/fpp-spec.html +++ b/docs/fpp-spec.html @@ -9272,7 +9272,7 @@

    7.19.1. Syntax

    ( template-arg-list ) ] [ -module { module-member-sequence } +{ module-member-sequence } ]

    @@ -12200,7 +12200,7 @@

    18. Expansion of Templates

    template expansion specifier S in the source model, transform S into an -expanded template expansion specifier E = S module { X }, where X +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 syntax X behaves as if it were literally included in @@ -12209,7 +12209,7 @@

    18. Expansion of Templates

    resolving names that appear inside E.

  • -

    For each expanded template expansion specifier E = S module { X } +

    For each expanded template expansion specifier E = S { X } in the source model, leave E unchanged.

  • @@ -12245,7 +12245,7 @@

    18.1. Algorithm

    Let X be a copy of the syntax specified in the body of T.

  • -

    Replace S with S module { X }.

    +

    Replace S with S { X }.

  • @@ -12300,7 +12300,7 @@

    18.2.1. Example 1

    module N { - expand M.T(constant 1) module { + expand M.T(constant 1) { constant c = a + b @@ -14573,7 +14573,7 @@

    25.4. Translation Tools

    diff --git a/docs/spec/Expansion-of-Templates.adoc b/docs/spec/Expansion-of-Templates.adoc index c583ba3a2..e08553de1 100644 --- a/docs/spec/Expansion-of-Templates.adoc +++ b/docs/spec/Expansion-of-Templates.adoc @@ -8,7 +8,7 @@ It produces a new model according to the following rules: template expansion specifier>> _S_ in the source model, transform _S_ into an -expanded template expansion specifier _E_ = _S_ `module` `{` _X_ `}`, where _X_ +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 syntax _X_ behaves as if it were literally included in @@ -17,7 +17,7 @@ special rules for <> that appear inside _E_. -. For each expanded template expansion specifier _E_ = _S_ `module` `{` _X_ `}` +. For each expanded template expansion specifier _E_ = _S_ `{` _X_ `}` in the source model, leave _E_ unchanged. Note in particular that applying template expansion twice @@ -41,7 +41,7 @@ Construct the output model _M'_ as follows: .. Let _X_ be a copy of the syntax specified in the body of _T_. -.. Replace _S_ with _S_ `module` `{` _X_ `}`. +.. Replace _S_ with _S_ `{` _X_ `}`. === Examples @@ -88,7 +88,7 @@ module M { module N { - expand M.T(constant 1) module { + expand M.T(constant 1) { constant c = a + b diff --git a/docs/spec/Specifiers/Template-Expansion-Specifiers.adoc b/docs/spec/Specifiers/Template-Expansion-Specifiers.adoc index 664ad9a71..49b27b09c 100644 --- a/docs/spec/Specifiers/Template-Expansion-Specifiers.adoc +++ b/docs/spec/Specifiers/Template-Expansion-Specifiers.adoc @@ -14,7 +14,7 @@ _[_ `(` _template-arg-list_ `)` _]_ _[_ -`module` `{` _module-member-sequence_ `}` +`{` _module-member-sequence_ `}` _]_ _template-arg-list_ is an From ebf0208dd6e124c551c90fdc4bd71792503bd80f Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Mon, 12 Oct 2026 17:36:32 -0700 Subject: [PATCH 05/51] Revise analysis Support syntactic analysis of expand specifiers with pre-expansions Revise tests --- .../src/main/scala/analysis/Analysis.scala | 2 +- .../analysis/Analyzers/ModuleAnalyzer.scala | 21 +++++++++++-------- .../Semantics/TemplateExpansion.scala | 2 +- compiler/tools/fpp-syntax/test/template.fpp | 14 ++++++------- .../tools/fpp-syntax/test/template.ref.txt | 20 ++++++++++++++++++ 5 files changed, 41 insertions(+), 18 deletions(-) diff --git a/compiler/lib/src/main/scala/analysis/Analysis.scala b/compiler/lib/src/main/scala/analysis/Analysis.scala index 506775030..f9ed7d98c 100644 --- a/compiler/lib/src/main/scala/analysis/Analysis.scala +++ b/compiler/lib/src/main/scala/analysis/Analysis.scala @@ -90,7 +90,7 @@ case class Analysis( 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 */ + /** Maps template expansion AST nodes to their expansions */ templateExpansionMap: Map[AstNode.Id, TemplateExpansion] = Map(), /** Tracks the current expansion we are analyzing inside of */ templateExpansion: Option[TemplateExpansion] = None, diff --git a/compiler/lib/src/main/scala/analysis/Analyzers/ModuleAnalyzer.scala b/compiler/lib/src/main/scala/analysis/Analyzers/ModuleAnalyzer.scala index 10604d50f..bca23d984 100644 --- a/compiler/lib/src/main/scala/analysis/Analyzers/ModuleAnalyzer.scala +++ b/compiler/lib/src/main/scala/analysis/Analyzers/ModuleAnalyzer.scala @@ -17,20 +17,23 @@ 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 an expand { ... } clause. + Right(a) } } diff --git a/compiler/lib/src/main/scala/analysis/Semantics/TemplateExpansion.scala b/compiler/lib/src/main/scala/analysis/Semantics/TemplateExpansion.scala index a806ae441..dd90af846 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/tools/fpp-syntax/test/template.fpp b/compiler/tools/fpp-syntax/test/template.fpp index 21bf40104..0748e77c0 100644 --- a/compiler/tools/fpp-syntax/test/template.fpp +++ b/compiler/tools/fpp-syntax/test/template.fpp @@ -23,10 +23,10 @@ module Unexpanded { } -#module Expanded { -# -# @ Expanded expansion specifier -# expand Tmpl(constant 10, type Type, instance .instance1) { constant a = 0 } -# @< Expanded 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/template.ref.txt b/compiler/tools/fpp-syntax/test/template.ref.txt index 92987959c..070cbb1d5 100644 --- a/compiler/tools/fpp-syntax/test/template.ref.txt +++ b/compiler/tools/fpp-syntax/test/template.ref.txt @@ -42,3 +42,23 @@ def module 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 array + ident Arr + size literal int 3 + type name qual ident TypeParam + def topology + ident Top + spec interface instance + qual ident inst + @< Expanded expansion specifier From 779f30f55c068567166231de27fb3e3739890c02 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Mon, 12 Oct 2026 19:57:09 -0700 Subject: [PATCH 06/51] Revise ExpandTemplates Refactor Handle expansion provided in source --- .../src/main/scala/analysis/Analysis.scala | 10 +- .../scala/transform/ExpandTemplates.scala | 125 ++++++++++-------- .../tools/fpp-syntax/test/template.ref.txt | 11 +- 3 files changed, 78 insertions(+), 68 deletions(-) diff --git a/compiler/lib/src/main/scala/analysis/Analysis.scala b/compiler/lib/src/main/scala/analysis/Analysis.scala index f9ed7d98c..d50c4c8cf 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, + /** Node ID of the current template expansion */ + templateExpansionId: Option[AstNode.Id] = None, /** Maps template expansion AST nodes to their expansions */ templateExpansionMap: Map[AstNode.Id, TemplateExpansion] = Map(), - /** Tracks the current expansion we are analyzing inside of */ + /** 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 definition */ + templateDefinitionId: Option[AstNode.Id] = None, /** 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/transform/ExpandTemplates.scala b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala index e0244a078..06b34dbc9 100644 --- a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala +++ b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala @@ -50,7 +50,7 @@ object ExpandTemplates extends AstTransformer a: Analysis, node: AstNode[T] ) = - a.template match { + a.templateExpansionId match { case None => Right((), node) case Some(expansionNode) => { val out = AstNode.create(node.data) @@ -80,7 +80,7 @@ object ExpandTemplates extends AstTransformer a: In, aNode: Ast.Annotated[AstNode[T]] ) = { - a.template match { + a.templateExpansionId match { // We are not currently in a template, leave the node alone case None => Right((), aNode) case Some(_) => @@ -95,7 +95,7 @@ object ExpandTemplates extends AstTransformer node: AstNode[T], data: T ) = - a.template match { + a.templateExpansionId match { case None => AstNode.create(data, node.id) case Some(expansionNode) => { val out = AstNode.create(data) @@ -122,8 +122,8 @@ object ExpandTemplates extends AstTransformer 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))) + val (_, elts1) = result + ((), cloneNode(a, node, Ast.ExprArray(elts1))) } override def exprArraySubscriptNode(a: In, node: AstNode[Ast.Expr], e: Ast.ExprArraySubscript): ResultNode[Ast.Expr] = @@ -151,15 +151,15 @@ object ExpandTemplates extends AstTransformer 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)))) + val (_, left) = result + ((), 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))) + val (_, value) = result + ((), cloneNode(a, node, Ast.ExprParen(value))) } def structMember( @@ -168,8 +168,8 @@ object ExpandTemplates extends AstTransformer ) = { for (result <- matchExprNode(a, node.data.value)) yield { - val (a1, value) = result - (a1, cloneNode(a, node, Ast.StructMember( + val (_, value) = result + ((), cloneNode(a, node, Ast.StructMember( node.data.name, value ))) @@ -204,8 +204,8 @@ object ExpandTemplates extends AstTransformer ) = for { result <- transformList(a, e.members, structMember) } yield { - val (a1, members1) = result - (a1, cloneNode(a, node, Ast.ExprStruct(members1))) + val (_, members1) = result + ((), cloneNode(a, node, Ast.ExprStruct(members1))) } override def exprUnopNode(a: In, node: AstNode[Ast.Expr], e: Ast.ExprUnop) = @@ -235,8 +235,8 @@ object ExpandTemplates extends AstTransformer case Some(value) => for (result <- matchExprNode(a, value)) yield { - val (a1, v1) = result - (a1, Some(v1)) + val (_, v1) = result + ((), Some(v1)) } } @@ -251,8 +251,8 @@ object ExpandTemplates extends AstTransformer case Some(size) => for (result <- matchExprNode(a, size)) yield { - val (a1, value) = result - (a1, cloneNode(a, node, Ast.TypeNameString(Some(value)))) + val (_, value) = result + ((), cloneNode(a, node, Ast.TypeNameString(Some(value)))) } } } @@ -275,8 +275,8 @@ object ExpandTemplates extends AstTransformer val data = aNode._2.data for (result <- matchTypeName(a, data.typeName)) yield { - val (a1, ty) = result - (a1, cloneAnnotatedNode( + val (_, ty) = result + ((), cloneAnnotatedNode( a, aNode, data.copy(typeName = ty) )) } @@ -315,8 +315,8 @@ object ExpandTemplates extends AstTransformer 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))) + val (_, members1) = result + ((), cloneAnnotatedNode(a, aNode, data.copy(members = members1.flatten))) } override def defComponentInstanceAnnotatedNode( @@ -356,8 +356,8 @@ object ExpandTemplates extends AstTransformer 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))) + val (_, members1) = result + ((), cloneAnnotatedNode(a, aNode, data.copy(members=members1))) } override def defConstantAnnotatedNode( @@ -794,8 +794,8 @@ object ExpandTemplates extends AstTransformer val data = aNode._2.data for (result <- matchExprNode(a, data.phase)) yield { - val (a1, phase1) = result - (a1, cloneAnnotatedNode(a, aNode, data.copy(phase=phase1))) + val (_, phase1) = result + ((), cloneAnnotatedNode(a, aNode, data.copy(phase=phase1))) } override def specInternalPortAnnotatedNode( @@ -1067,17 +1067,17 @@ object ExpandTemplates extends AstTransformer for { // Validate no nested template - _ <- a.templateDefinition match { + _ <- a.templateDefinitionId 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))) + a <- Right(a.copy(templateDefinitionId = Some(node.id))) params <- transformList(a, data.params, templateParam) members <- transformList(a, data.members, matchModuleMember) - a <- Right(a.copy(templateDefinition = None)) + a <- Right(a.copy(templateDefinitionId = None)) } yield { val (_, params1) = params @@ -1096,8 +1096,8 @@ object ExpandTemplates extends AstTransformer 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))) + val (_, members1) = result + ((), cloneAnnotatedNode(a, aNode, data.copy(members = members1.flatten))) } } @@ -1105,41 +1105,56 @@ object ExpandTemplates extends AstTransformer a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecTemplateExpand]] ): ResultAnnotatedNode[Ast.SpecTemplateExpand] = { - val (pre, node, post) = aNode + val (_, node, _) = aNode val data = node.data - - (a.template, a.templateDefinition) match { + (a.templateExpansionId, a.templateDefinitionId) 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)) + // Not inside a template: expand if needed + data.members match { + // Members are already there; nothing to do + case Some(members) => Right((), aNode) + // Members are not there; expand + case None => expandTemplate(a, aNode) } - case (_, Some(templateDefinition)) => + case (_, Some(templateDefinitionId)) => // The expansion specifier is nested inside a template body Left(SemanticError.TemplateExpansionInTemplate( Locations.get(node.id), - Locations.get(templateDefinition) + Locations.get(templateDefinitionId) )) case (Some(_), None) => throw new InternalError( "ExpandTemplates: expanding a template with no template definition" ) } } + + /** Expand a template */ + private def expandTemplate( + a: Analysis, + aNode: Ast.Annotated[AstNode[Ast.SpecTemplateExpand]] + ): ResultAnnotatedNode[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 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( + templateExpansionId = Some(node.id), + templateDefinitionId = 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)) + } + } + } diff --git a/compiler/tools/fpp-syntax/test/template.ref.txt b/compiler/tools/fpp-syntax/test/template.ref.txt index 070cbb1d5..cecd64f59 100644 --- a/compiler/tools/fpp-syntax/test/template.ref.txt +++ b/compiler/tools/fpp-syntax/test/template.ref.txt @@ -53,12 +53,7 @@ def module 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 + def constant + ident a + literal int 0 @< Expanded expansion specifier From fd871c164c88b1f52e4ad5c8f34ddf956aaca574 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Mon, 12 Oct 2026 20:24:27 -0700 Subject: [PATCH 07/51] Revise spec Refactor implementation --- compiler/lib/src/main/scala/analysis/Analysis.scala | 8 ++++---- .../main/scala/analysis/Analyzers/ModuleAnalyzer.scala | 3 ++- .../CheckSemantics/ExpandSyntaxAndEnterSymbols.scala | 2 ++ docs/fpp-spec.html | 7 ++++++- docs/spec/Specifiers/Template-Expansion-Specifiers.adoc | 4 ++++ docs/wiki/Check-Template-Uses.asciidoc | 2 +- 6 files changed, 19 insertions(+), 7 deletions(-) diff --git a/compiler/lib/src/main/scala/analysis/Analysis.scala b/compiler/lib/src/main/scala/analysis/Analysis.scala index d50c4c8cf..21ab1ba20 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 current template definition */ + templateDefinitionId: Option[AstNode.Id] = None, /** Node ID of the current template expansion */ templateExpansionId: Option[AstNode.Id] = None, - /** Maps template expansion AST nodes to their expansions */ - templateExpansionMap: Map[AstNode.Id, TemplateExpansion] = Map(), /** The current template expansion */ templateExpansion: Option[TemplateExpansion] = None, - /** Node ID of the current template definition */ - templateDefinitionId: 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 bca23d984..77d40738e 100644 --- a/compiler/lib/src/main/scala/analysis/Analyzers/ModuleAnalyzer.scala +++ b/compiler/lib/src/main/scala/analysis/Analyzers/ModuleAnalyzer.scala @@ -32,7 +32,8 @@ trait ModuleAnalyzer extends Analyzer { yield a2.copy(templateExpansion = a.templateExpansion) case None => // This node has not yet been expanded by analysis. - // The expansion is provided in an expand { ... } clause. + // 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/ExpandSyntaxAndEnterSymbols.scala b/compiler/lib/src/main/scala/analysis/CheckSemantics/ExpandSyntaxAndEnterSymbols.scala index b2351b7b9..8e4447508 100644 --- a/compiler/lib/src/main/scala/analysis/CheckSemantics/ExpandSyntaxAndEnterSymbols.scala +++ b/compiler/lib/src/main/scala/analysis/CheckSemantics/ExpandSyntaxAndEnterSymbols.scala @@ -16,6 +16,8 @@ object ExpandSyntaxAndEnterSymbols { (a, tul) <- ResolveSpecInclude.transUnitList(a, tul) tul <- AddStateEnums.transUnitList(tul) a <- EnterSymbols.visitList(a, tul, EnterSymbols.transUnit) + // TODO: CheckTemplateDefinitions + // TODO: CheckTemplateExpansions a <- CheckTemplateUses.visitList(a, tul, CheckTemplateUses.transUnit) (_, tul) <- ExpandTemplates.transformList(a, tul, ExpandTemplates.transUnit) a <- EnterTemplateExpansionSymbols.visitList(a, tul, EnterTemplateExpansionSymbols.transUnit) diff --git a/docs/fpp-spec.html b/docs/fpp-spec.html index fcb52cc52..c96f47e6b 100644 --- a/docs/fpp-spec.html +++ b/docs/fpp-spec.html @@ -9374,6 +9374,11 @@

    7.19.2. Semantics +
  • +

    If module-member-sequence is present, then it must not +transitively contain any module +template definitions or template expansion specifiers.

    +
  • @@ -14573,7 +14578,7 @@

    25.4. Translation Tools

    diff --git a/docs/spec/Specifiers/Template-Expansion-Specifiers.adoc b/docs/spec/Specifiers/Template-Expansion-Specifiers.adoc index 49b27b09c..19411a011 100644 --- a/docs/spec/Specifiers/Template-Expansion-Specifiers.adoc +++ b/docs/spec/Specifiers/Template-Expansion-Specifiers.adoc @@ -84,6 +84,10 @@ template argument. ... When _p_ is a type template parameter, _B_ is called a *type parameter definition*. +. If _module-member-sequence_ is present, then it must not +transitively contain any <> or template expansion specifiers. + ==== Examples [source,fpp] diff --git a/docs/wiki/Check-Template-Uses.asciidoc b/docs/wiki/Check-Template-Uses.asciidoc index 7a2fd175d..b5d383b05 100644 --- a/docs/wiki/Check-Template-Uses.asciidoc +++ b/docs/wiki/Check-Template-Uses.asciidoc @@ -1,5 +1,5 @@ This algorithm traverses a source model and checks that each use -of a module template definition refers to a valid template definition. +of a module template definition refers to a template definition. It also constructs the use-def map entries for template expansion specifiers. From 1464b48c1dac8a08d8b9ac6f3a39a1b176e621f5 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Mon, 12 Oct 2026 21:11:03 -0700 Subject: [PATCH 08/51] Refactor error checking --- .../src/main/scala/analysis/Analysis.scala | 2 +- .../CheckSemantics/CheckTemplateDefs.scala | 40 ++++ .../ExpandSyntaxAndEnterSymbols.scala | 2 +- .../scala/transform/ExpandTemplates.scala | 29 ++- compiler/lib/src/main/scala/util/Error.scala | 188 +++++++++--------- .../test/template/composition_invalid.ref.txt | 2 +- .../test/template/invalid_nested.ref.txt | 2 +- 7 files changed, 145 insertions(+), 120 deletions(-) create mode 100644 compiler/lib/src/main/scala/analysis/CheckSemantics/CheckTemplateDefs.scala diff --git a/compiler/lib/src/main/scala/analysis/Analysis.scala b/compiler/lib/src/main/scala/analysis/Analysis.scala index 21ab1ba20..67ecbca15 100644 --- a/compiler/lib/src/main/scala/analysis/Analysis.scala +++ b/compiler/lib/src/main/scala/analysis/Analysis.scala @@ -89,7 +89,7 @@ case class Analysis( /** The mapping from nodes to implied uses */ impliedUseMap: Map[AstNode.Id, ImpliedUse.Uses] = Map(), /** Node ID of the current template definition */ - templateDefinitionId: Option[AstNode.Id] = None, + templateDefId: Option[AstNode.Id] = None, /** Node ID of the current template expansion */ templateExpansionId: Option[AstNode.Id] = None, /** The current template expansion */ 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 000000000..a564e713d --- /dev/null +++ b/compiler/lib/src/main/scala/analysis/CheckSemantics/CheckTemplateDefs.scala @@ -0,0 +1,40 @@ +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) + } + 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]] + ) = 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 8e4447508..36ff9b9b3 100644 --- a/compiler/lib/src/main/scala/analysis/CheckSemantics/ExpandSyntaxAndEnterSymbols.scala +++ b/compiler/lib/src/main/scala/analysis/CheckSemantics/ExpandSyntaxAndEnterSymbols.scala @@ -16,7 +16,7 @@ object ExpandSyntaxAndEnterSymbols { (a, tul) <- ResolveSpecInclude.transUnitList(a, tul) tul <- AddStateEnums.transUnitList(tul) a <- EnterSymbols.visitList(a, tul, EnterSymbols.transUnit) - // TODO: CheckTemplateDefinitions + a <- CheckTemplateDefs.visitList(a, tul, CheckTemplateDefs.transUnit) // TODO: CheckTemplateExpansions a <- CheckTemplateUses.visitList(a, tul, CheckTemplateUses.transUnit) (_, tul) <- ExpandTemplates.transformList(a, tul, ExpandTemplates.transUnit) diff --git a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala index 06b34dbc9..09d8919a0 100644 --- a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala +++ b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala @@ -1066,18 +1066,10 @@ object ExpandTemplates extends AstTransformer } for { - // Validate no nested template - _ <- a.templateDefinitionId match { - case Some(parent) => Left(SemanticError.NestedTemplateDefinition( - Locations.get(aNode._2.id), - Locations.get(parent) - )) - case None => Right(()) - } - a <- Right(a.copy(templateDefinitionId = Some(node.id))) + a <- Right(a.copy(templateDefId = Some(node.id))) params <- transformList(a, data.params, templateParam) members <- transformList(a, data.members, matchModuleMember) - a <- Right(a.copy(templateDefinitionId = None)) + a <- Right(a.copy(templateDefId = None)) } yield { val (_, params1) = params @@ -1107,7 +1099,7 @@ object ExpandTemplates extends AstTransformer ): ResultAnnotatedNode[Ast.SpecTemplateExpand] = { val (_, node, _) = aNode val data = node.data - (a.templateExpansionId, a.templateDefinitionId) match { + (a.templateExpansionId, a.templateDefId) match { case (None, None) => // Not inside a template: expand if needed data.members match { @@ -1116,12 +1108,15 @@ object ExpandTemplates extends AstTransformer // Members are not there; expand case None => expandTemplate(a, aNode) } - case (_, Some(templateDefinitionId)) => + case (_, Some(templateDefId)) => // The expansion specifier is nested inside a template body - Left(SemanticError.TemplateExpansionInTemplate( - Locations.get(node.id), - Locations.get(templateDefinitionId) - )) + Left( + SemanticError.TemplateDefError( + Locations.get(node.id), + "template expansion specifiers cannot appear inside a module template", + Locations.get(templateDefId) + ) + ) case (Some(_), None) => throw new InternalError( "ExpandTemplates: expanding a template with no template definition" ) @@ -1146,7 +1141,7 @@ object ExpandTemplates extends AstTransformer members <- transformList( a.copy( templateExpansionId = Some(node.id), - templateDefinitionId = Some(tmpl.node._2.id) + templateDefId = Some(tmpl.node._2.id) ), tmpl.node._2.data.members, matchModuleMember diff --git a/compiler/lib/src/main/scala/util/Error.scala b/compiler/lib/src/main/scala/util/Error.scala index 0d66e7217..f17f1e8bb 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,24 @@ 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.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 +399,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 +621,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 +752,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 +781,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 +813,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 +825,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 +877,18 @@ object SemanticError { loc: Location ) extends Error } + /** Error in template definition */ + final case class TemplateDefError( + loc: Location, + msg: String, + defLoc: 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 +902,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/tools/fpp-check/test/template/composition_invalid.ref.txt b/compiler/tools/fpp-check/test/template/composition_invalid.ref.txt index 1ebb3e497..9df63fadb 100644 --- a/compiler/tools/fpp-check/test/template/composition_invalid.ref.txt +++ b/compiler/tools/fpp-check/test/template/composition_invalid.ref.txt @@ -3,7 +3,7 @@ fpp-check expand T1(constant p) ^ error: template expansion specifiers cannot appear inside a module template -enclosing template defined here: +enclosing template is 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/invalid_nested.ref.txt b/compiler/tools/fpp-check/test/template/invalid_nested.ref.txt index ec320733a..a20441bde 100644 --- a/compiler/tools/fpp-check/test/template/invalid_nested.ref.txt +++ b/compiler/tools/fpp-check/test/template/invalid_nested.ref.txt @@ -3,7 +3,7 @@ fpp-check module template Inner(constant c2: U32) { ^ error: module template definitions cannot be nested -parent template defined here: +enclosing template is defined here: [ local path prefix ]/compiler/tools/fpp-check/test/template/invalid_nested.fpp:1.1 module template Outer(constant c1: U32) { ^ From 450a092c3063cf1d5350e061217baed8621f5574 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Mon, 12 Oct 2026 21:21:49 -0700 Subject: [PATCH 09/51] Revise CheckTemplateDefs --- .../CheckSemantics/CheckTemplateDefs.scala | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/compiler/lib/src/main/scala/analysis/CheckSemantics/CheckTemplateDefs.scala b/compiler/lib/src/main/scala/analysis/CheckSemantics/CheckTemplateDefs.scala index a564e713d..61a92d176 100644 --- a/compiler/lib/src/main/scala/analysis/CheckSemantics/CheckTemplateDefs.scala +++ b/compiler/lib/src/main/scala/analysis/CheckSemantics/CheckTemplateDefs.scala @@ -35,6 +35,19 @@ object CheckTemplateDefs override def specTemplateExpandAnnotatedNode( a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecTemplateExpand]] - ) = Right(a) + ) = { + 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) + } + } } From 5bd75f76c0528b7bba459673536f5de5dbb59576 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Mon, 12 Oct 2026 21:35:20 -0700 Subject: [PATCH 10/51] Revise ExpandTemplates --- .../scala/transform/ExpandTemplates.scala | 32 ++++--------------- 1 file changed, 7 insertions(+), 25 deletions(-) diff --git a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala index 09d8919a0..b755a6be5 100644 --- a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala +++ b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala @@ -1099,27 +1099,11 @@ object ExpandTemplates extends AstTransformer ): ResultAnnotatedNode[Ast.SpecTemplateExpand] = { val (_, node, _) = aNode val data = node.data - (a.templateExpansionId, a.templateDefId) match { - case (None, None) => - // Not inside a template: expand if needed - data.members match { - // Members are already there; nothing to do - case Some(members) => Right((), aNode) - // Members are not there; expand - case None => expandTemplate(a, aNode) - } - case (_, Some(templateDefId)) => - // The expansion specifier is nested inside a template body - Left( - SemanticError.TemplateDefError( - Locations.get(node.id), - "template expansion specifiers cannot appear inside a module template", - Locations.get(templateDefId) - ) - ) - case (Some(_), None) => throw new InternalError( - "ExpandTemplates: expanding a template with no template definition" - ) + data.members match { + // Members are already there; nothing to do + case Some(members) => Right((), aNode) + // Members are not there; expand + case None => expandTemplate(a, aNode) } } @@ -1133,10 +1117,8 @@ object ExpandTemplates extends AstTransformer 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. + // Clone the template body, recording the expansion node so that + // cloned nodes point back at the expansion site. // Record the template definition too for diagnostics. members <- transformList( a.copy( From 4ff5579dee2a89877bdcf2b6c451bb0393efbbf7 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Mon, 12 Oct 2026 21:54:36 -0700 Subject: [PATCH 11/51] Refactor ExpandTemplates --- .../scala/transform/ExpandTemplates.scala | 270 +++++++++--------- 1 file changed, 134 insertions(+), 136 deletions(-) diff --git a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala index b755a6be5..afc70fef6 100644 --- a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala +++ b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala @@ -65,17 +65,6 @@ object ExpandTemplates extends AstTransformer } } - 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)) - } - override def defaultAnnotatedNode[T]( a: In, aNode: Ast.Annotated[AstNode[T]] @@ -90,35 +79,6 @@ object ExpandTemplates extends AstTransformer } } - 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) - Locations.put(out.id, Location( - inLoc.file, - inLoc.pos, - inLoc.includingLoc, - Some(Locations.get(expansionNode)) - )) - out - } - } - - inline def cloneAnnotatedNode[T]( - 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 { @@ -191,12 +151,6 @@ object ExpandTemplates extends AstTransformer } } - def qualIdentNode( - a: In, - node: AstNode[Ast.QualIdent] - ): ResultNode[Ast.QualIdent] = - Right(((), cloneQualIdentNode(a, node))) - override def exprStructNode( a: Analysis, node: AstNode[Ast.Expr], @@ -226,20 +180,6 @@ object ExpandTemplates extends AstTransformer )))) } - 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 (_, v1) = result - ((), Some(v1)) - } - } - override def typeNameStringNode( a: In, node: AstNode[Ast.TypeName], @@ -257,17 +197,6 @@ object ExpandTemplates extends AstTransformer } } - 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)) - } - override def defAliasTypeAnnotatedNode( a: In, aNode: Ast.Annotated[AstNode[Ast.DefAliasType]] @@ -304,7 +233,7 @@ object ExpandTemplates extends AstTransformer data.copy( size = size._2, eltType = eltType._2, - default = default._2, + default = default, format = cloneStringNodeOpt(a, data.format) ) ) @@ -342,10 +271,10 @@ object ExpandTemplates extends AstTransformer 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, + queueSize=queueSize, + stackSize=stackSize, + priority=priority, + cpu=cpu, initSpecs=initSpecs._2 ) ) @@ -380,7 +309,7 @@ object ExpandTemplates extends AstTransformer val data = aNode._2.data for (value <- exprNodeOpt(a, data.value)) yield { - ((), cloneAnnotatedNode(a, aNode, data.copy(value = value._2))) + ((), cloneAnnotatedNode(a, aNode, data.copy(value = value))) } override def defEnumAnnotatedNode( @@ -393,9 +322,9 @@ object ExpandTemplates extends AstTransformer constants <- transformList(a, data.constants, defEnumConstantAnnotatedNode) default <- exprNodeOpt(a, data.default) } yield ((), cloneAnnotatedNode(a, aNode, data.copy( - typeName = typeName._2, + typeName = typeName, constants = constants._2, - default = default._2 + default = default ))) def formalAnnotatatedParam( @@ -421,7 +350,7 @@ object ExpandTemplates extends AstTransformer returnType <- typeNameNodeOpt(a, data.returnType) } yield ((), cloneAnnotatedNode(a, aNode, data.copy( params = params._2, - returnType = returnType._2 + returnType = returnType ))) override def defStateMachineAnnotatedNodeExternal( @@ -457,7 +386,7 @@ object ExpandTemplates extends AstTransformer for { typeName <- typeNameNodeOpt(a, data.typeName) } yield { - ((), cloneAnnotatedNode(a, aNode, data.copy(typeName = typeName._2))) + ((), cloneAnnotatedNode(a, aNode, data.copy(typeName = typeName))) } def transitionExpr( @@ -497,7 +426,7 @@ object ExpandTemplates extends AstTransformer for { typeName <- typeNameNodeOpt(a, data.typeName) } yield { - ((), cloneAnnotatedNode(a, aNode, data.copy(typeName = typeName._2))) + ((), cloneAnnotatedNode(a, aNode, data.copy(typeName = typeName))) } override def defSignalAnnotatedNode( @@ -508,7 +437,7 @@ object ExpandTemplates extends AstTransformer for { typeName <- typeNameNodeOpt(a, data.typeName) } yield { - ((), cloneAnnotatedNode(a, aNode, data.copy(typeName = typeName._2))) + ((), cloneAnnotatedNode(a, aNode, data.copy(typeName = typeName))) } override def defStateAnnotatedNode( @@ -577,27 +506,11 @@ object ExpandTemplates extends AstTransformer } yield { ((), cloneAnnotatedNode(a, aNode, data.copy( signal = signal._2, - guard = guard._2, + guard = guard, 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) - ))) - } - override def defStructAnnotatedNode( a: In, aNode: Ast.Annotated[AstNode[Ast.DefStruct]] @@ -609,7 +522,7 @@ object ExpandTemplates extends AstTransformer } yield { ((), cloneAnnotatedNode(a, aNode, data.copy( members = members._2, - default = default._2 + default = default ))) } @@ -654,9 +567,9 @@ object ExpandTemplates extends AstTransformer } yield { ((), cloneAnnotatedNode(a, aNode, data.copy( params = params._2, - opcode = opcode._2, - priority = priority._2, - queueFull = queueFull._2, + opcode = opcode, + priority = priority, + queueFull = queueFull, ))) } @@ -704,9 +617,9 @@ object ExpandTemplates extends AstTransformer } yield { ((), connection.copy( fromPort = fromPort._2, - fromIndex = fromIndex._2, + fromIndex = fromIndex, toPort = toPort._2, - toIndex = toIndex._2, + toIndex = toIndex, )) } } @@ -738,8 +651,8 @@ object ExpandTemplates extends AstTransformer defaultPriority <- exprNodeOpt(a, data.defaultPriority) } yield { ((), cloneAnnotatedNode(a, aNode, data.copy( - id = id._2, - defaultPriority = defaultPriority._2, + id = id, + defaultPriority = defaultPriority, ))) } @@ -761,7 +674,7 @@ object ExpandTemplates extends AstTransformer every <- exprNodeOpt(a, throttle.data.every) } yield ((), Some(cloneNode( a, throttle, throttle.data.copy( - every = every._2, + every = every, count = count._2, ) ))) @@ -770,7 +683,7 @@ object ExpandTemplates extends AstTransformer } yield { ((), cloneAnnotatedNode(a, aNode, data.copy( params = params._2, - id = id._2, + id = id, format = format._2, throttle = throttle._2, ))) @@ -808,7 +721,7 @@ object ExpandTemplates extends AstTransformer priority <- exprNodeOpt(a, data.priority) } yield ((), cloneAnnotatedNode(a, aNode, data.copy( params = params._2, - priority = priority._2, + priority = priority, ))) override def specLocAnnotatedNode( @@ -837,24 +750,12 @@ object ExpandTemplates extends AstTransformer 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, + default = default, + id = id, + setOpcode = setOpcode, + saveOpcode = saveOpcode ))) - 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))) - } - } - override def specPortInstanceAnnotatedNode( a: In, aNode: Ast.Annotated[AstNode[Ast.SpecPortInstance]] @@ -869,10 +770,10 @@ object ExpandTemplates extends AstTransformer queueFull <- defaultNodeOpt(a, data.queueFull) } yield { ((), cloneAnnotatedNode(a, aNode, data.copy( - size = size._2, + size = size, port = port._2, - priority = priority._2, - queueFull = queueFull._2 + priority = priority, + queueFull = queueFull ))) } case data @ Ast.SpecPortInstance.Special(_, _, _, _, _) => @@ -881,8 +782,8 @@ object ExpandTemplates extends AstTransformer queueFull <- defaultNodeOpt(a, data.queueFull) } yield { ((), cloneAnnotatedNode(a, aNode, data.copy( - priority = priority._2, - queueFull = queueFull._2 + priority = priority, + queueFull = queueFull ))) } } @@ -910,7 +811,7 @@ object ExpandTemplates extends AstTransformer id <- exprNodeOpt(a, data.id) } yield (((), cloneAnnotatedNode(a, aNode, data.copy( recordType = recordType._2, - id = id._2 + id = id )))) override def specStateMachineInstanceAnnotatedNode( @@ -923,7 +824,7 @@ object ExpandTemplates extends AstTransformer priority <- exprNodeOpt(a, data.priority) } yield (((), cloneAnnotatedNode(a, aNode, data.copy( stateMachine = stateMachine._2, - priority = priority._2 + priority = priority )))) override def specTlmChannelAnnotatedNode( @@ -949,7 +850,7 @@ object ExpandTemplates extends AstTransformer high <- transformList(a, data.high, limit) } yield (((), cloneAnnotatedNode(a, aNode, data.copy( typeName = typeName._2, - id = id._2, + id = id, format = cloneStringNodeOpt(a, data.format), low = low._2, high = high._2 @@ -988,7 +889,7 @@ object ExpandTemplates extends AstTransformer group <- matchExprNode(a, data.group) members <- transformList(a, data.members, tlmPacketMember) } yield (((), cloneAnnotatedNode(a, aNode, data.copy( - id = id._2, + id = id, group = group._2, members = members._2, )))) @@ -1107,6 +1008,46 @@ object ExpandTemplates extends AstTransformer } } + 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) + Locations.put(out.id, Location( + inLoc.file, + inLoc.pos, + inLoc.includingLoc, + Some(Locations.get(expansionNode)) + )) + 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 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) + } + /** Expand a template */ private def expandTemplate( a: Analysis, @@ -1134,4 +1075,61 @@ object ExpandTemplates extends AstTransformer } } + private def exprNodeOpt( + a: In, + 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 qualIdentNode( + a: In, + node: AstNode[Ast.QualIdent] + ): ResultNode[Ast.QualIdent] = + Right(((), cloneQualIdentNode(a, node))) + + private 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))) + } + } + + private 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, + typeName = typeName._2, + format = cloneStringNodeOpt(a, data.format) + ))) + } + + private def typeNameNodeOpt( + a: In, + 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) + } + + } From a43331612c53447b452ae68793955538dd53d208 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Mon, 12 Oct 2026 22:19:00 -0700 Subject: [PATCH 12/51] Refactor ExpandTemplates --- .../scala/transform/ExpandTemplates.scala | 82 ++++++++++--------- 1 file changed, 43 insertions(+), 39 deletions(-) diff --git a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala index afc70fef6..661569d46 100644 --- a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala +++ b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala @@ -255,12 +255,12 @@ object ExpandTemplates extends AstTransformer 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) + (_, initSpecs) <- transformList(a, data.initSpecs, specInitAnnotatedNode) } yield { ( (), @@ -268,14 +268,14 @@ object ExpandTemplates extends AstTransformer a, aNode, data.copy( component=component, - baseId=baseId._2, + baseId=baseId, implType=cloneStringNodeOpt(a, data.implType), file=cloneStringNodeOpt(a, data.file), queueSize=queueSize, stackSize=stackSize, priority=priority, cpu=cpu, - initSpecs=initSpecs._2 + initSpecs=initSpecs ) ) ) @@ -398,7 +398,7 @@ object ExpandTemplates extends AstTransformer target <- qualIdentNode(a, node.data.target) } yield ((), cloneNode(a, node, node.data.copy( actions = actions._2, - target = target._2, + target = target, ))) override def defChoiceAnnotatedNode( @@ -481,19 +481,6 @@ object ExpandTemplates extends AstTransformer ((), 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)) - - override def specStateTransitionAnnotatedNode( a: In, aNode: Ast.Annotated[AstNode[Ast.SpecStateTransition]] @@ -507,7 +494,7 @@ object ExpandTemplates extends AstTransformer ((), cloneAnnotatedNode(a, aNode, data.copy( signal = signal._2, guard = guard, - transitionOrDo = transitionOrDo._2 + transitionOrDo = transitionOrDo ))) } @@ -550,7 +537,7 @@ object ExpandTemplates extends AstTransformer topology <- qualIdentNode(a, data.topology) } yield { ((), cloneAnnotatedNode(a, aNode, data.copy( - topology = topology._2 + topology = topology ))) } @@ -582,7 +569,7 @@ object ExpandTemplates extends AstTransformer instance <- qualIdentNode(a, data.instance) } yield { ((), cloneAnnotatedNode(a, aNode, data.copy( - instance = instance._2, + instance = instance, ))) } @@ -594,7 +581,7 @@ object ExpandTemplates extends AstTransformer interfaceInstance <- qualIdentNode(a, pii.data.interfaceInstance) portName <- defaultNode(a, pii.data.portName) } yield ((), cloneNode(a, pii, pii.data.copy( - interfaceInstance = interfaceInstance._2, + interfaceInstance = interfaceInstance, portName = portName._2, ))) } @@ -634,13 +621,14 @@ object ExpandTemplates extends AstTransformer case data @ Ast.SpecConnectionGraph.Pattern(_, source, targets) => for { source <- qualIdentNode(a, source) - targets <- transformList(a, targets, qualIdentNode) + (_, targets) <- transformList(a, targets, resultAdapter(qualIdentNode)) } yield ((), cloneAnnotatedNode(a, aNode, data.copy( - source = source._2, - targets = targets._2 + source = source, + targets = targets ))) } + override def specContainerAnnotatedNode( a: In, aNode: Ast.Annotated[AstNode[Ast.SpecContainer]] @@ -670,12 +658,12 @@ object ExpandTemplates extends AstTransformer case None => Right(((), None)) case Some(throttle) => for { - count <- matchExprNode(a, throttle.data.count) + (_, count) <- matchExprNode(a, throttle.data.count) every <- exprNodeOpt(a, throttle.data.every) } yield ((), Some(cloneNode( a, throttle, throttle.data.copy( every = every, - count = count._2, + count = count ) ))) } @@ -733,7 +721,7 @@ object ExpandTemplates extends AstTransformer symbol <- qualIdentNode(a, data.symbol) file <- defaultNode(a, data.file) } yield ((), cloneAnnotatedNode(a, aNode, data.copy( - symbol = symbol._2, + symbol = symbol, file = file._2, ))) @@ -771,7 +759,7 @@ object ExpandTemplates extends AstTransformer } yield { ((), cloneAnnotatedNode(a, aNode, data.copy( size = size, - port = port._2, + port = port, priority = priority, queueFull = queueFull ))) @@ -823,7 +811,7 @@ object ExpandTemplates extends AstTransformer stateMachine <- qualIdentNode(a, data.stateMachine) priority <- exprNodeOpt(a, data.priority) } yield (((), cloneAnnotatedNode(a, aNode, data.copy( - stateMachine = stateMachine._2, + stateMachine = stateMachine, priority = priority )))) @@ -877,7 +865,7 @@ object ExpandTemplates extends AstTransformer channelName <- defaultNode(a, node.data.channelName) } yield ((), Ast.TlmPacketMember.TlmChannelIdentifier( cloneNode(a, node, node.data.copy( - componentInstance = componentInstance._2, + componentInstance = componentInstance, channelName = channelName._2 )) )) @@ -919,7 +907,7 @@ object ExpandTemplates extends AstTransformer componentInstance <- qualIdentNode(a, data.componentInstance) channelName <- defaultNode(a, data.channelName) } yield ((), cloneNode(a, node, data.copy( - componentInstance = componentInstance._2, + componentInstance = componentInstance, channelName = channelName._2 ))) @@ -939,7 +927,7 @@ object ExpandTemplates extends AstTransformer for { sym <- qualIdentNode(a, data.sym) } yield ((), cloneAnnotatedNode(a, aNode, data.copy( - sym = sym._2, + sym = sym ))) override def defModuleTemplateAnnotatedNode( @@ -962,7 +950,7 @@ object ExpandTemplates extends AstTransformer 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))) + yield ((), cloneAnnotatedNode(a, param, data.copy(interface = interface))) } } @@ -1089,21 +1077,25 @@ object ExpandTemplates extends AstTransformer private def qualIdentNode( a: In, node: AstNode[Ast.QualIdent] - ): ResultNode[Ast.QualIdent] = - Right(((), cloneQualIdentNode(a, node))) + ): Result.Result[AstNode[Ast.QualIdent]] = + Right(cloneQualIdentNode(a, node)) private def qualIdentNodeOpt( a: In, qi: Option[AstNode[Ast.QualIdent]] - ): Result[Option[AstNode[Ast.QualIdent]]] = { + ): Result.Result[Option[AstNode[Ast.QualIdent]]] = { qi match { - case None => Right(((), None)) + case None => Right(None) case Some(value) => for (result <- qualIdentNode(a, value)) - yield (((), Some(result._2))) + yield Some(result) } } + /** Adapt a simple result function to the form required by the visitor */ + private def resultAdapter[A,B](f: (A, B) => Result.Result[B]) = + (a: A, b: B) => for (c <- f(a, b)) yield ((), c) + private def structTypeMemberAnnotatedNode( a: In, aNode: Ast.Annotated[AstNode[Ast.StructTypeMember]] @@ -1120,6 +1112,18 @@ object ExpandTemplates extends AstTransformer ))) } + private def transitionOrDo( + a: In, + 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: In, node: Option[AstNode[Ast.TypeName]] From a5e519bb78ab9098e9edf58942bea7103c2fd7c9 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Mon, 12 Oct 2026 22:40:49 -0700 Subject: [PATCH 13/51] Refactor ExpandTemplates --- .../scala/transform/ExpandTemplates.scala | 222 +++++++++--------- 1 file changed, 110 insertions(+), 112 deletions(-) diff --git a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala index 661569d46..c17101038 100644 --- a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala +++ b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala @@ -74,8 +74,8 @@ object ExpandTemplates extends AstTransformer case None => Right((), aNode) case Some(_) => val (pre, node, post) = aNode - for (inter <- defaultNode(a, node)) - yield (inter._1, (pre, inter._2, post)) + for ((_, inter) <- defaultNode(a, node)) + yield ((), (pre, inter, post)) } } @@ -222,8 +222,8 @@ object ExpandTemplates extends AstTransformer override def defArrayAnnotatedNode(a: In, aNode: Ast.Annotated[AstNode[Ast.DefArray]]): ResultAnnotatedNode[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 { ( @@ -231,8 +231,8 @@ object ExpandTemplates extends AstTransformer cloneAnnotatedNode( a, aNode, data.copy( - size = size._2, - eltType = eltType._2, + size = size, + eltType = eltType, default = default, format = cloneStringNodeOpt(a, data.format) ) @@ -319,27 +319,14 @@ object ExpandTemplates extends AstTransformer val data = aNode._2.data for { typeName <- typeNameNodeOpt(a, data.typeName) - constants <- transformList(a, data.constants, defEnumConstantAnnotatedNode) + (_, constants) <- transformList(a, data.constants, defEnumConstantAnnotatedNode) default <- exprNodeOpt(a, data.default) } yield ((), cloneAnnotatedNode(a, aNode, data.copy( typeName = typeName, - constants = constants._2, + constants = constants, default = default ))) - 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) - override def defPortAnnotatedNode( a: In, aNode: Ast.Annotated[AstNode[Ast.DefPort]] @@ -349,7 +336,7 @@ object ExpandTemplates extends AstTransformer params <- formalParamList(a, data.params) returnType <- typeNameNodeOpt(a, data.returnType) } yield ((), cloneAnnotatedNode(a, aNode, data.copy( - params = params._2, + params = params, returnType = returnType ))) @@ -389,32 +376,20 @@ object ExpandTemplates extends AstTransformer ((), cloneAnnotatedNode(a, aNode, data.copy(typeName = typeName))) } - 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, - ))) - override def defChoiceAnnotatedNode( a: In, 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, + guard = guard, + ifTransition = ifTransition, + elseTransition = elseTransition ))) } @@ -456,7 +431,7 @@ object ExpandTemplates extends AstTransformer for { transition <- transitionExpr(a, data.transition) } yield { - ((), cloneAnnotatedNode(a, aNode, data.copy(transition = transition._2))) + ((), cloneAnnotatedNode(a, aNode, data.copy(transition = transition))) } override def specStateEntryAnnotatedNode( @@ -476,9 +451,9 @@ object ExpandTemplates extends AstTransformer ): ResultAnnotatedNode[Ast.SpecStateExit] = val data = aNode._2.data for { - actions <- transformList(a, data.actions, defaultNode) + (_, actions) <- transformList(a, data.actions, defaultNode) } yield { - ((), cloneAnnotatedNode(a, aNode, data.copy(actions = actions._2))) + ((), cloneAnnotatedNode(a, aNode, data.copy(actions = actions))) } override def specStateTransitionAnnotatedNode( @@ -487,12 +462,12 @@ object ExpandTemplates extends AstTransformer ): 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, + signal = signal, guard = guard, transitionOrDo = transitionOrDo ))) @@ -504,11 +479,11 @@ object ExpandTemplates extends AstTransformer ): ResultAnnotatedNode[Ast.DefStruct] = val data = aNode._2.data for { - members <- transformList(a, data.members, structTypeMemberAnnotatedNode) + (_, members) <- transformList(a, data.members, structTypeMemberAnnotatedNode) default <- exprNodeOpt(a, data.default) } yield { ((), cloneAnnotatedNode(a, aNode, data.copy( - members = members._2, + members = members, default = default ))) } @@ -519,12 +494,12 @@ object ExpandTemplates extends AstTransformer ): ResultAnnotatedNode[Ast.DefTopology] = val data = aNode._2.data for { - members <- transformList(a, data.members, matchTopologyMember) - implements <- transformList(a, data.implements, (a, q) => Right(((), cloneQualIdentNode(a, q)))) + (_, members) <- transformList(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 + members = members.flatten, + implements = implements ))) } @@ -553,7 +528,7 @@ object ExpandTemplates extends AstTransformer queueFull <- defaultNodeOpt(a, data.queueFull) } yield { ((), cloneAnnotatedNode(a, aNode, data.copy( - params = params._2, + params = params, opcode = opcode, priority = priority, queueFull = queueFull, @@ -576,14 +551,14 @@ object ExpandTemplates extends AstTransformer def portInstanceIdentifierNode( a: In, pii: AstNode[Ast.PortInstanceIdentifier] - ): ResultNode[Ast.PortInstanceIdentifier] = { + ): Result.Result[AstNode[Ast.PortInstanceIdentifier]] = { for { interfaceInstance <- qualIdentNode(a, pii.data.interfaceInstance) - portName <- defaultNode(a, pii.data.portName) - } yield ((), cloneNode(a, pii, pii.data.copy( + (_, portName) <- defaultNode(a, pii.data.portName) + } yield cloneNode(a, pii, pii.data.copy( interfaceInstance = interfaceInstance, - portName = portName._2, - ))) + portName = portName + )) } override def specConnectionGraphAnnotatedNode( @@ -603,9 +578,9 @@ object ExpandTemplates extends AstTransformer toIndex <- exprNodeOpt(a, connection.toIndex) } yield { ((), connection.copy( - fromPort = fromPort._2, + fromPort = fromPort, fromIndex = fromIndex, - toPort = toPort._2, + toPort = toPort, toIndex = toIndex, )) } @@ -614,9 +589,9 @@ object ExpandTemplates extends AstTransformer data match { case data @ Ast.SpecConnectionGraph.Direct(_, connections) => for { - connections <- transformList(a, connections, connection) + (_, connections) <- transformList(a, connections, connection) } yield ((), cloneAnnotatedNode(a, aNode, data.copy( - connections = connections._2 + connections = connections ))) case data @ Ast.SpecConnectionGraph.Pattern(_, source, targets) => for { @@ -652,28 +627,28 @@ object ExpandTemplates extends AstTransformer for { params <- formalParamList(a, data.params) id <- exprNodeOpt(a, data.id) - format <- defaultNode(a, data.format) + (_, format) <- defaultNode(a, data.format) throttle <- { data.throttle match { - case None => Right(((), None)) + case None => Right(None) case Some(throttle) => for { (_, count) <- matchExprNode(a, throttle.data.count) every <- exprNodeOpt(a, throttle.data.every) - } yield ((), Some(cloneNode( + } yield Some(cloneNode( a, throttle, throttle.data.copy( every = every, count = count ) - ))) + )) } } } yield { ((), cloneAnnotatedNode(a, aNode, data.copy( - params = params._2, + params = params, id = id, - format = format._2, - throttle = throttle._2, + format = format, + throttle = throttle ))) } @@ -683,10 +658,8 @@ object ExpandTemplates extends AstTransformer ): 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, @@ -708,7 +681,7 @@ object ExpandTemplates extends AstTransformer params <- formalParamList(a, data.params) priority <- exprNodeOpt(a, data.priority) } yield ((), cloneAnnotatedNode(a, aNode, data.copy( - params = params._2, + params = params, priority = priority, ))) @@ -719,10 +692,10 @@ object ExpandTemplates extends AstTransformer val data = aNode._2.data for { symbol <- qualIdentNode(a, data.symbol) - file <- defaultNode(a, data.file) + (_, file) <- defaultNode(a, data.file) } yield ((), cloneAnnotatedNode(a, aNode, data.copy( symbol = symbol, - file = file._2, + file = file ))) override def specParamAnnotatedNode( @@ -731,13 +704,13 @@ object ExpandTemplates extends AstTransformer ): 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, + typeName = typeName, default = default, id = id, setOpcode = setOpcode, @@ -782,11 +755,11 @@ object ExpandTemplates extends AstTransformer ): ResultAnnotatedNode[Ast.SpecPortMatching] = val data = aNode._2.data for { - port1 <- defaultNode(a, data.port1) - port2 <- defaultNode(a, data.port2) + (_, port1) <- defaultNode(a, data.port1) + (_, port2) <- defaultNode(a, data.port2) } yield (((), cloneAnnotatedNode(a, aNode, data.copy( - port1 = port1._2, - port2 = port2._2 + port1 = port1, + port2 = port2 )))) override def specRecordAnnotatedNode( @@ -795,10 +768,10 @@ object ExpandTemplates extends AstTransformer ): 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, + recordType = recordType, id = id )))) @@ -826,22 +799,22 @@ object ExpandTemplates extends AstTransformer ): 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) + (_, low) <- transformList(a, data.low, limit) + (_, high) <- transformList(a, data.high, limit) } yield (((), cloneAnnotatedNode(a, aNode, data.copy( - typeName = typeName._2, + typeName = typeName, id = id, format = cloneStringNodeOpt(a, data.format), - low = low._2, - high = high._2 + low = low, + high = high )))) override def specTlmPacketAnnotatedNode( @@ -855,18 +828,18 @@ object ExpandTemplates extends AstTransformer ): Result[Ast.TlmPacketMember] = { member match { case Ast.TlmPacketMember.SpecInclude(node) => - for (file <- defaultNode(a, node.data.file)) + for ((_, file) <- defaultNode(a, node.data.file)) yield ((), Ast.TlmPacketMember.SpecInclude( - cloneNode(a, node, node.data.copy(file = file._2)) + cloneNode(a, node, node.data.copy(file = file)) )) case Ast.TlmPacketMember.TlmChannelIdentifier(node) => for { componentInstance <- qualIdentNode(a, node.data.componentInstance) - channelName <- defaultNode(a, node.data.channelName) + (_, channelName) <- defaultNode(a, node.data.channelName) } yield ((), Ast.TlmPacketMember.TlmChannelIdentifier( cloneNode(a, node, node.data.copy( componentInstance = componentInstance, - channelName = channelName._2 + channelName = channelName )) )) } @@ -874,12 +847,12 @@ object ExpandTemplates extends AstTransformer for { id <- exprNodeOpt(a, data.id) - group <- matchExprNode(a, data.group) - members <- transformList(a, data.members, tlmPacketMember) + (_, group) <- matchExprNode(a, data.group) + (_, members) <- transformList(a, data.members, tlmPacketMember) } yield (((), cloneAnnotatedNode(a, aNode, data.copy( id = id, - group = group._2, - members = members._2, + group = group, + members = members )))) override def specTopPortAnnotatedNode( @@ -890,7 +863,7 @@ object ExpandTemplates extends AstTransformer for { underlyingPort <- portInstanceIdentifierNode(a, data.underlyingPort) } yield ((), cloneAnnotatedNode(a, aNode, data.copy( - underlyingPort = underlyingPort._2, + underlyingPort = underlyingPort ))) override def specTlmPacketSetAnnotatedNode( @@ -905,18 +878,18 @@ object ExpandTemplates extends AstTransformer val data = node.data for { componentInstance <- qualIdentNode(a, data.componentInstance) - channelName <- defaultNode(a, data.channelName) + (_, channelName) <- defaultNode(a, data.channelName) } yield ((), cloneNode(a, node, data.copy( componentInstance = componentInstance, - channelName = channelName._2 + channelName = channelName ))) for { - members <- transformList(a, data.members, matchTlmPacketSetMember) - omitted <- transformList(a, data.omitted, tlmChannelIdentifier) + (_, members) <- transformList(a, data.members, matchTlmPacketSetMember) + (_, omitted) <- transformList(a, data.omitted, tlmChannelIdentifier) } yield ((), cloneAnnotatedNode(a, aNode, data.copy( - members = members._2.flatten, - omitted = omitted._2, + members = members.flatten, + omitted = omitted ))) override def specInterfaceImportAnnotatedNode( @@ -944,8 +917,8 @@ object ExpandTemplates extends AstTransformer 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))) + for ((_, tn) <- matchTypeName(a, tn)) + yield ((), cloneAnnotatedNode(a, param, data.copy(typeName = tn))) case data @ Ast.TemplateParam.Type(_) => Right(((), cloneAnnotatedNode(a, param, data))) case data @ Ast.TemplateParam.Interface(_, interface) => @@ -1049,7 +1022,7 @@ object ExpandTemplates extends AstTransformer // Clone the template body, recording the expansion node so that // cloned nodes point back at the expansion site. // Record the template definition too for diagnostics. - members <- transformList( + (_, members) <- transformList( a.copy( templateExpansionId = Some(node.id), templateDefId = Some(tmpl.node._2.id) @@ -1059,7 +1032,7 @@ object ExpandTemplates extends AstTransformer ) } yield { // Paste the expanded template body into the expansion specifier - ((), (pre, AstNode.create(data.copy(members = Some(members._2.flatten)), node.id), post)) + ((), (pre, AstNode.create(data.copy(members = Some(members.flatten)), node.id), post)) } } @@ -1074,6 +1047,19 @@ object ExpandTemplates extends AstTransformer yield Some(result) } + private 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))) + + private def formalParamList( + a: In, + aNode: Ast.FormalParamList + ) = for ((_, node) <- transformList(a, aNode, formalAnnotatatedParam)) yield node + private def qualIdentNode( a: In, node: AstNode[Ast.QualIdent] @@ -1103,22 +1089,34 @@ object ExpandTemplates extends AstTransformer val data = aNode._2.data for { size <- exprNodeOpt(a, data.size) - typeName <- matchTypeName(a, data.typeName) + (_, typeName) <- matchTypeName(a, data.typeName) } yield { ((), cloneAnnotatedNode(a, aNode, data.copy( size = size, - typeName = typeName._2, + typeName = typeName, format = cloneStringNodeOpt(a, data.format) ))) } + private def transitionExpr( + a: In, + node: AstNode[Ast.TransitionExpr] + ): Result.Result[AstNode[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, + target = target, + )) + private def transitionOrDo( a: In, transitionOrDo: Ast.TransitionOrDo ) = transitionOrDo match case Ast.TransitionOrDo.Transition(transition) => - for ((_, result) <- transitionExpr(a, transition)) + for (result <- transitionExpr(a, transition)) yield Ast.TransitionOrDo.Transition(result) case Ast.TransitionOrDo.Do(actions) => for ((_, result) <- transformList(a, actions, defaultNode)) From 910aa238fa03fb0c72a5cde45bcce1c3c7e6de97 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Mon, 12 Oct 2026 22:57:26 -0700 Subject: [PATCH 14/51] Refactor ExpandTemplates --- .../ExpandSyntaxAndEnterSymbols.scala | 2 +- .../scala/transform/ExpandTemplates.scala | 205 +++++++++--------- 2 files changed, 99 insertions(+), 108 deletions(-) diff --git a/compiler/lib/src/main/scala/analysis/CheckSemantics/ExpandSyntaxAndEnterSymbols.scala b/compiler/lib/src/main/scala/analysis/CheckSemantics/ExpandSyntaxAndEnterSymbols.scala index 36ff9b9b3..2df372f13 100644 --- a/compiler/lib/src/main/scala/analysis/CheckSemantics/ExpandSyntaxAndEnterSymbols.scala +++ b/compiler/lib/src/main/scala/analysis/CheckSemantics/ExpandSyntaxAndEnterSymbols.scala @@ -19,7 +19,7 @@ object ExpandSyntaxAndEnterSymbols { a <- CheckTemplateDefs.visitList(a, tul, CheckTemplateDefs.transUnit) // TODO: CheckTemplateExpansions 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/transform/ExpandTemplates.scala b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala index c17101038..bb24268c0 100644 --- a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala +++ b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala @@ -22,18 +22,17 @@ object ExpandTemplates extends AstTransformer s: State, list: List[A], transform: (State, A) => Result[B] - ): Result[List[B]] = { - def helper(in: List[A], out: List[B]): Result[List[B]] = { + ): Result.Result[List[B]] = { + def helper(in: List[A], out: List[B]): Result.Result[List[B]] = { in match { - case Nil => Right(((), out)) + 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) + helper(list, Nil).map(_.reverse) } override def transUnit( @@ -42,7 +41,7 @@ object ExpandTemplates extends AstTransformer ): Result[Ast.TransUnit] = { for { members <- transformList(a, tu.members, matchModuleMember) - } yield (members._1, Ast.TransUnit(members._2.flatten)) + } yield ((), Ast.TransUnit(members.flatten)) } // Duplicate every node inside a template definition @@ -82,8 +81,7 @@ object ExpandTemplates extends AstTransformer override def exprArrayNode(a: In, node: AstNode[Ast.Expr], e: Ast.ExprArray): ResultNode[Ast.Expr] = for { result <- transformList(a, e.elts, matchExprNode) } yield { - val (_, elts1) = result - ((), cloneNode(a, node, Ast.ExprArray(elts1))) + ((), cloneNode(a, node, Ast.ExprArray(result))) } override def exprArraySubscriptNode(a: In, node: AstNode[Ast.Expr], e: Ast.ExprArraySubscript): ResultNode[Ast.Expr] = @@ -122,35 +120,6 @@ object ExpandTemplates extends AstTransformer ((), cloneNode(a, node, Ast.ExprParen(value))) } - def structMember( - a: Analysis, - node: AstNode[Ast.StructMember] - ) = { - for (result <- matchExprNode(a, node.data.value)) - yield { - val (_, value) = result - ((), 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)) - } - } - override def exprStructNode( a: Analysis, node: AstNode[Ast.Expr], @@ -158,17 +127,16 @@ object ExpandTemplates extends AstTransformer ) = for { result <- transformList(a, e.members, structMember) } yield { - val (_, members1) = result - ((), cloneNode(a, node, Ast.ExprStruct(members1))) + ((), 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))) + 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))) + for ((_, result) <- matchTypeName(a, e.typeName)) + yield ((), cloneNode(a, node, Ast.ExprSizeOf(result))) override def typeNameQualIdentNode( a: In, @@ -210,15 +178,6 @@ object ExpandTemplates extends AstTransformer )) } - 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)) - } - override def defArrayAnnotatedNode(a: In, aNode: Ast.Annotated[AstNode[Ast.DefArray]]): ResultAnnotatedNode[Ast.DefArray] = val data = aNode._2.data for { @@ -244,8 +203,7 @@ object ExpandTemplates extends AstTransformer val data = aNode._2.data for (result <- transformList(a, data.members, matchComponentMember)) yield { - val (_, members1) = result - ((), cloneAnnotatedNode(a, aNode, data.copy(members = members1.flatten))) + ((), cloneAnnotatedNode(a, aNode, data.copy(members = result.flatten))) } override def defComponentInstanceAnnotatedNode( @@ -260,7 +218,7 @@ object ExpandTemplates extends AstTransformer stackSize <- exprNodeOpt(a, data.stackSize) priority <- exprNodeOpt(a, data.priority) cpu <- exprNodeOpt(a, data.cpu) - (_, initSpecs) <- transformList(a, data.initSpecs, specInitAnnotatedNode) + initSpecs <- transformList(a, data.initSpecs, specInitAnnotatedNode) } yield { ( (), @@ -285,8 +243,7 @@ object ExpandTemplates extends AstTransformer val data = aNode._2.data for (result <- transformList(a, data.members, matchInterfaceMember)) yield { - val (_, members1) = result - ((), cloneAnnotatedNode(a, aNode, data.copy(members=members1))) + ((), cloneAnnotatedNode(a, aNode, data.copy(members=result))) } override def defConstantAnnotatedNode( @@ -294,22 +251,12 @@ object ExpandTemplates extends AstTransformer aNode: Ast.Annotated[AstNode[Ast.DefConstant]] ): ResultAnnotatedNode[Ast.DefConstant] = val data = aNode._2.data - for (value <- matchExprNode(a, data.value)) + 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))) + data.copy(value = value))) } override def defEnumAnnotatedNode( @@ -319,7 +266,7 @@ object ExpandTemplates extends AstTransformer val data = aNode._2.data for { typeName <- typeNameNodeOpt(a, data.typeName) - (_, constants) <- transformList(a, data.constants, defEnumConstantAnnotatedNode) + constants <- transformList(a, data.constants, defEnumConstantAnnotatedNode) default <- exprNodeOpt(a, data.default) } yield ((), cloneAnnotatedNode(a, aNode, data.copy( typeName = typeName, @@ -353,7 +300,7 @@ object ExpandTemplates extends AstTransformer ): 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)))) + yield ((), cloneAnnotatedNode(a, aNode, data.copy(members = Some(result.flatten)))) override def defStateMachineAnnotatedNode( a: In, @@ -421,7 +368,7 @@ object ExpandTemplates extends AstTransformer ): 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))) + yield ((), cloneAnnotatedNode(a, aNode, data.copy(members = members.flatten))) override def specInitialTransitionAnnotatedNode( a: In, @@ -442,7 +389,7 @@ object ExpandTemplates extends AstTransformer for { actions <- transformList(a, data.actions, defaultNode) } yield { - ((), cloneAnnotatedNode(a, aNode, data.copy(actions = actions._2))) + ((), cloneAnnotatedNode(a, aNode, data.copy(actions = actions))) } override def specStateExitAnnotatedNode( @@ -451,7 +398,7 @@ object ExpandTemplates extends AstTransformer ): ResultAnnotatedNode[Ast.SpecStateExit] = val data = aNode._2.data for { - (_, actions) <- transformList(a, data.actions, defaultNode) + actions <- transformList(a, data.actions, defaultNode) } yield { ((), cloneAnnotatedNode(a, aNode, data.copy(actions = actions))) } @@ -479,7 +426,7 @@ object ExpandTemplates extends AstTransformer ): ResultAnnotatedNode[Ast.DefStruct] = val data = aNode._2.data for { - (_, members) <- transformList(a, data.members, structTypeMemberAnnotatedNode) + members <- transformList(a, data.members, structTypeMemberAnnotatedNode) default <- exprNodeOpt(a, data.default) } yield { ((), cloneAnnotatedNode(a, aNode, data.copy( @@ -494,8 +441,8 @@ object ExpandTemplates extends AstTransformer ): ResultAnnotatedNode[Ast.DefTopology] = val data = aNode._2.data for { - (_, members) <- transformList(a, data.members, matchTopologyMember) - (_, implements) <- transformList(a, data.implements, (a, q) => Right(((), cloneQualIdentNode(a, q)))) + members <- transformList(a, data.members, matchTopologyMember) + implements <- transformList(a, data.implements, (a, q) => Right(((), cloneQualIdentNode(a, q)))) } yield { ((), cloneAnnotatedNode(a, aNode, data.copy( members = members.flatten, @@ -548,19 +495,6 @@ object ExpandTemplates extends AstTransformer ))) } - def portInstanceIdentifierNode( - a: In, - pii: AstNode[Ast.PortInstanceIdentifier] - ): Result.Result[AstNode[Ast.PortInstanceIdentifier]] = { - for { - interfaceInstance <- qualIdentNode(a, pii.data.interfaceInstance) - (_, portName) <- defaultNode(a, pii.data.portName) - } yield cloneNode(a, pii, pii.data.copy( - interfaceInstance = interfaceInstance, - portName = portName - )) - } - override def specConnectionGraphAnnotatedNode( a: In, aNode: Ast.Annotated[AstNode[Ast.SpecConnectionGraph]] @@ -589,14 +523,14 @@ object ExpandTemplates extends AstTransformer data match { case data @ Ast.SpecConnectionGraph.Direct(_, connections) => for { - (_, connections) <- transformList(a, connections, connection) + connections <- transformList(a, connections, connection) } yield ((), cloneAnnotatedNode(a, aNode, data.copy( connections = connections ))) case data @ Ast.SpecConnectionGraph.Pattern(_, source, targets) => for { source <- qualIdentNode(a, source) - (_, targets) <- transformList(a, targets, resultAdapter(qualIdentNode)) + targets <- transformList(a, targets, resultAdapter(qualIdentNode)) } yield ((), cloneAnnotatedNode(a, aNode, data.copy( source = source, targets = targets @@ -807,8 +741,8 @@ object ExpandTemplates extends AstTransformer for { (_, typeName) <- matchTypeName(a, data.typeName) id <- exprNodeOpt(a, data.id) - (_, low) <- transformList(a, data.low, limit) - (_, high) <- transformList(a, data.high, limit) + low <- transformList(a, data.low, limit) + high <- transformList(a, data.high, limit) } yield (((), cloneAnnotatedNode(a, aNode, data.copy( typeName = typeName, id = id, @@ -848,7 +782,7 @@ object ExpandTemplates extends AstTransformer for { id <- exprNodeOpt(a, data.id) (_, group) <- matchExprNode(a, data.group) - (_, members) <- transformList(a, data.members, tlmPacketMember) + members <- transformList(a, data.members, tlmPacketMember) } yield (((), cloneAnnotatedNode(a, aNode, data.copy( id = id, group = group, @@ -885,8 +819,8 @@ object ExpandTemplates extends AstTransformer ))) for { - (_, members) <- transformList(a, data.members, matchTlmPacketSetMember) - (_, omitted) <- transformList(a, data.omitted, tlmChannelIdentifier) + members <- transformList(a, data.members, matchTlmPacketSetMember) + omitted <- transformList(a, data.omitted, tlmChannelIdentifier) } yield ((), cloneAnnotatedNode(a, aNode, data.copy( members = members.flatten, omitted = omitted @@ -934,11 +868,9 @@ object ExpandTemplates extends AstTransformer a <- Right(a.copy(templateDefId = None)) } yield { - val (_, params1) = params - val (_, members1) = members ((), cloneAnnotatedNode(a, aNode, data.copy( - params = params1, - members = members1.flatten + params = params, + members = members.flatten ))) } @@ -950,8 +882,7 @@ object ExpandTemplates extends AstTransformer val data = node.data for { result <- transformList(a, data.members, matchModuleMember) } yield { - val (_, members1) = result - ((), cloneAnnotatedNode(a, aNode, data.copy(members = members1.flatten))) + ((), cloneAnnotatedNode(a, aNode, data.copy(members = result.flatten))) } } @@ -998,6 +929,29 @@ object ExpandTemplates extends AstTransformer (pre, cloneNode(a, node, data), post) } + private 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)) + } + } + private 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)) + } + private def defaultNodeOpt[T]( a: Analysis, node: Option[AstNode[T]] @@ -1009,6 +963,16 @@ object ExpandTemplates extends AstTransformer yield Some(node) } + private 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))) + } + /** Expand a template */ private def expandTemplate( a: Analysis, @@ -1022,7 +986,7 @@ object ExpandTemplates extends AstTransformer // Clone the template body, recording the expansion node so that // cloned nodes point back at the expansion site. // Record the template definition too for diagnostics. - (_, members) <- transformList( + members <- transformList( a.copy( templateExpansionId = Some(node.id), templateDefId = Some(tmpl.node._2.id) @@ -1058,7 +1022,20 @@ object ExpandTemplates extends AstTransformer private def formalParamList( a: In, aNode: Ast.FormalParamList - ) = for ((_, node) <- transformList(a, aNode, formalAnnotatatedParam)) yield node + ) = for (node <- transformList(a, aNode, formalAnnotatatedParam)) yield node + + private def portInstanceIdentifierNode( + a: In, + pii: AstNode[Ast.PortInstanceIdentifier] + ): Result.Result[AstNode[Ast.PortInstanceIdentifier]] = { + for { + interfaceInstance <- qualIdentNode(a, pii.data.interfaceInstance) + (_, portName) <- defaultNode(a, pii.data.portName) + } yield cloneNode(a, pii, pii.data.copy( + interfaceInstance = interfaceInstance, + portName = portName + )) + } private def qualIdentNode( a: In, @@ -1082,6 +1059,20 @@ object ExpandTemplates extends AstTransformer private def resultAdapter[A,B](f: (A, B) => Result.Result[B]) = (a: A, b: B) => for (c <- f(a, b)) yield ((), c) + private def structMember( + a: Analysis, + node: AstNode[Ast.StructMember] + ) = { + for (result <- matchExprNode(a, node.data.value)) + yield { + val (_, value) = result + ((), cloneNode(a, node, Ast.StructMember( + node.data.name, + value + ))) + } + } + private def structTypeMemberAnnotatedNode( a: In, aNode: Ast.Annotated[AstNode[Ast.StructTypeMember]] @@ -1103,7 +1094,7 @@ object ExpandTemplates extends AstTransformer node: AstNode[Ast.TransitionExpr] ): Result.Result[AstNode[Ast.TransitionExpr]] = for { - (_, actions) <- transformList(a, node.data.actions, defaultNode) + actions <- transformList(a, node.data.actions, defaultNode) target <- qualIdentNode(a, node.data.target) } yield cloneNode(a, node, node.data.copy( actions = actions, @@ -1119,7 +1110,7 @@ object ExpandTemplates extends AstTransformer for (result <- transitionExpr(a, transition)) yield Ast.TransitionOrDo.Transition(result) case Ast.TransitionOrDo.Do(actions) => - for ((_, result) <- transformList(a, actions, defaultNode)) + for (result <- transformList(a, actions, defaultNode)) yield Ast.TransitionOrDo.Do(result) private def typeNameNodeOpt( From d313f138c7074f502531130c71ee31771323e3b8 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Mon, 12 Oct 2026 23:27:02 -0700 Subject: [PATCH 15/51] Refactor ExpandTemplates --- .../scala/transform/ExpandTemplates.scala | 269 +++++++++--------- 1 file changed, 139 insertions(+), 130 deletions(-) diff --git a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala index bb24268c0..f3c30b560 100644 --- a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala +++ b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala @@ -38,7 +38,7 @@ object ExpandTemplates extends AstTransformer override def transUnit( a: Analysis, tu: Ast.TransUnit - ): Result[Ast.TransUnit] = { + ) = { for { members <- transformList(a, tu.members, matchModuleMember) } yield ((), Ast.TransUnit(members.flatten)) @@ -78,91 +78,104 @@ object ExpandTemplates extends AstTransformer } } - override def exprArrayNode(a: In, node: AstNode[Ast.Expr], e: Ast.ExprArray): ResultNode[Ast.Expr] = + override def exprArrayNode( + a: In, + node: AstNode[Ast.Expr], + e: Ast.ExprArray + ) = for { result <- transformList(a, e.elts, matchExprNode) } - yield { - ((), cloneNode(a, node, Ast.ExprArray(result))) - } + yield ((), cloneNode(a, node, Ast.ExprArray(result))) - override def exprArraySubscriptNode(a: In, node: AstNode[Ast.Expr], e: Ast.ExprArraySubscript): ResultNode[Ast.Expr] = + override def exprArraySubscriptNode( + a: In, + 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: In, 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_))) + (_, e1) <- matchExprNode(a, e.e1) + (_, e2) <- matchExprNode(a, e.e2) } + yield ((), 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 (_, left) = result - ((), cloneNode(a, node, Ast.ExprDot(left, cloneNode(a, e.id, e.id.data)))) - } + override def exprDotNode( + a: In, + 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)))) - override def exprParenNode(a: In, node: AstNode[Ast.Expr], e: Ast.ExprParen): ResultNode[Ast.Expr] = - for (result <- matchExprNode(a, e.e)) - yield { - val (_, value) = result - ((), cloneNode(a, node, Ast.ExprParen(value))) - } + override def exprParenNode( + a: In, + 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 { - ((), cloneNode(a, node, Ast.ExprStruct(result))) - } + 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) = + override def exprUnopNode( + a: In, + node: AstNode[Ast.Expr], + e: Ast.ExprUnop + ) = for ((_, ec) <- matchExprNode(a, e.e)) - yield ((), cloneNode(a, node, Ast.ExprUnop(e.op, ec))) + yield ((), cloneNode(a, node, Ast.ExprUnop(e.op, ec))) - override def exprSizeOfNode(a: In, node: AstNode[Ast.Expr], e: Ast.ExprSizeOf): ResultNode[Ast.Expr] = + override def exprSizeOfNode( + a: In, + node: AstNode[Ast.Expr], + e: Ast.ExprSizeOf + ) = for ((_, result) <- matchTypeName(a, e.typeName)) - yield ((), cloneNode(a, node, Ast.ExprSizeOf(result))) + yield ((), cloneNode(a, node, Ast.ExprSizeOf(result))) override def typeNameQualIdentNode( a: In, node: AstNode[Ast.TypeName], tn: Ast.TypeNameQualIdent - ): ResultNode[Ast.TypeName] = { - Right(((), cloneNode(a, node, Ast.TypeNameQualIdent( - cloneQualIdentNode(a, tn.name) - )))) - } + ): ResultNode[Ast.TypeName] = + Right( + (), + cloneNode(a, node, Ast.TypeNameQualIdent(cloneQualIdentNode(a, tn.name))) + ) override def typeNameStringNode( a: In, 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 (_, value) = result - ((), cloneNode(a, node, Ast.TypeNameString(Some(value)))) - } +// tn.size match { +// case None => +// Right(((), cloneNode(a, node, Ast.TypeNameString(None)))) +// case Some(size) => +// for ((_, value) <- matchExprNode(a, size)) +// yield ((), cloneNode(a, node, Ast.TypeNameString(Some(value)))) +// } + 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( @@ -170,46 +183,48 @@ object ExpandTemplates extends AstTransformer aNode: Ast.Annotated[AstNode[Ast.DefAliasType]] ): ResultAnnotatedNode[Ast.DefAliasType] = val data = aNode._2.data - for (result <- matchTypeName(a, data.typeName)) - yield { - val (_, ty) = result - ((), cloneAnnotatedNode( - a, aNode, data.copy(typeName = ty) - )) - } + 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: In, + aNode: Ast.Annotated[AstNode[Ast.DefArray]] + ) = { val data = aNode._2.data for { (_, size) <- matchExprNode(a, data.size) (_, eltType) <- matchTypeName(a, data.eltType) default <- exprNodeOpt(a, data.default) - } yield { - ( - (), - cloneAnnotatedNode( - a, aNode, - data.copy( - size = size, - eltType = eltType, - default = default, - format = cloneStringNodeOpt(a, data.format) - ) + } yield ( + (), + cloneAnnotatedNode( + a, aNode, + data.copy( + size = size, + eltType = eltType, + default = default, + format = cloneStringNodeOpt(a, data.format) ) ) - } + ) + } - override def defComponentAnnotatedNode(a: In, aNode: Ast.Annotated[AstNode[Ast.DefComponent]]): ResultAnnotatedNode[Ast.DefComponent] = + override def defComponentAnnotatedNode( + a: In, + aNode: Ast.Annotated[AstNode[Ast.DefComponent]] + ) = { val data = aNode._2.data for (result <- transformList(a, data.members, matchComponentMember)) - yield { - ((), cloneAnnotatedNode(a, aNode, data.copy(members = result.flatten))) - } + yield ((), cloneAnnotatedNode(a, aNode, data.copy(members = result.flatten))) + } override def defComponentInstanceAnnotatedNode( a: In, aNode: Ast.Annotated[AstNode[Ast.DefComponentInstance]] - ): ResultAnnotatedNode[Ast.DefComponentInstance] = + ): ResultAnnotatedNode[Ast.DefComponentInstance] = { val data = aNode._2.data for { component <- Right(cloneQualIdentNode(a, data.component)) @@ -219,32 +234,33 @@ object ExpandTemplates extends AstTransformer 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, - implType=cloneStringNodeOpt(a, data.implType), - file=cloneStringNodeOpt(a, data.file), - queueSize=queueSize, - stackSize=stackSize, - priority=priority, - cpu=cpu, - initSpecs=initSpecs - ) + } yield ( + (), + cloneAnnotatedNode( + a, aNode, + 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 ) ) - } + ) + } - override def defInterfaceAnnotatedNode(a: In, aNode: Ast.Annotated[AstNode[Ast.DefInterface]]): ResultAnnotatedNode[Ast.DefInterface] = + override def defInterfaceAnnotatedNode( + a: In, + aNode: Ast.Annotated[AstNode[Ast.DefInterface]] + ) = { val data = aNode._2.data for (result <- transformList(a, data.members, matchInterfaceMember)) - yield { - ((), cloneAnnotatedNode(a, aNode, data.copy(members=result))) - } + yield ((), cloneAnnotatedNode(a, aNode, data.copy(members=result))) + } override def defConstantAnnotatedNode( a: In, @@ -266,7 +282,7 @@ object ExpandTemplates extends AstTransformer 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, @@ -377,9 +393,7 @@ object ExpandTemplates extends AstTransformer val data = aNode._2.data for { transition <- transitionExpr(a, data.transition) - } yield { - ((), cloneAnnotatedNode(a, aNode, data.copy(transition = transition))) - } + } yield ((), cloneAnnotatedNode(a, aNode, data.copy(transition = transition))) override def specStateEntryAnnotatedNode( a: In, @@ -388,9 +402,7 @@ object ExpandTemplates extends AstTransformer val data = aNode._2.data for { actions <- transformList(a, data.actions, defaultNode) - } yield { - ((), cloneAnnotatedNode(a, aNode, data.copy(actions = actions))) - } + } yield ((), cloneAnnotatedNode(a, aNode, data.copy(actions = actions))) override def specStateExitAnnotatedNode( a: In, @@ -399,9 +411,7 @@ object ExpandTemplates extends AstTransformer val data = aNode._2.data for { actions <- transformList(a, data.actions, defaultNode) - } yield { - ((), cloneAnnotatedNode(a, aNode, data.copy(actions = actions))) - } + } yield ((), cloneAnnotatedNode(a, aNode, data.copy(actions = actions))) override def specStateTransitionAnnotatedNode( a: In, @@ -426,7 +436,7 @@ object ExpandTemplates extends AstTransformer ): 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( @@ -589,7 +599,7 @@ object ExpandTemplates extends AstTransformer override def specIncludeAnnotatedNode( a: In, aNode: Ast.Annotated[AstNode[Ast.SpecInclude]] - ): ResultAnnotatedNode[Ast.SpecInclude] = + ) = val data = aNode._2.data for { (_, file) <- defaultNode(a, data.file) @@ -598,7 +608,7 @@ object ExpandTemplates extends AstTransformer override def specInitAnnotatedNode( a: In, aNode: Ast.Annotated[AstNode[Ast.SpecInit]] - ): ResultAnnotatedNode[Ast.SpecInit] = + ) = val data = aNode._2.data for (result <- matchExprNode(a, data.phase)) yield { @@ -896,7 +906,7 @@ object ExpandTemplates extends AstTransformer // Members are already there; nothing to do case Some(members) => Right((), aNode) // Members are not there; expand - case None => expandTemplate(a, aNode) + case None => (resultAdapter(expandTemplate))(a, aNode) } } @@ -943,6 +953,7 @@ object ExpandTemplates extends AstTransformer cloneNode(a, node, Ast.QualIdent.Unqualified(name, isAbsolute)) } } + private def cloneStringNodeOpt( a: In, node: Option[AstNode[String]] @@ -966,18 +977,16 @@ object ExpandTemplates extends AstTransformer private def defEnumConstantAnnotatedNode( a: In, aNode: Ast.Annotated[AstNode[Ast.DefEnumConstant]] - ): ResultAnnotatedNode[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))) - } + yield cloneAnnotatedNode(a, aNode, data.copy(value = value)) /** Expand a template */ private def expandTemplate( a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecTemplateExpand]] - ): ResultAnnotatedNode[Ast.SpecTemplateExpand] = { + ): Result.Result[Ast.Annotated[AstNode[Ast.SpecTemplateExpand]]] = { val (pre, node, post) = aNode val data = node.data for { @@ -996,7 +1005,7 @@ object ExpandTemplates extends AstTransformer ) } yield { // Paste the expanded template body into the expansion specifier - ((), (pre, AstNode.create(data.copy(members = Some(members.flatten)), node.id), post)) + (pre, AstNode.create(data.copy(members = Some(members.flatten)), node.id), post) } } @@ -1017,12 +1026,13 @@ object ExpandTemplates extends AstTransformer ) = val data = aNode._2.data for ((_, ty) <- matchTypeName(a, data.typeName)) - yield ((), cloneAnnotatedNode(a, aNode, data.copy(typeName = ty))) + yield cloneAnnotatedNode(a, aNode, data.copy(typeName = ty)) private def formalParamList( a: In, aNode: Ast.FormalParamList - ) = for (node <- transformList(a, aNode, formalAnnotatatedParam)) yield node + ) = for (node <- transformList(a, aNode, resultAdapter(formalAnnotatatedParam))) + yield node private def portInstanceIdentifierNode( a: In, @@ -1063,13 +1073,12 @@ object ExpandTemplates extends AstTransformer a: Analysis, node: AstNode[Ast.StructMember] ) = { - for (result <- matchExprNode(a, node.data.value)) + for ((_, value) <- matchExprNode(a, node.data.value)) yield { - val (_, value) = result - ((), cloneNode(a, node, Ast.StructMember( + cloneNode(a, node, Ast.StructMember( node.data.name, value - ))) + )) } } @@ -1082,11 +1091,11 @@ object ExpandTemplates extends AstTransformer size <- exprNodeOpt(a, data.size) (_, typeName) <- matchTypeName(a, data.typeName) } yield { - ((), cloneAnnotatedNode(a, aNode, data.copy( + cloneAnnotatedNode(a, aNode, data.copy( size = size, typeName = typeName, format = cloneStringNodeOpt(a, data.format) - ))) + )) } private def transitionExpr( @@ -1098,7 +1107,7 @@ object ExpandTemplates extends AstTransformer target <- qualIdentNode(a, node.data.target) } yield cloneNode(a, node, node.data.copy( actions = actions, - target = target, + target = target )) private def transitionOrDo( From bce7e7a498c53c0bbb00f68c3c3bb7d94d01d084 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Mon, 12 Oct 2026 23:50:16 -0700 Subject: [PATCH 16/51] Refactor ExpandTemplates --- .../scala/transform/ExpandTemplates.scala | 209 +++++++++--------- 1 file changed, 104 insertions(+), 105 deletions(-) diff --git a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala index f3c30b560..e5dc9cc54 100644 --- a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala +++ b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala @@ -35,13 +35,19 @@ object ExpandTemplates extends AstTransformer helper(list, Nil).map(_.reverse) } + /** Transform a list and flatten the result */ + def transformFlatList[A, B]( + s: State, + list: List[A], + transform: (State, A) => Result[List[B]] + ): Result.Result[List[B]] = transformList(s, list, transform).map(_.flatten) + override def transUnit( a: Analysis, tu: Ast.TransUnit ) = { - for { - members <- transformList(a, tu.members, matchModuleMember) - } yield ((), Ast.TransUnit(members.flatten)) + for (members <- transformFlatList(a, tu.members, matchModuleMember)) + yield ((), Ast.TransUnit(members)) } // Duplicate every node inside a template definition @@ -151,7 +157,7 @@ object ExpandTemplates extends AstTransformer a: In, node: AstNode[Ast.TypeName], tn: Ast.TypeNameQualIdent - ): ResultNode[Ast.TypeName] = + ) = Right( (), cloneNode(a, node, Ast.TypeNameQualIdent(cloneQualIdentNode(a, tn.name))) @@ -161,14 +167,7 @@ object ExpandTemplates extends AstTransformer a: In, 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 ((_, value) <- matchExprNode(a, size)) -// yield ((), cloneNode(a, node, Ast.TypeNameString(Some(value)))) -// } + ) = for { valueOpt <- tn.size match { case None => Right(None) @@ -176,7 +175,6 @@ object ExpandTemplates extends AstTransformer } } yield ((), cloneNode(a, node, Ast.TypeNameString(valueOpt))) - } override def defAliasTypeAnnotatedNode( a: In, @@ -217,14 +215,14 @@ object ExpandTemplates extends AstTransformer aNode: Ast.Annotated[AstNode[Ast.DefComponent]] ) = { val data = aNode._2.data - for (result <- transformList(a, data.members, matchComponentMember)) - yield ((), cloneAnnotatedNode(a, aNode, data.copy(members = result.flatten))) + for (members <- transformFlatList(a, data.members, matchComponentMember)) + yield ((), cloneAnnotatedNode(a, aNode, data.copy(members = members))) } override def defComponentInstanceAnnotatedNode( a: In, aNode: Ast.Annotated[AstNode[Ast.DefComponentInstance]] - ): ResultAnnotatedNode[Ast.DefComponentInstance] = { + ) = { val data = aNode._2.data for { component <- Right(cloneQualIdentNode(a, data.component)) @@ -265,7 +263,7 @@ object ExpandTemplates extends AstTransformer override def defConstantAnnotatedNode( a: In, aNode: Ast.Annotated[AstNode[Ast.DefConstant]] - ): ResultAnnotatedNode[Ast.DefConstant] = + ) = val data = aNode._2.data for ((_, value) <- matchExprNode(a, data.value)) yield { @@ -278,11 +276,15 @@ object ExpandTemplates extends AstTransformer override def defEnumAnnotatedNode( a: In, 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, resultAdapter(defEnumConstantAnnotatedNode)) + constants <- transformList( + a, + data.constants, + resultAdapter(defEnumConstantAnnotatedNode) + ) default <- exprNodeOpt(a, data.default) } yield ((), cloneAnnotatedNode(a, aNode, data.copy( typeName = typeName, @@ -293,7 +295,7 @@ object ExpandTemplates extends AstTransformer override def defPortAnnotatedNode( a: In, aNode: Ast.Annotated[AstNode[Ast.DefPort]] - ): ResultAnnotatedNode[Ast.DefPort] = + ) = val data = aNode._2.data for { params <- formalParamList(a, data.params) @@ -306,22 +308,22 @@ object ExpandTemplates extends AstTransformer override def defStateMachineAnnotatedNodeExternal( in: In, node: Ast.Annotated[AstNode[Ast.DefStateMachine]] - ): ResultAnnotatedNode[Ast.DefStateMachine] = + ) = defaultAnnotatedNode(in, node) override def defStateMachineAnnotatedNodeInternal( a: In, 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 ((), cloneAnnotatedNode(a, aNode, data.copy(members = Some(result.flatten)))) + for (members <- transformFlatList(a, members, matchStateMachineMember)) + yield ((), cloneAnnotatedNode(a, aNode, data.copy(members = Some(members)))) override def defStateMachineAnnotatedNode( a: In, aNode: Ast.Annotated[AstNode[Ast.DefStateMachine]] - ): ResultAnnotatedNode[Ast.DefStateMachine] = + ) = val data = aNode._2.data data.members match { case None => defStateMachineAnnotatedNodeExternal(a, aNode) @@ -331,7 +333,7 @@ object ExpandTemplates extends AstTransformer override def defActionAnnotatedNode( a: In, aNode: Ast.Annotated[AstNode[Ast.DefAction]] - ): ResultAnnotatedNode[Ast.DefAction] = + ) = val data = aNode._2.data for { typeName <- typeNameNodeOpt(a, data.typeName) @@ -342,7 +344,7 @@ object ExpandTemplates extends AstTransformer override def defChoiceAnnotatedNode( a: In, aNode: Ast.Annotated[AstNode[Ast.DefChoice]] - ): ResultAnnotatedNode[Ast.DefChoice] = + ) = val data = aNode._2.data for { (_, guard) <- defaultNode(a, data.guard) @@ -359,64 +361,55 @@ object ExpandTemplates extends AstTransformer override def defGuardAnnotatedNode( a: In, 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))) - } + for (typeName <- typeNameNodeOpt(a, data.typeName)) + yield ((), cloneAnnotatedNode(a, aNode, data.copy(typeName = typeName))) override def defSignalAnnotatedNode( a: In, 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))) - } + for (typeName <- typeNameNodeOpt(a, data.typeName)) + yield ((), cloneAnnotatedNode(a, aNode, data.copy(typeName = typeName))) override def defStateAnnotatedNode( a: In, 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.flatten))) + for (members <- transformFlatList(a, data.members, matchStateMember)) + yield ((), cloneAnnotatedNode(a, aNode, data.copy(members = members))) override def specInitialTransitionAnnotatedNode( a: In, 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))) + for (transition <- transitionExpr(a, data.transition)) + yield ((), cloneAnnotatedNode(a, aNode, data.copy(transition = transition))) override def specStateEntryAnnotatedNode( a: In, 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))) + for (actions <- transformList(a, data.actions, defaultNode)) + yield ((), cloneAnnotatedNode(a, aNode, data.copy(actions = actions))) override def specStateExitAnnotatedNode( a: In, 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))) + for (actions <- transformList(a, data.actions, defaultNode)) + yield ((), cloneAnnotatedNode(a, aNode, data.copy(actions = actions))) override def specStateTransitionAnnotatedNode( a: In, aNode: Ast.Annotated[AstNode[Ast.SpecStateTransition]] - ): ResultAnnotatedNode[Ast.SpecStateTransition] = + ) = val data = aNode._2.data for { (_, signal) <- defaultNode(a, data.signal) @@ -433,7 +426,7 @@ object ExpandTemplates extends AstTransformer override def defStructAnnotatedNode( a: In, aNode: Ast.Annotated[AstNode[Ast.DefStruct]] - ): ResultAnnotatedNode[Ast.DefStruct] = + ) = val data = aNode._2.data for { members <- transformList(a, data.members, resultAdapter(structTypeMemberAnnotatedNode)) @@ -448,35 +441,39 @@ object ExpandTemplates extends AstTransformer override def defTopologyAnnotatedNode( a: In, 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.flatten, - implements = implements - ))) - } + } yield ( + (), + cloneAnnotatedNode( + a, + aNode, + data.copy(members = members, implements = implements) + ) + ) override def defSystemAnnotatedNode( a: In, 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 - ))) - } + for (topology <- qualIdentNode(a, data.topology)) + yield ( + (), + cloneAnnotatedNode( + a, + aNode, + data.copy(topology = topology) + ) + ) override def specCommandAnnotatedNode( a: In, aNode: Ast.Annotated[AstNode[Ast.SpecCommand]] - ): ResultAnnotatedNode[Ast.SpecCommand] = + ) = val data = aNode._2.data for { params <- formalParamList(a, data.params) @@ -495,7 +492,7 @@ object ExpandTemplates extends AstTransformer override def specInstanceAnnotatedNode( a: In, aNode: Ast.Annotated[AstNode[Ast.SpecInstance]] - ): ResultAnnotatedNode[Ast.SpecInstance] = + ) = val data = aNode._2.data for { instance <- qualIdentNode(a, data.instance) @@ -508,7 +505,7 @@ object ExpandTemplates extends AstTransformer override def specConnectionGraphAnnotatedNode( a: In, aNode: Ast.Annotated[AstNode[Ast.SpecConnectionGraph]] - ): ResultAnnotatedNode[Ast.SpecConnectionGraph] = + ) = val data = aNode._2.data def connection( @@ -551,7 +548,7 @@ object ExpandTemplates extends AstTransformer override def specContainerAnnotatedNode( a: In, aNode: Ast.Annotated[AstNode[Ast.SpecContainer]] - ): ResultAnnotatedNode[Ast.SpecContainer] = + ) = val data = aNode._2.data for { id <- exprNodeOpt(a, data.id) @@ -566,7 +563,7 @@ object ExpandTemplates extends AstTransformer override def specEventAnnotatedNode( a: In, aNode: Ast.Annotated[AstNode[Ast.SpecEvent]] - ): ResultAnnotatedNode[Ast.SpecEvent] = + ) = val data = aNode._2.data for { params <- formalParamList(a, data.params) @@ -619,7 +616,7 @@ object ExpandTemplates extends AstTransformer override def specInternalPortAnnotatedNode( a: In, aNode: Ast.Annotated[AstNode[Ast.SpecInternalPort]] - ): ResultAnnotatedNode[Ast.SpecInternalPort] = + ) = val data = aNode._2.data for { params <- formalParamList(a, data.params) @@ -632,7 +629,7 @@ object ExpandTemplates extends AstTransformer override def specLocAnnotatedNode( a: In, aNode: Ast.Annotated[AstNode[Ast.SpecLoc]] - ): ResultAnnotatedNode[Ast.SpecLoc] = + ) = val data = aNode._2.data for { symbol <- qualIdentNode(a, data.symbol) @@ -645,7 +642,7 @@ object ExpandTemplates extends AstTransformer override def specParamAnnotatedNode( a: In, aNode: Ast.Annotated[AstNode[Ast.SpecParam]] - ): ResultAnnotatedNode[Ast.SpecParam] = + ) = val data = aNode._2.data for { (_, typeName) <- matchTypeName(a, data.typeName) @@ -664,7 +661,7 @@ object ExpandTemplates extends AstTransformer override def specPortInstanceAnnotatedNode( a: In, aNode: Ast.Annotated[AstNode[Ast.SpecPortInstance]] - ): ResultAnnotatedNode[Ast.SpecPortInstance] = + ) = val data = aNode._2.data data match { case data @ Ast.SpecPortInstance.General(_, _, _, _, _, _) => @@ -696,7 +693,7 @@ object ExpandTemplates extends AstTransformer override def specPortMatchingAnnotatedNode( a: In, aNode: Ast.Annotated[AstNode[Ast.SpecPortMatching]] - ): ResultAnnotatedNode[Ast.SpecPortMatching] = + ) = val data = aNode._2.data for { (_, port1) <- defaultNode(a, data.port1) @@ -709,7 +706,7 @@ object ExpandTemplates extends AstTransformer override def specRecordAnnotatedNode( a: In, aNode: Ast.Annotated[AstNode[Ast.SpecRecord]] - ): ResultAnnotatedNode[Ast.SpecRecord] = + ) = val data = aNode._2.data for { (_, recordType) <- matchTypeName(a, data.recordType) @@ -722,7 +719,7 @@ object ExpandTemplates extends AstTransformer override def specStateMachineInstanceAnnotatedNode( a: In, aNode: Ast.Annotated[AstNode[Ast.SpecStateMachineInstance]] - ): ResultAnnotatedNode[Ast.SpecStateMachineInstance] = + ) = val data = aNode._2.data for { stateMachine <- qualIdentNode(a, data.stateMachine) @@ -735,7 +732,7 @@ object ExpandTemplates extends AstTransformer override def specTlmChannelAnnotatedNode( a: In, aNode: Ast.Annotated[AstNode[Ast.SpecTlmChannel]] - ): ResultAnnotatedNode[Ast.SpecTlmChannel] = + ) = val data = aNode._2.data def limit( a: In, @@ -764,7 +761,7 @@ object ExpandTemplates extends AstTransformer override def specTlmPacketAnnotatedNode( a: In, aNode: Ast.Annotated[AstNode[Ast.SpecTlmPacket]] - ): ResultAnnotatedNode[Ast.SpecTlmPacket] = + ) = val data = aNode._2.data def tlmPacketMember( a: In, @@ -802,18 +799,22 @@ object ExpandTemplates extends AstTransformer override def specTopPortAnnotatedNode( a: In, 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 - ))) + for (underlyingPort <- portInstanceIdentifierNode(a, data.underlyingPort)) + yield ( + (), + cloneAnnotatedNode( + a, + aNode, + data.copy(underlyingPort = underlyingPort) + ) + ) override def specTlmPacketSetAnnotatedNode( a: In, aNode: Ast.Annotated[AstNode[Ast.SpecTlmPacketSet]] - ): ResultAnnotatedNode[Ast.SpecTlmPacketSet] = + ) = val data = aNode._2.data def tlmChannelIdentifier( a: In, @@ -829,17 +830,17 @@ object ExpandTemplates extends AstTransformer ))) 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.flatten, + members = members, omitted = omitted ))) override def specInterfaceImportAnnotatedNode( a: In, aNode: Ast.Annotated[AstNode[Ast.SpecImport]] - ): ResultAnnotatedNode[Ast.SpecImport] = + ) = val data = aNode._2.data for { sym <- qualIdentNode(a, data.sym) @@ -850,7 +851,7 @@ object ExpandTemplates extends AstTransformer override def defModuleTemplateAnnotatedNode( a: In, aNode: Ast.Annotated[AstNode[Ast.DefModuleTemplate]] - ): ResultAnnotatedNode[Ast.DefModuleTemplate] = + ) = val (_, node, _) = aNode val data = node.data @@ -874,13 +875,13 @@ object ExpandTemplates extends AstTransformer for { a <- Right(a.copy(templateDefId = Some(node.id))) params <- transformList(a, data.params, templateParam) - members <- transformList(a, data.members, matchModuleMember) + members <- transformFlatList(a, data.members, matchModuleMember) a <- Right(a.copy(templateDefId = None)) } yield { ((), cloneAnnotatedNode(a, aNode, data.copy( params = params, - members = members.flatten + members = members ))) } @@ -890,10 +891,8 @@ object ExpandTemplates extends AstTransformer ) = { val (_, node, _) = aNode val data = node.data - for { result <- transformList(a, data.members, matchModuleMember) } - yield { - ((), cloneAnnotatedNode(a, aNode, data.copy(members = result.flatten))) - } + for (members <- transformFlatList(a, data.members, matchModuleMember)) + yield ((), cloneAnnotatedNode(a, aNode, data.copy(members = members))) } override def specTemplateExpandAnnotatedNode( @@ -995,7 +994,7 @@ object ExpandTemplates extends AstTransformer // Clone the template body, recording the expansion node so that // cloned nodes point back at the expansion site. // Record the template definition too for diagnostics. - members <- transformList( + members <- transformFlatList( a.copy( templateExpansionId = Some(node.id), templateDefId = Some(tmpl.node._2.id) @@ -1005,7 +1004,7 @@ object ExpandTemplates extends AstTransformer ) } yield { // Paste the expanded template body into the expansion specifier - (pre, AstNode.create(data.copy(members = Some(members.flatten)), node.id), post) + (pre, AstNode.create(data.copy(members = Some(members)), node.id), post) } } From 84f9d3c76f934833b3c02ebd95cf6abd95040bc2 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Mon, 12 Oct 2026 23:59:18 -0700 Subject: [PATCH 17/51] Refactor ExpandTemplates --- .../scala/transform/ExpandTemplates.scala | 31 +++++++++++++------ 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala index e5dc9cc54..04fa2eb28 100644 --- a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala +++ b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala @@ -860,16 +860,27 @@ object ExpandTemplates extends AstTransformer 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))) - 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))) - } + 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)) +// node.data match { +// case data @ Ast.TemplateParam.Constant(_, tn) => +// for ((_, tn) <- matchTypeName(a, tn)) +// yield ((), cloneAnnotatedNode(a, param, data.copy(typeName = tn))) +// 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))) +// } } for { From c11355c9e788e76c0380b8c453ab35aabaf87b1d Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 13 Oct 2026 00:27:53 -0700 Subject: [PATCH 18/51] Refactor ExpandTemplates --- .../scala/transform/ExpandTemplates.scala | 620 +++++++++++------- 1 file changed, 381 insertions(+), 239 deletions(-) diff --git a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala index 04fa2eb28..cca90307a 100644 --- a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala +++ b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala @@ -60,12 +60,15 @@ object ExpandTemplates extends AstTransformer 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)) - )) + Locations.put( + out.id, + Location( + inLoc.file, + inLoc.pos, + inLoc.includingLoc, + Some(Locations.get(expansionNode)) + ) + ) Right((), out) } } @@ -90,7 +93,7 @@ object ExpandTemplates extends AstTransformer e: Ast.ExprArray ) = for { result <- transformList(a, e.elts, matchExprNode) } - yield ((), cloneNode(a, node, Ast.ExprArray(result))) + yield ((), cloneNode(a, node, Ast.ExprArray(result))) override def exprArraySubscriptNode( a: In, @@ -182,10 +185,10 @@ object ExpandTemplates extends AstTransformer ): ResultAnnotatedNode[Ast.DefAliasType] = val data = aNode._2.data for ((_, ty) <- matchTypeName(a, data.typeName)) - yield ( - (), - cloneAnnotatedNode(a, aNode, data.copy(typeName = ty)) - ) + yield ( + (), + cloneAnnotatedNode(a, aNode, data.copy(typeName = ty)) + ) override def defArrayAnnotatedNode( a: In, @@ -266,12 +269,13 @@ object ExpandTemplates extends AstTransformer ) = val data = aNode._2.data for ((_, value) <- matchExprNode(a, data.value)) - yield { - ((), - cloneAnnotatedNode( - a, aNode, - data.copy(value = value))) - } + yield ( + (), + cloneAnnotatedNode( + a, aNode, + data.copy(value = value) + ) + ) override def defEnumAnnotatedNode( a: In, @@ -286,11 +290,18 @@ object ExpandTemplates extends AstTransformer resultAdapter(defEnumConstantAnnotatedNode) ) default <- exprNodeOpt(a, data.default) - } yield ((), cloneAnnotatedNode(a, aNode, data.copy( - typeName = typeName, - constants = constants, - default = default - ))) + } yield ( + (), + cloneAnnotatedNode( + a, + aNode, + data.copy( + typeName = typeName, + constants = constants, + default = default + ) + ) + ) override def defPortAnnotatedNode( a: In, @@ -300,10 +311,14 @@ object ExpandTemplates extends AstTransformer for { params <- formalParamList(a, data.params) returnType <- typeNameNodeOpt(a, data.returnType) - } yield ((), cloneAnnotatedNode(a, aNode, data.copy( - params = params, - returnType = returnType - ))) + } yield ( + (), + cloneAnnotatedNode( + a, + aNode, + data.copy(params = params, returnType = returnType) + ) + ) override def defStateMachineAnnotatedNodeExternal( in: In, @@ -350,13 +365,18 @@ object ExpandTemplates extends AstTransformer (_, guard) <- defaultNode(a, data.guard) ifTransition <- transitionExpr(a, data.ifTransition) elseTransition <- transitionExpr(a, data.elseTransition) - } yield { - ((), cloneAnnotatedNode(a, aNode, data.copy( - guard = guard, - ifTransition = ifTransition, - elseTransition = elseTransition - ))) - } + } yield ( + (), + cloneAnnotatedNode( + a, + aNode, + data.copy( + guard = guard, + ifTransition = ifTransition, + elseTransition = elseTransition + ) + ) + ) override def defGuardAnnotatedNode( a: In, @@ -415,13 +435,18 @@ object ExpandTemplates extends AstTransformer (_, signal) <- defaultNode(a, data.signal) guard <- defaultNodeOpt(a, data.guard) transitionOrDo <- transitionOrDo(a, data.transitionOrDo) - } yield { - ((), cloneAnnotatedNode(a, aNode, data.copy( - signal = signal, - guard = guard, - transitionOrDo = transitionOrDo - ))) - } + } yield ( + (), + cloneAnnotatedNode( + a, + aNode, + data.copy( + signal = signal, + guard = guard, + transitionOrDo = transitionOrDo + ) + ) + ) override def defStructAnnotatedNode( a: In, @@ -431,12 +456,14 @@ object ExpandTemplates extends AstTransformer for { members <- transformList(a, data.members, resultAdapter(structTypeMemberAnnotatedNode)) default <- exprNodeOpt(a, data.default) - } yield { - ((), cloneAnnotatedNode(a, aNode, data.copy( - members = members, - default = default - ))) - } + } yield ( + (), + cloneAnnotatedNode( + a, + aNode, + data.copy(members = members, default = default) + ) + ) override def defTopologyAnnotatedNode( a: In, @@ -461,14 +488,14 @@ object ExpandTemplates extends AstTransformer ) = val data = aNode._2.data for (topology <- qualIdentNode(a, data.topology)) - yield ( - (), - cloneAnnotatedNode( - a, - aNode, - data.copy(topology = topology) + yield ( + (), + cloneAnnotatedNode( + a, + aNode, + data.copy(topology = topology) + ) ) - ) override def specCommandAnnotatedNode( a: In, @@ -480,14 +507,19 @@ object ExpandTemplates extends AstTransformer opcode <- exprNodeOpt(a, data.opcode) priority <- exprNodeOpt(a, data.priority) queueFull <- defaultNodeOpt(a, data.queueFull) - } yield { - ((), cloneAnnotatedNode(a, aNode, data.copy( - params = params, - opcode = opcode, - priority = priority, - queueFull = queueFull, - ))) - } + } yield ( + (), + cloneAnnotatedNode( + a, + aNode, + data.copy( + params = params, + opcode = opcode, + priority = priority, + queueFull = queueFull, + ) + ) + ) override def specInstanceAnnotatedNode( a: In, @@ -496,11 +528,14 @@ object ExpandTemplates extends AstTransformer val data = aNode._2.data for { instance <- qualIdentNode(a, data.instance) - } yield { - ((), cloneAnnotatedNode(a, aNode, data.copy( - instance = instance, - ))) - } + } yield ( + (), + cloneAnnotatedNode( + a, + aNode, + data.copy(instance = instance) + ) + ) override def specConnectionGraphAnnotatedNode( a: In, @@ -517,31 +552,40 @@ object ExpandTemplates extends AstTransformer fromIndex <- exprNodeOpt(a, connection.fromIndex) toPort <- portInstanceIdentifierNode(a, connection.toPort) toIndex <- exprNodeOpt(a, connection.toIndex) - } yield { - ((), connection.copy( + } yield ( + (), + connection.copy( fromPort = fromPort, fromIndex = fromIndex, toPort = toPort, - toIndex = toIndex, - )) - } + toIndex = toIndex + ) + ) } data match { case data @ Ast.SpecConnectionGraph.Direct(_, connections) => - for { - connections <- transformList(a, connections, connection) - } yield ((), cloneAnnotatedNode(a, aNode, data.copy( - connections = connections - ))) + for (connections <- transformList(a, connections, connection)) + yield ( + (), + cloneAnnotatedNode( + a, + aNode, + data.copy(connections = connections) + ) + ) case data @ Ast.SpecConnectionGraph.Pattern(_, source, targets) => for { source <- qualIdentNode(a, source) targets <- transformList(a, targets, resultAdapter(qualIdentNode)) - } yield ((), cloneAnnotatedNode(a, aNode, data.copy( - source = source, - targets = targets - ))) + } yield ( + (), + cloneAnnotatedNode( + a, + aNode, + data.copy(source = source, targets = targets) + ) + ) } @@ -553,12 +597,17 @@ object ExpandTemplates extends AstTransformer for { id <- exprNodeOpt(a, data.id) defaultPriority <- exprNodeOpt(a, data.defaultPriority) - } yield { - ((), cloneAnnotatedNode(a, aNode, data.copy( - id = id, - defaultPriority = defaultPriority, - ))) - } + } yield ( + (), + cloneAnnotatedNode( + a, + aNode, + data.copy( + id = id, + defaultPriority = defaultPriority + ) + ) + ) override def specEventAnnotatedNode( a: In, @@ -576,22 +625,31 @@ object ExpandTemplates extends AstTransformer for { (_, count) <- matchExprNode(a, throttle.data.count) every <- exprNodeOpt(a, throttle.data.every) - } yield Some(cloneNode( - a, throttle, throttle.data.copy( - every = every, - count = count + } yield Some( + cloneNode( + a, + throttle, + throttle.data.copy( + every = every, + count = count + ) ) - )) + ) } } - } yield { - ((), cloneAnnotatedNode(a, aNode, data.copy( - params = params, - id = id, - format = format, - throttle = throttle - ))) - } + } yield ( + (), + cloneAnnotatedNode( + a, + aNode, + data.copy( + params = params, + id = id, + format = format, + throttle = throttle + ) + ) + ) override def specIncludeAnnotatedNode( a: In, @@ -607,11 +665,8 @@ object ExpandTemplates extends AstTransformer aNode: Ast.Annotated[AstNode[Ast.SpecInit]] ) = val data = aNode._2.data - for (result <- matchExprNode(a, data.phase)) - yield { - val (_, phase1) = result - ((), 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, @@ -621,10 +676,17 @@ object ExpandTemplates extends AstTransformer for { params <- formalParamList(a, data.params) priority <- exprNodeOpt(a, data.priority) - } yield ((), cloneAnnotatedNode(a, aNode, data.copy( - params = params, - priority = priority, - ))) + } yield ( + (), + cloneAnnotatedNode( + a, + aNode, + data.copy( + params = params, + priority = priority, + ) + ) + ) override def specLocAnnotatedNode( a: In, @@ -634,10 +696,14 @@ object ExpandTemplates extends AstTransformer for { symbol <- qualIdentNode(a, data.symbol) (_, file) <- defaultNode(a, data.file) - } yield ((), cloneAnnotatedNode(a, aNode, data.copy( - symbol = symbol, - file = file - ))) + } yield ( + (), + cloneAnnotatedNode( + a, + aNode, + data.copy(symbol = symbol, file = file) + ) + ) override def specParamAnnotatedNode( a: In, @@ -650,13 +716,20 @@ object ExpandTemplates extends AstTransformer id <- exprNodeOpt(a, data.id) setOpcode <- exprNodeOpt(a, data.setOpcode) saveOpcode <- exprNodeOpt(a, data.saveOpcode) - } yield ((), cloneAnnotatedNode(a, aNode, data.copy( - typeName = typeName, - default = default, - id = id, - setOpcode = setOpcode, - saveOpcode = saveOpcode - ))) + } yield ( + (), + cloneAnnotatedNode( + a, + aNode, + data.copy( + typeName = typeName, + default = default, + id = id, + setOpcode = setOpcode, + saveOpcode = saveOpcode + ) + ) + ) override def specPortInstanceAnnotatedNode( a: In, @@ -670,23 +743,35 @@ object ExpandTemplates extends AstTransformer port <- qualIdentNodeOpt(a, data.port) priority <- exprNodeOpt(a, data.priority) queueFull <- defaultNodeOpt(a, data.queueFull) - } yield { - ((), cloneAnnotatedNode(a, aNode, data.copy( - size = size, - port = port, - priority = priority, - queueFull = queueFull - ))) - } + } yield ( + (), + cloneAnnotatedNode( + a, + aNode, + data.copy( + size = size, + port = port, + priority = priority, + queueFull = queueFull + ) + ) + ) case data @ Ast.SpecPortInstance.Special(_, _, _, _, _) => for { priority <- exprNodeOpt(a, data.priority) queueFull <- defaultNodeOpt(a, data.queueFull) } yield { - ((), cloneAnnotatedNode(a, aNode, data.copy( - priority = priority, - queueFull = queueFull - ))) + ( + (), + cloneAnnotatedNode( + a, + aNode, + data.copy( + priority = priority, + queueFull = queueFull + ) + ) + ) } } @@ -698,10 +783,14 @@ object ExpandTemplates extends AstTransformer for { (_, port1) <- defaultNode(a, data.port1) (_, port2) <- defaultNode(a, data.port2) - } yield (((), cloneAnnotatedNode(a, aNode, data.copy( - port1 = port1, - port2 = port2 - )))) + } yield ( + (), + cloneAnnotatedNode( + a, + aNode, + data.copy(port1 = port1, port2 = port2) + ) + ) override def specRecordAnnotatedNode( a: In, @@ -711,10 +800,14 @@ object ExpandTemplates extends AstTransformer for { (_, recordType) <- matchTypeName(a, data.recordType) id <- exprNodeOpt(a, data.id) - } yield (((), cloneAnnotatedNode(a, aNode, data.copy( - recordType = recordType, - id = id - )))) + } yield ( + (), + cloneAnnotatedNode( + a, + aNode, + data.copy(recordType = recordType, id = id) + ) + ) override def specStateMachineInstanceAnnotatedNode( a: In, @@ -724,10 +817,14 @@ object ExpandTemplates extends AstTransformer for { stateMachine <- qualIdentNode(a, data.stateMachine) priority <- exprNodeOpt(a, data.priority) - } yield (((), cloneAnnotatedNode(a, aNode, data.copy( - stateMachine = stateMachine, - priority = priority - )))) + } yield ( + (), + cloneAnnotatedNode( + a, + aNode, + data.copy(stateMachine = stateMachine, priority = priority) + ) + ) override def specTlmChannelAnnotatedNode( a: In, @@ -742,7 +839,7 @@ object ExpandTemplates extends AstTransformer for { (_, kind) <- defaultNode(a, kind) (_, value) <- matchExprNode(a, value) - } yield (((), (kind, value))) + } yield ((), (kind, value)) } for { @@ -750,13 +847,20 @@ object ExpandTemplates extends AstTransformer 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, - id = id, - format = cloneStringNodeOpt(a, data.format), - low = low, - high = high - )))) + } yield ( + (), + cloneAnnotatedNode( + a, + aNode, + data.copy( + typeName = typeName, + id = id, + format = cloneStringNodeOpt(a, data.format), + low = low, + high = high + ) + ) + ) override def specTlmPacketAnnotatedNode( a: In, @@ -770,19 +874,29 @@ object ExpandTemplates extends AstTransformer 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)) - )) + yield ( + (), + Ast.TlmPacketMember.SpecInclude( + cloneNode(a, node, node.data.copy(file = file)) + ) + ) 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, - channelName = channelName - )) - )) + } yield ( + (), + Ast.TlmPacketMember.TlmChannelIdentifier( + cloneNode( + a, + node, + node.data.copy( + componentInstance = componentInstance, + channelName = channelName + ) + ) + ) + ) } } @@ -790,11 +904,18 @@ object ExpandTemplates extends AstTransformer id <- exprNodeOpt(a, data.id) (_, group) <- matchExprNode(a, data.group) members <- transformList(a, data.members, tlmPacketMember) - } yield (((), cloneAnnotatedNode(a, aNode, data.copy( - id = id, - group = group, - members = members - )))) + } yield ( + (), + cloneAnnotatedNode( + a, + aNode, + data.copy( + id = id, + group = group, + members = members + ) + ) + ) override def specTopPortAnnotatedNode( a: In, @@ -802,14 +923,14 @@ object ExpandTemplates extends AstTransformer ) = val data = aNode._2.data for (underlyingPort <- portInstanceIdentifierNode(a, data.underlyingPort)) - yield ( - (), - cloneAnnotatedNode( - a, - aNode, - data.copy(underlyingPort = underlyingPort) + yield ( + (), + cloneAnnotatedNode( + a, + aNode, + data.copy(underlyingPort = underlyingPort) + ) ) - ) override def specTlmPacketSetAnnotatedNode( a: In, @@ -824,18 +945,29 @@ object ExpandTemplates extends AstTransformer for { componentInstance <- qualIdentNode(a, data.componentInstance) (_, channelName) <- defaultNode(a, data.channelName) - } yield ((), cloneNode(a, node, data.copy( - componentInstance = componentInstance, - channelName = channelName - ))) + } yield ( + (), + cloneNode( + a, + node, + data.copy( + componentInstance = componentInstance, + channelName = channelName + ) + ) + ) for { members <- transformFlatList(a, data.members, matchTlmPacketSetMember) omitted <- transformList(a, data.omitted, tlmChannelIdentifier) - } yield ((), cloneAnnotatedNode(a, aNode, data.copy( - members = members, - omitted = omitted - ))) + } yield ( + (), + cloneAnnotatedNode( + a, + aNode, + data.copy(members = members, omitted = omitted) + ) + ) override def specInterfaceImportAnnotatedNode( a: In, @@ -844,9 +976,14 @@ object ExpandTemplates extends AstTransformer val data = aNode._2.data for { sym <- qualIdentNode(a, data.sym) - } yield ((), cloneAnnotatedNode(a, aNode, data.copy( - sym = sym - ))) + } yield ( + (), + cloneAnnotatedNode( + a, + aNode, + data.copy(sym = sym) + ) + ) override def defModuleTemplateAnnotatedNode( a: In, @@ -871,16 +1008,6 @@ object ExpandTemplates extends AstTransformer yield data.copy(interface = interface) } } yield ((), cloneAnnotatedNode(a, param, data)) -// node.data match { -// case data @ Ast.TemplateParam.Constant(_, tn) => -// for ((_, tn) <- matchTypeName(a, tn)) -// yield ((), cloneAnnotatedNode(a, param, data.copy(typeName = tn))) -// 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))) -// } } for { @@ -889,12 +1016,14 @@ object ExpandTemplates extends AstTransformer members <- transformFlatList(a, data.members, matchModuleMember) a <- Right(a.copy(templateDefId = None)) } - yield { - ((), cloneAnnotatedNode(a, aNode, data.copy( - params = params, - members = members - ))) - } + yield ( + (), + cloneAnnotatedNode( + a, + aNode, + data.copy(params = params, members = members) + ) + ) override def defModuleAnnotatedNode( a: Analysis, @@ -909,7 +1038,7 @@ object ExpandTemplates extends AstTransformer override def specTemplateExpandAnnotatedNode( a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecTemplateExpand]] - ): ResultAnnotatedNode[Ast.SpecTemplateExpand] = { + ) = { val (_, node, _) = aNode val data = node.data data.members match { @@ -930,12 +1059,15 @@ object ExpandTemplates extends AstTransformer 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)) - )) + Locations.put( + out.id, + Location( + inLoc.file, + inLoc.pos, + inLoc.includingLoc, + Some(Locations.get(expansionNode)) + ) + ) out } } @@ -955,10 +1087,14 @@ object ExpandTemplates extends AstTransformer ): 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) - )) + 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)) } @@ -981,7 +1117,7 @@ object ExpandTemplates extends AstTransformer case None => Right(None) case Some(node) => for ((_, node) <- defaultNode(a, node)) - yield Some(node) + yield Some(node) } private def defEnumConstantAnnotatedNode( @@ -990,7 +1126,7 @@ object ExpandTemplates extends AstTransformer ): 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)) + yield cloneAnnotatedNode(a, aNode, data.copy(value = value)) /** Expand a template */ private def expandTemplate( @@ -1027,7 +1163,7 @@ object ExpandTemplates extends AstTransformer case None => Right(None) case Some(value) => for ((_, result) <- matchExprNode(a, value)) - yield Some(result) + yield Some(result) } private def formalAnnotatatedParam( @@ -1036,7 +1172,7 @@ object ExpandTemplates extends AstTransformer ) = val data = aNode._2.data for ((_, ty) <- matchTypeName(a, data.typeName)) - yield cloneAnnotatedNode(a, aNode, data.copy(typeName = ty)) + yield cloneAnnotatedNode(a, aNode, data.copy(typeName = ty)) private def formalParamList( a: In, @@ -1051,10 +1187,14 @@ object ExpandTemplates extends AstTransformer for { interfaceInstance <- qualIdentNode(a, pii.data.interfaceInstance) (_, portName) <- defaultNode(a, pii.data.portName) - } yield cloneNode(a, pii, pii.data.copy( - interfaceInstance = interfaceInstance, - portName = portName - )) + } yield cloneNode( + a, + pii, + pii.data.copy( + interfaceInstance = interfaceInstance, + portName = portName + ) + ) } private def qualIdentNode( @@ -1071,7 +1211,7 @@ object ExpandTemplates extends AstTransformer case None => Right(None) case Some(value) => for (result <- qualIdentNode(a, value)) - yield Some(result) + yield Some(result) } } @@ -1084,12 +1224,11 @@ object ExpandTemplates extends AstTransformer node: AstNode[Ast.StructMember] ) = { for ((_, value) <- matchExprNode(a, node.data.value)) - yield { - cloneNode(a, node, Ast.StructMember( - node.data.name, - value - )) - } + yield cloneNode( + a, + node, + Ast.StructMember(node.data.name, value) + ) } private def structTypeMemberAnnotatedNode( @@ -1100,13 +1239,15 @@ object ExpandTemplates extends AstTransformer for { size <- exprNodeOpt(a, data.size) (_, typeName) <- matchTypeName(a, data.typeName) - } yield { - cloneAnnotatedNode(a, aNode, data.copy( - size = size, - typeName = typeName, - format = cloneStringNodeOpt(a, data.format) - )) - } + } yield cloneAnnotatedNode( + a, + aNode, + data.copy( + size = size, + typeName = typeName, + format = cloneStringNodeOpt(a, data.format) + ) + ) private def transitionExpr( a: In, @@ -1115,10 +1256,11 @@ object ExpandTemplates extends AstTransformer for { actions <- transformList(a, node.data.actions, defaultNode) target <- qualIdentNode(a, node.data.target) - } yield cloneNode(a, node, node.data.copy( - actions = actions, - target = target - )) + } yield cloneNode( + a, + node, + node.data.copy(actions = actions, target = target) + ) private def transitionOrDo( a: In, @@ -1127,10 +1269,10 @@ object ExpandTemplates extends AstTransformer transitionOrDo match case Ast.TransitionOrDo.Transition(transition) => for (result <- transitionExpr(a, transition)) - yield Ast.TransitionOrDo.Transition(result) + yield Ast.TransitionOrDo.Transition(result) case Ast.TransitionOrDo.Do(actions) => for (result <- transformList(a, actions, defaultNode)) - yield Ast.TransitionOrDo.Do(result) + yield Ast.TransitionOrDo.Do(result) private def typeNameNodeOpt( a: In, @@ -1140,7 +1282,7 @@ object ExpandTemplates extends AstTransformer case None => Right(None) case Some(tn) => for ((_, tn) <- matchTypeName(a, tn)) - yield Some(tn) + yield Some(tn) } From 3895d4d07eb43208f734f2b07559ee0e675e1b99 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 13 Oct 2026 00:38:24 -0700 Subject: [PATCH 19/51] Refactor ExpandTemplates --- .../scala/transform/ExpandTemplates.scala | 46 ++++++++----------- 1 file changed, 18 insertions(+), 28 deletions(-) diff --git a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala index cca90307a..370346a5c 100644 --- a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala +++ b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala @@ -15,7 +15,7 @@ object ExpandTemplates extends AstTransformer type Out = Unit def default(a: Analysis) = - throw new InternalError("ExpandTemplates: Transformer not implemented") + throw InternalError("ExpandTemplates: Transformer not implemented") /** Transform a list in sequence, threading state */ def transformList[A, B]( @@ -78,7 +78,8 @@ object ExpandTemplates extends AstTransformer aNode: Ast.Annotated[AstNode[T]] ) = { a.templateExpansionId match { - // We are not currently in a template, leave the node alone + // We are not currently in a template expansion. + // Leave the node alone. case None => Right((), aNode) case Some(_) => val (pre, node, post) = aNode @@ -92,7 +93,7 @@ object ExpandTemplates extends AstTransformer node: AstNode[Ast.Expr], e: Ast.ExprArray ) = - for { result <- transformList(a, e.elts, matchExprNode) } + for (result <- transformList(a, e.elts, matchExprNode)) yield ((), cloneNode(a, node, Ast.ExprArray(result))) override def exprArraySubscriptNode( @@ -352,9 +353,7 @@ object ExpandTemplates extends AstTransformer val data = aNode._2.data for { typeName <- typeNameNodeOpt(a, data.typeName) - } yield { - ((), cloneAnnotatedNode(a, aNode, data.copy(typeName = typeName))) - } + } yield ((), cloneAnnotatedNode(a, aNode, data.copy(typeName = typeName))) override def defChoiceAnnotatedNode( a: In, @@ -618,24 +617,19 @@ object ExpandTemplates extends AstTransformer 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, - count = count - ) - ) + 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, count = count) ) - } + ) } } yield ( (), @@ -681,10 +675,7 @@ object ExpandTemplates extends AstTransformer cloneAnnotatedNode( a, aNode, - data.copy( - params = params, - priority = priority, - ) + data.copy(params = params, priority = priority) ) ) @@ -1285,5 +1276,4 @@ object ExpandTemplates extends AstTransformer yield Some(tn) } - } From c36ae19fe53348d7046ed12b444ebf2567ee4984 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 13 Oct 2026 00:47:10 -0700 Subject: [PATCH 20/51] Refactor ExpandTemplates --- .../scala/transform/ExpandTemplates.scala | 76 ++++++++----------- 1 file changed, 31 insertions(+), 45 deletions(-) diff --git a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala index 370346a5c..421832d5a 100644 --- a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala +++ b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala @@ -200,18 +200,16 @@ object ExpandTemplates extends AstTransformer (_, size) <- matchExprNode(a, data.size) (_, eltType) <- matchTypeName(a, data.eltType) default <- exprNodeOpt(a, data.default) - } yield ( - (), - cloneAnnotatedNode( - a, aNode, - data.copy( - size = size, - eltType = eltType, - default = default, - format = cloneStringNodeOpt(a, data.format) - ) + } yield { + 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( @@ -332,9 +330,9 @@ object ExpandTemplates extends AstTransformer aNode: Ast.Annotated[AstNode[Ast.DefStateMachine]], members: List[Ast.StateMachineMember] ) = - val data = aNode._2.data - for (members <- transformFlatList(a, members, matchStateMachineMember)) - yield ((), cloneAnnotatedNode(a, aNode, data.copy(members = Some(members)))) + 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, @@ -551,40 +549,34 @@ object ExpandTemplates extends AstTransformer fromIndex <- exprNodeOpt(a, connection.fromIndex) toPort <- portInstanceIdentifierNode(a, connection.toPort) toIndex <- exprNodeOpt(a, connection.toIndex) - } yield ( - (), - connection.copy( + } yield { + 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) - ) - ) + 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, resultAdapter(qualIdentNode)) - } yield ( - (), - cloneAnnotatedNode( - a, - aNode, - data.copy(source = source, targets = targets) - ) - ) + } yield { + val dataCopy = data.copy(source = source, targets = targets) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) + } } @@ -596,17 +588,11 @@ object ExpandTemplates extends AstTransformer for { id <- exprNodeOpt(a, data.id) defaultPriority <- exprNodeOpt(a, data.defaultPriority) - } yield ( - (), - cloneAnnotatedNode( - a, - aNode, - data.copy( - id = id, - defaultPriority = defaultPriority - ) - ) - ) + } yield { + val dataCopy = data.copy(id = id, defaultPriority = defaultPriority) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) + } override def specEventAnnotatedNode( a: In, From bab45e5634d2f4b7ae18a7551065b98906525c15 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 13 Oct 2026 00:54:57 -0700 Subject: [PATCH 21/51] Refactor ExpandTemplates --- .../scala/transform/ExpandTemplates.scala | 56 +++++++++---------- 1 file changed, 25 insertions(+), 31 deletions(-) diff --git a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala index 421832d5a..dfe87578e 100644 --- a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala +++ b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala @@ -60,15 +60,13 @@ object ExpandTemplates extends AstTransformer 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)) - ) + val outLoc = Location( + inLoc.file, + inLoc.pos, + inLoc.includingLoc, + Some(Locations.get(expansionNode)) ) + Locations.put(out.id, outLoc) Right((), out) } } @@ -234,23 +232,21 @@ object ExpandTemplates extends AstTransformer 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, - implType=cloneStringNodeOpt(a, data.implType), - file=cloneStringNodeOpt(a, data.file), - queueSize=queueSize, - stackSize=stackSize, - priority=priority, - cpu=cpu, - initSpecs=initSpecs - ) + } yield { + 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( @@ -268,13 +264,11 @@ object ExpandTemplates extends AstTransformer ) = val data = aNode._2.data for ((_, value) <- matchExprNode(a, data.value)) - yield ( - (), - cloneAnnotatedNode( - a, aNode, - data.copy(value = value) - ) - ) + yield { + val dataCopy = data.copy(value = value) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) + } override def defEnumAnnotatedNode( a: In, From be387f3988cb25e29823c6302561e2e4582807ca Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 13 Oct 2026 00:59:27 -0700 Subject: [PATCH 22/51] Refactor ExpandTemplates --- .../scala/transform/ExpandTemplates.scala | 46 +++++++++---------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala index dfe87578e..932d7312a 100644 --- a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala +++ b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala @@ -54,22 +54,22 @@ object ExpandTemplates extends AstTransformer override def defaultNode[T]( a: Analysis, node: AstNode[T] - ) = - a.templateExpansionId match { - case None => Right((), node) - case Some(expansionNode) => { - val out = AstNode.create(node.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) - Right((), out) - } - } + ) = Right((), cloneNode(a, node, node.data)) +// a.templateExpansionId match { +// case None => Right((), node) +// case Some(expansionNode) => { +// val out = AstNode.create(node.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) +// Right((), out) +// } +// } override def defaultAnnotatedNode[T]( a: In, @@ -1030,15 +1030,13 @@ object ExpandTemplates extends AstTransformer 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)) - ) + val outLoc = Location( + inLoc.file, + inLoc.pos, + inLoc.includingLoc, + Some(Locations.get(expansionNode)) ) + Locations.put(out.id, outLoc) out } } From a3f73404012654256144265163dc3a7c481f96d4 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 13 Oct 2026 01:07:22 -0700 Subject: [PATCH 23/51] Refactor ExpandTemplates --- .../scala/transform/ExpandTemplates.scala | 69 +++++++------------ 1 file changed, 23 insertions(+), 46 deletions(-) diff --git a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala index 932d7312a..18af8ae67 100644 --- a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala +++ b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala @@ -55,21 +55,6 @@ object ExpandTemplates extends AstTransformer a: Analysis, node: AstNode[T] ) = Right((), cloneNode(a, node, node.data)) -// a.templateExpansionId match { -// case None => Right((), node) -// case Some(expansionNode) => { -// val out = AstNode.create(node.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) -// Right((), out) -// } -// } override def defaultAnnotatedNode[T]( a: In, @@ -283,18 +268,15 @@ object ExpandTemplates extends AstTransformer resultAdapter(defEnumConstantAnnotatedNode) ) default <- exprNodeOpt(a, data.default) - } yield ( - (), - cloneAnnotatedNode( - a, - aNode, - data.copy( - typeName = typeName, - constants = constants, - default = default - ) + } yield { + val dataCopy = data.copy( + typeName = typeName, + constants = constants, + default = default ) - ) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) + } override def defPortAnnotatedNode( a: In, @@ -304,14 +286,11 @@ object ExpandTemplates extends AstTransformer for { params <- formalParamList(a, data.params) returnType <- typeNameNodeOpt(a, data.returnType) - } yield ( - (), - cloneAnnotatedNode( - a, - aNode, - data.copy(params = params, returnType = returnType) - ) - ) + } yield { + val dataCopy = data.copy(params = params, returnType = returnType) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) + } override def defStateMachineAnnotatedNodeExternal( in: In, @@ -356,18 +335,15 @@ object ExpandTemplates extends AstTransformer (_, guard) <- defaultNode(a, data.guard) ifTransition <- transitionExpr(a, data.ifTransition) elseTransition <- transitionExpr(a, data.elseTransition) - } yield ( - (), - cloneAnnotatedNode( - a, - aNode, - data.copy( - guard = guard, - ifTransition = ifTransition, - elseTransition = elseTransition - ) + } yield { + val dataCopy = data.copy( + guard = guard, + ifTransition = ifTransition, + elseTransition = elseTransition ) - ) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) + } override def defGuardAnnotatedNode( a: In, @@ -531,7 +507,7 @@ object ExpandTemplates extends AstTransformer override def specConnectionGraphAnnotatedNode( a: In, aNode: Ast.Annotated[AstNode[Ast.SpecConnectionGraph]] - ) = + ) = { val data = aNode._2.data def connection( @@ -573,6 +549,7 @@ object ExpandTemplates extends AstTransformer } } + } override def specContainerAnnotatedNode( a: In, From c99182f1696b8dd9248afd5134d394e1030b0228 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 13 Oct 2026 07:49:44 -0700 Subject: [PATCH 24/51] Refactor ExpandTemplates --- .../scala/transform/ExpandTemplates.scala | 139 +++++++----------- 1 file changed, 56 insertions(+), 83 deletions(-) diff --git a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala index 18af8ae67..f9af57a10 100644 --- a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala +++ b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala @@ -144,11 +144,10 @@ object ExpandTemplates extends AstTransformer a: In, node: AstNode[Ast.TypeName], tn: Ast.TypeNameQualIdent - ) = - Right( - (), - cloneNode(a, node, Ast.TypeNameQualIdent(cloneQualIdentNode(a, tn.name))) - ) + ) = { + val qidNode = cloneQualIdentNode(a, tn.name) + Right((), cloneNode(a, node, Ast.TypeNameQualIdent(qidNode))) + } override def typeNameStringNode( a: In, @@ -169,10 +168,7 @@ object ExpandTemplates extends AstTransformer ): ResultAnnotatedNode[Ast.DefAliasType] = val data = aNode._2.data for ((_, ty) <- matchTypeName(a, data.typeName)) - yield ( - (), - cloneAnnotatedNode(a, aNode, data.copy(typeName = ty)) - ) + yield ((), cloneAnnotatedNode(a, aNode, data.copy(typeName = ty))) override def defArrayAnnotatedNode( a: In, @@ -402,18 +398,15 @@ object ExpandTemplates extends AstTransformer (_, signal) <- defaultNode(a, data.signal) guard <- defaultNodeOpt(a, data.guard) transitionOrDo <- transitionOrDo(a, data.transitionOrDo) - } yield ( - (), - cloneAnnotatedNode( - a, - aNode, - data.copy( - signal = signal, - guard = guard, - transitionOrDo = transitionOrDo - ) + } yield { + val dataCopy = data.copy( + signal = signal, + guard = guard, + transitionOrDo = transitionOrDo ) - ) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) + } override def defStructAnnotatedNode( a: In, @@ -423,14 +416,11 @@ object ExpandTemplates extends AstTransformer for { members <- transformList(a, data.members, resultAdapter(structTypeMemberAnnotatedNode)) default <- exprNodeOpt(a, data.default) - } yield ( - (), - cloneAnnotatedNode( - a, - aNode, - data.copy(members = members, default = default) - ) - ) + } yield { + val dataCopy = data.copy(members = members, default = default) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) + } override def defTopologyAnnotatedNode( a: In, @@ -440,14 +430,11 @@ object ExpandTemplates extends AstTransformer for { 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, implements = implements) - ) - ) + } yield { + val dataCopy = data.copy(members = members, implements = implements) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) + } override def defSystemAnnotatedNode( a: In, @@ -455,14 +442,11 @@ object ExpandTemplates extends AstTransformer ) = val data = aNode._2.data for (topology <- qualIdentNode(a, data.topology)) - yield ( - (), - cloneAnnotatedNode( - a, - aNode, - data.copy(topology = topology) - ) - ) + yield { + val dataCopy = data.copy(topology = topology) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) + } override def specCommandAnnotatedNode( a: In, @@ -474,19 +458,16 @@ object ExpandTemplates extends AstTransformer opcode <- exprNodeOpt(a, data.opcode) priority <- exprNodeOpt(a, data.priority) queueFull <- defaultNodeOpt(a, data.queueFull) - } yield ( - (), - cloneAnnotatedNode( - a, - aNode, - data.copy( - params = params, - opcode = opcode, - priority = priority, - queueFull = queueFull, - ) + } yield { + val dataCopy = data.copy( + params = params, + opcode = opcode, + priority = priority, + queueFull = queueFull, ) - ) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) + } override def specInstanceAnnotatedNode( a: In, @@ -580,27 +561,22 @@ object ExpandTemplates extends AstTransformer for { (_, count) <- matchExprNode(a, throttle.data.count) every <- exprNodeOpt(a, throttle.data.every) - } yield Some( - cloneNode( - a, - throttle, - throttle.data.copy(every = every, count = count) - ) - ) + } 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, - id = id, - format = format, - throttle = throttle - ) + } yield { + val dataCopy = data.copy( + params = params, + id = id, + format = format, + throttle = throttle ) - ) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) + } override def specIncludeAnnotatedNode( a: In, @@ -627,14 +603,11 @@ object ExpandTemplates extends AstTransformer for { params <- formalParamList(a, data.params) priority <- exprNodeOpt(a, data.priority) - } yield ( - (), - cloneAnnotatedNode( - a, - aNode, - data.copy(params = params, priority = priority) - ) - ) + } yield { + val dataCopy = data.copy(params = params, priority = priority) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) + } override def specLocAnnotatedNode( a: In, From 7404f063cd9f8128f1948e77c42af16cf626e2df Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 13 Oct 2026 08:03:02 -0700 Subject: [PATCH 25/51] Refactor ExpandTemplates --- .../scala/transform/ExpandTemplates.scala | 200 +++++++----------- 1 file changed, 80 insertions(+), 120 deletions(-) diff --git a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala index f9af57a10..4aa206a88 100644 --- a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala +++ b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala @@ -476,14 +476,11 @@ object ExpandTemplates extends AstTransformer val data = aNode._2.data for { instance <- qualIdentNode(a, data.instance) - } yield ( - (), - cloneAnnotatedNode( - a, - aNode, - data.copy(instance = instance) - ) - ) + } yield { + val dataCopy = data.copy(instance = instance) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) + } override def specConnectionGraphAnnotatedNode( a: In, @@ -617,14 +614,11 @@ object ExpandTemplates extends AstTransformer for { symbol <- qualIdentNode(a, data.symbol) (_, file) <- defaultNode(a, data.file) - } yield ( - (), - cloneAnnotatedNode( - a, - aNode, - data.copy(symbol = symbol, file = file) - ) - ) + } yield { + val dataCopy = data.copy(symbol = symbol, file = file) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) + } override def specParamAnnotatedNode( a: In, @@ -637,20 +631,17 @@ object ExpandTemplates extends AstTransformer id <- exprNodeOpt(a, data.id) setOpcode <- exprNodeOpt(a, data.setOpcode) saveOpcode <- exprNodeOpt(a, data.saveOpcode) - } yield ( - (), - cloneAnnotatedNode( - a, - aNode, - data.copy( - typeName = typeName, - default = default, - id = id, - setOpcode = setOpcode, - saveOpcode = saveOpcode - ) + } 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, @@ -658,41 +649,30 @@ object ExpandTemplates extends AstTransformer ) = 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, - port = port, - priority = priority, - queueFull = queueFull - ) + } yield { + val dataCopy = data.copy( + size = size, + port = port, + priority = priority, + queueFull = queueFull ) - ) - case data @ Ast.SpecPortInstance.Special(_, _, _, _, _) => + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) + } + case data : Ast.SpecPortInstance.Special => for { priority <- exprNodeOpt(a, data.priority) queueFull <- defaultNodeOpt(a, data.queueFull) } yield { - ( - (), - cloneAnnotatedNode( - a, - aNode, - data.copy( - priority = priority, - queueFull = queueFull - ) - ) - ) + val dataCopy = data.copy(priority = priority, queueFull = queueFull) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) } } @@ -704,14 +684,11 @@ object ExpandTemplates extends AstTransformer for { (_, port1) <- defaultNode(a, data.port1) (_, port2) <- defaultNode(a, data.port2) - } yield ( - (), - cloneAnnotatedNode( - a, - aNode, - data.copy(port1 = port1, port2 = port2) - ) - ) + } yield { + val dataCopy = data.copy(port1 = port1, port2 = port2) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) + } override def specRecordAnnotatedNode( a: In, @@ -721,14 +698,11 @@ object ExpandTemplates extends AstTransformer for { (_, recordType) <- matchTypeName(a, data.recordType) id <- exprNodeOpt(a, data.id) - } yield ( - (), - cloneAnnotatedNode( - a, - aNode, - data.copy(recordType = recordType, id = id) - ) - ) + } yield { + val dataCopy = data.copy(recordType = recordType, id = id) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) + } override def specStateMachineInstanceAnnotatedNode( a: In, @@ -738,14 +712,11 @@ object ExpandTemplates extends AstTransformer for { stateMachine <- qualIdentNode(a, data.stateMachine) priority <- exprNodeOpt(a, data.priority) - } yield ( - (), - cloneAnnotatedNode( - a, - aNode, - data.copy(stateMachine = stateMachine, priority = priority) - ) - ) + } yield { + val dataCopy = data.copy(stateMachine = stateMachine, priority = priority) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) + } override def specTlmChannelAnnotatedNode( a: In, @@ -768,20 +739,17 @@ object ExpandTemplates extends AstTransformer 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, - id = id, - format = cloneStringNodeOpt(a, data.format), - low = low, - high = high - ) + } 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, @@ -795,29 +763,24 @@ object ExpandTemplates extends AstTransformer 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)) - ) - ) + 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, - channelName = channelName - ) - ) + } yield { + val dataCopy = node.data.copy( + componentInstance = componentInstance, + channelName = channelName ) - ) + val nodeCopy = cloneNode(a, node, dataCopy) + val channelIdCopy = Ast.TlmPacketMember.TlmChannelIdentifier(nodeCopy) + ((), channelIdCopy) + } } } @@ -825,18 +788,15 @@ object ExpandTemplates extends AstTransformer id <- exprNodeOpt(a, data.id) (_, group) <- matchExprNode(a, data.group) members <- transformList(a, data.members, tlmPacketMember) - } yield ( - (), - cloneAnnotatedNode( - a, - aNode, - data.copy( - id = id, - group = group, - members = members - ) + } yield { + val dataCopy = data.copy( + id = id, + group = group, + members = members ) - ) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) + } override def specTopPortAnnotatedNode( a: In, From 14c498ef4dd569c9b56022f81ef93350421192eb Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 13 Oct 2026 08:11:42 -0700 Subject: [PATCH 26/51] Refactor ExpandTemplates --- .../scala/transform/ExpandTemplates.scala | 80 +++++++------------ 1 file changed, 31 insertions(+), 49 deletions(-) diff --git a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala index 4aa206a88..4ae251685 100644 --- a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala +++ b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala @@ -804,14 +804,11 @@ object ExpandTemplates extends AstTransformer ) = val data = aNode._2.data for (underlyingPort <- portInstanceIdentifierNode(a, data.underlyingPort)) - yield ( - (), - cloneAnnotatedNode( - a, - aNode, - data.copy(underlyingPort = underlyingPort) - ) - ) + yield { + val dataCopy = data.copy(underlyingPort = underlyingPort) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) + } override def specTlmPacketSetAnnotatedNode( a: In, @@ -826,29 +823,23 @@ object ExpandTemplates extends AstTransformer for { componentInstance <- qualIdentNode(a, data.componentInstance) (_, channelName) <- defaultNode(a, data.channelName) - } yield ( - (), - cloneNode( - a, - node, - data.copy( - componentInstance = componentInstance, - channelName = channelName - ) + } yield { + val dataCopy = data.copy( + componentInstance = componentInstance, + channelName = channelName ) - ) + val nodeCopy = cloneNode(a, node, dataCopy) + ((), nodeCopy) + } for { members <- transformFlatList(a, data.members, matchTlmPacketSetMember) omitted <- transformList(a, data.omitted, tlmChannelIdentifier) - } yield ( - (), - cloneAnnotatedNode( - a, - aNode, - data.copy(members = members, omitted = omitted) - ) - ) + } yield { + val dataCopy = data.copy(members = members, omitted = omitted) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) + } override def specInterfaceImportAnnotatedNode( a: In, @@ -857,14 +848,11 @@ object ExpandTemplates extends AstTransformer val data = aNode._2.data for { sym <- qualIdentNode(a, data.sym) - } yield ( - (), - cloneAnnotatedNode( - a, - aNode, - data.copy(sym = sym) - ) - ) + } yield { + val dataCopy = data.copy(sym = sym) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) + } override def defModuleTemplateAnnotatedNode( a: In, @@ -897,14 +885,11 @@ object ExpandTemplates extends AstTransformer members <- transformFlatList(a, data.members, matchModuleMember) a <- Right(a.copy(templateDefId = None)) } - yield ( - (), - cloneAnnotatedNode( - a, - aNode, - data.copy(params = params, members = members) - ) - ) + yield { + val dataCopy = data.copy(params = params, members = members) + val node = cloneAnnotatedNode(a, aNode, dataCopy) + ((), node) + } override def defModuleAnnotatedNode( a: Analysis, @@ -966,14 +951,11 @@ object ExpandTemplates extends AstTransformer ): 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) - ) + 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)) } From 3431b941e97e5c95eeeb23d22df6e03f4096345d Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 13 Oct 2026 08:20:44 -0700 Subject: [PATCH 27/51] Refactor ExpandTemplates --- .../src/main/scala/transform/ExpandTemplates.scala | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala index 4ae251685..dc2966383 100644 --- a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala +++ b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala @@ -60,15 +60,9 @@ object ExpandTemplates extends AstTransformer a: In, aNode: Ast.Annotated[AstNode[T]] ) = { - a.templateExpansionId match { - // We are not currently in a template expansion. - // Leave the node alone. - case None => Right((), aNode) - case Some(_) => - val (pre, node, post) = aNode - for ((_, inter) <- defaultNode(a, node)) - yield ((), (pre, inter, post)) - } + val (pre, node, post) = aNode + val node1 = cloneNode(a, node, node.data) + Right((), (pre, node1, post)) } override def exprArrayNode( From 44839b050507b13b48cddd75032aed627c65ab3a Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 13 Oct 2026 08:31:31 -0700 Subject: [PATCH 28/51] Refactor ExpandTemplates --- .../scala/transform/ExpandTemplates.scala | 35 +++++++++---------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala index dc2966383..d88742b0e 100644 --- a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala +++ b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala @@ -1042,14 +1042,13 @@ object ExpandTemplates extends AstTransformer for { interfaceInstance <- qualIdentNode(a, pii.data.interfaceInstance) (_, portName) <- defaultNode(a, pii.data.portName) - } yield cloneNode( - a, - pii, - pii.data.copy( + } yield { + val dataCopy = pii.data.copy( interfaceInstance = interfaceInstance, portName = portName ) - ) + cloneNode(a, pii, dataCopy) + } } private def qualIdentNode( @@ -1094,15 +1093,14 @@ object ExpandTemplates extends AstTransformer for { size <- exprNodeOpt(a, data.size) (_, typeName) <- matchTypeName(a, data.typeName) - } yield cloneAnnotatedNode( - a, - aNode, - data.copy( - size = size, - typeName = typeName, - format = cloneStringNodeOpt(a, data.format) - ) - ) + } yield { + val dataCopy = data.copy( + size = size, + typeName = typeName, + format = cloneStringNodeOpt(a, data.format) + ) + cloneAnnotatedNode(a, aNode, dataCopy) + } private def transitionExpr( a: In, @@ -1111,11 +1109,10 @@ object ExpandTemplates extends AstTransformer for { actions <- transformList(a, node.data.actions, defaultNode) target <- qualIdentNode(a, node.data.target) - } yield cloneNode( - a, - node, - node.data.copy(actions = actions, target = target) - ) + } yield { + val dataCopy = node.data.copy(actions = actions, target = target) + cloneNode(a, node, dataCopy) + } private def transitionOrDo( a: In, From c59d1b540acb759ce2d60250a34f87f01786dafc Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 13 Oct 2026 08:37:17 -0700 Subject: [PATCH 29/51] Refactor ExpandTemplates --- compiler/lib/src/main/scala/transform/ExpandTemplates.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala index d88742b0e..57c2adb6d 100644 --- a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala +++ b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala @@ -1006,7 +1006,9 @@ object ExpandTemplates extends AstTransformer ) } yield { // Paste the expanded template body into the expansion specifier - (pre, AstNode.create(data.copy(members = Some(members)), node.id), post) + val dataCopy = data.copy(members = Some(members)) + val nodeCopy = AstNode.create(dataCopy, node.id) + (pre, nodeCopy, post) } } From 40c439dd4049405acd5986ea84f6c2ab8e1e69ba Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 13 Oct 2026 08:45:21 -0700 Subject: [PATCH 30/51] Refactor ExpandTemplates --- .../scala/transform/ExpandTemplates.scala | 148 +++++++++--------- 1 file changed, 74 insertions(+), 74 deletions(-) diff --git a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala index 57c2adb6d..5a9e2904f 100644 --- a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala +++ b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala @@ -57,7 +57,7 @@ object ExpandTemplates extends AstTransformer ) = Right((), cloneNode(a, node, node.data)) override def defaultAnnotatedNode[T]( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[T]] ) = { val (pre, node, post) = aNode @@ -66,7 +66,7 @@ object ExpandTemplates extends AstTransformer } override def exprArrayNode( - a: In, + a: Analysis, node: AstNode[Ast.Expr], e: Ast.ExprArray ) = @@ -74,7 +74,7 @@ object ExpandTemplates extends AstTransformer yield ((), cloneNode(a, node, Ast.ExprArray(result))) override def exprArraySubscriptNode( - a: In, + a: Analysis, node: AstNode[Ast.Expr], e: Ast.ExprArraySubscript ) = @@ -85,7 +85,7 @@ object ExpandTemplates extends AstTransformer yield ((), cloneNode(a, node, Ast.ExprArraySubscript(e1, e2))) override def exprBinopNode( - a: In, node: AstNode[Ast.Expr], + a: Analysis, node: AstNode[Ast.Expr], e: Ast.ExprBinop ) = for { @@ -95,15 +95,15 @@ object ExpandTemplates extends AstTransformer yield ((), cloneNode(a, node, Ast.ExprBinop(e1, e.op, e2))) override def exprDotNode( - a: In, + a: Analysis, 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)))) override def exprParenNode( - a: In, + a: Analysis, node: AstNode[Ast.Expr], e: Ast.ExprParen ) = @@ -119,7 +119,7 @@ object ExpandTemplates extends AstTransformer yield ((), cloneNode(a, node, Ast.ExprStruct(result))) override def exprUnopNode( - a: In, + a: Analysis, node: AstNode[Ast.Expr], e: Ast.ExprUnop ) = @@ -127,7 +127,7 @@ object ExpandTemplates extends AstTransformer yield ((), cloneNode(a, node, Ast.ExprUnop(e.op, ec))) override def exprSizeOfNode( - a: In, + a: Analysis, node: AstNode[Ast.Expr], e: Ast.ExprSizeOf ) = @@ -135,7 +135,7 @@ object ExpandTemplates extends AstTransformer yield ((), cloneNode(a, node, Ast.ExprSizeOf(result))) override def typeNameQualIdentNode( - a: In, + a: Analysis, node: AstNode[Ast.TypeName], tn: Ast.TypeNameQualIdent ) = { @@ -144,7 +144,7 @@ object ExpandTemplates extends AstTransformer } override def typeNameStringNode( - a: In, + a: Analysis, node: AstNode[Ast.TypeName], tn: Ast.TypeNameString ) = @@ -157,7 +157,7 @@ object ExpandTemplates extends AstTransformer 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 @@ -165,7 +165,7 @@ object ExpandTemplates extends AstTransformer yield ((), cloneAnnotatedNode(a, aNode, data.copy(typeName = ty))) override def defArrayAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefArray]] ) = { val data = aNode._2.data @@ -186,7 +186,7 @@ object ExpandTemplates extends AstTransformer } override def defComponentAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefComponent]] ) = { val data = aNode._2.data @@ -195,7 +195,7 @@ object ExpandTemplates extends AstTransformer } override def defComponentInstanceAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefComponentInstance]] ) = { val data = aNode._2.data @@ -225,7 +225,7 @@ object ExpandTemplates extends AstTransformer } override def defInterfaceAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefInterface]] ) = { val data = aNode._2.data @@ -234,7 +234,7 @@ object ExpandTemplates extends AstTransformer } override def defConstantAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefConstant]] ) = val data = aNode._2.data @@ -246,7 +246,7 @@ object ExpandTemplates extends AstTransformer } override def defEnumAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefEnum]] ) = val data = aNode._2.data @@ -269,7 +269,7 @@ object ExpandTemplates extends AstTransformer } override def defPortAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefPort]] ) = val data = aNode._2.data @@ -289,7 +289,7 @@ object ExpandTemplates extends AstTransformer defaultAnnotatedNode(in, node) override def defStateMachineAnnotatedNodeInternal( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefStateMachine]], members: List[Ast.StateMachineMember] ) = @@ -298,7 +298,7 @@ object ExpandTemplates extends AstTransformer yield ((), cloneAnnotatedNode(a, aNode, data.copy(members = Some(members)))) override def defStateMachineAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefStateMachine]] ) = val data = aNode._2.data @@ -308,7 +308,7 @@ object ExpandTemplates extends AstTransformer } override def defActionAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefAction]] ) = val data = aNode._2.data @@ -317,7 +317,7 @@ object ExpandTemplates extends AstTransformer } yield ((), cloneAnnotatedNode(a, aNode, data.copy(typeName = typeName))) override def defChoiceAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefChoice]] ) = val data = aNode._2.data @@ -336,7 +336,7 @@ object ExpandTemplates extends AstTransformer } override def defGuardAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefGuard]] ) = val data = aNode._2.data @@ -344,7 +344,7 @@ object ExpandTemplates extends AstTransformer yield ((), cloneAnnotatedNode(a, aNode, data.copy(typeName = typeName))) override def defSignalAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefSignal]] ) = val data = aNode._2.data @@ -352,7 +352,7 @@ object ExpandTemplates extends AstTransformer yield ((), cloneAnnotatedNode(a, aNode, data.copy(typeName = typeName))) override def defStateAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefState]] ) = val data = aNode._2.data @@ -360,7 +360,7 @@ object ExpandTemplates extends AstTransformer yield ((), cloneAnnotatedNode(a, aNode, data.copy(members = members))) override def specInitialTransitionAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecInitialTransition]] ) = val data = aNode._2.data @@ -368,7 +368,7 @@ object ExpandTemplates extends AstTransformer yield ((), cloneAnnotatedNode(a, aNode, data.copy(transition = transition))) override def specStateEntryAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecStateEntry]] ) = val data = aNode._2.data @@ -376,7 +376,7 @@ object ExpandTemplates extends AstTransformer yield ((), cloneAnnotatedNode(a, aNode, data.copy(actions = actions))) override def specStateExitAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecStateExit]] ) = val data = aNode._2.data @@ -384,7 +384,7 @@ object ExpandTemplates extends AstTransformer yield ((), cloneAnnotatedNode(a, aNode, data.copy(actions = actions))) override def specStateTransitionAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecStateTransition]] ) = val data = aNode._2.data @@ -403,7 +403,7 @@ object ExpandTemplates extends AstTransformer } override def defStructAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefStruct]] ) = val data = aNode._2.data @@ -417,7 +417,7 @@ object ExpandTemplates extends AstTransformer } override def defTopologyAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefTopology]] ) = val data = aNode._2.data @@ -431,7 +431,7 @@ object ExpandTemplates extends AstTransformer } override def defSystemAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefSystem]] ) = val data = aNode._2.data @@ -443,7 +443,7 @@ object ExpandTemplates extends AstTransformer } override def specCommandAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecCommand]] ) = val data = aNode._2.data @@ -464,7 +464,7 @@ object ExpandTemplates extends AstTransformer } override def specInstanceAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecInstance]] ) = val data = aNode._2.data @@ -477,13 +477,13 @@ object ExpandTemplates extends AstTransformer } override def specConnectionGraphAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecConnectionGraph]] ) = { val data = aNode._2.data def connection( - a: In, + a: Analysis, connection: Ast.SpecConnectionGraph.Connection ): Result[Ast.SpecConnectionGraph.Connection] = { for { @@ -524,7 +524,7 @@ object ExpandTemplates extends AstTransformer } override def specContainerAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecContainer]] ) = val data = aNode._2.data @@ -538,7 +538,7 @@ object ExpandTemplates extends AstTransformer } override def specEventAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecEvent]] ) = val data = aNode._2.data @@ -570,7 +570,7 @@ object ExpandTemplates extends AstTransformer } override def specIncludeAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecInclude]] ) = val data = aNode._2.data @@ -579,7 +579,7 @@ object ExpandTemplates extends AstTransformer } yield ((), cloneAnnotatedNode(a, aNode, data.copy(file = file))) override def specInitAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecInit]] ) = val data = aNode._2.data @@ -587,7 +587,7 @@ object ExpandTemplates extends AstTransformer yield ((), cloneAnnotatedNode(a, aNode, data.copy(phase=phase))) override def specInternalPortAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecInternalPort]] ) = val data = aNode._2.data @@ -601,7 +601,7 @@ object ExpandTemplates extends AstTransformer } override def specLocAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecLoc]] ) = val data = aNode._2.data @@ -615,7 +615,7 @@ object ExpandTemplates extends AstTransformer } override def specParamAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecParam]] ) = val data = aNode._2.data @@ -638,7 +638,7 @@ object ExpandTemplates extends AstTransformer } override def specPortInstanceAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecPortInstance]] ) = val data = aNode._2.data @@ -671,7 +671,7 @@ object ExpandTemplates extends AstTransformer } override def specPortMatchingAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecPortMatching]] ) = val data = aNode._2.data @@ -685,7 +685,7 @@ object ExpandTemplates extends AstTransformer } override def specRecordAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecRecord]] ) = val data = aNode._2.data @@ -699,7 +699,7 @@ object ExpandTemplates extends AstTransformer } override def specStateMachineInstanceAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecStateMachineInstance]] ) = val data = aNode._2.data @@ -713,12 +713,12 @@ object ExpandTemplates extends AstTransformer } override def specTlmChannelAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[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 @@ -746,12 +746,12 @@ object ExpandTemplates extends AstTransformer } override def specTlmPacketAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecTlmPacket]] ) = val data = aNode._2.data def tlmPacketMember( - a: In, + a: Analysis, member: Ast.TlmPacketMember ): Result[Ast.TlmPacketMember] = { member match { @@ -793,7 +793,7 @@ object ExpandTemplates extends AstTransformer } override def specTopPortAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecTopPort]] ) = val data = aNode._2.data @@ -805,12 +805,12 @@ object ExpandTemplates extends AstTransformer } override def specTlmPacketSetAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecTlmPacketSet]] ) = val data = aNode._2.data def tlmChannelIdentifier( - a: In, + a: Analysis, node: AstNode[Ast.TlmChannelIdentifier] ): ResultNode[Ast.TlmChannelIdentifier] = val data = node.data @@ -836,7 +836,7 @@ object ExpandTemplates extends AstTransformer } override def specInterfaceImportAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecImport]] ) = val data = aNode._2.data @@ -849,14 +849,14 @@ object ExpandTemplates extends AstTransformer } override def defModuleTemplateAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[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 @@ -903,7 +903,7 @@ object ExpandTemplates extends AstTransformer val data = node.data data.members match { // Members are already there; nothing to do - case Some(members) => Right((), aNode) + case Some(members) => Right((), aNode) // Members are not there; expand case None => (resultAdapter(expandTemplate))(a, aNode) } @@ -940,7 +940,7 @@ object ExpandTemplates extends AstTransformer } private def cloneQualIdentNode( - a: In, + a: Analysis, node: AstNode[Ast.QualIdent] ): AstNode[Ast.QualIdent] = { node.data match { @@ -956,7 +956,7 @@ object ExpandTemplates extends AstTransformer } private def cloneStringNodeOpt( - a: In, + a: Analysis, node: Option[AstNode[String]] ): Option[AstNode[String]] = node match { @@ -976,7 +976,7 @@ object ExpandTemplates extends AstTransformer } private def defEnumConstantAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefEnumConstant]] ): Result.Result[Ast.Annotated[AstNode[Ast.DefEnumConstant]]] = val data = aNode._2.data @@ -993,7 +993,7 @@ object ExpandTemplates extends AstTransformer for { // Look up the template def tmpl <- a.getTemplateSymbol(data.template.id) - // Clone the template body, recording the expansion node so that + // Clone the template body, recording the expansion node so that // cloned nodes point back at the expansion site. // Record the template definition too for diagnostics. members <- transformFlatList( @@ -1013,7 +1013,7 @@ object ExpandTemplates extends AstTransformer } private def exprNodeOpt( - a: In, + a: Analysis, node: Option[AstNode[Ast.Expr]] ): Result.Result[Option[AstNode[Ast.Expr]]] = node match { @@ -1024,7 +1024,7 @@ object ExpandTemplates extends AstTransformer } private def formalAnnotatatedParam( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.FormalParam]] ) = val data = aNode._2.data @@ -1032,13 +1032,13 @@ object ExpandTemplates extends AstTransformer yield cloneAnnotatedNode(a, aNode, data.copy(typeName = ty)) private def formalParamList( - a: In, + a: Analysis, aNode: Ast.FormalParamList ) = for (node <- transformList(a, aNode, resultAdapter(formalAnnotatatedParam))) yield node private def portInstanceIdentifierNode( - a: In, + a: Analysis, pii: AstNode[Ast.PortInstanceIdentifier] ): Result.Result[AstNode[Ast.PortInstanceIdentifier]] = { for { @@ -1054,13 +1054,13 @@ object ExpandTemplates extends AstTransformer } private def qualIdentNode( - a: In, + a: Analysis, node: AstNode[Ast.QualIdent] ): Result.Result[AstNode[Ast.QualIdent]] = Right(cloneQualIdentNode(a, node)) private def qualIdentNodeOpt( - a: In, + a: Analysis, qi: Option[AstNode[Ast.QualIdent]] ): Result.Result[Option[AstNode[Ast.QualIdent]]] = { qi match { @@ -1088,7 +1088,7 @@ object ExpandTemplates extends AstTransformer } private def structTypeMemberAnnotatedNode( - a: In, + a: Analysis, aNode: Ast.Annotated[AstNode[Ast.StructTypeMember]] ) = val data = aNode._2.data @@ -1105,7 +1105,7 @@ object ExpandTemplates extends AstTransformer } private def transitionExpr( - a: In, + a: Analysis, node: AstNode[Ast.TransitionExpr] ): Result.Result[AstNode[Ast.TransitionExpr]] = for { @@ -1117,7 +1117,7 @@ object ExpandTemplates extends AstTransformer } private def transitionOrDo( - a: In, + a: Analysis, transitionOrDo: Ast.TransitionOrDo ) = transitionOrDo match @@ -1127,9 +1127,9 @@ object ExpandTemplates extends AstTransformer case Ast.TransitionOrDo.Do(actions) => for (result <- transformList(a, actions, defaultNode)) yield Ast.TransitionOrDo.Do(result) - + private def typeNameNodeOpt( - a: In, + a: Analysis, node: Option[AstNode[Ast.TypeName]] ): Result.Result[Option[AstNode[Ast.TypeName]]] = node match { From 06f86b0871fab480c60fcde9e4a536f2b18a67c3 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 13 Oct 2026 08:56:22 -0700 Subject: [PATCH 31/51] Refactor analysis --- .../scala/analysis/CheckSemantics/CheckTemplateDefs.scala | 2 +- .../lib/src/main/scala/transform/ExpandTemplates.scala | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/compiler/lib/src/main/scala/analysis/CheckSemantics/CheckTemplateDefs.scala b/compiler/lib/src/main/scala/analysis/CheckSemantics/CheckTemplateDefs.scala index 61a92d176..09777f515 100644 --- a/compiler/lib/src/main/scala/analysis/CheckSemantics/CheckTemplateDefs.scala +++ b/compiler/lib/src/main/scala/analysis/CheckSemantics/CheckTemplateDefs.scala @@ -24,7 +24,7 @@ object CheckTemplateDefs Locations.get(defId) ) ) - case None => Right(a) + case None => Right(()) } a <- Right(a.copy(templateDefId = Some(node.id))) a <- visitList(a, data.members, matchModuleMember) diff --git a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala index 5a9e2904f..5a06ebc8f 100644 --- a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala +++ b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala @@ -874,10 +874,9 @@ object ExpandTemplates extends AstTransformer } for { - a <- Right(a.copy(templateDefId = Some(node.id))) - params <- transformList(a, data.params, templateParam) - members <- transformFlatList(a, data.members, matchModuleMember) - a <- Right(a.copy(templateDefId = None)) + a1 <- Right(a.copy(templateDefId = Some(node.id))) + params <- transformList(a1, data.params, templateParam) + members <- transformFlatList(a1, data.members, matchModuleMember) } yield { val dataCopy = data.copy(params = params, members = members) From 1f16a9e69f2b1e21aa432036fe79678a4e92ad0b Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 13 Oct 2026 09:04:02 -0700 Subject: [PATCH 32/51] Add outline of CheckTemplateExpansions --- .../CheckTemplateExpansions.scala | 22 +++++++++++++++++++ .../ExpandSyntaxAndEnterSymbols.scala | 2 +- compiler/lib/src/main/scala/util/Error.scala | 16 +++++++++++++- 3 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 compiler/lib/src/main/scala/analysis/CheckSemantics/CheckTemplateExpansions.scala 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 000000000..646f49ac0 --- /dev/null +++ b/compiler/lib/src/main/scala/analysis/CheckSemantics/CheckTemplateExpansions.scala @@ -0,0 +1,22 @@ +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]] + ) = Right(a) + + override def specTemplateExpandAnnotatedNode( + a: Analysis, + aNode: Ast.Annotated[AstNode[Ast.SpecTemplateExpand]] + ) = 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 2df372f13..5fe3c2f5a 100644 --- a/compiler/lib/src/main/scala/analysis/CheckSemantics/ExpandSyntaxAndEnterSymbols.scala +++ b/compiler/lib/src/main/scala/analysis/CheckSemantics/ExpandSyntaxAndEnterSymbols.scala @@ -17,7 +17,7 @@ object ExpandSyntaxAndEnterSymbols { tul <- AddStateEnums.transUnitList(tul) a <- EnterSymbols.visitList(a, tul, EnterSymbols.transUnit) a <- CheckTemplateDefs.visitList(a, tul, CheckTemplateDefs.transUnit) - // TODO: CheckTemplateExpansions + a <- CheckTemplateExpansions.visitList(a, tul, CheckTemplateExpansions.transUnit) a <- CheckTemplateUses.visitList(a, tul, CheckTemplateUses.transUnit) tul <- ExpandTemplates.transformList(a, tul, ExpandTemplates.transUnit) a <- EnterTemplateExpansionSymbols.visitList(a, tul, EnterTemplateExpansionSymbols.transUnit) diff --git a/compiler/lib/src/main/scala/util/Error.scala b/compiler/lib/src/main/scala/util/Error.scala index f17f1e8bb..01f2858e3 100644 --- a/compiler/lib/src/main/scala/util/Error.scala +++ b/compiler/lib/src/main/scala/util/Error.scala @@ -387,10 +387,18 @@ sealed trait Error { 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:") @@ -883,6 +891,12 @@ object SemanticError { 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, From 9e01546855b47b60d80cd25b459c88704aca5dce Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 13 Oct 2026 09:37:31 -0700 Subject: [PATCH 33/51] Revise CheckTemplateExpansions --- .../CheckTemplateExpansions.scala | 40 +++++++++++++++++-- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/compiler/lib/src/main/scala/analysis/CheckSemantics/CheckTemplateExpansions.scala b/compiler/lib/src/main/scala/analysis/CheckSemantics/CheckTemplateExpansions.scala index 646f49ac0..132bc4fad 100644 --- a/compiler/lib/src/main/scala/analysis/CheckSemantics/CheckTemplateExpansions.scala +++ b/compiler/lib/src/main/scala/analysis/CheckSemantics/CheckTemplateExpansions.scala @@ -12,11 +12,43 @@ object CheckTemplateExpansions override def defModuleTemplateAnnotatedNode( a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefModuleTemplate]] - ) = Right(a) + ) = + 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 specTemplateExpandAnnotatedNode( + override def specTemplateExpandAnnotatedNodeExpanded( a: Analysis, - aNode: Ast.Annotated[AstNode[Ast.SpecTemplateExpand]] - ) = Right(a) + 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) + } } From 672eb469fb57edcf4848727da0e39351df28919e Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 13 Oct 2026 09:45:49 -0700 Subject: [PATCH 34/51] Rename Expand Syntax To conform to the style of the other analysis passes --- docs/wiki/Checking-Semantics.asciidoc | 2 +- ...ymbols.asciidoc => Expand-Syntax-and-Enter-Symbols.asciidoc} | 0 docs/wiki/fpp-filenames.asciidoc | 2 +- docs/wiki/fpp-locate-defs.asciidoc | 2 +- docs/wiki/fpp-syntax.asciidoc | 2 +- docs/wiki/fpp-to-fpp.asciidoc | 2 +- 6 files changed, 5 insertions(+), 5 deletions(-) rename docs/wiki/{Expanding-Syntax-and-Entering-Symbols.asciidoc => Expand-Syntax-and-Enter-Symbols.asciidoc} (100%) diff --git a/docs/wiki/Checking-Semantics.asciidoc b/docs/wiki/Checking-Semantics.asciidoc index a0331d10b..43a56dc1e 100644 --- a/docs/wiki/Checking-Semantics.asciidoc +++ b/docs/wiki/Checking-Semantics.asciidoc @@ -16,7 +16,7 @@ the results of syntax expansion. == Procedure -. https://github.com/nasa/fpp/wiki/Expanding-Syntax-and-Entering-Symbols[Expand syntax and enter symbols] +. https://github.com/nasa/fpp/wiki/Expand-Syntax-and-Enter-Symbols[Expand syntax and enter symbols] for _a_ and _tul_. . https://github.com/nasa/fpp/wiki/Construct-Implied-Use-Map[Construct the implied use map] for _a_ and _tul_. diff --git a/docs/wiki/Expanding-Syntax-and-Entering-Symbols.asciidoc b/docs/wiki/Expand-Syntax-and-Enter-Symbols.asciidoc similarity index 100% rename from docs/wiki/Expanding-Syntax-and-Entering-Symbols.asciidoc rename to docs/wiki/Expand-Syntax-and-Enter-Symbols.asciidoc diff --git a/docs/wiki/fpp-filenames.asciidoc b/docs/wiki/fpp-filenames.asciidoc index 731b26fbc..18fe46394 100644 --- a/docs/wiki/fpp-filenames.asciidoc +++ b/docs/wiki/fpp-filenames.asciidoc @@ -28,7 +28,7 @@ by running `fpp-to-cpp` with the corresponding options. . Parse each of the files in _fl_, generating a list _tul_ of translation units. . Run the first three steps of -https://github.com/nasa/fpp/wiki/Expanding-Syntax-and-Entering-Symbols[expanding +https://github.com/nasa/fpp/wiki/Expand-Syntax-and-Enter-Symbols[expanding syntax and entering symbols] (up to template resolution) on _tul_. . Walk the AST and identify the definitions that cause C++ or JSON files to diff --git a/docs/wiki/fpp-locate-defs.asciidoc b/docs/wiki/fpp-locate-defs.asciidoc index 2c29049f5..4823964d3 100644 --- a/docs/wiki/fpp-locate-defs.asciidoc +++ b/docs/wiki/fpp-locate-defs.asciidoc @@ -34,7 +34,7 @@ symbol defined in _fl_. . Parse each of the files in _fl_, generating a list _tul_ of translation units. -. https://github.com/nasa/fpp/wiki/Expanding-Syntax-and-Entering-Symbols[Expand +. https://github.com/nasa/fpp/wiki/Expand-Syntax-and-Enter-Symbols[Expand syntax and enter symbols] for _tul_. . For each definition _d_ appearing in _tul_ write out a location specifier diff --git a/docs/wiki/fpp-syntax.asciidoc b/docs/wiki/fpp-syntax.asciidoc index 2d58602a4..ec9345ffa 100644 --- a/docs/wiki/fpp-syntax.asciidoc +++ b/docs/wiki/fpp-syntax.asciidoc @@ -33,7 +33,7 @@ the individual ASTs. message. . If `-e` is present, then -https://github.com/nasa/fpp/wiki/Expanding-Syntax-and-Entering-Symbols[expand +https://github.com/nasa/fpp/wiki/Expand-Syntax-and-Enter-Symbols[expand syntax and enter symbols], yielding a new list _tul'_ of translation units. diff --git a/docs/wiki/fpp-to-fpp.asciidoc b/docs/wiki/fpp-to-fpp.asciidoc index ae0ce4aba..e31db929f 100644 --- a/docs/wiki/fpp-to-fpp.asciidoc +++ b/docs/wiki/fpp-to-fpp.asciidoc @@ -44,7 +44,7 @@ errors that occur. include cycles. Upon detecting an include cycle, halt with an error message. . If `-e` is present, then -https://github.com/nasa/fpp/wiki/Expanding-Syntax-and-Entering-Symbols[expand +https://github.com/nasa/fpp/wiki/Expand-Syntax-and-Enter-Symbols[expand syntax and enter symbols]. . Write out the formatted source code. From 50f1f0f433863f77bb0593167545ba44e8696905 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 13 Oct 2026 10:01:22 -0700 Subject: [PATCH 35/51] Revise ExpandSyntax Add CheckTemplateDefinitions --- ...s.scala => CheckTemplateDefinitions.scala} | 2 +- .../ExpandSyntaxAndEnterSymbols.scala | 2 +- docs/wiki/Check-Template-Definitions.asciidoc | 27 +++++++++++++++++++ .../Expand-Syntax-and-Enter-Symbols.asciidoc | 5 ++++ 4 files changed, 34 insertions(+), 2 deletions(-) rename compiler/lib/src/main/scala/analysis/CheckSemantics/{CheckTemplateDefs.scala => CheckTemplateDefinitions.scala} (97%) create mode 100644 docs/wiki/Check-Template-Definitions.asciidoc diff --git a/compiler/lib/src/main/scala/analysis/CheckSemantics/CheckTemplateDefs.scala b/compiler/lib/src/main/scala/analysis/CheckSemantics/CheckTemplateDefinitions.scala similarity index 97% rename from compiler/lib/src/main/scala/analysis/CheckSemantics/CheckTemplateDefs.scala rename to compiler/lib/src/main/scala/analysis/CheckSemantics/CheckTemplateDefinitions.scala index 09777f515..e11bcbf20 100644 --- a/compiler/lib/src/main/scala/analysis/CheckSemantics/CheckTemplateDefs.scala +++ b/compiler/lib/src/main/scala/analysis/CheckSemantics/CheckTemplateDefinitions.scala @@ -4,7 +4,7 @@ import fpp.compiler.ast._ import fpp.compiler.util._ /** Check template definitions */ -object CheckTemplateDefs +object CheckTemplateDefinitions extends Analyzer with ModuleAnalyzer { diff --git a/compiler/lib/src/main/scala/analysis/CheckSemantics/ExpandSyntaxAndEnterSymbols.scala b/compiler/lib/src/main/scala/analysis/CheckSemantics/ExpandSyntaxAndEnterSymbols.scala index 5fe3c2f5a..a8cc751ce 100644 --- a/compiler/lib/src/main/scala/analysis/CheckSemantics/ExpandSyntaxAndEnterSymbols.scala +++ b/compiler/lib/src/main/scala/analysis/CheckSemantics/ExpandSyntaxAndEnterSymbols.scala @@ -16,7 +16,7 @@ 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 <- CheckTemplateDefinitions.visitList(a, tul, CheckTemplateDefinitions.transUnit) a <- CheckTemplateExpansions.visitList(a, tul, CheckTemplateExpansions.transUnit) a <- CheckTemplateUses.visitList(a, tul, CheckTemplateUses.transUnit) tul <- ExpandTemplates.transformList(a, tul, ExpandTemplates.transUnit) diff --git a/docs/wiki/Check-Template-Definitions.asciidoc b/docs/wiki/Check-Template-Definitions.asciidoc new file mode 100644 index 000000000..49bd0807f --- /dev/null +++ b/docs/wiki/Check-Template-Definitions.asciidoc @@ -0,0 +1,27 @@ +This algorithm traverses a source model and checks template +definitions for correctness. + +== Input + +. A list _tul_ of translation units. + +. An +https://github.com/nasa/fpp/wiki/Analysis-Data-Structure[analysis +data structure] _a_ +representing the results of analysis so far. + +== Output + +. None if the check passes; otherwise an error. + +== Procedure + +Currently this analysis does the following: + +. Check that no template definition transitively contains a template definition. + +. Check that no template definition transitively contains a template expansion. + +Eventually we will implement all of the checking described in the +https://nasa.github.io/fpp/fpp-spec.html#Definitions_Module-Template-Definitions_Semantics[FPP +specification]. diff --git a/docs/wiki/Expand-Syntax-and-Enter-Symbols.asciidoc b/docs/wiki/Expand-Syntax-and-Enter-Symbols.asciidoc index 4a9307bba..3569e967b 100644 --- a/docs/wiki/Expand-Syntax-and-Enter-Symbols.asciidoc +++ b/docs/wiki/Expand-Syntax-and-Enter-Symbols.asciidoc @@ -37,6 +37,11 @@ machine definition that has a body has a state enum definition. . https://github.com/nasa/fpp/wiki/Enter-Symbols[Enter symbols] for _a_ and _tul_. +. https://github.com/nasa/fpp/wiki/Check-Template-Definitions[Check template + definitions] for _a_ and _tul_. + +. TODO: Check template expansions + . https://github.com/nasa/fpp/wiki/Check-Template-Uses[Check template uses] for _a_ and _tul_. . https://github.com/nasa/fpp/wiki/Expand-Templates[Expand templates] for _a_ and _tul_, From 0c95945557029785011449a730db210c91a68411 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 13 Oct 2026 10:15:36 -0700 Subject: [PATCH 36/51] Revise ExpandSyntax --- docs/wiki/Check-Template-Expansions.asciidoc | 23 +++++++++++++++++++ .../Expand-Syntax-and-Enter-Symbols.asciidoc | 3 ++- 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 docs/wiki/Check-Template-Expansions.asciidoc diff --git a/docs/wiki/Check-Template-Expansions.asciidoc b/docs/wiki/Check-Template-Expansions.asciidoc new file mode 100644 index 000000000..c92e01ae1 --- /dev/null +++ b/docs/wiki/Check-Template-Expansions.asciidoc @@ -0,0 +1,23 @@ +This algorithm traverses a source model and checks template +expansions for correctness. +This check covers only pre-expanded `expand` specifiers, i.e., +expand specifiers written in the form `expand T { ... }`. + +== Input + +. A list _tul_ of translation units. + +. An +https://github.com/nasa/fpp/wiki/Analysis-Data-Structure[analysis +data structure] _a_ +representing the results of analysis so far. + +== Output + +. None if the check passes; otherwise an error. + +== Procedure + +. Check that no template expansion transitively contains a template definition. + +. Check that no template expansion transitively contains a template expansion. diff --git a/docs/wiki/Expand-Syntax-and-Enter-Symbols.asciidoc b/docs/wiki/Expand-Syntax-and-Enter-Symbols.asciidoc index 3569e967b..aab8921bc 100644 --- a/docs/wiki/Expand-Syntax-and-Enter-Symbols.asciidoc +++ b/docs/wiki/Expand-Syntax-and-Enter-Symbols.asciidoc @@ -40,7 +40,8 @@ machine definition that has a body has a state enum definition. . https://github.com/nasa/fpp/wiki/Check-Template-Definitions[Check template definitions] for _a_ and _tul_. -. TODO: Check template expansions +. https://github.com/nasa/fpp/wiki/Check-Template-Expansions[Check template + expansions] for _a_ and _tul_. . https://github.com/nasa/fpp/wiki/Check-Template-Uses[Check template uses] for _a_ and _tul_. From faaab98cbaf652640c63d829d388a392c14da6c5 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 13 Oct 2026 11:17:52 -0700 Subject: [PATCH 37/51] Revise fpp-check tests --- .../test/template/composition_invalid.fpp | 11 ---------- .../test/template/composition_invalid.ref.txt | 9 -------- .../test/template/expand_in_template_def.fpp | 9 ++++++++ .../template/expand_in_template_def.ref.txt | 9 ++++++++ .../test/template/invalid_nested.fpp | 22 ------------------- .../test/template/invalid_nested.ref.txt | 9 -------- .../test/template/nested_template_def.fpp | 7 ++++++ .../test/template/nested_template_def.ref.txt | 9 ++++++++ .../tools/fpp-check/test/template/tests.sh | 4 ++-- 9 files changed, 36 insertions(+), 53 deletions(-) delete mode 100644 compiler/tools/fpp-check/test/template/composition_invalid.fpp delete mode 100644 compiler/tools/fpp-check/test/template/composition_invalid.ref.txt create mode 100644 compiler/tools/fpp-check/test/template/expand_in_template_def.fpp create mode 100644 compiler/tools/fpp-check/test/template/expand_in_template_def.ref.txt delete mode 100644 compiler/tools/fpp-check/test/template/invalid_nested.fpp delete mode 100644 compiler/tools/fpp-check/test/template/invalid_nested.ref.txt create mode 100644 compiler/tools/fpp-check/test/template/nested_template_def.fpp create mode 100644 compiler/tools/fpp-check/test/template/nested_template_def.ref.txt 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 a5c9e08cd..000000000 --- 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 9df63fadb..000000000 --- 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 is 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 000000000..54621c4d9 --- /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 000000000..469ffdc57 --- /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 e52774a66..000000000 --- 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 a20441bde..000000000 --- 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 -enclosing template is 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_template_def.fpp b/compiler/tools/fpp-check/test/template/nested_template_def.fpp new file mode 100644 index 000000000..0b47b127c --- /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 000000000..f3c2f2542 --- /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/tests.sh b/compiler/tools/fpp-check/test/template/tests.sh index 711ed0c51..8a84ef5c4 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,10 +35,10 @@ 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_scope_resolution nested_scope_resolution_ok +nested_template_def param_body_def_different_group_ok param_conflict_body_def param_conflict_same_name_group From d673cac3d089e72a34022764c6b416d060da3625 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Tue, 13 Oct 2026 11:25:54 -0700 Subject: [PATCH 38/51] Revise fpp-check tests --- .../tools/fpp-check/test/template/nested_expand.fpp | 9 +++++++++ .../fpp-check/test/template/nested_expand.ref.txt | 9 +++++++++ .../test/template/source_expand_bad_args.fpp | 9 +++++++++ .../test/template/source_expand_bad_args.ref.txt | 9 +++++++++ .../fpp-check/test/template/source_expand_ok.fpp | 9 +++++++++ .../fpp-check/test/template/source_expand_ok.ref.txt | 0 .../test/template/source_expand_undefined_symbol.fpp | 9 +++++++++ .../template/source_expand_undefined_symbol.ref.txt | 6 ++++++ .../test/template/template_def_in_expand.fpp | 11 +++++++++++ .../test/template/template_def_in_expand.ref.txt | 9 +++++++++ compiler/tools/fpp-check/test/template/tests.sh | 5 +++++ 11 files changed, 85 insertions(+) create mode 100644 compiler/tools/fpp-check/test/template/nested_expand.fpp create mode 100644 compiler/tools/fpp-check/test/template/nested_expand.ref.txt create mode 100644 compiler/tools/fpp-check/test/template/source_expand_bad_args.fpp create mode 100644 compiler/tools/fpp-check/test/template/source_expand_bad_args.ref.txt create mode 100644 compiler/tools/fpp-check/test/template/source_expand_ok.fpp create mode 100644 compiler/tools/fpp-check/test/template/source_expand_ok.ref.txt create mode 100644 compiler/tools/fpp-check/test/template/source_expand_undefined_symbol.fpp create mode 100644 compiler/tools/fpp-check/test/template/source_expand_undefined_symbol.ref.txt create mode 100644 compiler/tools/fpp-check/test/template/template_def_in_expand.fpp create mode 100644 compiler/tools/fpp-check/test/template/template_def_in_expand.ref.txt 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 000000000..a9e989c18 --- /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 000000000..5db5a806b --- /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/source_expand_bad_args.fpp b/compiler/tools/fpp-check/test/template/source_expand_bad_args.fpp new file mode 100644 index 000000000..796116e62 --- /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 000000000..1c04c9f7b --- /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 000000000..b0de9cc16 --- /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 000000000..e69de29bb 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 000000000..76a128ddc --- /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 000000000..1aa8df51b --- /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 000000000..ecdf65e96 --- /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 000000000..ae9b5a94e --- /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 8a84ef5c4..a065b37a7 100644 --- a/compiler/tools/fpp-check/test/template/tests.sh +++ b/compiler/tools/fpp-check/test/template/tests.sh @@ -36,6 +36,7 @@ interfaces_topology_arg_ok interfaces_topology_arg_order_ok interfaces_valid_port_instance_name_aliased module_merge_ok +nested_expand nested_scope_resolution nested_scope_resolution_ok nested_template_def @@ -45,6 +46,9 @@ 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 From 840123cb4e258027a8c1fe5b8355c85af7e3e2d8 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Wed, 14 Oct 2026 08:28:07 -0700 Subject: [PATCH 39/51] Refactor ExpandTemplates --- .../main/scala/transform/ExpandTemplates.scala | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala index 5a06ebc8f..a340213c8 100644 --- a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala +++ b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala @@ -8,25 +8,23 @@ import fpp.compiler.util._ object ExpandTemplates extends AstTransformer { - type State = Analysis - - type In = State + type In = Analysis type Out = Unit def default(a: Analysis) = throw InternalError("ExpandTemplates: Transformer not implemented") - /** Transform a list in sequence, threading state */ + /** Transform a list in sequence */ def transformList[A, B]( - s: State, + a: Analysis, list: List[A], - transform: (State, A) => Result[B] + transform: (Analysis, A) => Result[B] ): Result.Result[List[B]] = { def helper(in: List[A], out: List[B]): Result.Result[List[B]] = { in match { case Nil => Right(out) - case head :: tail => transform(s, head) match { + case head :: tail => transform(a, head) match { case Left(e) => Left(e) case Right((_, list)) => helper(tail, list :: out) } @@ -37,10 +35,10 @@ object ExpandTemplates extends AstTransformer /** Transform a list and flatten the result */ def transformFlatList[A, B]( - s: State, + a: Analysis, list: List[A], - transform: (State, A) => Result[List[B]] - ): Result.Result[List[B]] = transformList(s, list, transform).map(_.flatten) + transform: (Analysis, A) => Result[List[B]] + ): Result.Result[List[B]] = transformList(a, list, transform).map(_.flatten) override def transUnit( a: Analysis, From 58da0ee4780baa16c15ddb30e57b65b90ed6b7b8 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Wed, 14 Oct 2026 08:38:23 -0700 Subject: [PATCH 40/51] Refactor ExpandTemplates Add AstUnitTransformer --- .../main/scala/ast/AstUnitTransformer.scala | 38 +++++++++++++++++++ .../scala/transform/ExpandTemplates.scala | 29 +------------- 2 files changed, 39 insertions(+), 28 deletions(-) create mode 100644 compiler/lib/src/main/scala/ast/AstUnitTransformer.scala 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 000000000..21fe92a3c --- /dev/null +++ b/compiler/lib/src/main/scala/ast/AstUnitTransformer.scala @@ -0,0 +1,38 @@ +package fpp.compiler.transform + +import fpp.compiler.analysis._ +import fpp.compiler.ast._ +import fpp.compiler.util._ + +/** Transform an AST, producing no 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) + +} diff --git a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala index a340213c8..ab92a417e 100644 --- a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala +++ b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala @@ -5,41 +5,14 @@ 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 In = Analysis - type Out = Unit - def default(a: Analysis) = throw InternalError("ExpandTemplates: Transformer not implemented") - /** Transform a list in sequence */ - def transformList[A, B]( - a: Analysis, - list: List[A], - transform: (Analysis, A) => Result[B] - ): Result.Result[List[B]] = { - def helper(in: List[A], out: List[B]): Result.Result[List[B]] = { - in match { - case Nil => Right(out) - case head :: tail => transform(a, head) match { - case Left(e) => Left(e) - case Right((_, list)) => helper(tail, list :: out) - } - } - } - helper(list, Nil).map(_.reverse) - } - - /** Transform a list and flatten the result */ - def transformFlatList[A, B]( - a: Analysis, - list: List[A], - transform: (Analysis, A) => Result[List[B]] - ): Result.Result[List[B]] = transformList(a, list, transform).map(_.flatten) - override def transUnit( a: Analysis, tu: Ast.TransUnit From f4814f701517675f1d3c2578e2e2403f169f9a1d Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Wed, 14 Oct 2026 08:41:11 -0700 Subject: [PATCH 41/51] Revise comment --- compiler/lib/src/main/scala/ast/AstUnitTransformer.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/lib/src/main/scala/ast/AstUnitTransformer.scala b/compiler/lib/src/main/scala/ast/AstUnitTransformer.scala index 21fe92a3c..e2bab5302 100644 --- a/compiler/lib/src/main/scala/ast/AstUnitTransformer.scala +++ b/compiler/lib/src/main/scala/ast/AstUnitTransformer.scala @@ -4,7 +4,7 @@ import fpp.compiler.analysis._ import fpp.compiler.ast._ import fpp.compiler.util._ -/** Transform an AST, producing no value */ +/** Transform an AST, producing a unit Out value */ trait AstUnitTransformer extends AstTransformer { From 5b070c8a6057897f591be18369b142f15d626d1f Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Wed, 14 Oct 2026 09:00:12 -0700 Subject: [PATCH 42/51] Refactor ExpandTemplates and AstUnitTransformer --- compiler/lib/src/main/scala/ast/AstUnitTransformer.scala | 4 ++++ compiler/lib/src/main/scala/transform/ExpandTemplates.scala | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/lib/src/main/scala/ast/AstUnitTransformer.scala b/compiler/lib/src/main/scala/ast/AstUnitTransformer.scala index e2bab5302..b4d2f51e4 100644 --- a/compiler/lib/src/main/scala/ast/AstUnitTransformer.scala +++ b/compiler/lib/src/main/scala/ast/AstUnitTransformer.scala @@ -35,4 +35,8 @@ trait AstUnitTransformer extends AstTransformer 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/transform/ExpandTemplates.scala b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala index ab92a417e..dad042111 100644 --- a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala +++ b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala @@ -1041,10 +1041,6 @@ object ExpandTemplates extends AstUnitTransformer } } - /** Adapt a simple result function to the form required by the visitor */ - private def resultAdapter[A,B](f: (A, B) => Result.Result[B]) = - (a: A, b: B) => for (c <- f(a, b)) yield ((), c) - private def structMember( a: Analysis, node: AstNode[Ast.StructMember] From d8623ccd274c4e75334fa4c9d993e9a835bdaeee Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Thu, 15 Oct 2026 08:32:32 -0700 Subject: [PATCH 43/51] Rename CheckTemplateDefinitions --- .../{CheckTemplateDefinitions.scala => CheckTemplateDefs.scala} | 2 +- .../analysis/CheckSemantics/ExpandSyntaxAndEnterSymbols.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename compiler/lib/src/main/scala/analysis/CheckSemantics/{CheckTemplateDefinitions.scala => CheckTemplateDefs.scala} (97%) diff --git a/compiler/lib/src/main/scala/analysis/CheckSemantics/CheckTemplateDefinitions.scala b/compiler/lib/src/main/scala/analysis/CheckSemantics/CheckTemplateDefs.scala similarity index 97% rename from compiler/lib/src/main/scala/analysis/CheckSemantics/CheckTemplateDefinitions.scala rename to compiler/lib/src/main/scala/analysis/CheckSemantics/CheckTemplateDefs.scala index e11bcbf20..09777f515 100644 --- a/compiler/lib/src/main/scala/analysis/CheckSemantics/CheckTemplateDefinitions.scala +++ b/compiler/lib/src/main/scala/analysis/CheckSemantics/CheckTemplateDefs.scala @@ -4,7 +4,7 @@ import fpp.compiler.ast._ import fpp.compiler.util._ /** Check template definitions */ -object CheckTemplateDefinitions +object CheckTemplateDefs extends Analyzer with ModuleAnalyzer { diff --git a/compiler/lib/src/main/scala/analysis/CheckSemantics/ExpandSyntaxAndEnterSymbols.scala b/compiler/lib/src/main/scala/analysis/CheckSemantics/ExpandSyntaxAndEnterSymbols.scala index a8cc751ce..5fe3c2f5a 100644 --- a/compiler/lib/src/main/scala/analysis/CheckSemantics/ExpandSyntaxAndEnterSymbols.scala +++ b/compiler/lib/src/main/scala/analysis/CheckSemantics/ExpandSyntaxAndEnterSymbols.scala @@ -16,7 +16,7 @@ object ExpandSyntaxAndEnterSymbols { (a, tul) <- ResolveSpecInclude.transUnitList(a, tul) tul <- AddStateEnums.transUnitList(tul) a <- EnterSymbols.visitList(a, tul, EnterSymbols.transUnit) - a <- CheckTemplateDefinitions.visitList(a, tul, CheckTemplateDefinitions.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) From b2114450c0dbab383cfe22db9fa976ad10eb7230 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Thu, 15 Oct 2026 09:57:48 -0700 Subject: [PATCH 44/51] Revise spec and user's guide --- docs/fpp-spec.html | 28 +++++++++++++++---- docs/fpp-users-guide.html | 2 +- .../Template-Expansion-Specifiers.adoc | 17 +++++++++-- .../Defining-and-Using-Module-Templates.adoc | 16 +++++------ 4 files changed, 46 insertions(+), 17 deletions(-) diff --git a/docs/fpp-spec.html b/docs/fpp-spec.html index c96f47e6b..8303493df 100644 --- a/docs/fpp-spec.html +++ b/docs/fpp-spec.html @@ -9306,7 +9306,7 @@

    7.19.1. Syntax

    The optional module member list represents the result of expanding the template. If a template expansion specifier has a module member -list, then is called an expanded template. +list, then it is called an expanded template. Otherwise it is called an unexpanded template.

    @@ -9375,9 +9375,27 @@

    7.19.2. Semantics
  • -

    If module-member-sequence is present, then it must not -transitively contain any module -template definitions or template expansion specifiers.

    +

    If module-member-sequence is present, then

    +
    +
      +
    1. +

      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.

      +
    2. +
    3. +

      module-member-sequence is not required to conform to the syntax produced +by expanding the template referred to in the specifier.

      +
    4. +
    5. +

      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.

      +
    6. +
    +
  • @@ -14578,7 +14596,7 @@

    25.4. Translation Tools

    diff --git a/docs/fpp-users-guide.html b/docs/fpp-users-guide.html index f8c184f24..a550d3fc9 100644 --- a/docs/fpp-users-guide.html +++ b/docs/fpp-users-guide.html @@ -18571,7 +18571,7 @@

    19.4. S diff --git a/docs/spec/Specifiers/Template-Expansion-Specifiers.adoc b/docs/spec/Specifiers/Template-Expansion-Specifiers.adoc index 19411a011..30379037a 100644 --- a/docs/spec/Specifiers/Template-Expansion-Specifiers.adoc +++ b/docs/spec/Specifiers/Template-Expansion-Specifiers.adoc @@ -37,7 +37,7 @@ _module-member-sequence_ is the same as for a The optional module member list represents the result of <>. If a template expansion specifier has a module member -list, then is called an *expanded template*. +list, then it is called an *expanded template*. Otherwise it is called an *unexpanded template*. ==== Semantics @@ -84,9 +84,20 @@ template argument. ... When _p_ is a type template parameter, _B_ is called a *type parameter definition*. -. If _module-member-sequence_ is present, then it must not -transitively contain any <> 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 <>. ==== Examples diff --git a/docs/users-guide/Defining-and-Using-Module-Templates.adoc b/docs/users-guide/Defining-and-Using-Module-Templates.adoc index c4b0791ce..5d76ecbb5 100644 --- a/docs/users-guide/Defining-and-Using-Module-Templates.adoc +++ b/docs/users-guide/Defining-and-Using-Module-Templates.adoc @@ -80,7 +80,7 @@ template definition to be replicated at each expansion point. After template expansion, the model looks like this: [source,fpp] --------- +---- module template T { constant c = 0 @@ -106,7 +106,7 @@ module N { } } --------- +---- You can see this by running the tool `fpp-to-fpp -e` on the original model shown above. @@ -230,7 +230,7 @@ Here we provide 1 and 2 as the arguments, and we write After template expansion, the model looks like this: [source,fpp] --------- +---- module template T(constant p: U32) { constant c = p @@ -256,7 +256,7 @@ module N { } } --------- +---- Notice that the `expand T { ... }` syntax provides the bindings of the constant values at the points of expansion. @@ -568,7 +568,7 @@ expand M.T After template expansion, the model looks like this: [source,fpp] --------- +---- module M { constant a = 0 @@ -586,7 +586,7 @@ expand M.T { constant b = a } --------- +---- Notice that in the expanded template, there is a use of the name `a`. @@ -627,7 +627,7 @@ expand M.T Here is the model after expansion: [source,fpp] --------- +---- module M { constant a = 0 @@ -647,7 +647,7 @@ expand M.T { constant b = a } --------- +---- Here the symbol `a` is defined at the point of the expansion. However, the definition there gives `a` the value 1, whereas From 99114941d6647af2cdda1159b2c0fd13f84bade8 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Thu, 15 Oct 2026 10:05:22 -0700 Subject: [PATCH 45/51] Revise Analysis structure and wiki --- .../src/main/scala/analysis/Analysis.scala | 4 +- docs/wiki/Analysis-Data-Structure.asciidoc | 44 +++++++++---------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/compiler/lib/src/main/scala/analysis/Analysis.scala b/compiler/lib/src/main/scala/analysis/Analysis.scala index 67ecbca15..7f681fe52 100644 --- a/compiler/lib/src/main/scala/analysis/Analysis.scala +++ b/compiler/lib/src/main/scala/analysis/Analysis.scala @@ -90,10 +90,10 @@ case class Analysis( impliedUseMap: Map[AstNode.Id, ImpliedUse.Uses] = Map(), /** Node ID of the current template definition */ templateDefId: Option[AstNode.Id] = None, - /** Node ID of the current template expansion */ - templateExpansionId: Option[AstNode.Id] = None, /** The current template expansion */ templateExpansion: Option[TemplateExpansion] = 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 */ diff --git a/docs/wiki/Analysis-Data-Structure.asciidoc b/docs/wiki/Analysis-Data-Structure.asciidoc index a651b85fa..862c51171 100644 --- a/docs/wiki/Analysis-Data-Structure.asciidoc +++ b/docs/wiki/Analysis-Data-Structure.asciidoc @@ -12,28 +12,6 @@ https://github.com/nasa/fpp/wiki/Analysis#data-structures[component instance sym to the corresponding https://github.com/nasa/fpp/wiki/Analysis#data-structures[component instances]. -* *Current template:* The AST node identifier of the template expansion -specifier whose body is currently being copied, if there is one. -Used during -https://github.com/nasa/fpp/wiki/Expand-Templates[template expansion]: -when it is present, each node visited is copied, and the copy records -this node as its expansion point. - -* *Current template definition:* The AST node identifier of the module -template definition whose body is currently being traversed, if there is -one. -Used during -https://github.com/nasa/fpp/wiki/Expand-Templates[template expansion] to -reject a nested template definition and a template expansion inside a -template. - -* *Current template expansion:* The -https://github.com/nasa/fpp/wiki/Analysis#data-structures[template -expansion] whose members are currently being analyzed, if there is one. -Used during -https://github.com/nasa/fpp/wiki/Check-Uses[check uses] to resolve names -against the local scope map of the expansion. - * *Dependency file set:* The set of https://github.com/nasa/fpp/wiki/Analysis#data-structures[files] on which the analysis transitively depends. @@ -121,6 +99,28 @@ https://github.com/nasa/fpp/wiki/Analysis#data-structures[systems]. The map has either zero elements (if the model is not a system model) or one element (if the model is a system model). +* *Template def id:* The AST node identifier of the module +template definition whose body is currently being traversed, if there is +one. +Used during +https://github.com/nasa/fpp/wiki/Expand-Templates[template expansion] to +reject a nested template definition and a template expansion inside a +template. + +* *Template expansion:* The +https://github.com/nasa/fpp/wiki/Analysis#data-structures[template +expansion] whose members are currently being analyzed, if there is one. +Used during +https://github.com/nasa/fpp/wiki/Check-Uses[check uses] to resolve names +against the local scope map of the expansion. + +* *Template expansion id:* The AST node identifier of the template expansion +specifier whose body is currently being copied, if there is one. +Used during +https://github.com/nasa/fpp/wiki/Expand-Templates[template expansion]: +when it is present, each node visited is copied, and the copy records +this node as its expansion point. + * *Template expansion map*: A map from the AST node identifier of each template expansion specifier to the corresponding https://github.com/nasa/fpp/wiki/Analysis#data-structures[template From 23a9fa5020b70eed6dc37581447d8c26d3b1a572 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Thu, 15 Oct 2026 10:16:32 -0700 Subject: [PATCH 46/51] Revise ExpandTemplates --- .../scala/transform/ExpandTemplates.scala | 11 ++----- docs/wiki/Expand-Templates.asciidoc | 30 ++++--------------- 2 files changed, 9 insertions(+), 32 deletions(-) diff --git a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala index dad042111..bfd50e6c2 100644 --- a/compiler/lib/src/main/scala/transform/ExpandTemplates.scala +++ b/compiler/lib/src/main/scala/transform/ExpandTemplates.scala @@ -845,9 +845,8 @@ object ExpandTemplates extends AstUnitTransformer } for { - a1 <- Right(a.copy(templateDefId = Some(node.id))) - params <- transformList(a1, data.params, templateParam) - members <- transformFlatList(a1, data.members, matchModuleMember) + params <- transformList(a, data.params, templateParam) + members <- transformFlatList(a, data.members, matchModuleMember) } yield { val dataCopy = data.copy(params = params, members = members) @@ -965,12 +964,8 @@ object ExpandTemplates extends AstUnitTransformer tmpl <- a.getTemplateSymbol(data.template.id) // Clone the template body, recording the expansion node so that // cloned nodes point back at the expansion site. - // Record the template definition too for diagnostics. members <- transformFlatList( - a.copy( - templateExpansionId = Some(node.id), - templateDefId = Some(tmpl.node._2.id) - ), + a.copy(templateExpansionId = Some(node.id)), tmpl.node._2.data.members, matchModuleMember ) diff --git a/docs/wiki/Expand-Templates.asciidoc b/docs/wiki/Expand-Templates.asciidoc index fa522480a..3fdc8e0f6 100644 --- a/docs/wiki/Expand-Templates.asciidoc +++ b/docs/wiki/Expand-Templates.asciidoc @@ -59,48 +59,30 @@ visit each member of _d_. .. *Template expansion specifiers:* If _tum_ is a template expansion specifier _te_, then -... If the -https://github.com/nasa/fpp/wiki/Analysis-Data-Structure[current -template definition] member of _a_ is present, then report an error for -a template expansion inside a template, citing the location of the -enclosing template definition. - -... Otherwise - -.... Look up the module template definition _t_ that the template name +... Look up the module template definition _t_ that the template name of _te_ refers to using the https://github.com/nasa/fpp/wiki/Analysis-Data-Structure[use-def map] of _a_. Report an error if the name does not resolve to a template symbol. -.... Set the +... Set the https://github.com/nasa/fpp/wiki/Analysis-Data-Structure[current template] member of _a_ to _te_ and the https://github.com/nasa/fpp/wiki/Analysis-Data-Structure[current template definition] member of _a_ to _t_. -.... Copy each member of _t_. +... Copy each member of _t_. -.... Restore the current template and current template definition +... Restore the current template and current template definition members of _a_. -.... Replace _te_ with a specifier that has the same identity as _te_ +... Replace _te_ with a specifier that has the same identity as _te_ and that carries the copied members. .. *Module template definitions:* If _tum_ is a module template -definition _t_, then - -... If the -https://github.com/nasa/fpp/wiki/Analysis-Data-Structure[current -template definition] member of _a_ is present, then _t_ is enclosed in -another module template definition. -Report an error for a nested template definition, citing the location -of the enclosing definition. - -... Otherwise set the current template definition member of _a_ to _t_, +definition _t_, then set the current template definition member of _a_ to _t_, visit the parameters and the members of _t_, and restore the current template definition member of _a_. - .. *Other translation unit members:* For any other translation unit member _m_, visit _m_. From 9ecccf13dc4564f0f0a1ce2ced52c8b0d9d198a5 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Thu, 15 Oct 2026 11:22:45 -0700 Subject: [PATCH 47/51] Revise AstTransformer Add cases for expanded and unexpanded forms --- .../lib/src/main/scala/ast/AstTransformer.scala | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/compiler/lib/src/main/scala/ast/AstTransformer.scala b/compiler/lib/src/main/scala/ast/AstTransformer.scala index dd4499b4b..c3f6c6649 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) From 83244624451c318313e95536a07899836147b947 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Thu, 15 Oct 2026 11:57:29 -0700 Subject: [PATCH 48/51] Revise ast transformers Refactor AstStateTransformer and ModuleStateTransformer Revise ModuleStateTransformer to descend into expansions --- .../main/scala/ast/AstStateTransformer.scala | 9 +++++++++ .../scala/ast/ModuleStateTransformer.scala | 20 ++++++++++++++++--- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/compiler/lib/src/main/scala/ast/AstStateTransformer.scala b/compiler/lib/src/main/scala/ast/AstStateTransformer.scala index b92cfcd4f..d2be4f968 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/ModuleStateTransformer.scala b/compiler/lib/src/main/scala/ast/ModuleStateTransformer.scala index 1b09561e4..e372f9f1f 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) From 72f1a73c03b9e77705c2b44dd1e87b910218b2c5 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Thu, 15 Oct 2026 13:17:52 -0700 Subject: [PATCH 49/51] Update fpp-syntax tests --- .../test/include-module-template-expand.fpp | 9 +++++++++ .../test/include-module-template-expand.ref.txt | 9 +++++++++ .../fpp-syntax/test/include-module-template.fpp | 5 +++++ .../fpp-syntax/test/include-module-template.ref.txt | 7 +++++++ compiler/tools/fpp-syntax/test/run | 12 ++++++++++++ compiler/tools/fpp-syntax/test/update-ref | 2 ++ 6 files changed, 44 insertions(+) create mode 100644 compiler/tools/fpp-syntax/test/include-module-template-expand.fpp create mode 100644 compiler/tools/fpp-syntax/test/include-module-template-expand.ref.txt create mode 100644 compiler/tools/fpp-syntax/test/include-module-template.fpp create mode 100644 compiler/tools/fpp-syntax/test/include-module-template.ref.txt 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 000000000..8e05a24cf --- /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 000000000..eff5fbd18 --- /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 000000000..b1d2ecf33 --- /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 000000000..7f8e14b51 --- /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/run b/compiler/tools/fpp-syntax/test/run index 5283847ce..dd4d5d3b2 100755 --- a/compiler/tools/fpp-syntax/test/run +++ b/compiler/tools/fpp-syntax/test/run @@ -73,6 +73,16 @@ include_module() run_test -ia include-module } +include_module_template() +{ + run_test -ia include-module-template +} + +include_module_template_expand() +{ + run_test -ia include-module-template-expand +} + include_parse_error() { run_test -i include-parse-error @@ -177,6 +187,8 @@ 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 diff --git a/compiler/tools/fpp-syntax/test/update-ref b/compiler/tools/fpp-syntax/test/update-ref index d036a8739..dd294bf94 100755 --- a/compiler/tools/fpp-syntax/test/update-ref +++ b/compiler/tools/fpp-syntax/test/update-ref @@ -43,6 +43,8 @@ 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 From c57e2340ef00a8d481e028b2e420155abe6618a5 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Thu, 15 Oct 2026 13:26:21 -0700 Subject: [PATCH 50/51] Refactor fpp-syntax tests --- .../{template.fpp => module-template.fpp} | 0 ...mplate.ref.txt => module-template.ref.txt} | 0 compiler/tools/fpp-syntax/test/run | 58 +++++++++---------- compiler/tools/fpp-syntax/test/update-ref | 10 ++-- 4 files changed, 34 insertions(+), 34 deletions(-) rename compiler/tools/fpp-syntax/test/{template.fpp => module-template.fpp} (100%) rename compiler/tools/fpp-syntax/test/{template.ref.txt => module-template.ref.txt} (100%) diff --git a/compiler/tools/fpp-syntax/test/template.fpp b/compiler/tools/fpp-syntax/test/module-template.fpp similarity index 100% rename from compiler/tools/fpp-syntax/test/template.fpp rename to compiler/tools/fpp-syntax/test/module-template.fpp diff --git a/compiler/tools/fpp-syntax/test/template.ref.txt b/compiler/tools/fpp-syntax/test/module-template.ref.txt similarity index 100% rename from compiler/tools/fpp-syntax/test/template.ref.txt rename to compiler/tools/fpp-syntax/test/module-template.ref.txt diff --git a/compiler/tools/fpp-syntax/test/run b/compiler/tools/fpp-syntax/test/run index dd4d5d3b2..99f75df8f 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 @@ -83,14 +88,19 @@ include_module_template_expand() run_test -ia include-module-template-expand } +include_parent_dir() +{ + run_test -ia subdir/include-parent-dir +} + include_parse_error() { run_test -i include-parse-error } -include_parent_dir() +include_state_machine() { - run_test -ia subdir/include-parent-dir + run_test -ia include-state-machine } include_state_machine() @@ -103,14 +113,19 @@ include_subdir() run_test -ia include-subdir } -include_state_machine() +include_topology() { - run_test -ia include-state-machine + run_test -ia include-topology } -include_topology() +module_template() { - run_test -ia include-topology + run_test -iea module-template +} + +numeric_shift() +{ + run_test "" numeric-shift } parse_error() @@ -128,11 +143,6 @@ syntax() run_test "" syntax } -syntax_kwd_names() -{ - run_test "" syntax-kwd-names -} - syntax_ast() { run_test -a syntax syntax-ast @@ -143,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() @@ -165,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 @@ -194,6 +195,8 @@ include_parse_error include_state_machine include_subdir include_topology +module_template +numeric_shift parse_error state_machine syntax @@ -201,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/update-ref b/compiler/tools/fpp-syntax/test/update-ref index dd294bf94..38bc1642e 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 @@ -49,11 +49,11 @@ update -ia include-state-machine update -ia include-state-machine update -ia include-subdir update -ia include-topology -update -ia topology-ports -update -iea 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 From 9e4c73b083c48472faa9b908a016eb43df04890a Mon Sep 17 00:00:00 2001 From: Bevin K Duckett Date: Fri, 16 Oct 2026 10:34:25 -0700 Subject: [PATCH 51/51] Include annotation for packets from FPP in dictionary --- .../DictionaryJsonWriter/DictionaryJsonEncoder.scala | 8 ++++++-- compiler/tools/fpp-to-dict/test/dictionary.schema.json | 6 ++++++ .../test/top/FirstTopTopologyDictionary.ref.json | 9 ++++++--- compiler/tools/fpp-to-dict/test/top/multipleTops.fpp | 3 +++ 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/compiler/lib/src/main/scala/codegen/DictionaryJsonWriter/DictionaryJsonEncoder.scala b/compiler/lib/src/main/scala/codegen/DictionaryJsonWriter/DictionaryJsonEncoder.scala index 7a625e7f3..e5beed02f 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/tools/fpp-to-dict/test/dictionary.schema.json b/compiler/tools/fpp-to-dict/test/dictionary.schema.json index f9335794b..a0d82cb72 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 c0f8226ee..35e2facc8 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 62f693e48..670cfd3c8 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 }