pug-php / pug

Pug template engine for PHP
https://www.phug-lang.com
MIT License
387 stars 42 forks source link

Error when calling mixin with attributes while expressionLanguage=js #109

Closed J5lx closed 7 years ago

J5lx commented 7 years ago

MWE:

mixin test
  div&attributes(attributes)
body
  +test(class='test')
$pug = new Pug\Pug(['expressionLanguage' => 'js']);
$pug->render(/* above code */);

Expected result:

<body><div class="test"></div></body>

Actual result:

  [ErrorException (34)]
  Error on the mixin "test" line 4:
  Unexpected : in  on line 1 near from \Jade\Compiler:

Exception trace:
 () at /tmp/pug-js-mixin-attributes/vendor/pug-php/pug/src/Jade/Compiler/Visitor.php:52
 Jade\Compiler\Visitor->visitNode() at /tmp/pug-js-mixin-attributes/vendor/pug-php/pug/src/Jade/Compiler/Visitor.php:20
 Jade\Compiler\Visitor->visit() at /tmp/pug-js-mixin-attributes/vendor/pug-php/pug/src/Jade/Compiler/Visitor.php:73
 Jade\Compiler\Visitor->visitBlock() at /tmp/pug-js-mixin-attributes/vendor/pug-php/pug/src/Jade/Compiler/Visitor.php:38
 Jade\Compiler\Visitor->visitNode() at /tmp/pug-js-mixin-attributes/vendor/pug-php/pug/src/Jade/Compiler/Visitor.php:20
 Jade\Compiler\Visitor->visit() at /tmp/pug-js-mixin-attributes/vendor/pug-php/pug/src/Jade/Compiler/TagVisitor.php:78
 Jade\Compiler\TagVisitor->visitTagContents() at /tmp/pug-js-mixin-attributes/vendor/pug-php/pug/src/Jade/Compiler/TagVisitor.php:94
 Jade\Compiler\TagVisitor->compileTag() at n/a:n/a
 call_user_func_array() at /tmp/pug-js-mixin-attributes/vendor/pug-php/pug/src/Jade/Compiler/Indenter.php:57
 Jade\Compiler\Indenter->tempPrettyPrint() at /tmp/pug-js-mixin-attributes/vendor/pug-php/pug/src/Jade/Compiler/TagVisitor.php:113
 Jade\Compiler\TagVisitor->visitTag() at /tmp/pug-js-mixin-attributes/vendor/pug-php/pug/src/Jade/Compiler/Visitor.php:38
 Jade\Compiler\Visitor->visitNode() at /tmp/pug-js-mixin-attributes/vendor/pug-php/pug/src/Jade/Compiler/Visitor.php:20
 Jade\Compiler\Visitor->visit() at /tmp/pug-js-mixin-attributes/vendor/pug-php/pug/src/Jade/Compiler/Visitor.php:73
 Jade\Compiler\Visitor->visitBlock() at /tmp/pug-js-mixin-attributes/vendor/pug-php/pug/src/Jade/Compiler/Visitor.php:38
 Jade\Compiler\Visitor->visitNode() at /tmp/pug-js-mixin-attributes/vendor/pug-php/pug/src/Jade/Compiler/Visitor.php:20
 Jade\Compiler\Visitor->visit() at /tmp/pug-js-mixin-attributes/vendor/pug-php/pug/src/Jade/Compiler.php:102
 Jade\Compiler->compile() at /tmp/pug-js-mixin-attributes/vendor/pug-php/pug/src/Jade/Jade.php:119
 Jade\Jade->compile() at /tmp/pug-js-mixin-attributes/vendor/pug-php/pug/src/Jade/Jade.php:158
 Jade\Jade->render() at […]
 […]

  [JsPhpize\Parser\Exception (8)]
  Unexpected : in  on line 1 near from \Jade\Compiler:

