Skip to content

Commit 88e1a89

Browse files
authored
Merge pull request #28 from pug-php/feature/support-back-ticks
Support back ticks and interpolation
2 parents 8bd3a87 + 718bc40 commit 88e1a89

File tree

14 files changed

+116
-7
lines changed

14 files changed

+116
-7
lines changed

examples/interpolation.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
name = 'Bob';
2+
3+
return `Hello ${name}, \${not} can you ${(function (verb) { return verb; })('tell')}?`;

examples/interpolation.return

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Hello Bob, ${not} can you tell?

examples/typeof-return.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
return typeof 'foobar'

examples/typeof-return.return

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
string

src/JsPhpize/Compiler/Compiler.php

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
class Compiler
2222
{
2323
use DyiadeTrait;
24+
use InterpolationTrait;
2425

2526
/**
2627
* @const string
@@ -42,9 +43,15 @@ class Compiler
4243
*/
4344
protected $arrayShortSyntax;
4445

45-
public function __construct(JsPhpize $engine)
46+
/**
47+
* @var string
48+
*/
49+
protected $filename;
50+
51+
public function __construct(JsPhpize $engine, $filename = null)
4652
{
4753
$this->engine = $engine;
54+
$this->filename = $filename;
4855
$this->setPrefixes($engine->getVarPrefix(), $engine->getConstPrefix());
4956
$this->arrayShortSyntax = $engine->getOption('arrayShortSyntax', false);
5057
}
@@ -138,12 +145,25 @@ function ($pair) use ($visitNode, $indent) {
138145
protected function visitConstant(Constant $constant)
139146
{
140147
$value = $constant->value;
141-
if ($constant->type === 'string' && mb_substr($constant->value, 0, 1) === '"') {
142-
$value = str_replace('$', '\\$', $value);
148+
149+
if ($constant->type === 'string') {
150+
if (substr($value, 0, 1) === '`') {
151+
return implode(
152+
' . ',
153+
iterator_to_array($this->readInterpolation(substr($value, 1, -1)))
154+
);
155+
}
156+
157+
if (mb_substr($constant->value, 0, 1) === '"') {
158+
return str_replace('$', '\\$', $value);
159+
}
143160
}
161+
144162
if ($constant->type === 'regexp') {
145-
$regExp = $this->engine->getHelperName('regExp');
146-
$value = $this->helperWrap($regExp, [var_export($value, true)]);
163+
return $this->helperWrap(
164+
$this->engine->getHelperName('regExp'),
165+
[var_export($value, true)]
166+
);
147167
}
148168

149169
return $value;
@@ -217,6 +237,7 @@ protected function visitFunctionCall(FunctionCall $functionCall, $indent)
217237
$staticCall = $name . '(' . $arguments . ')';
218238

219239
$functions = str_replace(["\n", "\t", "\r", ' '], '', static::STATIC_CALL_FUNCTIONS);
240+
220241
if ($applicant === 'new' || in_array($name, explode(',', $functions))) {
221242
return $staticCall;
222243
}
@@ -270,6 +291,7 @@ public function visitNode(Node $node, $indent)
270291
get_class($node)
271292
);
272293
$php = method_exists($this, $method) ? $this->$method($node, $indent) : '';
294+
273295
if ($node instanceof Value) {
274296
$php = $node->getBefore() . $php . $node->getAfter();
275297
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
namespace JsPhpize\Compiler;
4+
5+
use JsPhpize\Parser\Parser;
6+
7+
trait InterpolationTrait
8+
{
9+
protected function readInterpolation($value)
10+
{
11+
while (strlen($value)) {
12+
preg_match('/^(.*)(?:(\\\\|\\${).*)?$/U', $value, $match);
13+
14+
yield var_export($match[1], true);
15+
16+
$value = mb_substr($value, mb_strlen($match[1]));
17+
18+
if (isset($match[2])) {
19+
if ($match[2] === '\\') {
20+
yield var_export(mb_substr($value, 1, 1), true);
21+
22+
$value = mb_substr($value, 2);
23+
24+
continue;
25+
}
26+
27+
$value = mb_substr($value, 2);
28+
29+
$parser = new Parser($this->engine, $value, $this->filename);
30+
31+
yield rtrim($this->visitInstruction($parser->parse()->instructions[0], ''), ";\t\n\r\0\x0B ");
32+
33+
$value = $parser->rest();
34+
}
35+
}
36+
}
37+
}

src/JsPhpize/JsPhpize.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,13 @@ public function compile($input, $filename = null)
5252

5353
$start = '';
5454
$end = '';
55+
5556
if (preg_match('/^([)}\]\s]*)(.*?)([({\[\s]*)$/', trim($input), $match)) {
5657
list(, $start, $input, $end) = $match;
5758
}
5859

5960
$parser = new Parser($this, $input, $filename);
60-
$compiler = new Compiler($this);
61+
$compiler = new Compiler($this, $filename);
6162
$block = $parser->parse();
6263
$php = $compiler->compile($block);
6364

@@ -70,6 +71,7 @@ public function compile($input, $filename = null)
7071
}
7172

7273
$dependencies = $compiler->getDependencies();
74+
7375
if ($this->getOption('catchDependencies')) {
7476
$this->dependencies = array_unique(array_merge($this->dependencies, $dependencies));
7577
$dependencies = [];

src/JsPhpize/JsPhpizeOptions.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public function __construct($options = [])
5050
$this->options['patterns'] = [
5151
new Pattern(10, 'newline', '\n'),
5252
new Pattern(20, 'comment', '\/\/.*?\n|\/\*[\s\S]*?\*\/'),
53-
new Pattern(30, 'string', '"(?:\\\\.|[^"\\\\])*"|\'(?:\\\\.|[^\'\\\\])*\''),
53+
new Pattern(30, 'string', '"(?:\\\\.|[^"\\\\])*"|\'(?:\\\\.|[^\'\\\\])*\'|`(?:\\\\.|[^`\\\\])*`'),
5454
new Pattern(40, 'number', '0[bB][01]+|0[oO][0-7]+|0[xX][0-9a-fA-F]+|(\d+(\.\d*)?|\.\d+)([eE]-?\d+)?'),
5555
new Pattern(50, 'lambda', '=>'),
5656
new Pattern(60, 'operator', ['delete', 'typeof', 'void'], true),

src/JsPhpize/Lexer/Lexer.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ public function exceptionInfos()
6161
' near from ' . trim($this->consumed);
6262
}
6363

64+
public function rest()
65+
{
66+
return $this->input;
67+
}
68+
6469
protected function consume($consumed)
6570
{
6671
$consumed = is_int($consumed) ? mb_substr($this->input, 0, $consumed) : $consumed;

src/JsPhpize/Nodes/Constant.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ public function __construct($type, $value)
3535
if (!in_array($type, ['constant', 'number', 'string', 'regexp'])) {
3636
throw new Exception("The given type [$type] is not a valid constant type.", 23);
3737
}
38+
3839
$this->type = $type;
3940
$this->value = $value;
4041
}
@@ -44,9 +45,11 @@ public function getNonAssignableReason()
4445
if ($this->type !== 'constant') {
4546
return "{$this->type} is not assignable.";
4647
}
48+
4749
if (in_array($this->value, ['NAN', 'INF'])) {
4850
return "{$this->value} is not assignable.";
4951
}
52+
5053
if (mb_substr($this->value, 0, 2) === 'M_') {
5154
return "'M_' prefix is reserved to mathematical constants.";
5255
}

0 commit comments

Comments
 (0)