Files
compiler-explorer/test/ast/python-long.ast
Sirui Mu 7a6af91bc9 Enable AST output for Python (#8858)
This patch adds support for viewing the abstract syntax tree (AST) of
Python source code in Compiler Explorer, matching the existing AST
viewer feature for C/C++ (Clang AST).

- This patch adds a helper script `ast_dump.py` that parses and dumps
the AST for a Python source code file. `python -m ast` should also work,
but it's not available in old versions of Python.
- This patch adds an AST parser for Python which mimics the structure of
the C/C++ AST parser. It also updates the Python compiler to enable AST
output.
- All existing and new tests pass.

Assisted-by: GitHub Copilot / DeepSeek v4 Flash
Assisted-by: GitHub Copilot / DeepSeek v4 Pro

<!-- THIS COMMENT IS INVISIBLE IN THE FINAL PR, BUT FEEL FREE TO REMOVE
IT
Thanks for taking the time to improve CE. We really appreciate it.
Before opening the PR, please make sure that the tests & linter pass
their checks,
  by running `make check`.
In the best case scenario, you are also adding tests to back up your
changes,
  but don't sweat it if you don't. We can discuss them at a later date.
Feel free to append your name to the CONTRIBUTORS.md file
Thanks again, we really appreciate this!
-->

Co-authored-by: Matt Godbolt <matt@godbolt.org>
2026-07-14 08:46:10 +01:00

161 lines
5.1 KiB
Plaintext

Module(
body=[
Expr(
value=Constant(value='Dumps the AST of a Python source file as structured JSON for Compiler Explorer.')),
Import(
names=[
alias(name='argparse')]),
Import(
names=[
alias(name='ast')]),
Import(
names=[
alias(name='sys')]),
FunctionDef(
name='main',
args=arguments(),
body=[
Assign(
targets=[
Name(id='parser', ctx=Store())],
value=Call(
func=Attribute(
value=Name(id='argparse', ctx=Load()),
attr='ArgumentParser',
ctx=Load()),
keywords=[
keyword(
arg='description',
value=Constant(value='Parse and dump the AST of an Python source file'))])),
Expr(
value=Call(
func=Attribute(
value=Name(id='parser', ctx=Load()),
attr='add_argument',
ctx=Load()),
args=[
Constant(value='input')],
keywords=[
keyword(
arg='help',
value=Constant(value='Path to input Python source code file'))])),
Assign(
targets=[
Name(id='args', ctx=Store())],
value=Call(
func=Attribute(
value=Name(id='parser', ctx=Load()),
attr='parse_args',
ctx=Load()))),
Try(
body=[
With(
items=[
withitem(
context_expr=Call(
func=Name(id='open', ctx=Load()),
args=[
Attribute(
value=Name(id='args', ctx=Load()),
attr='input',
ctx=Load()),
Constant(value='r')],
keywords=[
keyword(
arg='encoding',
value=Constant(value='utf-8'))]),
optional_vars=Name(id='f', ctx=Store()))],
body=[
Assign(
targets=[
Name(id='source', ctx=Store())],
value=Call(
func=Attribute(
value=Name(id='f', ctx=Load()),
attr='read',
ctx=Load())))])],
handlers=[
ExceptHandler(
type=Name(id='IOError', ctx=Load()),
name='err',
body=[
Expr(
value=Call(
func=Name(id='print', ctx=Load()),
args=[
BinOp(
left=Constant(value='Error reading file: %s'),
op=Mod(),
right=Name(id='err', ctx=Load()))])),
Expr(
value=Call(
func=Attribute(
value=Name(id='sys', ctx=Load()),
attr='exit',
ctx=Load()),
args=[
Constant(value=1)]))])]),
Try(
body=[
Assign(
targets=[
Name(id='tree', ctx=Store())],
value=Call(
func=Attribute(
value=Name(id='ast', ctx=Load()),
attr='parse',
ctx=Load()),
args=[
Name(id='source', ctx=Load())],
keywords=[
keyword(
arg='optimize',
value=Constant(value=0))]))],
handlers=[
ExceptHandler(
type=Name(id='SyntaxError', ctx=Load()),
name='err',
body=[
Expr(
value=Call(
func=Name(id='print', ctx=Load()),
args=[
BinOp(
left=Constant(value='SyntaxError: %s'),
op=Mod(),
right=Name(id='err', ctx=Load()))])),
Expr(
value=Call(
func=Attribute(
value=Name(id='sys', ctx=Load()),
attr='exit',
ctx=Load()),
args=[
Constant(value=1)]))])]),
Expr(
value=Call(
func=Name(id='print', ctx=Load()),
args=[
Call(
func=Attribute(
value=Name(id='ast', ctx=Load()),
attr='dump',
ctx=Load()),
args=[
Name(id='tree', ctx=Load())],
keywords=[
keyword(
arg='indent',
value=Constant(value=2))])]))]),
If(
test=Compare(
left=Name(id='__name__', ctx=Load()),
ops=[
Eq()],
comparators=[
Constant(value='__main__')]),
body=[
Expr(
value=Call(
func=Name(id='main', ctx=Load())))])])