Exception trace:
 () at /tmp/pug-js-mixin-attributes/vendor/js-phpize/js-phpize/src/JsPhpize/Parser/TokenCrawler.php:40
 JsPhpize\Parser\TokenCrawler->unexpected() at /tmp/pug-js-mixin-attributes/vendor/js-phpize/js-phpize/src/JsPhpize/Parser/Parser.php:96
 JsPhpize\Parser\Parser->parseParentheses() at /tmp/pug-js-mixin-attributes/vendor/js-phpize/js-phpize/src/JsPhpize/Parser/TokenExtractor.php:172
 JsPhpize\Parser\TokenExtractor->appendFunctionsCalls() at /tmp/pug-js-mixin-attributes/vendor/js-phpize/js-phpize/src/JsPhpize/Parser/TokenExtractor.php:108
 JsPhpize\Parser\TokenExtractor->getValueFromToken() at /tmp/pug-js-mixin-attributes/vendor/js-phpize/js-phpize/src/JsPhpize/Parser/TokenExtractor.php:99
 JsPhpize\Parser\TokenExtractor->getInstructionFromToken() at /tmp/pug-js-mixin-attributes/vendor/js-phpize/js-phpize/src/JsPhpize/Parser/Parser.php:314
 JsPhpize\Parser\Parser->parseInstructions() at /tmp/pug-js-mixin-attributes/vendor/js-phpize/js-phpize/src/JsPhpize/Parser/Parser.php:343
 JsPhpize\Parser\Parser->parseBlock() at /tmp/pug-js-mixin-attributes/vendor/js-phpize/js-phpize/src/JsPhpize/Parser/Parser.php:351
 JsPhpize\Parser\Parser->parse() at /tmp/pug-js-mixin-attributes/vendor/js-phpize/js-phpize/src/JsPhpize/JsPhpize.php:52
 JsPhpize\JsPhpize->compile() at /tmp/pug-js-mixin-attributes/vendor/js-phpize/js-phpize/src/JsPhpize/JsPhpize.php:86
 JsPhpize\JsPhpize->compileCode() at n/a:n/a
 call_user_func() at /tmp/pug-js-mixin-attributes/vendor/pug-php/pug/src/Jade/Compiler/ExpressionCompiler.php:64
 Jade\Compiler\ExpressionCompiler->getPhpCodeFromJs() at /tmp/pug-js-mixin-attributes/vendor/pug-php/pug/src/Jade/Compiler/ExpressionCompiler.php:22
 Jade\Compiler\ExpressionCompiler->getArgumentExpression() at /tmp/pug-js-mixin-attributes/vendor/pug-php/pug/src/Jade/Compiler.php:302
 Jade\Compiler->createStatements() at n/a:n/a
 call_user_func_array() at /tmp/pug-js-mixin-attributes/vendor/pug-php/pug/src/Jade/Compiler.php:159
 Jade\Compiler->apply() at /tmp/pug-js-mixin-attributes/vendor/pug-php/pug/src/Jade/Compiler/MixinVisitor.php:206
 Jade\Compiler\MixinVisitor->visitMixinCall() at /tmp/pug-js-mixin-attributes/vendor/pug-php/pug/src/Jade/Compiler/MixinVisitor.php:297
 Jade\Compiler\MixinVisitor->visitMixin() at /tmp/pug-js-mixin-attributes/vendor/pug-php/pug/src/Jade/Compiler/Visitor.php:38
 Jade\Compiler\Visitor->visitNode() at /tmp/pug-js-mixin-attributes/vendor/pug-php/pug/src/Jade/Compiler/Visitor.php:20
 Jade\Compiler\Visitor->visit() at /tmp/pug-js-mixin-attributes/vendor/pug-php/pug/src/Jade/Compiler/Visitor.php:73
 Jade\Compiler\Visitor->visitBlock() at /tmp/pug-js-mixin-attributes/vendor/pug-php/pug/src/Jade/Compiler/Visitor.php:38
 Jade\Compiler\Visitor->visitNode() at /tmp/pug-js-mixin-attributes/vendor/pug-php/pug/src/Jade/Compiler/Visitor.php:20
 Jade\Compiler\Visitor->visit() at /tmp/pug-js-mixin-attributes/vendor/pug-php/pug/src/Jade/Compiler/TagVisitor.php:78
 Jade\Compiler\TagVisitor->visitTagContents() at /tmp/pug-js-mixin-attributes/vendor/pug-php/pug/src/Jade/Compiler/TagVisitor.php:94
 Jade\Compiler\TagVisitor->compileTag() at n/a:n/a
 call_user_func_array() at /tmp/pug-js-mixin-attributes/vendor/pug-php/pug/src/Jade/Compiler/Indenter.php:57
 Jade\Compiler\Indenter->tempPrettyPrint() at /tmp/pug-js-mixin-attributes/vendor/pug-php/pug/src/Jade/Compiler/TagVisitor.php:113
 Jade\Compiler\TagVisitor->visitTag() at /tmp/pug-js-mixin-attributes/vendor/pug-php/pug/src/Jade/Compiler/Visitor.php:38
 Jade\Compiler\Visitor->visitNode() at /tmp/pug-js-mixin-attributes/vendor/pug-php/pug/src/Jade/Compiler/Visitor.php:20
 Jade\Compiler\Visitor->visit() at /tmp/pug-js-mixin-attributes/vendor/pug-php/pug/src/Jade/Compiler/Visitor.php:73
 Jade\Compiler\Visitor->visitBlock() at /tmp/pug-js-mixin-attributes/vendor/pug-php/pug/src/Jade/Compiler/Visitor.php:38
 Jade\Compiler\Visitor->visitNode() at /tmp/pug-js-mixin-attributes/vendor/pug-php/pug/src/Jade/Compiler/Visitor.php:20
 Jade\Compiler\Visitor->visit() at /tmp/pug-js-mixin-attributes/vendor/pug-php/pug/src/Jade/Compiler.php:102
 Jade\Compiler->compile() at /tmp/pug-js-mixin-attributes/vendor/pug-php/pug/src/Jade/Jade.php:119
 Jade\Jade->compile() at /tmp/pug-js-mixin-attributes/vendor/pug-php/pug/src/Jade/Jade.php:158
 Jade\Jade->render() at […]
 […]

