Skip to content

Commit

Permalink
Merge pull request #34 from pug-php/magic-methods
Browse files Browse the repository at this point in the history
Improve magic methods support
  • Loading branch information
kylekatarnls authored Apr 6, 2020
2 parents 41a3f8e + 6d3137e commit fb51f7b
Show file tree
Hide file tree
Showing 13 changed files with 642 additions and 78 deletions.
2 changes: 1 addition & 1 deletion examples/replace.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
var url = 'https://www.pugjs.org';

return url.replace('https://', '').replace(/^www\./, '');
return url.replace('https://', '').replace(/^WWW\./i, '');
74 changes: 55 additions & 19 deletions src/JsPhpize/Compiler/Compiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

class Compiler
{
const DOT_DISABLED = 1;

use DyiadeTrait;
use InterpolationTrait;

Expand Down Expand Up @@ -99,7 +101,8 @@ protected function getBlockHead(Block $block, $indent)
' => $__current_value)';
}

return $block->type . ($block->value
return $block->type . (
$block->value
? ' ' . $this->visitNode($block->value, $indent)
: ''
);
Expand Down Expand Up @@ -204,12 +207,12 @@ protected function visitDyiade(Dyiade $dyiade, $indent)
return $leftHand . ' ' . $dyiade->operator . ' ' . $rightHand;
}

