hhvm / hack-codegen

Library to programatically generate Hack code and write it to signed files
https://hhvm.github.io/hack-codegen/
MIT License
341 stars 93 forks source link

Codegen breaks heredocs with indentation #107

Closed ssandler closed 6 years ago

ssandler commented 6 years ago

When trying to include a heredoc in a generated function, the indentation will break the heredoc.

This also happens when using codegenHackBuilder, below is just a simpler example using body() directly with a string.

<?hh // strict

use type Facebook\HackCodegen\{
  HackCodegenFactory,
  CodegenFileType,
  HackCodegenConfig,
};

<<__Entrypoint>>
function test_main(): noreturn {
  $cg = new HackCodegenFactory(new HackCodegenConfig());
  $codegen_class = $cg->codegenClass('ExampleTest');

  $body = '<<<EOT
foo
EOT;';

  $codegen_class->addMethod(
    $cg->codegenMethod('docblockExample')
      ->setReturnType('string')
      ->setPublic()
      ->setBody($body),
  );

  $file = $cg->codegenFile('codegen_output.php')
    ->setFileType(CodegenFileType::HACK_STRICT)
    ->addClass($codegen_class)
    ->save();

  exit();
}

Actual Result

The heredoc is indented such that it is not closed, creating a parse error in the file.

<?hh // strict
/**
 * This file is generated. Do not modify it manually!
 *
 * @generated SignedSource<<e20d016823c9d42b6c3524d76287e77e>>
 */

class ExampleTest {

        public function docblockExample(): string {
                <<<EOT
                foo
                EOT;
        }
}

Expected Result

Heredocs and nowdocs could be treated specially so that they are not indented.

<?hh // strict
/**
 * This file is generated. Do not modify it manually!
 *
 * @generated SignedSource<<e20d016823c9d42b6c3524d76287e77e>>
 */

class ExampleTest {

        public function docblockExample(): string {
                <<<EOT
foo
EOT;
        }
}

Or maybe Hack could adopt this RFC such that the generated code is actually valid :-) https://wiki.php.net/rfc/flexible_heredoc_nowdoc_indentation

fredemmott commented 6 years ago

Probably need to add $builder->addHeredoc() or similar; it's not going to be practical to try and detect heredocs in strings, given that HackCodegen doesn't put any restrictions on if a string is even a series of tokens, or even part of a token.