Repository: twigphp/Twig (php)

Issue:
New CaptureNode + macro generate syntax errors
It seems that the [new CaptureNode](https://github.com/twigphp/Twig/pull/3954) is (one of) the main explanation for the failing tests on symfony/symfony right now, but i'm not sure to understand all what happen there.

Failing tests: https://github.com/symfony/symfony/actions/runs/7368940944 

In the WebProfilerBundle, in the [request.html.twig](https://github.com/symfony/web-profiler-bundle/blob/7.1/Resources/views/Collector/request.html.twig) template, a macro is declared. 

The generated corresponding PHP class contains syntax errors that seems related to the new CaptureNode usage, and probably to node optimizer but i did not find the exact order of events :/ 


```php
// The return statement contains some code that should not be inserted there i guess

return         $__internal_5a27a8ba21ca79b61932376b2fa922d2 = $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
$__internal_5a27a8ba21ca79b61 
// [...]

// End at the end same thing, with a missing ; and some code
  } finally {
        ob_end_clean();
    }
})()        
$__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);        
$__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
;
```        


Should i post on symfony/symfony instead ? I do feel that there is something here but i'm not 100% so feel free to close this one and/or ask me to create one on the symfony/symfony repo.


<details>
<summary>Full code</summary>

```php

    // line 414
    public function macro_set_handler($__controller__ = null, $__route__ = null, $__method__ = null, ...$__varargs__)
    {
        $macros = $this->macros;
        $context = $this->env->mergeGlobals([
            "controller" => $__controller__,
            "route" => $__route__,
            "method" => $__method__,
            "varargs" => $__varargs__,
        ]);

        $blocks = [];

        return         $__internal_5a27a8ba21ca79b61932376b2fa922d2 = $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
        $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "macro", "set_handler"));

        $__internal_6f47bbe9983af81f1e7450e9a3e3768f = $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
        $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "macro", "set_handler"));

(function () use (&$context, $macros) {
            ob_start();
            try {
                // [...]

                return ('' === $tmp = ob_get_contents()) ? '' : new Markup($tmp, $this->env->getCharset());
            } finally {
                ob_end_clean();
            }
        })()        
        $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);

        
        $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);

;
    }
```
</details>



Pull request:
rework the CaptureNode implementation
fixes #3955

Patch:
diff --git a/src/Node/CaptureNode.php b/src/Node/CaptureNode.php
index dae441c8..418f0863 100644
--- a/src/Node/CaptureNode.php
+++ b/src/Node/CaptureNode.php
@@ -57,7 +57,7 @@ class CaptureNode extends Node
             ->outdent()
             ->write("}\n")
             ->outdent()
-            ->write('})()')
+            ->write('})();')
         ;
     }
 }
diff --git a/src/Node/MacroNode.php b/src/Node/MacroNode.php
index 4f645eb2..63fb8dea 100644
--- a/src/Node/MacroNode.php
+++ b/src/Node/MacroNode.php
@@ -31,8 +31,6 @@ class MacroNode extends Node
             }
         }
 
-        $body = new CaptureNode($body, $lineno, $tag);
-
         parent::__construct(['body' => $body, 'arguments' => $arguments], ['name' => $name], $lineno, $tag);
     }
 
@@ -88,8 +86,8 @@ class MacroNode extends Node
             ->write("]);\n\n")
             ->write("\$blocks = [];\n\n")
             ->write('return ')
-            ->subcompile($this->getNode('body'))
-            ->raw(";\n")
+            ->subcompile(new CaptureNode($this->getNode('body'), $this->getNode('body')->lineno, $this->getNode('body')->tag))
+            ->raw("\n")
             ->outdent()
             ->write("}\n\n")
         ;
diff --git a/src/Node/SetNode.php b/src/Node/SetNode.php
index 9559193b..1d33cc77 100644
--- a/src/Node/SetNode.php
+++ b/src/Node/SetNode.php
@@ -86,8 +86,10 @@ class SetNode extends Node implements NodeCaptureInterface
                     $compiler->subcompile($this->getNode('values'));
                 }
             }
+
+            $compiler->raw(';');
         }
 
-        $compiler->raw(";\n");
+        $compiler->raw("\n");
     }
 }


Test patch:
diff --git a/tests/Node/MacroTest.php b/tests/Node/MacroTest.php
index f11bf167..bd7140b8 100644
--- a/tests/Node/MacroTest.php
+++ b/tests/Node/MacroTest.php
@@ -26,7 +26,7 @@ class MacroTest extends NodeTestCase
         $arguments = new Node([new NameExpression('foo', 1)], [], 1);
         $node = new MacroNode('foo', $body, $arguments, 1);
 
-        $this->assertEquals($body, $node->getNode('body')->getNode('body'));
+        $this->assertEquals($body, $node->getNode('body'));
         $this->assertEquals($arguments, $node->getNode('arguments'));
         $this->assertEquals('foo', $node->getAttribute('name'));
     }