Add "kind" attribute to LNumbers

Kind specifies whether the number was formatted as decimal, octal,
binary or hex. The pretty printer reproduces the number kind (but
not necessarily the exact formatting).
This commit is contained in:
Nikita Popov 2016-03-09 21:10:55 +01:00
parent 47c342a3e4
commit ae30f97af6
6 changed files with 47 additions and 13 deletions

View File

@ -27,7 +27,7 @@ if (empty($files)) {
}
$lexer = new PhpParser\Lexer\Emulative(array('usedAttributes' => array(
'startLine', 'endLine', 'startFilePos', 'endFilePos', 'comments'
'startLine', 'endLine', 'startFilePos', 'endFilePos', 'comments', 'kind'
)));
$parser = (new PhpParser\ParserFactory)->create(PhpParser\ParserFactory::PREFER_PHP7, $lexer);
$dumper = new PhpParser\NodeDumper(['dumpComments' => true]);

View File

@ -2,6 +2,7 @@
namespace PhpParser;
use PhpParser\Node\Scalar\LNumber;
use PhpParser\Parser\Tokens;
class Lexer
@ -21,10 +22,10 @@ class Lexer
* Creates a Lexer.
*
* @param array $options Options array. Currently only the 'usedAttributes' option is supported,
* which is an array of attributes to add to the AST nodes. Possible attributes
* are: 'comments', 'startLine', 'endLine', 'startTokenPos', 'endTokenPos',
* 'startFilePos', 'endFilePos'. The option defaults to the first three.
* For more info see getNextToken() docs.
* which is an array of attributes to add to the AST nodes. Possible
* attributes are: 'comments', 'kind', 'startLine', 'endLine',
* 'startTokenPos', 'endTokenPos', 'startFilePos', 'endFilePos'. The
* option defaults to the first four. For more info see getNextToken() docs.
*/
public function __construct(array $options = array()) {
// map from internal tokens to PhpParser tokens
@ -37,7 +38,7 @@ class Lexer
// the usedAttributes member is a map of the used attribute names to a dummy
// value (here "true")
$options += array(
'usedAttributes' => array('comments', 'startLine', 'endLine'),
'usedAttributes' => array('comments', 'kind', 'startLine', 'endLine'),
);
$this->usedAttributes = array_fill_keys($options['usedAttributes'], true);
}
@ -115,12 +116,14 @@ class Lexer
* * 'comments' => Array of PhpParser\Comment or PhpParser\Comment\Doc instances,
* representing all comments that occurred between the previous
* non-discarded token and the current one.
* * 'kind' => For some tokens, this will provide additional information about the
* formatting of the node (e.g. whether a numeric literal is binary/...)
* * 'startLine' => Line in which the node starts.
* * 'endLine' => Line in which the node ends.
* * 'startTokenPos' => Offset into the token array of the first token in the node.
* * 'endTokenPos' => Offset into the token array of the last token in the node.
* * 'startFilePos' => Offset into the code string of the first character that is part of the node.
* * 'endFilePos' => Offset into the code string of the last character that is part of the node
* * 'endFilePos' => Offset into the code string of the last character that is part of the node.
*
* @param mixed $value Variable to store token content in
* @param mixed $startAttributes Variable to store start attributes in
@ -201,8 +204,20 @@ class Lexer
$endAttributes['endFilePos'] = $this->filePos - 1;
}
if ($token[0] === T_EXIT) {
$startAttributes['kind'] = strtolower($token[1]);
if (isset($this->usedAttributes['kind'])) {
if ($token[0] === T_EXIT) {
$startAttributes['kind'] = strtolower($value);
} elseif ($token[0] === T_LNUMBER) {
if ($value === '0' || $value[0] !== '0') {
$startAttributes['kind'] = LNumber::KIND_DEC;
} elseif ($value[1] === 'x' || $value[1] === 'X') {
$startAttributes['kind'] = LNumber::KIND_HEX;
} elseif ($value[1] === 'b' || $value[1] === 'B') {
$startAttributes['kind'] = LNumber::KIND_BIN;
} else {
$startAttributes['kind'] = LNumber::KIND_OCT;
}
}
}
return $this->tokenMap[$token[0]];

View File

@ -6,6 +6,12 @@ use PhpParser\Node\Scalar;
class LNumber extends Scalar
{
/* For use in "kind" attribute */
const KIND_BIN = 2;
const KIND_OCT = 8;
const KIND_DEC = 10;
const KIND_HEX = 16;
/** @var int Number value */
public $value;

View File

@ -92,7 +92,17 @@ class Standard extends PrettyPrinterAbstract
}
public function pScalar_LNumber(Scalar\LNumber $node) {
return (string) $node->value;
$str = (string) $node->value;
switch ($node->getAttribute('kind', Scalar\LNumber::KIND_DEC)) {
case Scalar\LNumber::KIND_BIN:
return '0b' . base_convert($str, 10, 2);
case Scalar\LNumber::KIND_OCT:
return '0' . base_convert($str, 10, 8);
case Scalar\LNumber::KIND_DEC:
return $str;
case Scalar\LNumber::KIND_HEX:
return '0x' . base_convert($str, 10, 16);
}
}
public function pScalar_DNumber(Scalar\DNumber $node) {

View File

@ -68,6 +68,9 @@ CODE;
<attribute:startLine>
<scalar:int>4</scalar:int>
</attribute:startLine>
<attribute:kind>
<scalar:int>10</scalar:int>
</attribute:kind>
<attribute:endLine>
<scalar:int>4</scalar:int>
</attribute:endLine>

View File

@ -107,9 +107,9 @@ FALSE;
// integers (normalized to decimal)
0;
11;
9;
17;
3;
011;
0x11;
0b11;
// floats (normalized to ... something)
0.0;
0.0;