python / python/cpython

"pegen.py python" should validate the output file.

未关闭
#101,925 1 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

build type-bug
主要语言
Python
星标
77.2k
派生
36k
PR 合并指标
PR 指标待抓取

描述

I ran pegen python -o grammar_parser.py after making an incorrect change to metagrammar.gram. This was invoked by make regen-pegen-metaparser, or build.bat --regen on Windows.
The resulting output file was syntactically correct, but it could not correctly parse the metagrammar file. So when I ran the make again later, it failed. The call to GeneratedParser.start() raised an exception.

The previous (correctly working) version of grammar_parser.py is now lost, unless I could get it back from Git.

Desired behavior

pegen must be sure that the newly generated output file will work correctly, before writing it out to the filesystem.

Generation of the output file begins in pegen/build.py,

def build_python_generator(
    grammar: Grammar,
    grammar_file: str,
    output_file: str,
    skip_actions: bool = False,
) -> ParserGenerator:
    with open(output_file, "w") as file:
        gen: ParserGenerator = PythonParserGenerator(grammar, file)  # TODO: skip_actions
        gen.generate(grammar_file)
    return gen

This creates a new output file. Even if the body of the with raises an exception, the output file is closed and remains in the filesystem, overwriting the previous version.
Instead,

  1. Use a StringIO as the file, instead of a real open() file. Call it result.
  2. Generate the file, which fills in result.
  3. Validate result (see more below).
  4. If validation succeeds, then write the result to a new open(output_file, "w").
  5. Otherwise, do nothing more. The file designated by output_file will still be intact.

Validating the output file

To validate the output file result, go through the entire process of generating result, except using
result instead of the grammar_parser module. This process is the entire code of build_python_parser_and_generator, not just the build_python_generator function.

grammar_parser is used to import the class GeneratedParser. For validation purposes, exec(result) with an empty globals/locals dict, then use the ['GeneratedParser'] item. Note, in build.py, this class is imported as the name GrammarParser.
This process should generate a new_result StringIO, and it should be identical to result. Perhaps there may be some insignificant differences between the two, and if so, they shouldn't be compared.
If the generation of new_result raises an exception, then the validation has failed.

Linked PRs
  • gh-101937

贡献指南

打开贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

调研方向

从 pegen/build.py 开始,重点查看 build_python_generator 和 build_python_parser_and_generator。跟踪生成的 parser 输出是如何生成和验证的,然后在验证失败时保留现有的输出文件,并确认只有在验证通过后才写入成功的输出。查看链接的 PR gh-101937,了解已经在进行的工作。

由索引模型根据 Issue 内容生成。

评估

技术栈
python
领域
build-system, compilers
Issue 类型
缺陷
难度
4/5
预计耗时
3-5 天
活跃度
停滞
描述清晰度
描述清楚
新手友好度
32/100

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。