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 摘要。