microsoft/tolerant-php-parser

适用于IDE使用场景的容错PHP-to-AST解析器

v0.1.2 2022-10-05 17:30 UTC

README

CI

这是一个早期阶段的PHP解析器,从一开始就是为了IDE使用场景而设计的(更多详细信息,请参阅设计目标)。还有很多工作要做,所以在这个阶段,这个存储库主要作为一个实验和对话的开始。

image

这是v0.1分支,它更改了数据结构以支持在初始0.0.x发布线之后添加的语法。

入门

在您配置了您的机器之后,您可以使用解析器通过友好的API生成并处理抽象语法树(AST)。

<?php
// Autoload required classes
require __DIR__ . "/vendor/autoload.php";

use Microsoft\PhpParser\{DiagnosticsProvider, Node, Parser, PositionUtilities};

// Instantiate new parser instance
$parser = new Parser();

// Return and print an AST from string contents
$astNode = $parser->parseSourceFile('<?php /* comment */ echo "hi!"');
var_dump($astNode);

// Gets and prints errors from AST Node. The parser handles errors gracefully,
// so it can be used in IDE usage scenarios (where code is often incomplete).
$errors = DiagnosticsProvider::getDiagnostics($astNode);
var_dump($errors);

// Traverse all Node descendants of $astNode
foreach ($astNode->getDescendantNodes() as $descendant) {
    if ($descendant instanceof Node\StringLiteral) {
        // Print the Node text (without whitespace or comments)
        var_dump($descendant->getText());

        // All Nodes link back to their parents, so it's easy to navigate the tree.
        $grandParent = $descendant->getParent()->getParent();
        var_dump($grandParent->getNodeKindName());

        // The AST is fully-representative, and round-trippable to the original source.
        // This enables consumers to build reliable formatting and refactoring tools.
        var_dump($grandParent->getLeadingCommentAndWhitespaceText());
    }

    // In addition to retrieving all children or descendants of a Node,
    // Nodes expose properties specific to the Node type.
    if ($descendant instanceof Node\Expression\EchoExpression) {
        $echoKeywordStartPosition = $descendant->echoKeyword->getStartPosition();
        // To cut down on memory consumption, positions are represented as a single integer
        // index into the document, but their line and character positions are easily retrieved.
        $lineCharacterPosition = PositionUtilities::getLineCharacterPositionFromPosition(
            $echoKeywordStartPosition,
            $descendant->getFileContents()
        );
        echo "line: $lineCharacterPosition->line, character: $lineCharacterPosition->character";
    }
}

注意: API尚未最终确定,因此请提交问题以让我们知道您想公开的功能,我们将看看我们能做什么!同时,也请提交任何关于解析树中意外行为的错误。我们仍处于早期阶段,您提供的任何反馈都将非常感谢 😃。

设计目标

  • 容错设计 - 在IDE场景中,代码从定义上就是不完全的。在输入无效代码的情况下,解析器仍然应该能够恢复并生成一个有效且完整的树,以及相关的诊断。
  • 快速且轻量级(应该能够每秒解析数MB的源代码,为其他功能留出空间)。
    • 内存高效的数据结构
    • 允许未来进行增量解析
  • 遵循PHP语言规范,支持PHP5和PHP7语法
  • 生成的AST提供了语义和转换操作所需的属性(完全代表等),同时也需要高效。
    • 完全代表,可以回绕到解析的文本(包括所有空白和注释“琐事”)
    • 可以通过父/子节点轻松遍历树
    • < 100 ms UI响应时间,因此每个语言服务器操作应小于50 ms,为并行进行的所有其他操作留出空间。
  • 简单且易于维护 - 解析器有快速变得非常混乱的倾向,因此可读性和可调试性是优先事项。
  • 可测试 - 解析器应生成可证明有效的解析树。我们通过定义并持续测试关于树的一组不变性来实现这一点。
  • 友好且描述性的API,使其易于他人构建。
  • 用PHP编写 - 使PHP社区消费和贡献尽可能容易。

当前状态和策略

为了确保每一步都达到足够的正确性水平,解析器正在使用以下增量方法进行开发

  • 阶段1:编写不支持PHP语法的词法分析器,但支持EOF和未知标记。为所有不变性编写测试。
  • 阶段2:支持PHP词法语法,大量测试
  • 第3阶段:编写一个不支持PHP语法的解析器,但能生成错误节点树的解析器。为所有不变性编写测试。
  • 第4阶段:支持PHP语法,大量测试
  • 第5阶段(进行中 🏃):进行实际验证和优化
    • 正确性:验证在样本代码库上没有产生错误,与其他解析器进行基准测试(调查任何不一致的实例),模糊测试
    • 性能:分析,与大型PHP应用程序进行基准测试
  • 第6阶段:最终确定API,使其尽可能容易供人们使用。

附加说明

一些PHP语法结构(特别是yield表达式和模板字符串)尚未支持,也存在其他一些杂项错误。然而,由于解析器具有容错性,这些错误被优雅地处理,生成的树在其他方面是完整的。要更全面地了解我们的位置,可以运行“验证”测试套件(有关运行测试的更多信息,请参阅贡献指南)。或者简单地查看当前的验证测试结果

尽管我们尚未开始性能优化阶段,但我们已经看到了有希望的结果,还有很大的改进空间。有关我们当前方法的详细信息,请参阅工作原理,并在您的机器上运行性能测试以亲自查看。

了解更多信息

🎯 设计目标 - 了解项目的目标(功能、性能指标等)。

📖 文档 - 了解如何从您的项目中引用解析器,以及如何对AST执行操作以回答有关您的代码的问题。

👀 语法可视化工具 - 获得对AST的更直观的感受。发挥创意 - 看看你是否能破坏它!

📈 当前状态和方法 - 支持了多少语法?性能?内存?API稳定性?

🔧 工作原理 - 了解架构、设计决策和权衡。

💖 贡献! - 了解如何参与,查看一些教育性提交的指针,这些提交将帮助您快速熟悉代码库(即使您以前从未编写过解析器),以及推荐的工作流程,使迭代更容易。

本项目已采用Microsoft开源行为准则。有关更多信息,请参阅行为准则常见问题解答或联系opencode@microsoft.com,如有任何其他问题或评论。