Skip to content

Commit b670fc9

Browse files
authored
Merge pull request microsoft#74 from mousetraps/refactor-utilities
Refactor Utilities.php and write tests for Position helpers
2 parents c06a6dd + 04646fb commit b670fc9

File tree

12 files changed

+154
-62
lines changed

12 files changed

+154
-62
lines changed

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
* text=auto
2+
/tests/*.php text eol=lf
23
/tests/cases/**/*.php text eol=lf
34

45
syntax-visualizer/ export-ignore

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ var_dump($astNode);
2424

2525
// Gets and prints errors from AST Node. The parser handles errors gracefully,
2626
// so it can be used in IDE usage scenarios (where code is often incomplete).
27-
$errors = Microsoft\PhpParser\Utilities::getDiagnostics($astNode);
27+
$errors = Microsoft\PhpParser\Diagnostics::getDiagnostics($astNode);
2828
var_dump(iterator_to_array($errors));
2929

3030
// Traverse all Node descendants of $astNode
@@ -48,8 +48,9 @@ foreach ($astNode->getDescendantNodes() as $descendant) {
4848
$echoKeywordStartPosition = $descendant->echoKeyword->getStartPosition();
4949
// To cut down on memory consumption, positions are represented as a single integer
5050
// index into the document, but their line and character positions are easily retrieved.
51-
$lineCharacterPosition = \Microsoft\PhpParser\Utilities::getLineCharacterPositionFromPosition(
52-
$echoKeywordStartPosition, $descendant->getText()
51+
$lineCharacterPosition = \Microsoft\PhpParser\PositionUtilities::getLineCharacterPositionFromPosition(
52+
$echoKeywordStartPosition,
53+
$descendant->getFileContents()
5354
);
5455
echo "line: $lineCharacterPosition->line, character: $lineCharacterPosition->character";
5556
}

docs/GettingStarted.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ require "vendor/autoload.php"; # autoloads required classes
6363

6464
$parser = new Microsoft\PhpParser\Parser(); # instantiates a new parser instance
6565
$astNode = $parser->parseSourceFile('<?php /* comment */ echo "hi!";'); # returns an AST from string contents
66-
$errors = Microsoft\PhpParser\Utilities::getDiagnostics($astNode); # get errors from AST Node (as a Generator)
66+
$errors = Microsoft\PhpParser\Diagnostics::getDiagnostics($astNode); # get errors from AST Node (as a Generator)
6767

6868
var_dump($astNode); # prints full AST
6969
var_dump(iterator_to_array($errors)); # prints all errors

phpunit.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131

3232
<testsuite name="api">
3333
<file>tests/NodeApiTest.php</file>
34+
<file>tests/PositionUtilitiesTest.php</file>
3435
</testsuite>
3536

3637
<testsuite name="performance">
Lines changed: 3 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88

99
use Microsoft\PhpParser\Node;
1010

11-
class Utilities {
11+
class Diagnostics {
1212
public static function getDiagnostics($node) {
13-
$tokenKindToText = array_flip(array_merge(
13+
$tokenKindToText = \array_flip(\array_merge(
1414
TokenStringMaps::OPERATORS_AND_PUNCTUATORS,
1515
TokenStringMaps::KEYWORDS,
1616
TokenStringMaps::RESERVED_WORDS
@@ -63,52 +63,7 @@ public static function getDiagnostics($node) {
6363
}
6464

6565
foreach ($node->getChildNodesAndTokens() as $child) {
66-
yield from Utilities::getDiagnostics($child);
66+
yield from Diagnostics::getDiagnostics($child);
6767
}
6868
}
69-
70-
public static function getRangeFromPosition($pos, $length, $text) {
71-
$start = self::getLineCharacterPositionFromPosition($pos, $text);
72-
$end = self::getLineCharacterPositionFromPosition($pos + $length, $text);
73-
74-
return new Range ($start, $end);
75-
}
76-
77-
public static function getLineCharacterPositionFromPosition($pos, $text) : LineCharacterPosition {
78-
$newlinePositions = [];
79-
$newlinePos = -1;
80-
while ($newlinePos = strpos($text, "\n", $newlinePos + 1)) {
81-
if ($newlinePos < $pos) {
82-
$newlinePositions[] = $newlinePos;
83-
continue;
84-
}
85-
break;
86-
}
87-
88-
$lastNewline = count($newlinePositions) - 1;
89-
$char = $pos - ($lastNewline >= 0 ? $newlinePositions[$lastNewline] + 1 : 0);
90-
$line = count($newlinePositions);
91-
92-
return new LineCharacterPosition($line, $char);
93-
}
94-
}
95-
96-
class Range {
97-
public $start;
98-
public $end;
99-
100-
public function __construct(LineCharacterPosition $start, LineCharacterPosition $end) {
101-
$this->start = $start;
102-
$this->end = $end;
103-
}
104-
}
105-
106-
class LineCharacterPosition {
107-
public $line;
108-
public $character;
109-
110-
public function __construct(int $line, int $character) {
111-
$this->line = $line;
112-
$this->character = $character;
113-
}
11469
}

src/LineCharacterPosition.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
/*---------------------------------------------------------------------------------------------
3+
* Copyright (c) Microsoft Corporation. All rights reserved.
4+
* Licensed under the MIT License. See License.txt in the project root for license information.
5+
*--------------------------------------------------------------------------------------------*/
6+
7+
namespace Microsoft\PhpParser;
8+
9+
class LineCharacterPosition {
10+
public $line;
11+
public $character;
12+
13+
public function __construct(int $line, int $character) {
14+
$this->line = $line;
15+
$this->character = $character;
16+
}
17+
}

src/PositionUtilities.php

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
/*---------------------------------------------------------------------------------------------
3+
* Copyright (c) Microsoft Corporation. All rights reserved.
4+
* Licensed under the MIT License. See License.txt in the project root for license information.
5+
*--------------------------------------------------------------------------------------------*/
6+
7+
namespace Microsoft\PhpParser;
8+
9+
class PositionUtilities {
10+
public static function getRangeFromPosition($pos, $length, $text) {
11+
$start = self::getLineCharacterPositionFromPosition($pos, $text);
12+
$end = self::getLineCharacterPositionFromPosition($pos + $length, $text);
13+
14+
return new Range ($start, $end);
15+
}
16+
17+
/**
18+
* Get's 0-indexed LineCharacterPosition from 0-indexed position into $text.
19+
*
20+
* Out of bounds positions are handled gracefully. Positions greater than the length of text length
21+
* are resolved to text length, and negative positions are resolved to 0.
22+
* TODO consider throwing exception instead.
23+
*
24+
* @param $pos
25+
* @param $text
26+
* @return LineCharacterPosition
27+
*/
28+
public static function getLineCharacterPositionFromPosition($pos, $text) : LineCharacterPosition {
29+
if ($pos >= \strlen($text)) {
30+
$pos = \strlen($text);
31+
} elseif ($pos < 0) {
32+
$pos = 0;
33+
}
34+
35+
$newlinePositions = [];
36+
$newlinePos = -1;
37+
while ($newlinePos = \strpos($text, "\n", $newlinePos + 1)) {
38+
if ($newlinePos < $pos) {
39+
$newlinePositions[] = $newlinePos;
40+
continue;
41+
}
42+
break;
43+
}
44+
45+
$lastNewline = \count($newlinePositions) - 1;
46+
$char = $pos - ($lastNewline >= 0 ? $newlinePositions[$lastNewline] + 1 : 0);
47+
$line = \count($newlinePositions);
48+
49+
return new LineCharacterPosition($line, $char);
50+
}
51+
}

src/Range.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
/*---------------------------------------------------------------------------------------------
3+
* Copyright (c) Microsoft Corporation. All rights reserved.
4+
* Licensed under the MIT License. See License.txt in the project root for license information.
5+
*--------------------------------------------------------------------------------------------*/
6+
7+
namespace Microsoft\PhpParser;
8+
9+
class Range {
10+
public $start;
11+
public $end;
12+
13+
public function __construct(LineCharacterPosition $start, LineCharacterPosition $end) {
14+
$this->start = $start;
15+
$this->end = $end;
16+
}
17+
}
Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
<?php
22

3+
use Microsoft\PhpParser\Parser;
4+
use Microsoft\PhpParser\Diagnostics;
5+
use Microsoft\PhpParser\PositionUtilities;
6+
37
$configFile = __DIR__ . "/config.php";
48
if (file_exists($configFile)) {
59
require_once($configFile);
@@ -11,25 +15,20 @@
1115

1216
require_once($GLOBALS["PARSER_PATH"] . "bootstrap.php");
1317

14-
use Microsoft\PhpParser\Parser;
15-
use Microsoft\PhpParser\Utilities;
16-
1718
$contents = file_get_contents($argv[1]);
1819
$parser = new Parser();
1920
$sourceFile = $parser->parseSourceFile($contents);
2021

2122
file_put_contents($argv[1] . ".ast", json_encode($sourceFile, JSON_PRETTY_PRINT));
2223

23-
$diagnostics = Utilities::getDiagnostics($sourceFile);
24+
$diagnostics = Diagnostics::getDiagnostics($sourceFile);
2425
$diagnosticsAsLineCol = [];
2526
foreach ($diagnostics as $diagnostic) {
2627
$diagnosticsAsLineCol[] = [
2728
"error" => $diagnostic->kind,
2829
"message" => $diagnostic->message,
29-
"range" => Utilities::getRangeFromPosition($diagnostic->start, $diagnostic->length, $contents)
30+
"range" => PositionUtilities::getRangeFromPosition($diagnostic->start, $diagnostic->length, $contents)
3031
];
3132
}
3233

33-
//echo $argv[1];
34-
3534
echo json_encode($diagnosticsAsLineCol, JSON_PRETTY_PRINT);

tests/ParserGrammarTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
require_once(__DIR__ . "/../src/Token.php");
1010

1111
use Microsoft\PhpParser\Token;
12-
use Microsoft\PhpParser\Utilities;
12+
use Microsoft\PhpParser\Diagnostics;
1313
use PHPUnit\Framework\TestCase;
1414

1515
class ParserGrammarTest extends TestCase {
@@ -79,7 +79,7 @@ public function testSpecOutputTreeClassificationAndLength($testCaseFile, $expect
7979
$tokens = str_replace("\r\n", "\n", json_encode($sourceFile, JSON_PRETTY_PRINT));
8080
file_put_contents($expectedTreeFile, $tokens);
8181

82-
$this->assertEquals(0, iterator_count(Utilities::getDiagnostics($sourceFile)));
82+
$this->assertEquals(0, iterator_count(Diagnostics::getDiagnostics($sourceFile)));
8383
}
8484

8585
public function outTreeProvider() {

0 commit comments

Comments
 (0)