phphhvmhacklang

running minimal app with xhp-lib v4 and hhvm v 4.81.1 throws error


I'm trying the following setup and am getting this error:

\nFatal error: Uncaught Error: Found top-level code in /home/user/code/xhp-simple/src/example.php:7\nStack trace:\n#0 (): main()\n#1 {main}

Setup:

composer.json

{
    "require": {
        "hhvm/hhvm-autoload": "^3.1",
        "facebook/xhp-lib": "^4.0"
    }
}

src/index.hack

use type Facebook\XHP\HTML\div;
//  require_once(__DIR__."/../vendor/hh_autoload.hh");  // also tried here instead of in main

<<__EntryPoint>>
function main(): void {
  require_once(__DIR__."/../vendor/hh_autoload.hh");
  echo <div>{1 + 2}</div>;
}

hh_autoload.json

{"roots": ["src/"]}

run command:

hhvm -m server -p 8080 -d hhvm.server.default_document=./src/example.hack

I have hhvm v 4.83.1 installed


Solution

  • I think that you're running into the fact that hhvm-autoload hasn't caught up with the recent restrictions to top-level code. In particular, where require_once seems to no longer be allowed at the top level. With your hh_autoload.json, hhvm-autoload generates this hh_autoload.hh:

    <?hh // partial
    require_once(__DIR__.'/autoload.hack');
    Facebook\AutoloadMap\initialize();
    

    Where I believe that require_once is illegal. If you place this code in your main, it should work. I tested this with no problems on HHVM 4.84.0:

    // src/index.hack
    use type Facebook\XHP\HTML\div;
    
    <<__EntryPoint>>
    async function main(): Awaitable<void> {
        require_once(__DIR__.'/../vendor/autoload.hack');
        Facebook\AutoloadMap\initialize();
        echo await (<div>{1 + 2}</div>)->toStringAsync();
    }
    
    $ # run with:
    $ hhvm src/index.hack
    

    Also note that all rendering is async now with XHP-lib, so you can't just echo XHP objects directly; instead:

    Calls to $xhp->toString() need to be updated to $xhp->toStringAsync().


    I've just noticed the updated README on hhvm-autoload, where indeed hh_autoload.hh has been phased out and you need to need to generate the autoload map yourself (emphasis mine):

    Replace any references to vendor/autoload.php with vendor/autoload.hack and call Facebook\AutoloadMap\initialize()