mirror of
https://github.com/danog/PHP-Parser.git
synced 2025-01-20 12:46:47 +01:00
Fix problem with indented strings by introducing PrettyPrinter->pSafe
This commit is contained in:
parent
352cfde568
commit
b80f326b6a
@ -139,7 +139,7 @@ The pretty printer compiles nodes back to PHP code. "Pretty printing" here is ju
|
||||
name of the process and does not mean that the output is in any way pretty.
|
||||
|
||||
$prettyPrinter = new PrettyPrinter_Zend;
|
||||
echo '<pre>' . htmlspecialchars($prettyPrinter->pStmts($stmts)) . '</pre>';
|
||||
echo '<pre>' . htmlspecialchars($prettyPrinter->prettyPrint($stmts)) . '</pre>';
|
||||
|
||||
For the code mentioned in the above section this should create the output:
|
||||
|
||||
@ -151,6 +151,3 @@ For the code mentioned in the above section this should create the output:
|
||||
|
||||
Known Issues
|
||||
============
|
||||
|
||||
* When pretty printing strings and InlineHTML those are indented like any other code, thus causing
|
||||
extra whitespace to be inserted (causes 23 compare fails in test against Symfony Beta 3).
|
@ -53,7 +53,7 @@ class PrettyPrinter_Zend extends PrettyPrinterAbstract
|
||||
public function pScalar_String(Node_Scalar_String $node) {
|
||||
return ($node->isBinary ? 'b' : '')
|
||||
. (Node_Scalar_String::SINGLE_QUOTED === $node->type
|
||||
? '\'' . addcslashes($node->value, '\'\\') . '\''
|
||||
? '\'' . $this->pSafe(addcslashes($node->value, '\'\\')) . '\''
|
||||
: '"' . addcslashes($node->value, "\n\r\t\f\v$\"\\") . '"'
|
||||
);
|
||||
}
|
||||
@ -394,7 +394,7 @@ class PrettyPrinter_Zend extends PrettyPrinterAbstract
|
||||
return 'function ' . ($node->byRef ? '&' : '')
|
||||
. '(' . $this->pCommaSeparated($node->params) . ')'
|
||||
. (!empty($node->useVars) ? ' use(' . $this->pCommaSeparated($node->useVars) . ')': '')
|
||||
. ' {' . "\n" . $this->pIndent($this->pStmts($node->stmts)) . '}';
|
||||
. ' {' . "\n" . $this->pStmts($node->stmts) . "\n" . '}';
|
||||
}
|
||||
|
||||
public function pExpr_LambdaFuncUse(Node_Expr_LambdaFuncUse $node) {
|
||||
@ -436,7 +436,7 @@ class PrettyPrinter_Zend extends PrettyPrinterAbstract
|
||||
public function pStmt_Interface(Node_Stmt_Interface $node) {
|
||||
return 'interface ' . $node->name
|
||||
. (!empty($node->extends) ? ' extends ' . $this->pCommaSeparated($node->extends) : '')
|
||||
. "\n" . '{' . "\n" . $this->pIndent($this->pStmts($node->stmts)) . '}';
|
||||
. "\n" . '{' . "\n" . $this->pStmts($node->stmts) . "\n" . '}';
|
||||
}
|
||||
|
||||
public function pStmt_Class(Node_Stmt_Class $node) {
|
||||
@ -444,7 +444,7 @@ class PrettyPrinter_Zend extends PrettyPrinterAbstract
|
||||
. 'class ' . $node->name
|
||||
. (null !== $node->extends ? ' extends ' . $this->p($node->extends) : '')
|
||||
. (!empty($node->implements) ? ' implements ' . $this->pCommaSeparated($node->implements) : '')
|
||||
. "\n" . '{' . "\n" . $this->pIndent($this->pStmts($node->stmts)) . '}';
|
||||
. "\n" . '{' . "\n" . $this->pStmts($node->stmts) . "\n" . '}';
|
||||
}
|
||||
|
||||
public function pStmt_Property(Node_Stmt_Property $node) {
|
||||
@ -461,7 +461,7 @@ class PrettyPrinter_Zend extends PrettyPrinterAbstract
|
||||
. 'function ' . ($node->byRef ? '&' : '') . $node->name
|
||||
. '(' . $this->pCommaSeparated($node->params) . ')'
|
||||
. (null !== $node->stmts
|
||||
? "\n" . '{' . "\n" . $this->pIndent($this->pStmts($node->stmts)) . '}'
|
||||
? "\n" . '{' . "\n" . $this->pStmts($node->stmts) . "\n" . '}'
|
||||
: ';');
|
||||
}
|
||||
|
||||
@ -475,8 +475,8 @@ class PrettyPrinter_Zend extends PrettyPrinterAbstract
|
||||
|
||||
public function pStmt_Func(Node_Stmt_Func $node) {
|
||||
return 'function ' . ($node->byRef ? '&' : '') . $node->name
|
||||
. '(' . $this->pCommaSeparated($node->params) . ')' . "\n" . '{' . "\n"
|
||||
. $this->pIndent($this->pStmts($node->stmts)) . '}';
|
||||
. '(' . $this->pCommaSeparated($node->params) . ')'
|
||||
. "\n" . '{' . "\n" . $this->pStmts($node->stmts) . "\n" . '}';
|
||||
}
|
||||
|
||||
public function pStmt_FuncParam(Node_Stmt_FuncParam $node) {
|
||||
@ -497,20 +497,19 @@ class PrettyPrinter_Zend extends PrettyPrinterAbstract
|
||||
// Control flow
|
||||
|
||||
public function pStmt_If(Node_Stmt_If $node) {
|
||||
return 'if (' . $this->p($node->cond) . ') {' . "\n"
|
||||
. $this->pIndent($this->pStmts($node->stmts)) . '}'
|
||||
return 'if (' . $this->p($node->cond) . ') {'
|
||||
. "\n" . $this->pStmts($node->stmts) . "\n" . '}'
|
||||
. $this->pImplode($node->elseifList)
|
||||
. (null !== $node->else ? $this->p($node->else) : '');
|
||||
}
|
||||
|
||||
public function pStmt_Elseif(Node_Stmt_Elseif $node) {
|
||||
return ' elseif (' . $this->p($node->cond) . ') {' . "\n"
|
||||
. $this->pIndent($this->pStmts($node->stmts)) . '}';
|
||||
return ' elseif (' . $this->p($node->cond) . ') {'
|
||||
. "\n" . $this->pStmts($node->stmts) . "\n" . '}';
|
||||
}
|
||||
|
||||
public function pStmt_Else(Node_Stmt_Else $node) {
|
||||
return ' else {' . "\n"
|
||||
. $this->pIndent($this->pStmts($node->stmts)) . '}';
|
||||
return ' else {' . "\n" . $this->pStmts($node->stmts) . "\n" . '}';
|
||||
}
|
||||
|
||||
public function pStmt_For(Node_Stmt_For $node) {
|
||||
@ -518,44 +517,44 @@ class PrettyPrinter_Zend extends PrettyPrinterAbstract
|
||||
. $this->pCommaSeparated($node->init) . ';'
|
||||
. $this->pCommaSeparated($node->cond) . ';'
|
||||
. $this->pCommaSeparated($node->loop)
|
||||
. ') {' . "\n" . $this->pIndent($this->pStmts($node->stmts)) . '}';
|
||||
. ') {' . "\n" . $this->pStmts($node->stmts) . "\n" . '}';
|
||||
}
|
||||
|
||||
public function pStmt_Foreach(Node_Stmt_Foreach $node) {
|
||||
return 'foreach (' . $this->p($node->expr) . ' as '
|
||||
. (null !== $node->keyVar ? $this->p($node->keyVar) . ' => ' : '')
|
||||
. ($node->byRef ? '&' : '') . $this->p($node->valueVar) . ') {' . "\n"
|
||||
. $this->pIndent($this->pStmts($node->stmts)) . '}';
|
||||
. ($node->byRef ? '&' : '') . $this->p($node->valueVar) . ') {'
|
||||
. "\n" . $this->pStmts($node->stmts) . "\n" . '}';
|
||||
}
|
||||
|
||||
public function pStmt_While(Node_Stmt_While $node) {
|
||||
return 'while (' . $this->p($node->cond) . ') {'
|
||||
. "\n" . $this->pIndent($this->pStmts($node->stmts)) . '}';
|
||||
. "\n" . $this->pStmts($node->stmts) . "\n" . '}';
|
||||
}
|
||||
|
||||
public function pStmt_Do(Node_Stmt_Do $node) {
|
||||
return 'do {' . "\n" . $this->pIndent($this->pStmts($node->stmts))
|
||||
. '} while (' . $this->p($node->cond) . ')';
|
||||
return 'do {' . "\n" . $this->pStmts($node->stmts)
|
||||
. '} while (' . $this->p($node->cond) . "\n" . ')';
|
||||
}
|
||||
|
||||
public function pStmt_Switch(Node_Stmt_Switch $node) {
|
||||
return 'switch (' . $this->p($node->cond) . ') {'
|
||||
. "\n" . $this->pIndent($this->pImplode($node->caseList)) . '}';
|
||||
. "\n" . $this->pImplode($node->caseList) . '}';
|
||||
}
|
||||
|
||||
public function pStmt_TryCatch(Node_Stmt_TryCatch $node) {
|
||||
return 'try {' . "\n" . $this->pIndent($this->pStmts($node->stmts)) . '}'
|
||||
return 'try {' . "\n" . $this->pStmts($node->stmts) . "\n" . '}'
|
||||
. $this->pImplode($node->catches);
|
||||
}
|
||||
|
||||
public function pStmt_Catch(Node_Stmt_Catch $node) {
|
||||
return ' catch (' . $this->p($node->type) . ' $' . $node->var . ') {'
|
||||
. "\n" . $this->pIndent($this->pStmts($node->stmts)) . '}';
|
||||
. "\n" . $this->pStmts($node->stmts) . "\n" . '}';
|
||||
}
|
||||
|
||||
public function pStmt_Case(Node_Stmt_Case $node) {
|
||||
return (null !== $node->cond ? 'case ' . $this->p($node->cond) : 'default') . ':'
|
||||
. "\n" . $this->pIndent($this->pStmts($node->stmts));
|
||||
. "\n" . $this->pStmts($node->stmts) . "\n";
|
||||
}
|
||||
|
||||
public function pStmt_Break(Node_Stmt_Break $node) {
|
||||
@ -606,7 +605,8 @@ class PrettyPrinter_Zend extends PrettyPrinterAbstract
|
||||
}
|
||||
|
||||
public function pStmt_InlineHTML(Node_Stmt_InlineHTML $node) {
|
||||
return '?>' . ("\n" === $node->value[0] ? "\n" : '') . $node->value . '<?php ';
|
||||
return '?>' . ("\n" === $node->value[0] || "\r" === $node->value[0] ? "\n" : '')
|
||||
. $this->pSafe($node->value) . '<?php ';
|
||||
}
|
||||
|
||||
// Helpers
|
||||
@ -643,14 +643,6 @@ class PrettyPrinter_Zend extends PrettyPrinterAbstract
|
||||
foreach ($encapsList as $i => $element) {
|
||||
if (is_string($element)) {
|
||||
$return .= addcslashes($element, "\n\r\t\f\v$\"\\");
|
||||
} elseif ($element instanceof Node_Variable
|
||||
&& is_string($element->name)
|
||||
&& (!isset($encapsList[$i + 1])
|
||||
|| !is_string($encapsList[$i + 1])
|
||||
|| '[' !== $encapsList[$i + 1][0]
|
||||
)
|
||||
) {
|
||||
$return .= '$' . $element->name;
|
||||
} else {
|
||||
$return .= '{' . $this->p($element) . '}';
|
||||
}
|
||||
|
@ -56,40 +56,62 @@ abstract class PrettyPrinterAbstract
|
||||
'Expr_LogicalXor' => 17,
|
||||
'Expr_LogicalOr' => 18,
|
||||
);
|
||||
protected $stmtsWithoutSemicolon = array(
|
||||
'Stmt_Func' => true,
|
||||
'Stmt_Interface' => true,
|
||||
'Stmt_Class' => true,
|
||||
'Stmt_ClassMethod' => true,
|
||||
'Stmt_For' => true,
|
||||
'Stmt_Foreach' => true,
|
||||
'Stmt_If' => true,
|
||||
'Stmt_Switch' => true,
|
||||
'Stmt_While' => true,
|
||||
'Stmt_TryCatch' => true,
|
||||
'Stmt_Label' => true,
|
||||
);
|
||||
|
||||
protected $precedenceStack = array(19);
|
||||
protected $precedenceStackPos = 0;
|
||||
protected $precedenceStack;
|
||||
protected $precedenceStackPos;
|
||||
protected $noIndentToken;
|
||||
|
||||
/**
|
||||
* Pretty prints an array of statements.
|
||||
* Pretty prints an array of nodes (statements).
|
||||
*
|
||||
* @param array $nodes Array of statements
|
||||
* @param array $nodes Array of nodes
|
||||
*
|
||||
* @return string Pretty printed nodes
|
||||
*/
|
||||
public function prettyPrint(array $nodes) {
|
||||
$this->precedenceStack = array($this->precedenceStackPos = 0 => 19);
|
||||
$this->noIndentToken = uniqid('_NO_INDENT_');
|
||||
|
||||
return str_replace("\n" . $this->noIndentToken, "\n", $this->pStmts($nodes, false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Pretty prints an array of nodes (statements) and indents them optionally.
|
||||
*
|
||||
* @param array $nodes Array of nodes
|
||||
* @param bool $indent Whether to indent the printed nodes
|
||||
*
|
||||
* @return string Pretty printed statements
|
||||
*/
|
||||
public function pStmts(array $nodes) {
|
||||
$return = '';
|
||||
protected function pStmts(array $nodes, $indent = true) {
|
||||
$pNodes = array();
|
||||
foreach ($nodes as $node) {
|
||||
$return .= $this->p($node);
|
||||
|
||||
if ( $node instanceof Node_Stmt_Func
|
||||
|| $node instanceof Node_Stmt_Interface
|
||||
|| $node instanceof Node_Stmt_Class
|
||||
|| $node instanceof Node_Stmt_ClassMethod
|
||||
|| $node instanceof Node_Stmt_For
|
||||
|| $node instanceof Node_Stmt_Foreach
|
||||
|| $node instanceof Node_Stmt_If
|
||||
|| $node instanceof Node_Stmt_Switch
|
||||
|| $node instanceof Node_Stmt_While
|
||||
|| $node instanceof Node_Stmt_TryCatch
|
||||
|| $node instanceof Node_Stmt_Label
|
||||
) {
|
||||
$return .= "\n";
|
||||
} else {
|
||||
$return .= ';' . "\n";
|
||||
}
|
||||
$pNodes[] = $this->p($node)
|
||||
. (isset($this->stmtsWithoutSemicolon[$node->getType()]) ? '' : ';');
|
||||
}
|
||||
|
||||
if ($indent) {
|
||||
return ' ' . preg_replace(
|
||||
'~\n(?!$|' . $this->noIndentToken . ')~',
|
||||
"\n" . ' ',
|
||||
implode("\n", $pNodes)
|
||||
);
|
||||
} else {
|
||||
return implode("\n", $pNodes);
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -99,7 +121,7 @@ abstract class PrettyPrinterAbstract
|
||||
*
|
||||
* @return string Pretty printed node
|
||||
*/
|
||||
public function p(NodeAbstract $node) {
|
||||
protected function p(NodeAbstract $node) {
|
||||
$type = $node->getType();
|
||||
|
||||
if (isset($this->precedanceMap[$type])) {
|
||||
@ -150,20 +172,13 @@ abstract class PrettyPrinterAbstract
|
||||
}
|
||||
|
||||
/**
|
||||
* Indents a string by four space characters.
|
||||
* Signifies the pretty printer that a string shall not be indented.
|
||||
*
|
||||
* @param string $string String to indent
|
||||
* @param string $string Not to be indented string
|
||||
*
|
||||
* @return string Indented string
|
||||
* @return mixed String marked with $this->noIndentToken's.
|
||||
*/
|
||||
protected function pIndent($string) {
|
||||
$lines = explode("\n", $string);
|
||||
foreach ($lines as &$line) {
|
||||
if ('' !== $line) {
|
||||
$line = ' ' . $line;
|
||||
}
|
||||
}
|
||||
|
||||
return implode("\n", $lines);
|
||||
protected function pSafe($string) {
|
||||
return str_replace("\n", "\n" . $this->noIndentToken, $string);
|
||||
}
|
||||
}
|
@ -54,7 +54,7 @@ foreach (new RecursiveIteratorIterator(
|
||||
if (false !== $stmts) {
|
||||
++$ppCount;
|
||||
$ppTime -= microtime(true);
|
||||
$code = '<?php' . "\n" . $prettyPrinter->pStmts($stmts);
|
||||
$code = '<?php' . "\n" . $prettyPrinter->prettyPrint($stmts);
|
||||
$ppTime += microtime(true);
|
||||
|
||||
$ppStmts = $parser->parse(
|
||||
|
Loading…
x
Reference in New Issue
Block a user