protected function mapNodesArray($array, $indent, $pattern = null)
protected function mapNodesArray($array, $indent, $pattern = null, $options = 0)
{
$visitNode = [$this, 'visitNode'];

return array_map(function ($value) use ($visitNode, $indent, $pattern) {
$value = $visitNode($value, $indent);
return array_map(function ($value) use ($visitNode, $indent, $pattern, $options) {
$value = $visitNode($value, $indent, $options);

if ($pattern) {
$value = sprintf($pattern, $value);
Expand All @@ -219,17 +222,23 @@ protected function mapNodesArray($array, $indent, $pattern = null)
}, $array);
}

protected function visitNodesArray($array, $indent, $glue = '', $pattern = null)
protected function visitNodesArray($array, $indent, $glue = '', $pattern = null, $options = 0)
{
return implode($glue, $this->mapNodesArray($array, $indent, $pattern));
return implode($glue, $this->mapNodesArray($array, $indent, $pattern, $options));
}

protected function visitFunctionCall(FunctionCall $functionCall, $indent)
{
$function = $functionCall->function;
$arguments = $functionCall->arguments;
$applicant = $functionCall->applicant;
$arguments = $this->visitNodesArray($arguments, $indent, ', ');
$arguments = $this->visitNodesArray(
$arguments,
$indent,
', ',
null,
$function instanceof Variable && $function->name === 'isset' ? static::DOT_DISABLED : 0
);
$dynamicCall = $this->visitNode($function, $indent) . '(' . $arguments . ')';

if ($function instanceof Variable && count($function->children) === 0) {
Expand Down Expand Up @@ -272,9 +281,11 @@ protected function visitInstruction(Instruction $group, $indent)
$value = $visitNode($instruction, $indent);

return $indent .
($instruction instanceof Block && $instruction->handleInstructions()
(
$instruction instanceof Block && $instruction->handleInstructions()
? $value
: ($isReturnPrepended && !preg_match('/^\s*return(?![a-zA-Z0-9_])/', $value)
: (
$isReturnPrepended && !preg_match('/^\s*return(?![a-zA-Z0-9_])/', $value)
? ' return '
: ''
) . $value . ';'
Expand All @@ -283,14 +294,14 @@ protected function visitInstruction(Instruction $group, $indent)
}, $group->instructions));
}

public function visitNode(Node $node, $indent)
public function visitNode(Node $node, $indent, $options = 0)
{
$method = preg_replace(
'/^(.+\\\\)?([^\\\\]+)$/',
'visit$2',
get_class($node)
);
$php = method_exists($this, $method) ? $this->$method($node, $indent) : '';
$php = method_exists($this, $method) ? $this->$method($node, $indent, $options) : '';

if ($node instanceof Value) {
$php = $node->getBefore() . $php . $node->getAfter();
Expand All @@ -311,19 +322,41 @@ protected function visitTernary(Ternary $ternary, $indent)
' : ' . $this->visitNode($ternary->falseValue, $indent);
}

protected function handleVariableChildren(DynamicValue $dynamicValue, $indent, $php)
protected function handleVariableChildren(DynamicValue $dynamicValue, $indent, $php, $options = 0)
{
if (count($dynamicValue->children)) {
$arguments = $this->mapNodesArray($dynamicValue->children, $indent);
array_unshift($arguments, $php);
$dot = $this->engine->getHelperName('dot');
$php = $this->helperWrap($dot, $arguments);
$children = $dynamicValue->children;

if (count($children)) {
return $this->wrapVariableChildren($children, $indent, $php, $options);
}

return $php;
}

protected function visitVariable(Variable $variable, $indent)
protected function wrapVariableChildren($children, $indent, $php, $options)
{
$arguments = $this->mapNodesArray($children, $indent);
array_unshift($arguments, $php);
$dot = $this->engine->getHelperName('dot');
$dotDisabled = $options & static::DOT_DISABLED;

if ($dotDisabled) {
$lastChild = end($children);
$dotChild = $lastChild instanceof Constant && $lastChild->dotChild;
$lastChild = array_pop($arguments);
}

$php = $this->helperWrap($dot, $arguments);

if ($dotDisabled) {
$pattern = $dotChild ? '%s->{%s}' : '%s[%s]';
$php = sprintf($pattern, $php, $lastChild);
}

return $php;
}

protected function visitVariable(Variable $variable, $indent, $options = 0)
{
$name = $variable->name;
if (in_array($name, ['Math', 'RegExp'])) {
Expand All @@ -332,8 +365,11 @@ protected function visitVariable(Variable $variable, $indent)
if ($variable->scope) {
$name = '__let_' . spl_object_hash($variable->scope) . $name;
}
if (!$this->engine->getOption('ignoreDollarVariable') || mb_substr($name, 0, 1) !== '$') {
$name = '$' . $name;
}

return $this->handleVariableChildren($variable, $indent, '$' . $name);
return $this->handleVariableChildren($variable, $indent, $name, $options);
}

public function compile(Block $block, $indent = '')
Expand Down
79 changes: 77 additions & 2 deletions src/JsPhpize/Compiler/Helpers/Dot.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ function ($base) {
};
$getCallable = function ($base, $key) use ($getFromArray) {
if (is_callable(array($base, $key))) {
return array($base, $key);
return new JsPhpizeDotCarrier(array($base, $key));
}
if ($base instanceof \ArrayAccess) {
return $getFromArray($base, $key);
}
};
$getRegExp = function ($value) {
return is_object($value) && isset($value->isRegularExpression) && $value->isRegularExpression ? $value->regExp : null;
return is_object($value) && isset($value->isRegularExpression) && $value->isRegularExpression ? $value->regExp . $value->flags : null;
};
$fallbackDot = function ($base, $key) use ($getCallable, $getRegExp) {
if (is_string($base)) {
Expand Down Expand Up @@ -99,4 +99,79 @@ function ($base) {
}

return $base;
};

if (!class_exists('JsPhpizeDotCarrier')) {
class JsPhpizeDotCarrier extends ArrayObject
{
public function getValue()
{
if ($this->isArrayAccessible()) {
return $this[0][$this[1]];
}

return $this[0]->{$this[1]} ?? null;
}

public function setValue($value)
{
if ($this->isArrayAccessible()) {
$this[0][$this[1]] = $value;

return;
}

$this[0]->{$this[1]} = $value;
}

public function getCallable()
{
return $this->getArrayCopy();
}

public function __isset($name)
{
$value = $this->getValue();

if ((is_array($value) || $value instanceof ArrayAccess) && isset($value[$name])) {
return true;
}

return is_object($value) && isset($value->$name);
}

public function __get($name)
{
return new self(array($this->getValue(), $name));
}

public function __set($name, $value)
{
$value = $this->getValue();

if (is_array($value)) {
$value[$name] = $value;
$this->setValue($value);

return;
}

$value->$name = $value;
}

public function __toString()
{
return (string) $this->getValue();
}

public function __invoke(...$arguments)
{
return call_user_func_array($this->getCallable(), $arguments);
}

private function isArrayAccessible()
{
return is_array($this[0]) || $this[0] instanceof ArrayAccess && !isset($this[0]->{$this[1]});
}
}
}
79 changes: 77 additions & 2 deletions src/JsPhpize/Compiler/Helpers/Dot.ref.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ function (&$base) {
};
$getCallable = function (&$base, $key) use ($getFromArray) {
if (is_callable(array($base, $key))) {
return array($base, $key);
return new JsPhpizeDotCarrier(array($base, $key));
}
if ($base instanceof \ArrayAccess) {
return $getFromArray($base, $key);
}
};
$getRegExp = function ($value) {
return is_object($value) && isset($value->isRegularExpression) && $value->isRegularExpression ? $value->regExp : null;
return is_object($value) && isset($value->isRegularExpression) && $value->isRegularExpression ? $value->regExp . $value->flags : null;
};
$fallbackDot = function (&$base, $key) use ($getCallable, $getRegExp) {
if (is_string($base)) {
Expand Down Expand Up @@ -102,4 +102,79 @@ function (&$base) {
}

return $result;
};

if (!class_exists('JsPhpizeDotCarrier')) {
class JsPhpizeDotCarrier extends ArrayObject
{
public function getValue()
{
if ($this->isArrayAccessible()) {
return $this[0][$this[1]];
}

return $this[0]->{$this[1]} ?? null;
}

public function setValue($value)
{
if ($this->isArrayAccessible()) {
$this[0][$this[1]] = $value;

return;
}

$this[0]->{$this[1]} = $value;
}

public function getCallable()
{
return $this->getArrayCopy();
}

public function __isset($name)
{
$value = $this->getValue();

if ((is_array($value) || $value instanceof ArrayAccess) && isset($value[$name])) {
return true;
}

return is_object($value) && isset($value->$name);
}

public function __get($name)
{
return new self(array($this->getValue(), $name));
}

public function __set($name, $value)
{
$value = $this->getValue();

if (is_array($value)) {
$value[$name] = $value;
$this->setValue($value);

return;
}

$value->$name = $value;
}

public function __toString()
{
return (string) $this->getValue();
}

public function __invoke(...$arguments)
{
return call_user_func_array($this->getCallable(), $arguments);
}

private function isArrayAccessible()
{
return is_array($this[0]) || $this[0] instanceof ArrayAccess && !isset($this[0]->{$this[1]});
}
}
}
Loading

0 comments on commit fb51f7b

Please sign in to comment.