--
0:  () at vendor/pug-php/pug/src/Jade/Compiler/Visitor.php:52

Apparent cause:

Jade\Compiler\MixinVisitor::visitMixinCall() first passes the attributes to Jade\Compiler\MixinVisitor::parseMixinAttributes() to generate PHP code from them. This PHP code is then later merged with $arguments and passed to Jade\Compiler::createStatements(), where it is further passed down to Jade\Compiler\ExpressionCompiler::getArgumentExpression(). This function then checks for the value of the expressionLanguage option, and since it is set to JS, it tries to convert all arguments, including the generated PHP code, from JavaScript to PHP. And there you have it: The converter trips over PHP’s Paamayim Nekudotayim.

To solve the issue, there would obviously need to be a way to prevent the compiler from trying to convert the PHP code to PHP. It seems to me that ExpressionCompiler::getPhpCodeFromJs() already does this for some array and isset calls, but I'm not quite sure I understand the logic behind those regexes correctly.

J5lx commented 7 years ago

For reference, this is the relevant PHP that JsPhpize trips over (in my actual, non-MWE project) (if that helps at all):

array_merge(\Jade\Compiler::withMixinAttributes(array (
  'name' => 'site',
  'required' => true,
), array (
  0 =>
  array (
    'name' => 'name',
    'value' => 'site',
    'escaped' => true,
  ),
  1 =>
  array (
    'name' => 'required',
    'value' => true,
    'escaped' => true,
  ),
)), (isset($attributes)) ? $attributes : array())
kylekatarnls commented 7 years ago

I tried your code on https://pug-demo.herokuapp.com/ and get your expected result.

What is you version of PHP and of Pug?

J5lx commented 7 years ago

Ah, that's because I forgot a pair of parentheses. I'm sorry for that! The actual code should be:

mixin test
  div&attributes(attributes)
body
  +test()(class='test')

After all, the empty pair of parens is recommended in the documentation:

The syntax +link(class="btn") is also valid and equivalent to +link()(class="btn") since Pug try to detect if parentheses contents are attributes or arguments but we encourage you to use the second syntax as you pass explicitly no arguments and you ensure the first parenthesis is the arguments list.

kylekatarnls commented 7 years ago

Haha, trapped by my own words!

https://github.com/pugjs/pug-en/commit/ceba4d29433bcc5cfed6148c91dbd5868074d67e#diff-2d94b1160d9ee957a87b2069622d0821

I will try to fix it.

kylekatarnls commented 7 years ago

Please try to update to 2.5.4, it's fixed. Feel free to re-open if anything goes wrong.

J5lx commented 7 years ago

Works fine now. Thanks for fixing!