-
Notifications
You must be signed in to change notification settings - Fork 40
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #60 from antecedent/interception-of-language-const…
…ructs Make language constructs (print, eval, clone etc.) redefinable
- Loading branch information
Showing
10 changed files
with
322 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
121 changes: 121 additions & 0 deletions
121
src/CodeManipulation/Actions/RedefinitionOfLanguageConstructs.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
<?php | ||
|
||
/** | ||
* @link http://patchwork2.org/ | ||
* @author Ignas Rudaitis <ignas.rudaitis@gmail.com> | ||
* @copyright 2010-2017 Ignas Rudaitis | ||
* @license http://www.opensource.org/licenses/mit-license.html | ||
*/ | ||
namespace Patchwork\CodeManipulation\Actions\RedefinitionOfLanguageConstructs; | ||
|
||
use Patchwork\CodeManipulation\Source; | ||
use Patchwork\CodeManipulation\Actions\Generic; | ||
use Patchwork\Exceptions; | ||
use Patchwork\Config; | ||
|
||
const LANGUAGE_CONSTRUCT_PREFIX = 'Patchwork\Redefinitions\LanguageConstructs\_'; | ||
|
||
/** | ||
* @since 2.0.5 | ||
*/ | ||
function spliceAllConfiguredLanguageConstructs() | ||
{ | ||
$mapping = getMappingOfConstructs(); | ||
$used = []; | ||
$actions = []; | ||
foreach (Config\getRedefinableLanguageConstructs() as $construct) { | ||
if (isset($used[$mapping[$construct]])) { | ||
continue; | ||
} | ||
$used[$mapping[$construct]] = true; | ||
$actions[] = spliceLanguageConstruct($mapping[$construct]); | ||
} | ||
return Generic\chain($actions); | ||
} | ||
|
||
function getMappingOfConstructs() | ||
{ | ||
return [ | ||
'echo' => T_ECHO, | ||
'print' => T_PRINT, | ||
'eval' => T_EVAL, | ||
'die' => T_EXIT, | ||
'exit' => T_EXIT, | ||
'isset' => T_ISSET, | ||
'unset' => T_UNSET, | ||
'empty' => T_EMPTY, | ||
'require' => T_REQUIRE, | ||
'require_once' => T_REQUIRE_ONCE, | ||
'include' => T_INCLUDE, | ||
'include_once' => T_INCLUDE_ONCE, | ||
'clone' => T_CLONE, | ||
]; | ||
} | ||
|
||
function getInnerTokens() | ||
{ | ||
return [ | ||
'$', | ||
',', | ||
T_OBJECT_OPERATOR, | ||
T_DOUBLE_COLON, | ||
T_NS_SEPARATOR, | ||
T_STRING, | ||
T_LNUMBER, | ||
T_DNUMBER, | ||
T_WHITESPACE, | ||
T_CONSTANT_ENCAPSED_STRING, | ||
T_COMMENT, | ||
T_DOC_COMMENT, | ||
]; | ||
} | ||
|
||
function getBracketTokens() | ||
{ | ||
return [ | ||
Generic\LEFT_ROUND, | ||
Generic\LEFT_SQUARE, | ||
Generic\LEFT_CURLY, | ||
T_CURLY_OPEN, | ||
]; | ||
} | ||
|
||
function spliceLanguageConstruct($token) | ||
{ | ||
return function(Source $s) use ($token) { | ||
foreach ($s->all($token) as $pos) { | ||
$s->splice('\\' . LANGUAGE_CONSTRUCT_PREFIX, $pos, 0, Source::PREPEND); | ||
if (lacksParentheses($s, $pos)) { | ||
addParentheses($s, $pos); | ||
} | ||
} | ||
}; | ||
} | ||
|
||
function lacksParentheses(Source $s, $pos) | ||
{ | ||
if ($s->is(T_ECHO, $pos)) { | ||
return true; | ||
} | ||
$next = $s->skip(Source::junk(), $pos); | ||
return !$s->is(Generic\LEFT_ROUND, $next); | ||
} | ||
|
||
function addParentheses(Source $s, $pos) | ||
{ | ||
$pos = $s->skip(Source::junk(), $pos); | ||
$s->splice(Generic\LEFT_ROUND, $pos, 0, Source::PREPEND); | ||
while ($pos < count($s->tokens)) { | ||
if ($s->is(getInnerTokens(), $pos)) { | ||
$pos++; | ||
} elseif ($s->is(getBracketTokens(), $pos)) { | ||
$pos = $s->match($pos) + 1; | ||
} else { | ||
break; | ||
} | ||
} | ||
if ($s->is(Source::junk(), $pos)) { | ||
$pos = $s->skipBack(Source::junk(), $pos); | ||
} | ||
$s->splice(Generic\RIGHT_ROUND, $pos, 0, Source::APPEND); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
<?php | ||
|
||
/** | ||
* @link http://patchwork2.org/ | ||
* @author Ignas Rudaitis <ignas.rudaitis@gmail.com> | ||
* @copyright 2010-2017 Ignas Rudaitis | ||
* @license http://www.opensource.org/licenses/mit-license.html | ||
*/ | ||
namespace Patchwork\Redefinitions\LanguageConstructs; | ||
|
||
function _echo($string) | ||
{ | ||
foreach (func_get_args() as $argument) { | ||
echo $argument; | ||
} | ||
} | ||
|
||
function _print($string) | ||
{ | ||
return print($string); | ||
} | ||
|
||
function _eval($code) | ||
{ | ||
return eval($code); | ||
} | ||
|
||
function _die($message = null) | ||
{ | ||
die($message); | ||
} | ||
|
||
function _exit($message = null) | ||
{ | ||
exit($message); | ||
} | ||
|
||
function _isset(&$lvalue) | ||
{ | ||
return isset($lvalue); | ||
} | ||
|
||
function _unset(&$lvalue) | ||
{ | ||
unset($lvalue); | ||
} | ||
|
||
function _empty(&$lvalue) | ||
{ | ||
return empty($lvalue); | ||
} | ||
|
||
function _require($path) | ||
{ | ||
return require($path); | ||
} | ||
|
||
function _require_once($path) | ||
{ | ||
return require_once($path); | ||
} | ||
|
||
function _include($path) | ||
{ | ||
return include($path); | ||
} | ||
|
||
function _include_once($path) | ||
{ | ||
return include_once($path); | ||
} | ||
|
||
function _clone($object) | ||
{ | ||
return clone $object; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<?php | ||
|
||
echo 'This is a string'; | ||
echo 'This is a string', ' and this is another one'; | ||
print(404); | ||
exit('error'); | ||
die(); | ||
die; | ||
false or die; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
--TEST-- | ||
Redefining language constructs like die(), echo, require_once etc. (https://github.com/antecedent/patchwork/issues/59) | ||
|
||
--SKIPIF-- | ||
<?php !defined('HHVM_VERSION') | ||
or die('skip because the redefinition of language constructs is not yet implemented for HHVM') ?> | ||
|
||
--FILE-- | ||
<?php | ||
|
||
namespace Patchwork; | ||
|
||
assert_options(ASSERT_ACTIVE, 1); | ||
assert_options(ASSERT_WARNING, 1); | ||
error_reporting(E_ALL | E_STRICT); | ||
|
||
$_SERVER['PHP_SELF'] = __FILE__; | ||
|
||
require __DIR__ . "/../Patchwork.php"; | ||
|
||
$calls = [ | ||
'die' => [], | ||
'exit' => [], | ||
'echo' => [], | ||
'print' => [], | ||
]; | ||
|
||
function collect(array &$collection) | ||
{ | ||
return function() use (&$collection) { | ||
$collection[] = func_get_args(); | ||
}; | ||
} | ||
|
||
redefine('die', collect($calls['die'])); | ||
redefine('exit', collect($calls['exit'])); | ||
redefine('echo', collect($calls['echo'])); | ||
redefine('print', collect($calls['print'])); | ||
|
||
require __DIR__ . "/includes/LanguageConstructUsages.php"; | ||
|
||
assert($calls['die'] == [ | ||
[], | ||
[], | ||
[], | ||
]); | ||
|
||
assert($calls['exit'] == [ | ||
['error'], | ||
]); | ||
|
||
assert($calls['echo'] == [ | ||
['This is a string'], | ||
['This is a string', ' and this is another one'], | ||
]); | ||
|
||
assert($calls['print'] == [ | ||
[404], | ||
]); | ||
|
||
?> | ||
===DONE=== | ||
|
||
--EXPECT-- | ||
===DONE=== |
Oops, something went wrong.