diff --git a/_images/00_pgo.png b/_images/00_pgo.png new file mode 100644 index 0000000..fd2f053 Binary files /dev/null and b/_images/00_pgo.png differ diff --git a/_images/train_diagram.svg b/_images/00_train_diagram.svg similarity index 100% rename from _images/train_diagram.svg rename to _images/00_train_diagram.svg diff --git a/_images/01_train_diagram_coffee.png b/_images/01_train_diagram_coffee.png new file mode 100644 index 0000000..477a600 Binary files /dev/null and b/_images/01_train_diagram_coffee.png differ diff --git a/_images/02_train_diagram_while.jpeg b/_images/02_train_diagram_while.jpeg new file mode 100644 index 0000000..0781c3c Binary files /dev/null and b/_images/02_train_diagram_while.jpeg differ diff --git a/_images/03_train_diagram_try.png b/_images/03_train_diagram_try.png new file mode 100644 index 0000000..23dddab Binary files /dev/null and b/_images/03_train_diagram_try.png differ diff --git a/_images/code_tokenized.png b/_images/code_tokenized.png deleted file mode 100644 index 04848cd..0000000 Binary files a/_images/code_tokenized.png and /dev/null differ diff --git a/_images/small_stmt.png b/_images/small_stmt.png deleted file mode 100644 index 7e5e9e6..0000000 Binary files a/_images/small_stmt.png and /dev/null differ diff --git a/_images/tokens.png b/_images/tokens.png deleted file mode 100644 index b3b73ca..0000000 Binary files a/_images/tokens.png and /dev/null differ diff --git a/_sources/docs/10_0_parallel_and_concurrent.md b/_sources/docs/10_0_parallel_and_concurrent.md index 00e5078..f16f681 100644 --- a/_sources/docs/10_0_parallel_and_concurrent.md +++ b/_sources/docs/10_0_parallel_and_concurrent.md @@ -1 +1 @@ -# 병렬성과 동시성 +# 10. 병렬성과 동시성 diff --git a/_sources/docs/11_0_object_and_type.md b/_sources/docs/11_0_object_and_type.md index b988849..1eeb9cf 100644 --- a/_sources/docs/11_0_object_and_type.md +++ b/_sources/docs/11_0_object_and_type.md @@ -1 +1 @@ -# 객체와 타입 +# 11. 객체와 타입 diff --git a/_sources/docs/12_0_standard_library.md b/_sources/docs/12_0_standard_library.md index 0584615..a2e2fc1 100644 --- a/_sources/docs/12_0_standard_library.md +++ b/_sources/docs/12_0_standard_library.md @@ -1 +1 @@ -# 표준 라이브러리 +# 12. 표준 라이브러리 diff --git a/_sources/docs/13_0_test_suite.md b/_sources/docs/13_0_test_suite.md index e6ef5c9..eda7197 100644 --- a/_sources/docs/13_0_test_suite.md +++ b/_sources/docs/13_0_test_suite.md @@ -1 +1 @@ -# 테스트 스위트 +# 13. 테스트 스위트 diff --git a/_sources/docs/1_0_welcome_to_cpython.md b/_sources/docs/1_0_welcome_to_cpython.md new file mode 100644 index 0000000..f4c7b60 --- /dev/null +++ b/_sources/docs/1_0_welcome_to_cpython.md @@ -0,0 +1,79 @@ +# 1. CPython 살펴보기 + +> 앞으로 저희는 CPython에 대해 아래 내용을 다루게 됩니다 🚀 +> - **CPython 소스 코드 읽고 탐색 / 컴파일**하기 +> - Python 문법 수정하고 컴파일해서 자신만의 CPython 버전 만들기 +> - list, dictionary, generator 등의 **내부 작동 방식 이해**하기 +> - CPython **메모리 관리 기능** 이해하기 +> - **병렬성과 동시성**을 통해 Python 코드 확장하기 +> - 코어 타입에 새로운 기능 추가하기 +> - **테스트 스위트** 실행하기 +> - Python **코드와 런타임 성능을 프로파일하고 벤치마크**하기 +> - C 코드와 Python 코드를 전문가처럼 **디버깅**하기 +> - CPython 라이브러리의 구성 요소를 수정하거나 개선해서 **향후 CPython에 기여**하기 + +## 1.1 CPython이란? + +- Python 구현체 중 하나로, 일반적으로 이용하는 [python.org](http://python.org) 에서 제공하는 공식 파이썬 구현체입니다. +- 이름에서 알 수 있듯이, CPython은 C로 구현되어 있습니다. +- 다른 python 구현체 + - Jython + - Java로 작성된 파이썬 구현체 + - JVM(Java Virtual Machine)에서 실행 + - IronPython + - C#로 작성된 파이썬 구현체 + - .NET 프레임워크 사용 + - PyPy + - Python 정적 타입으로 작성된 파이썬 구현체 +
(정적 타입: 실행하기 전에 변수의 type을 미리 결정하고, 그 이후에는 type을 변경하지 않는 방식) + - JIT(Just-In-Time: 프로그램을 실행하는 동안 실시간으로 기계어로 변환) 컴파일러 방식으로 구현되어 기존 interpreter 방식보다 빠르고 효율적 + +## 1.2 CPython 배포판 구성 요소 + +- **언어 사양(Language Specification)**: 파이썬 언어의 문법, 구문, 의미론 + - ex) `[]`: 인덱싱, 슬라이싱, 빈 리스트 생성을 위해 사용 +- **컴파일러(Interpreter)**: C 언어로 작성된 컴파일러 + - 파이썬 소스 코드 → 실행 가능한 기계어로 변환하는 역할 +- **표준 라이브러리 모듈(Standard Library Modules)**: 기본적으로 포함되어 있는 패키지 + - ex) 파일 입출력, 네트워킹, 문자열 처리, 데이터 구조, GUI 프로그래밍 등 +- **코어 타입(Core Types)**: 내장 데이터 type + - ex) 숫자, 문자열, list, tuple, dictionary +- **테스트 스위트(Test Suite)**: 개발 및 유지 보수에 사용되는 테스트 모음 + - ex) 유닛 테스트, 통합 테스트, 성능 테스트 + +## 1.3 소스 코드 들여다보기 + +- 소스 코드 다운로드 (3.9 버전을 기준으로 살펴볼 예정입니다.) + ```bash + git clone --branch 3.9 https://github.com/python/cpython + ``` +- 소스 코드 구성 + ```bash + cpython + ├── CODE_OF_CONDUCT.md + ├── Doc # 문서 소스 파일 + ├── Grammar # 컴퓨터가 읽을 수 있는 언어 정의 + ├── Include # C 헤더 파일 + ├── LICENSE + ├── Lib # 파이썬으로 작성된 표준 라이브러리 모듈 + ├── Mac # macOS를 위한 파일 + ├── Makefile.pre.in + ├── Misc # 기타 파일 + ├── Modules # C로 작성된 표준 라이브러리 모듈 + ├── Objects # 코어 타입과 객체 모델 + ├── PC # 이전 버전의 윈도우를 위한 윈도우 빌드 지원 파일 + ├── PCbuild # 윈도우 빌드 지원 파일 + ├── Parser # 파이썬 파서 소스 코드 + ├── Programs # python 실행 파일과 기타 바이너리를 위한 소스 코드 + ├── Python # CPython 인터프리터 소스 코드 + ├── README.rst + ├── Tools # CPython 빌드하거나 확장하는 데 유용한 독립 실행형 도구 + ├── aclocal.m4 + ├── config.guess + ├── config.sub + ├── configure + ├── configure.ac + ├── install-sh + ├── pyconfig.h.in + └── setup.py + ``` diff --git a/_sources/docs/2_0_settings.md b/_sources/docs/2_0_settings.md new file mode 100644 index 0000000..c6ca533 --- /dev/null +++ b/_sources/docs/2_0_settings.md @@ -0,0 +1,91 @@ +# 2. 개발 환경 세팅 + +CPython-Guide는 CPython 파헤치기 책과 동일한 Python 3.9 버전을 기반으로 진행됩니다. + +## Visual Studio Code 개발 환경 세팅 + +### 플러그인 설치 +아래와 같은 플러그인들을 설치해줍니다. +![VSCode 설치 플러그인](../images/2_settings/00_vscode_plugin.png) + +### .vscode/task.json 작성 +프로젝트 실행 명령에 대한 json 파일 `.vscode/task.json`을 아래와 같이 생성해줍니다. + +```json +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "type": "shell", + "group": { + "kind": "build", + "isDefault": true + }, + "windows": { + "command": "PCBuild/build.bat", + "args": ["-p", "x64", "-c", "Debug"] + }, + "linux": { + "command": "make -j2 -s" + }, + "osx": { + "command": "make -j2 -s" + } + } + ] +} +``` + +위와 같이 파일 작성을 완료하면 TASK EXPLORER의 vscode 하위에 작성한 build task가 추가된 것을 볼 수 있습니다. +![태스크 세팅 결과](../images/2_settings/01_tasks_explorer_result.png) + + +### .vscode/launch.json 작성 +디버거를 위한 json 파일 `.vscode/launch.json`을 아래와 같이 생성해줍니다. + +- macOS + ```json + { + "version": "0.2.0", + "configurations": [ + { + "name": "Debug C Code", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/python.exe", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": true, + "MIMode": "lldb" + } + ] + } + ``` +- Windows + ```json + { + "version": "0.2.0", + "configurations": [ + { + "name": "msvc cl.exe debug cpython", + "type": "cppvsdbg", + "request": "launch", + "program": "PCBuild/amd64/python_d.exe", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": true, + "preLaunchTask": "build" + } + ] + } + ``` + +이제 F5를 누르면 CPython 빌드 진행 및 디버깅을 할 수 있습니다. +CPython의 진입점이 되는 Programs/python.c의 9번 라인에 디버그 브레이크를 걸고 실행해보면, +아래와 같이 디버깅이 잡힌 것을 확인할 수 있습니다. +![CPyhton 디버깅](../images/2_settings/02_cpython_debugging.png) diff --git a/_sources/docs/3_0_compile.md b/_sources/docs/3_0_compile.md new file mode 100644 index 0000000..8b94c57 --- /dev/null +++ b/_sources/docs/3_0_compile.md @@ -0,0 +1,225 @@ +# 3. 컴파일하기 + +> 지난 챕터까지는 CPython 개발 환경을 구성했다면, +
이번 챕터에서는 CPython 소스 코드를 실제로 작동시키는 interpreter로 컴파일하고자 합니다 🚀 + + + +### macOS + +```bash +# C 컴파일러 툴킷(Xcode Command Line Tools) 설치 +xcode-select --install ## make, GNU Compiler Collection(gcc) 등 설치 + +# 외부 라이브러리 설치 +brew install openssl xz zlib gdbm sqlite + +# Makefile 생성 (configure 스크립트 실행) +CPPFLAGS="-I$(brew --prefix zlib)/include" \ +LDFLAGS="-L$(brew --prefix zlib)/lib" \ +./configure --with-openssl=$(brew --prefix openssl) --with-pydebug + +## 애플칩(M1, M2, ...)은 아래와 같이 xz 경로도 추가해주기 +CPPFLAGS="-I$(brew --prefix zlib)/include -I$(brew --prefix xz)/include" \ +LDFLAGS="-L$(brew --prefix zlib)/lib -L$(brew --prefix xz)/lib" \ +./configure --with-openssl=$(brew --prefix openssl) --with-pydebug + +# CPython 바이러니 빌드 +make -j2 -s # -j2: 동시 작업 2개 / -s: 실행된 명령어 출력 X + +# 바이너리 파일 실행 +./python.exe +``` + +
+make란? + +- 소프트웨어 빌드 자동화 도구로, C/C++ 프로젝트 빌드 자동화에서 사용합니다. +- Makefile을 기반으로 실행되며, `make [옵션] [target]` 을 통해 해당하는 명령어(command)가 실행됩니다. + ```makefile + # Makefile 형식 + 목표(target): 의존성(dependencies) + 명령어(commands) + + # 예시 (make docclean / make pythoninfo) + docclean: + -rm -rf Doc/build + -rm -rf Doc/tools/sphinx Doc/tools/pygments Doc/tools/docutils + + pythoninfo: build_all + $(RUNSHARED) ./$(BUILDPYTHON) -m test.pythoninfo + ``` + +- make 옵션 + - `-d`(`--debug`): 디버깅 정보 출력 + - `-e` (`—environment-overrides`): Makefile보다 우선할 환경 변수 지정 + - `-i`(`—-ignore-errors`): 에러 무시하기 + - `-j [N]`(`—-jobs`): N개 작업 동시 실행 + - `-k`(`—-keep-going`): 특정 타깃 실패하더라도 계속 진행 + - `-l [N]` (`--load-average`, `--max-load`): 평균 부하가 N 미만일 때 동시 작업 시작 + - `-n`(`-dry-run`): 명령 실행하지 않고 출력하기 + - `-s`(`--silent`): 실행 명령어 출력 X + - `-S`(`--stop`): 타깃 실패하면 중지하기 + +- make를 사용하는 이유 + - C/C++ 같은 컴파일 언어 사용 시, + 애플리케이션을 소스에서 컴파일 할 때 시스템의 외부 라이브러리 링크해야 하는데, + 코드를 올바르게 로드하고 링크 및 컴파일하기 위해 많은 명령어를 실행해야 할 수도 있습니다. + - CPython에서처럼 `./configure` 실행 시 autoconf를 통해 필요한 라이브러리 위치 찾아서 Makefile에 붙여 넣어주고, + make 실행을 통해 위와 같은 문제를 쉽게 실행할 수 있도록 해결해줍니다. + +- CPython make 타깃 + - 빌드 타깃 + - all(기본): 컴파일러, 라이브러리, 모듈 빌드 + - clinic: 모든 소스 파일에 대해 인자 클리닉 실행 + - profile-opt: 프로파일 기반 최적화를 통해 파이썬 바이너리 빌드 + - regen-all: 생성된 파일을 전부 다시 생성 + - sharedmods: 공유 모듈 빌드 + - 테스트 타깃 + - coverage: 컴파일 후 gcov로 테스트 실행 + - coverage-lcov: html 커버리지 보고 생성 + - quicktest: 빠른 회귀 테스트만 실행 (오래 걸리는 테스트 제외) + - test: 기본적인 회귀 테스트 실행 + - testall: .pyc 파일 없는/있는 상태로 한 번씩 전체 테스트 스위트 실행 + - testuniversal: macOS 유니버셜 빌드에서 여러 아키텍처에 대한 테스트 스위트 실행 + - 정리 타깃 + - check-clean-src: 빌드 시 소스 검사 + - clean: .pyc 파일과 컴파일된 라이브러리, 프로파일 삭제 + - cleantest: 직전에 실패한 테스트의 test_python_* 경로 삭제 + - clobber: 라이브러리, 태그, 구성, 빌드 삭제 + - distclean: Makefile을 비롯한 소스에서 생성된 모든 파일 삭제 + - docclean: Doc/ 경로에 생성된 문서 삭제 + - profile-removal: 모든 최적화 프로파일 삭제 + - pycremoval: .pyc 파일 삭제 + - 설치 타깃 + - altbininstall: 버전 명시한 python 인터프리터 설치 (ex: python3.9) + - altinstall: 공유 라이브러리, 바이너리, 문서를 버전 접미사와 함께 설치 + - altmaninstall: 버전 붙은 매뉴얼 설치 + - bininstall: python, idle, 2to3 등 모든 바이너리 설치 + - commoninstall: 공유 라이브러리 및 모듈 설치 + - libinstall: 공유 라이브러리 설치 + - maninstall: 문서 설치 + - install: 공유 라이브러리, 바이너리, 문서 설치 + (commoninstall + bininstall + maninstall 실행) + - sharedinstall: 동적으로 모듈 로드 + - 기타 타깃 + - autoconf: configure / pyconfig.h.in 다시 생성 + - python-config: python-config 스크립트 생성 + - recheck: 이전과 같은 옵션으로 configure 다시 실행 + - smelly: 내보내진 심벌이 Py 또는 _Py로 시작하는지 확인 + - tags: vi용 태그 파일 생성 + - TAGS: 이맥스용 태그 파일 생성 +
+ +### Windows + +여기에서는 “명령 프롬프트 사용하기” 방식만 다룰 예정이며, +
”Visual Studio에서 PCbuild/pcbuild.sln 열어서 빌드하기” 방식도 있습니다. +
(CPython 파헤치기 도서 32페이지 참고) + +```powershell +# 의존성 설치 (외부 도구, 라이브러리, C 헤더 등 설치) +PCbuild/get_externals.bat + +# PCbuild/amd64/python_d.exe 바이너리 파일 생성 +build.bat -p x64 -c Debug # 디버그 버전 +# 디버그 버전 바이너리 파일 실행 +amd64\python_d.exe + +# PCbuild/amd64/python.exe 바이너리 파일 생성 +build.bat -p x64 -c Release # 릴리즈 버전 (프로파일 기반 최적화 구성 사용됨) +# 릴리즈 버전 바이너리 파일 실행 +amd64\python.exe +``` + +### 프로파일 기반 최적화 + +- 프로파일 기반 최적화(PGO: Profile-Guided Optimization)는 컴파일러에서 제공하는 기능으로, +최초 컴파일 후 → 일련의 테스트 실행 → 애플리케이션을 프로파일링하는 최적화 방식입니다. +- `python -m test --pgo`로 실행합니다. (Lib/test/libregrtest/pgo.py 회귀 테스트 실행) + ![프로파일 기반 최적화 실행](../images/3_compile/00_pgo.png) +- 출력 내용 + ```python + Raised RLIMIT_NOFILE: 256 -> 1024 + 0:00:00 load avg: 2.78 Run tests sequentially + 0:00:00 load avg: 2.78 [ 1/43] test_array + 0:00:01 load avg: 4.64 [ 2/43] test_base64 + 0:00:01 load avg: 4.64 [ 3/43] test_binascii + 0:00:01 load avg: 4.64 [ 4/43] test_binop + 0:00:01 load avg: 4.64 [ 5/43] test_bisect + 0:00:02 load avg: 4.64 [ 6/43] test_bytes + 0:00:05 load avg: 4.42 [ 7/43] test_bz2 + 0:00:06 load avg: 4.42 [ 8/43] test_cmath + 0:00:06 load avg: 4.42 [ 9/43] test_codecs + 0:00:09 load avg: 4.42 [10/43] test_collections + /Users/user/Documents/cpython/Lib/test/test_collections.py:1509: DeprecationWarning: Please use assertEqual instead. + self.assertEquals(len(s), len(items) - 1) + 0:00:10 load avg: 4.63 [11/43] test_complex + 0:00:11 load avg: 4.63 [12/43] test_dataclasses + 0:00:11 load avg: 4.63 [13/43] test_datetime + 0:00:18 load avg: 4.66 [14/43] test_decimal + ------------------------------------------------ NOTICE ------------------------------------------------ + test_decimal may generate "malloc can't allocate region" + warnings on macOS systems. This behavior is known. Do not + report a bug unless tests are also failing. See bpo-40928. + -------------------------------------------------------------------------------------------------------- + 0:00:26 load avg: 5.08 [15/43] test_difflib + 0:00:28 load avg: 5.08 [16/43] test_embed + 0:00:36 load avg: 5.62 [17/43] test_float + 0:00:36 load avg: 5.62 [18/43] test_fstring + 0:00:37 load avg: 5.62 [19/43] test_functools + 0:00:37 load avg: 5.62 [20/43] test_generators + 0:00:38 load avg: 5.62 [21/43] test_hashlib + 0:00:39 load avg: 5.62 [22/43] test_heapq + 0:00:40 load avg: 5.33 [23/43] test_int + 0:00:41 load avg: 5.33 [24/43] test_itertools + 0:00:49 load avg: 5.30 [25/43] test_json + 0:00:54 load avg: 5.04 [26/43] test_long + 0:01:00 load avg: 4.64 [27/43] test_lzma + 0:01:00 load avg: 4.64 [28/43] test_math -- test_lzma skipped + 0:01:05 load avg: 4.75 [29/43] test_memoryview + 0:01:06 load avg: 4.75 [30/43] test_operator + 0:01:06 load avg: 4.75 [31/43] test_ordered_dict + 0:01:07 load avg: 4.75 [32/43] test_pickle + 0:01:18 load avg: 5.11 [33/43] test_pprint + 0:01:19 load avg: 5.11 [34/43] test_re + 0:01:21 load avg: 5.10 [35/43] test_set + 0:01:30 load avg: 4.63 [36/43] test_sqlite + 0:01:31 load avg: 4.63 [37/43] test_statistics + 0:01:34 load avg: 4.63 [38/43] test_struct + 0:01:35 load avg: 4.58 [39/43] test_tabnanny + 0:01:36 load avg: 4.58 [40/43] test_time + 0:01:38 load avg: 4.58 [41/43] test_unicode + 0:01:40 load avg: 4.37 [42/43] test_xml_etree + 0:01:41 load avg: 4.37 [43/43] test_xml_etree_c + + Total duration: 1 min 43 sec + Tests result: SUCCESS + ``` +- 최적화 된 파이썬 배포 + - macOS: `./configure --enable-optimization` + - Windows: `build.bat --pgo` +- 최적화에 포함되는 기능 + - **함수 inline 처리** + : 다른 함수에서 자주 호출될 경우, 스택 크기 줄이기 위해 inline으로 변경되거나 호출자 함수에 복사됩니다. + - **가상 호출 추론** + : 특정 함수에 대한 가상 함수 호출이 빈번하게 일어나면, 조건부로 실행되는 직접 호출을 대상 함수에 추가합니다. + - **레지스터 할당 최적화** + : 프로파일 데이터를 기반으로 최적화를 하면 레지스터 할당이 향상됩니다. + - **기본 블록 최적화** + : 지정된 프레임 내 일시적으로 자주 실행되는 기본 블록을 동일한 페이지 집합에 배치 + → 사용되는 페이지 수 최소화 → 메모리 오버헤드도 최소화 시킵니다. + - **핫스팟 최적화** + : 가장 많이 실행되는 함수의 실행 시간을 최적화시킵니다. + - **함수 레이아웃 최적화** + : 호출 그래프에 따라 동일한 실행 경로를 따르는 함수를 컴파일된 애플리케이션의 동일한 섹션에 배치합니다. + - **조건부 분기 최적화** + : 같은 분기에서 가장 자주 사용되는 분기를 찾아 바로 실행될 수 있도록 해당 분기를 먼저 배치합니다. + - **미사용 코드 분리** + : 호출되지 않은 코드를 애플리케이션의 별도 섹션으로 옮깁니다. diff --git a/_sources/docs/4_0_python_grammar.md b/_sources/docs/4_0_python_grammar.md index 59073c4..145dd40 100644 --- a/_sources/docs/4_0_python_grammar.md +++ b/_sources/docs/4_0_python_grammar.md @@ -1,51 +1,299 @@ -# 파이썬 언어와 문법 +# 4. 언어와 문법 + +- 파이썬 애플리케이션은 보통 소스 코드 형태로 배포됩니다. +- 소스 코드를 바이트코드라는 중간 언어로 컴파일하고 → `.pyc` 파일에 저장 + 실행 위해 캐싱을 진행합니다. +- 파이썬 인터프리터가 해당 바이트코드(`.pyc`)를 한 줄씩 읽고 실행합니다. + - CPython 런타임이 첫 번째 실행될 때 코드를 컴파일하지만, 일반 사용자에게 노출되지는 않습니다. + - 코드 변경 없이 같은 파이썬 애플리케이션 다시 실행하면 → 컴파일된 바이트코드를 불러와서 더 빠르게 실행합니다. + +
+💡 이식성(portability)을 기준으로 컴파일러를 선택한다면.. + +> - 저수준 기계어 +> - 시스템에서 바로 실행할 수 있는 기계어로 컴파일 +> - 바이러니 실행 파일로 컴파일 → 컴파일한 플랫폼과 동일한 플랫폼에서 사용 가능 +> - ex) C, Go, C++, Pascal +> - 중간 언어 +> - 가상 머신에서 실행하기 위한 언어로 컴파일 +> - 여러 시스템 아키텍처에서 사용 가능한 중간 언어로 컴파일 +> - ex) 닷넷 CLR, JAVA, **Python** + +
+ ## 4.1 CPython이 파이썬이 아니라 C로 작성된 이유 -CPython은 C로 만들어진 컴파일러를 사용한다. -- 파이썬에서 이용하는 많은 라이브러리가 C로 되어있기 때문 -## 4.2 파이썬 언어 사양 +
+결론 먼저 보기 -### 언어 레퍼넌스 -Doc/reference에 언어의 구조, 키워드를 정의해둔다 +> - CPython은 파이썬에서 이용하는 많은 라이브러리가 C로 되어있기 때문에 C로 만들어진 컴파일러를 사용합니다. +> - 안정적인 언어로 다양한 표준 라이브러리 모듈을 이용하기 위해서 C 컴파일러를 사용하고 있습니다. -### 문법 -PEG 표현식을 이용 +
+ +
-- \* 반복을 의미 -- \+ 최소 한번의 반복 -- \[\] 선택적 -- | 대안 -- () 그룹 +- 새로운 프로그래밍 언어를 만들려면 한 언어(source language)를 다른 만들고자 하는 언어(target language)로 바꿔줄 컴파일러가 필요합니다. +- 새로운 언어 개발 시 어떤 프로그램이든 실행할 수 있어야 하기 때문에 보통 **더 오래되고 안정적인 언어**로 컴파일러를 작성합니다. -eg) -coffee: 'cup' ('espresso') + \['water'\] \[milk\] +> 💡 컴파일러 유형 +> - 셀프 호스팅 컴파일러 +> - 자기 자신으로 작성한 컴파일러 (부트스트래핑 단계를 통해 만들어짐) +> - ex) Go(C로 작성된 첫번째 Go 컴파일러가 Go를 컴파일할 수 있게 되자 → 컴파일러를 Go로 재작성), PyPy(파이썬으로 작성된 파이썬 컴파일러) +> - 소스 대 소스(source-to-source) 컴파일러 +> - 이미 갖고 있는 다른 언어로 작성한 컴파일러 +> - ex) CPython (C → Python) -milk: 'full-fat' | 'skimmed' | 'soy' +- 여러 표준 라이브러리 모듈(ssl, sockets 등)도 저수준 운영체제 API에 접근하기 위해서 C로 작성되어 있고, +
네트워크 소켓 만들기, 파일 시스템 조작, 디스플레이와 상호작용하는 윈도우/리눅스 커널 API도 모두 C로 작성되어 있기 때문에 **파이썬 또한 확장성을 고려하여 C로 작성되었다**고 볼 수 있습니다. -철도 다이어그램 -![철도 다이어그램](../images/4_grammar/train_diagram.svg) -### Parser -Grammar/python.gram에 파이썬 문법이 PEG로 정의가 되어있다 -![small_stmt 예시](../images/4_grammar/small_stmt.png) +## 4.2 파이썬 언어 사양 +- 컴파일러가 언어를 실행하기 위해서는 문법 구조에 대한 엄격한 규칙인 **언어 사양**이 필요합니다. +- 언어 사양은 모든 파이썬 인터프리터 구현이 사용하는 레퍼런스 사양으로, + - 사람이 읽을 수 있는 형식 + 기계가 읽을 수 있는 형식으로 제공합니다. + - 문법 형식 + 각 문법 요소가 실행되는 방식을 자세히 설명하고 있습니다. +### 언어 레퍼런스 +사람이 읽을 수 있는 형식으로, Doc/reference에 언어의 구조, 키워드를 정의해두고 있습니다. +```bash +Doc/reference +├── index.rst # 언어 레퍼런스 목차 +├── introduction.rst # 레퍼런스 문서 개요 +├── compound_stmts.rst # 복합문 (if, while, for, 함수 정의 등) +├── datamodel.rst # 객체, 값, 타입 +├── executionmodel.rst # 프로그램 구조 +├── expressions.rst # 표현식 구성 요소 +├── grammar.rst # 문법 규격(Grammar/Grammar 참조) +├── import.rst # import 시스템 +├── lexical_analysis.rst # 어휘 구조 (줄, 들여쓰기, 토큰, 키워드 등) +├── simple_stmts.rst # 단순문 (assert, import, return, yield 등) +└── toplevel_components.rst # 스크립트 및 모듈 실행 방법 설명 ``` -'pass' { _Py_Pass(EXTRA) } +
+ex1) if (compound_stmts.rst) + +```markdown +.. _if: +.. _elif: +.. _else: + +The :keyword:`!if` statement +============================ + +.. index:: + ! statement: if + keyword: elif + keyword: else + single: : (colon); compound statement + +The :keyword:`if` statement is used for conditional execution: + +.. productionlist:: python-grammar + if_stmt: "if" `assignment_expression` ":" `suite` + : ("elif" `assignment_expression` ":" `suite`)* + : ["else" ":" `suite`] + +It selects exactly one of the suites by evaluating the expressions one by one +until one is found to be true (see section :ref:`booleans` for the definition of +true and false); then that suite is executed (and no other part of the +:keyword:`if` statement is executed or evaluated). If all expressions are +false, the suite of the :keyword:`else` clause, if present, is executed. ``` -줄을 +
+ +
+ex2) Class instance (datamodel.rst) + +```markdown +Class instances + .. index:: + object: class instance + object: instance + pair: class; instance + pair: class instance; attribute + + A class instance is created by calling a class object (see above). A class + instance has a namespace implemented as a dictionary which is the first place + in which attribute references are searched. When an attribute is not found + there, and the instance's class has an attribute by that name, the search + continues with the class attributes. If a class attribute is found that is a + user-defined function object, it is transformed into an instance method + object whose :attr:`__self__` attribute is the instance. Static method and + class method objects are also transformed; see above under "Classes". See + section :ref:`descriptors` for another way in which attributes of a class + retrieved via its instances may differ from the objects actually stored in + the class's :attr:`~object.__dict__`. If no class attribute is found, and the + object's class has a :meth:`~object.__getattr__` method, that is called to satisfy + the lookup. + + .. index:: triple: class instance; attribute; assignment + Attribute assignments and deletions update the instance's dictionary, never a + class's dictionary. If the class has a :meth:`~object.__setattr__` or + :meth:`~object.__delattr__` method, this is called instead of updating the instance + dictionary directly. + .. index:: + object: numeric + object: sequence + object: mapping + + Class instances can pretend to be numbers, sequences, or mappings if they have + methods with certain special names. See section :ref:`specialnames`. + + .. index:: + single: __dict__ (instance attribute) + single: __class__ (instance attribute) + + Special attributes: :attr:`~object.__dict__` is the attribute dictionary; + :attr:`~instance.__class__` is the instance's class. ``` -('pass'|'proceed') { _Py_Pass(EXTRA) } + +
+ + +### 문법 +기계가 읽을 수 있는 형식으로, Grammar/python.gram에 PEG 표현식을 통해 정의하고 있습니다. + +- 파서 표현식 문법(parsing expression grammar, PEG) 사양 + - `*`: 반복 + - `+`: 최소 1번 반복 + - `[]`: 선택적인 부분 + - `|`: 대안 + - `()`: 그룹 +- 철도 다이어그램 +
![철도 다이어그램](../images/4_grammar/00_train_diagram.svg) + + +
+ex0) 커피 레시피 + +- 예시 + - 컵 필요: `'cup'` + - 최소 에스프레소 한 샷 이상: `('espresso')+` + - 물 사용 (옵션): `['water']` + - 우유 사용 (옵션): `[milk]` + - 우유 사용했다면, 탈지우유나 두유 등 여러 종류의 우유 선택 가능: `milk: 'full-fat' | 'skimmed' | 'soy'` +- 정의 + + ```makefile + coffee: 'cup' ('espresso')+ ['water'] [milk] + milk: 'full-fat' | 'skimmed' | 'soy' + ``` +- 철도 다이어그램 + ![커피 레시피 철도 다이어그램](../images/4_grammar/01_train_diagram_coffee.png) + +
+ +
+ex1) while문 + +- 예시 + 1. 표현식 & `:` 단말 기호 & 코드 블록으로 구성 + + ```python + while finished: + do_things() + ``` + + 2. named_expression 대입 표현식 사용 (값 할당하는 동시에 그 값을 평가하는 표현식) + + ```python + while letters := read(document, 10): + print(letters) + ``` + + 3. while문 다음에 else 블록 사용 + + ```python + while item := next(iterable): + print(item) + else: + print("Iterable is empty") + ``` + +- 정의 (while_stmt 문법 파일) + + ```python + # Grammar/python.gram#L165 + + while_stmt[stmt_ty]: + | 'while' a=named_expression ':' b=block c=[else_block] ... + ``` + +- 철도 다이어그램 + + ![while문 철도 다이어그램](../images/4_grammar/02_train_diagram_while.jpeg) + +
+ +
+ex2) try문 + +- 정의 + + ```python + # Grammar/python.gram#L189 + + try_stmt[stmt_ty]: + | 'try' ':' b=block f=finally_block { _Py_Try(b, NULL, NULL, f, EXTRA) } + | 'try' ':' b=block ex=except_block+ el=[else_block] f=[finally_block] { _Py_Try(b, ex, el, f, EXTRA) } + + finally_block[asdl_seq*]: 'finally' ':' a=block { a } + + except_block[excepthandler_ty]: + | 'except' e=expression t=['as' z=NAME { z }] ':' b=block { + _Py_ExceptHandler(e, (t) ? ((expr_ty) t)->v.Name.id : NULL, b, EXTRA) } + | 'except' ':' b=block { _Py_ExceptHandler(NULL, NULL, b, EXTRA) } + + else_block[asdl_seq*]: 'else' ':' b=block { b } + ``` + +- 철도 다이어그램 + + ![try문 철도 다이어그램](../images/4_grammar/03_train_diagram_try.png) + +
+ + +##### 문법 다시 생성해보기 + +Grammar/python.gram 에서 간단문 정의(small_stmt)에서 pass 문이 정의된 것을 볼 수 있습니다. + +```python +small_stmt[stmt_ty] (memo): + | assignment + | e=star_expressions { _Py_Expr(e, EXTRA) } + | &'return' return_stmt + | &('import' | 'from') import_stmt + | &'raise' raise_stmt + **| 'pass' { _Py_Pass(EXTRA) }** + | &'del' del_stmt + | &'yield' yield_stmt + | &'assert' assert_stmt + | 'break' { _Py_Break(EXTRA) } + | 'continue' { _Py_Continue(EXTRA) } + | &'global' global_stmt + | &'nonlocal' nonlocal_stmt ``` -로 바꾸고 컴파일 하면, +pass 정의 `'pass' { _Py_Pass(EXTRA) }`를 +
`('pass'|'proceed') { _Py_Pass(EXTRA) }`로 바꾸고 아래와 같이 컴파일 하면, +``` +# macOS +make regen-pegen +make -j2 -s -proceed라는 함수가 pass랑 동일한 action을 하게 된다 +# Windows +build.bat --regen +build.bat -t CleanAll +build.bat -t Build +``` +proceed라는 함수가 pass랑 동일한 action을 하게 됩니다. ``` def test1(): pass @@ -54,15 +302,1006 @@ def test2(): proceed ``` -위에서 test1()이랑 test2()의 action은 동일하다. +위에서 test1()이랑 test2()의 action은 동일하게 됩니다. +
이처럼, python.gram 파일 수정을 통해서 파이썬 문법을 변경할 수 있습니다. -python.gram파일 수정을 통해서 파이썬 문법을 변경할 수 있다 + -python코드가 tokenizer를 통해서 토큰으로 파싱이 된다. 위 코드를 tokenize를 하면: +### 토큰 +Grammar/Tokens 파일은 파스 트리의 Leaf node에서 사용되는 고유 토큰들을 정의합니다. +코드 tokenization은 추후 컴파일링 할 때 이용되며, +각 토큰별로 이름, 자동으로 생성된 고유 ID를 지니고 있습니다. +```python +LPAR '(' +RPAR ')' +LSQB '[' +RSQB ']' +COLON ':' +COMMA ',' +``` + +tokenizer를 통해서 토큰으로 파싱이 되며, 아래 예시를 통해 tokenize 되는 결과를 확인할 수 있습니다. + +- 예시 스크립트 파일 (test_tokens.py) + ```python + def my_function(): + pass + ``` +- `./python.exe -m tokenize -e test_tokens.py` (토큰 목록 출력) + ```python + 0,0-0,0: ENCODING 'utf-8' + 1,0-1,3: NAME 'def' + 1,4-1,15: NAME 'my_function' + 1,15-1,16: LPAR '(' + 1,16-1,17: RPAR ')' + 1,17-1,18: COLON ':' + 1,18-1,19: NEWLINE '\n' + 2,0-2,4: INDENT ' ' + 2,4-2,8: NAME 'pass' + 2,8-2,9: NEWLINE '\n' + 3,0-3,0: DEDENT '' + 3,0-3,0: ENDMARKER '' + ``` + +
+`./python.exe -d test_tokens.py` (디버그 빌드) + +```python + > file[0-0]: statements? $ + > statements[0-0]: statement+ + > _loop1_11[0-0]: statement + > statement[0-0]: compound_stmt + > compound_stmt[0-0]: &('def' | '@' | ASYNC) function_def + > _tmp_15[0-0]: 'def' + + _tmp_15[0-1]: 'def' succeeded! + > function_def[0-0]: decorators function_def_raw + > decorators[0-0]: (('@' named_expression NEWLINE))+ + > _loop1_68[0-0]: ('@' named_expression NEWLINE) + > _tmp_140[0-0]: '@' named_expression NEWLINE + - _tmp_140[0-0]: '@' named_expression NEWLINE failed! + - _loop1_68[0-0]: ('@' named_expression NEWLINE) failed! + - decorators[0-0]: (('@' named_expression NEWLINE))+ failed! + - function_def[0-0]: decorators function_def_raw failed! + > function_def[0-0]: function_def_raw + > function_def_raw[0-0]: 'def' NAME '(' params? ')' ['->' expression] ':' func_type_comment? block + > params[3-3]: parameters + > parameters[3-3]: slash_no_default param_no_default* param_with_default* star_etc? + > slash_no_default[3-3]: param_no_default+ '/' ',' + > _loop1_60[3-3]: param_no_default + > param_no_default[3-3]: param ',' TYPE_COMMENT? + > param[3-3]: NAME annotation? + - param[3-3]: NAME annotation? failed! + - param_no_default[3-3]: param ',' TYPE_COMMENT? failed! + > param_no_default[3-3]: param TYPE_COMMENT? &')' + > param[3-3]: NAME annotation? + - param[3-3]: NAME annotation? failed! + - param_no_default[3-3]: param TYPE_COMMENT? &')' failed! + - _loop1_60[3-3]: param_no_default failed! + - slash_no_default[3-3]: param_no_default+ '/' ',' failed! + > slash_no_default[3-3]: param_no_default+ '/' &')' + > _loop1_61[3-3]: param_no_default + > param_no_default[3-3]: param ',' TYPE_COMMENT? + > param[3-3]: NAME annotation? + - param[3-3]: NAME annotation? failed! + - param_no_default[3-3]: param ',' TYPE_COMMENT? failed! + > param_no_default[3-3]: param TYPE_COMMENT? &')' + > param[3-3]: NAME annotation? + - param[3-3]: NAME annotation? failed! + - param_no_default[3-3]: param TYPE_COMMENT? &')' failed! + - _loop1_61[3-3]: param_no_default failed! + - slash_no_default[3-3]: param_no_default+ '/' &')' failed! + - parameters[3-3]: slash_no_default param_no_default* param_with_default* star_etc? failed! + > parameters[3-3]: slash_with_default param_with_default* star_etc? + > slash_with_default[3-3]: param_no_default* param_with_default+ '/' ',' + > _loop0_62[3-3]: param_no_default + > param_no_default[3-3]: param ',' TYPE_COMMENT? + > param[3-3]: NAME annotation? + - param[3-3]: NAME annotation? failed! + - param_no_default[3-3]: param ',' TYPE_COMMENT? failed! + > param_no_default[3-3]: param TYPE_COMMENT? &')' + > param[3-3]: NAME annotation? + - param[3-3]: NAME annotation? failed! + - param_no_default[3-3]: param TYPE_COMMENT? &')' failed! + - _loop0_62[3-3]: param_no_default failed! + > _loop1_63[3-3]: param_with_default + > param_with_default[3-3]: param default ',' TYPE_COMMENT? + > param[3-3]: NAME annotation? + - param[3-3]: NAME annotation? failed! + - param_with_default[3-3]: param default ',' TYPE_COMMENT? failed! + > param_with_default[3-3]: param default TYPE_COMMENT? &')' + > param[3-3]: NAME annotation? + - param[3-3]: NAME annotation? failed! + - param_with_default[3-3]: param default TYPE_COMMENT? &')' failed! + - _loop1_63[3-3]: param_with_default failed! + - slash_with_default[3-3]: param_no_default* param_with_default+ '/' ',' failed! + > slash_with_default[3-3]: param_no_default* param_with_default+ '/' &')' + > _loop0_64[3-3]: param_no_default + > param_no_default[3-3]: param ',' TYPE_COMMENT? + > param[3-3]: NAME annotation? + - param[3-3]: NAME annotation? failed! + - param_no_default[3-3]: param ',' TYPE_COMMENT? failed! + > param_no_default[3-3]: param TYPE_COMMENT? &')' + > param[3-3]: NAME annotation? + - param[3-3]: NAME annotation? failed! + - param_no_default[3-3]: param TYPE_COMMENT? &')' failed! + - _loop0_64[3-3]: param_no_default failed! + > _loop1_65[3-3]: param_with_default + > param_with_default[3-3]: param default ',' TYPE_COMMENT? + > param[3-3]: NAME annotation? + - param[3-3]: NAME annotation? failed! + - param_with_default[3-3]: param default ',' TYPE_COMMENT? failed! + > param_with_default[3-3]: param default TYPE_COMMENT? &')' + > param[3-3]: NAME annotation? + - param[3-3]: NAME annotation? failed! + - param_with_default[3-3]: param default TYPE_COMMENT? &')' failed! + - _loop1_65[3-3]: param_with_default failed! + - slash_with_default[3-3]: param_no_default* param_with_default+ '/' &')' failed! + - parameters[3-3]: slash_with_default param_with_default* star_etc? failed! + > parameters[3-3]: param_no_default+ param_with_default* star_etc? + > _loop1_57[3-3]: param_no_default + > param_no_default[3-3]: param ',' TYPE_COMMENT? + > param[3-3]: NAME annotation? + - param[3-3]: NAME annotation? failed! + - param_no_default[3-3]: param ',' TYPE_COMMENT? failed! + > param_no_default[3-3]: param TYPE_COMMENT? &')' + > param[3-3]: NAME annotation? + - param[3-3]: NAME annotation? failed! + - param_no_default[3-3]: param TYPE_COMMENT? &')' failed! + - _loop1_57[3-3]: param_no_default failed! + - parameters[3-3]: param_no_default+ param_with_default* star_etc? failed! + > parameters[3-3]: param_with_default+ star_etc? + > _loop1_59[3-3]: param_with_default + > param_with_default[3-3]: param default ',' TYPE_COMMENT? + > param[3-3]: NAME annotation? + - param[3-3]: NAME annotation? failed! + - param_with_default[3-3]: param default ',' TYPE_COMMENT? failed! + > param_with_default[3-3]: param default TYPE_COMMENT? &')' + > param[3-3]: NAME annotation? + - param[3-3]: NAME annotation? failed! + - param_with_default[3-3]: param default TYPE_COMMENT? &')' failed! + - _loop1_59[3-3]: param_with_default failed! + - parameters[3-3]: param_with_default+ star_etc? failed! + > parameters[3-3]: star_etc + > star_etc[3-3]: '*' param_no_default param_maybe_default* kwds? + - star_etc[3-3]: '*' param_no_default param_maybe_default* kwds? failed! + > star_etc[3-3]: '*' ',' param_maybe_default+ kwds? + - star_etc[3-3]: '*' ',' param_maybe_default+ kwds? failed! + > star_etc[3-3]: kwds + > kwds[3-3]: '**' param_no_default + - kwds[3-3]: '**' param_no_default failed! + - star_etc[3-3]: kwds failed! + - parameters[3-3]: star_etc failed! + - params[3-3]: parameters failed! + > _tmp_51[4-4]: '->' expression + - _tmp_51[4-4]: '->' expression failed! + > func_type_comment[5-5]: NEWLINE TYPE_COMMENT &(NEWLINE INDENT) + - func_type_comment[5-5]: NEWLINE TYPE_COMMENT &(NEWLINE INDENT) failed! + > func_type_comment[5-5]: TYPE_COMMENT + - func_type_comment[5-5]: TYPE_COMMENT failed! + > block[5-5]: NEWLINE INDENT statements DEDENT + > statements[7-7]: statement+ + > _loop1_11[7-7]: statement + > statement[7-7]: compound_stmt + > compound_stmt[7-7]: &('def' | '@' | ASYNC) function_def + > _tmp_15[7-7]: 'def' + - _tmp_15[7-7]: 'def' failed! + > _tmp_15[7-7]: '@' + - _tmp_15[7-7]: '@' failed! + > _tmp_15[7-7]: ASYNC + - _tmp_15[7-7]: ASYNC failed! + - compound_stmt[7-7]: &('def' | '@' | ASYNC) function_def failed! + > compound_stmt[7-7]: &'if' if_stmt + - compound_stmt[7-7]: &'if' if_stmt failed! + > compound_stmt[7-7]: &('class' | '@') class_def + > _tmp_16[7-7]: 'class' + - _tmp_16[7-7]: 'class' failed! + > _tmp_16[7-7]: '@' + - _tmp_16[7-7]: '@' failed! + - compound_stmt[7-7]: &('class' | '@') class_def failed! + > compound_stmt[7-7]: &('with' | ASYNC) with_stmt + > _tmp_17[7-7]: 'with' + - _tmp_17[7-7]: 'with' failed! + > _tmp_17[7-7]: ASYNC + - _tmp_17[7-7]: ASYNC failed! + - compound_stmt[7-7]: &('with' | ASYNC) with_stmt failed! + > compound_stmt[7-7]: &('for' | ASYNC) for_stmt + > _tmp_18[7-7]: 'for' + - _tmp_18[7-7]: 'for' failed! + > _tmp_18[7-7]: ASYNC + - _tmp_18[7-7]: ASYNC failed! + - compound_stmt[7-7]: &('for' | ASYNC) for_stmt failed! + > compound_stmt[7-7]: &'try' try_stmt + - compound_stmt[7-7]: &'try' try_stmt failed! + > compound_stmt[7-7]: &'while' while_stmt + - compound_stmt[7-7]: &'while' while_stmt failed! + - statement[7-7]: compound_stmt failed! + > statement[7-7]: simple_stmt + > simple_stmt[7-7]: small_stmt !';' NEWLINE + > small_stmt[7-7]: assignment + > assignment[7-7]: NAME ':' expression ['=' annotated_rhs] + - assignment[7-7]: NAME ':' expression ['=' annotated_rhs] failed! + > assignment[7-7]: ('(' single_target ')' | single_subscript_attribute_target) ':' expression ['=' annotated_rhs] + > _tmp_20[7-7]: '(' single_target ')' + - _tmp_20[7-7]: '(' single_target ')' failed! + > _tmp_20[7-7]: single_subscript_attribute_target + > single_subscript_attribute_target[7-7]: t_primary '.' NAME !t_lookahead + > t_primary[7-7]: t_primary '.' NAME &t_lookahead + - t_primary[7-7]: t_primary '.' NAME &t_lookahead failed! + > t_primary[7-7]: t_primary '[' slices ']' &t_lookahead + - t_primary[7-7]: t_primary '[' slices ']' &t_lookahead failed! + > t_primary[7-7]: t_primary genexp &t_lookahead + - t_primary[7-7]: t_primary genexp &t_lookahead failed! + > t_primary[7-7]: t_primary '(' arguments? ')' &t_lookahead + - t_primary[7-7]: t_primary '(' arguments? ')' &t_lookahead failed! + > t_primary[7-7]: atom &t_lookahead + > atom[7-7]: NAME + - atom[7-7]: NAME failed! + > atom[7-7]: 'True' + - atom[7-7]: 'True' failed! + > atom[7-7]: 'False' + - atom[7-7]: 'False' failed! + > atom[7-7]: 'None' + - atom[7-7]: 'None' failed! + > atom[7-7]: '__peg_parser__' + - atom[7-7]: '__peg_parser__' failed! + > atom[7-7]: &STRING strings + - atom[7-7]: &STRING strings failed! + > atom[7-7]: NUMBER + - atom[7-7]: NUMBER failed! + > atom[7-7]: &'(' (tuple | group | genexp) + - atom[7-7]: &'(' (tuple | group | genexp) failed! + > atom[7-7]: &'[' (list | listcomp) + - atom[7-7]: &'[' (list | listcomp) failed! + > atom[7-7]: &'{' (dict | set | dictcomp | setcomp) + - atom[7-7]: &'{' (dict | set | dictcomp | setcomp) failed! + > atom[7-7]: '...' + - atom[7-7]: '...' failed! + - t_primary[7-7]: atom &t_lookahead failed! + - single_subscript_attribute_target[7-7]: t_primary '.' NAME !t_lookahead failed! + > single_subscript_attribute_target[7-7]: t_primary '[' slices ']' !t_lookahead + - single_subscript_attribute_target[7-7]: t_primary '[' slices ']' !t_lookahead failed! + - _tmp_20[7-7]: single_subscript_attribute_target failed! + - assignment[7-7]: ('(' single_target ')' | single_subscript_attribute_target) ':' expression ['=' annotated_rhs] failed! + > assignment[7-7]: ((star_targets '='))+ (yield_expr | star_expressions) !'=' TYPE_COMMENT? + > _loop1_22[7-7]: (star_targets '=') + > _tmp_137[7-7]: star_targets '=' + > star_targets[7-7]: star_target !',' + > star_target[7-7]: '*' (!'*' star_target) + - star_target[7-7]: '*' (!'*' star_target) failed! + > star_target[7-7]: target_with_star_atom + > target_with_star_atom[7-7]: t_primary '.' NAME !t_lookahead + - target_with_star_atom[7-7]: t_primary '.' NAME !t_lookahead failed! + > target_with_star_atom[7-7]: t_primary '[' slices ']' !t_lookahead + - target_with_star_atom[7-7]: t_primary '[' slices ']' !t_lookahead failed! + > target_with_star_atom[7-7]: star_atom + > star_atom[7-7]: NAME + - star_atom[7-7]: NAME failed! + > star_atom[7-7]: '(' target_with_star_atom ')' + - star_atom[7-7]: '(' target_with_star_atom ')' failed! + > star_atom[7-7]: '(' star_targets_tuple_seq? ')' + - star_atom[7-7]: '(' star_targets_tuple_seq? ')' failed! + > star_atom[7-7]: '[' star_targets_list_seq? ']' + - star_atom[7-7]: '[' star_targets_list_seq? ']' failed! + - target_with_star_atom[7-7]: star_atom failed! + - star_target[7-7]: target_with_star_atom failed! + - star_targets[7-7]: star_target !',' failed! + > star_targets[7-7]: star_target ((',' star_target))* ','? + - star_targets[7-7]: star_target ((',' star_target))* ','? failed! + - _tmp_137[7-7]: star_targets '=' failed! + - _loop1_22[7-7]: (star_targets '=') failed! + - assignment[7-7]: ((star_targets '='))+ (yield_expr | star_expressions) !'=' TYPE_COMMENT? failed! + > assignment[7-7]: single_target augassign ~ (yield_expr | star_expressions) + > single_target[7-7]: single_subscript_attribute_target + > single_subscript_attribute_target[7-7]: t_primary '.' NAME !t_lookahead + - single_subscript_attribute_target[7-7]: t_primary '.' NAME !t_lookahead failed! + > single_subscript_attribute_target[7-7]: t_primary '[' slices ']' !t_lookahead + - single_subscript_attribute_target[7-7]: t_primary '[' slices ']' !t_lookahead failed! + - single_target[7-7]: single_subscript_attribute_target failed! + > single_target[7-7]: NAME + - single_target[7-7]: NAME failed! + > single_target[7-7]: '(' single_target ')' + - single_target[7-7]: '(' single_target ')' failed! + - assignment[7-7]: single_target augassign ~ (yield_expr | star_expressions) failed! + - small_stmt[7-7]: assignment failed! + > small_stmt[7-7]: star_expressions + > star_expressions[7-7]: star_expression ((',' star_expression))+ ','? + > star_expression[7-7]: '*' bitwise_or + - star_expression[7-7]: '*' bitwise_or failed! + > star_expression[7-7]: expression + > expression[7-7]: disjunction 'if' disjunction 'else' expression + > disjunction[7-7]: conjunction (('or' conjunction))+ + > conjunction[7-7]: inversion (('and' inversion))+ + > inversion[7-7]: 'not' inversion + - inversion[7-7]: 'not' inversion failed! + > inversion[7-7]: comparison + > comparison[7-7]: bitwise_or compare_op_bitwise_or_pair+ + > bitwise_or[7-7]: bitwise_or '|' bitwise_xor + - bitwise_or[7-7]: bitwise_or '|' bitwise_xor failed! + > bitwise_or[7-7]: bitwise_xor + > bitwise_xor[7-7]: bitwise_xor '^' bitwise_and + - bitwise_xor[7-7]: bitwise_xor '^' bitwise_and failed! + > bitwise_xor[7-7]: bitwise_and + > bitwise_and[7-7]: bitwise_and '&' shift_expr + - bitwise_and[7-7]: bitwise_and '&' shift_expr failed! + > bitwise_and[7-7]: shift_expr + > shift_expr[7-7]: shift_expr '<<' sum + - shift_expr[7-7]: shift_expr '<<' sum failed! + > shift_expr[7-7]: shift_expr '>>' sum + - shift_expr[7-7]: shift_expr '>>' sum failed! + > shift_expr[7-7]: sum + > sum[7-7]: sum '+' term + - sum[7-7]: sum '+' term failed! + > sum[7-7]: sum '-' term + - sum[7-7]: sum '-' term failed! + > sum[7-7]: term + > term[7-7]: term '*' factor + - term[7-7]: term '*' factor failed! + > term[7-7]: term '/' factor + - term[7-7]: term '/' factor failed! + > term[7-7]: term '//' factor + - term[7-7]: term '//' factor failed! + > term[7-7]: term '%' factor + - term[7-7]: term '%' factor failed! + > term[7-7]: term '@' factor + - term[7-7]: term '@' factor failed! + > term[7-7]: factor + > factor[7-7]: '+' factor + - factor[7-7]: '+' factor failed! + > factor[7-7]: '-' factor + - factor[7-7]: '-' factor failed! + > factor[7-7]: '~' factor + - factor[7-7]: '~' factor failed! + > factor[7-7]: power + > power[7-7]: await_primary '**' factor + > await_primary[7-7]: AWAIT primary + - await_primary[7-7]: AWAIT primary failed! + > await_primary[7-7]: primary + > primary[7-7]: primary '.' NAME + - primary[7-7]: primary '.' NAME failed! + > primary[7-7]: primary genexp + - primary[7-7]: primary genexp failed! + > primary[7-7]: primary '(' arguments? ')' + - primary[7-7]: primary '(' arguments? ')' failed! + > primary[7-7]: primary '[' slices ']' + - primary[7-7]: primary '[' slices ']' failed! + > primary[7-7]: atom + > atom[7-7]: NAME + - atom[7-7]: NAME failed! + > atom[7-7]: 'True' + - atom[7-7]: 'True' failed! + > atom[7-7]: 'False' + - atom[7-7]: 'False' failed! + > atom[7-7]: 'None' + - atom[7-7]: 'None' failed! + > atom[7-7]: '__peg_parser__' + - atom[7-7]: '__peg_parser__' failed! + > atom[7-7]: &STRING strings + - atom[7-7]: &STRING strings failed! + > atom[7-7]: NUMBER + - atom[7-7]: NUMBER failed! + > atom[7-7]: &'(' (tuple | group | genexp) + - atom[7-7]: &'(' (tuple | group | genexp) failed! + > atom[7-7]: &'[' (list | listcomp) + - atom[7-7]: &'[' (list | listcomp) failed! + > atom[7-7]: &'{' (dict | set | dictcomp | setcomp) + - atom[7-7]: &'{' (dict | set | dictcomp | setcomp) failed! + > atom[7-7]: '...' + - atom[7-7]: '...' failed! + - primary[7-7]: atom failed! + - await_primary[7-7]: primary failed! + - power[7-7]: await_primary '**' factor failed! + > power[7-7]: await_primary + - power[7-7]: await_primary failed! + - factor[7-7]: power failed! + - term[7-7]: factor failed! + - sum[7-7]: term failed! + - shift_expr[7-7]: sum failed! + - bitwise_and[7-7]: shift_expr failed! + - bitwise_xor[7-7]: bitwise_and failed! + - bitwise_or[7-7]: bitwise_xor failed! + - comparison[7-7]: bitwise_or compare_op_bitwise_or_pair+ failed! + > comparison[7-7]: bitwise_or + - comparison[7-7]: bitwise_or failed! + - inversion[7-7]: comparison failed! + - conjunction[7-7]: inversion (('and' inversion))+ failed! + > conjunction[7-7]: inversion + - conjunction[7-7]: inversion failed! + - disjunction[7-7]: conjunction (('or' conjunction))+ failed! + > disjunction[7-7]: conjunction + - disjunction[7-7]: conjunction failed! + - expression[7-7]: disjunction 'if' disjunction 'else' expression failed! + > expression[7-7]: disjunction + - expression[7-7]: disjunction failed! + > expression[7-7]: lambdef + > lambdef[7-7]: 'lambda' lambda_params? ':' expression + - lambdef[7-7]: 'lambda' lambda_params? ':' expression failed! + - expression[7-7]: lambdef failed! + - star_expression[7-7]: expression failed! + - star_expressions[7-7]: star_expression ((',' star_expression))+ ','? failed! + > star_expressions[7-7]: star_expression ',' + - star_expressions[7-7]: star_expression ',' failed! + > star_expressions[7-7]: star_expression + - star_expressions[7-7]: star_expression failed! + - small_stmt[7-7]: star_expressions failed! + > small_stmt[7-7]: &'return' return_stmt + - small_stmt[7-7]: &'return' return_stmt failed! + > small_stmt[7-7]: &('import' | 'from') import_stmt + > _tmp_14[7-7]: 'import' + - _tmp_14[7-7]: 'import' failed! + > _tmp_14[7-7]: 'from' + - _tmp_14[7-7]: 'from' failed! + - small_stmt[7-7]: &('import' | 'from') import_stmt failed! + > small_stmt[7-7]: &'raise' raise_stmt + - small_stmt[7-7]: &'raise' raise_stmt failed! + > small_stmt[7-7]: 'pass' + + small_stmt[7-8]: 'pass' succeeded! + + simple_stmt[7-9]: small_stmt !';' NEWLINE succeeded! + + statement[7-9]: simple_stmt succeeded! + > statement[9-9]: compound_stmt + > compound_stmt[9-9]: &('def' | '@' | ASYNC) function_def + > _tmp_15[9-9]: 'def' + - _tmp_15[9-9]: 'def' failed! + > _tmp_15[9-9]: '@' + - _tmp_15[9-9]: '@' failed! + > _tmp_15[9-9]: ASYNC + - _tmp_15[9-9]: ASYNC failed! + - compound_stmt[9-9]: &('def' | '@' | ASYNC) function_def failed! + > compound_stmt[9-9]: &'if' if_stmt + - compound_stmt[9-9]: &'if' if_stmt failed! + > compound_stmt[9-9]: &('class' | '@') class_def + > _tmp_16[9-9]: 'class' + - _tmp_16[9-9]: 'class' failed! + > _tmp_16[9-9]: '@' + - _tmp_16[9-9]: '@' failed! + - compound_stmt[9-9]: &('class' | '@') class_def failed! + > compound_stmt[9-9]: &('with' | ASYNC) with_stmt + > _tmp_17[9-9]: 'with' + - _tmp_17[9-9]: 'with' failed! + > _tmp_17[9-9]: ASYNC + - _tmp_17[9-9]: ASYNC failed! + - compound_stmt[9-9]: &('with' | ASYNC) with_stmt failed! + > compound_stmt[9-9]: &('for' | ASYNC) for_stmt + > _tmp_18[9-9]: 'for' + - _tmp_18[9-9]: 'for' failed! + > _tmp_18[9-9]: ASYNC + - _tmp_18[9-9]: ASYNC failed! + - compound_stmt[9-9]: &('for' | ASYNC) for_stmt failed! + > compound_stmt[9-9]: &'try' try_stmt + - compound_stmt[9-9]: &'try' try_stmt failed! + > compound_stmt[9-9]: &'while' while_stmt + - compound_stmt[9-9]: &'while' while_stmt failed! + - statement[9-9]: compound_stmt failed! + > statement[9-9]: simple_stmt + > simple_stmt[9-9]: small_stmt !';' NEWLINE + > small_stmt[9-9]: assignment + > assignment[9-9]: NAME ':' expression ['=' annotated_rhs] + - assignment[9-9]: NAME ':' expression ['=' annotated_rhs] failed! + > assignment[9-9]: ('(' single_target ')' | single_subscript_attribute_target) ':' expression ['=' annotated_rhs] + > _tmp_20[9-9]: '(' single_target ')' + - _tmp_20[9-9]: '(' single_target ')' failed! + > _tmp_20[9-9]: single_subscript_attribute_target + > single_subscript_attribute_target[9-9]: t_primary '.' NAME !t_lookahead + > t_primary[9-9]: t_primary '.' NAME &t_lookahead + - t_primary[9-9]: t_primary '.' NAME &t_lookahead failed! + > t_primary[9-9]: t_primary '[' slices ']' &t_lookahead + - t_primary[9-9]: t_primary '[' slices ']' &t_lookahead failed! + > t_primary[9-9]: t_primary genexp &t_lookahead + - t_primary[9-9]: t_primary genexp &t_lookahead failed! + > t_primary[9-9]: t_primary '(' arguments? ')' &t_lookahead + - t_primary[9-9]: t_primary '(' arguments? ')' &t_lookahead failed! + > t_primary[9-9]: atom &t_lookahead + > atom[9-9]: NAME + - atom[9-9]: NAME failed! + > atom[9-9]: 'True' + - atom[9-9]: 'True' failed! + > atom[9-9]: 'False' + - atom[9-9]: 'False' failed! + > atom[9-9]: 'None' + - atom[9-9]: 'None' failed! + > atom[9-9]: '__peg_parser__' + - atom[9-9]: '__peg_parser__' failed! + > atom[9-9]: &STRING strings + - atom[9-9]: &STRING strings failed! + > atom[9-9]: NUMBER + - atom[9-9]: NUMBER failed! + > atom[9-9]: &'(' (tuple | group | genexp) + - atom[9-9]: &'(' (tuple | group | genexp) failed! + > atom[9-9]: &'[' (list | listcomp) + - atom[9-9]: &'[' (list | listcomp) failed! + > atom[9-9]: &'{' (dict | set | dictcomp | setcomp) + - atom[9-9]: &'{' (dict | set | dictcomp | setcomp) failed! + > atom[9-9]: '...' + - atom[9-9]: '...' failed! + - t_primary[9-9]: atom &t_lookahead failed! + - single_subscript_attribute_target[9-9]: t_primary '.' NAME !t_lookahead failed! + > single_subscript_attribute_target[9-9]: t_primary '[' slices ']' !t_lookahead + - single_subscript_attribute_target[9-9]: t_primary '[' slices ']' !t_lookahead failed! + - _tmp_20[9-9]: single_subscript_attribute_target failed! + - assignment[9-9]: ('(' single_target ')' | single_subscript_attribute_target) ':' expression ['=' annotated_rhs] failed! + > assignment[9-9]: ((star_targets '='))+ (yield_expr | star_expressions) !'=' TYPE_COMMENT? + > _loop1_22[9-9]: (star_targets '=') + > _tmp_137[9-9]: star_targets '=' + > star_targets[9-9]: star_target !',' + > star_target[9-9]: '*' (!'*' star_target) + - star_target[9-9]: '*' (!'*' star_target) failed! + > star_target[9-9]: target_with_star_atom + > target_with_star_atom[9-9]: t_primary '.' NAME !t_lookahead + - target_with_star_atom[9-9]: t_primary '.' NAME !t_lookahead failed! + > target_with_star_atom[9-9]: t_primary '[' slices ']' !t_lookahead + - target_with_star_atom[9-9]: t_primary '[' slices ']' !t_lookahead failed! + > target_with_star_atom[9-9]: star_atom + > star_atom[9-9]: NAME + - star_atom[9-9]: NAME failed! + > star_atom[9-9]: '(' target_with_star_atom ')' + - star_atom[9-9]: '(' target_with_star_atom ')' failed! + > star_atom[9-9]: '(' star_targets_tuple_seq? ')' + - star_atom[9-9]: '(' star_targets_tuple_seq? ')' failed! + > star_atom[9-9]: '[' star_targets_list_seq? ']' + - star_atom[9-9]: '[' star_targets_list_seq? ']' failed! + - target_with_star_atom[9-9]: star_atom failed! + - star_target[9-9]: target_with_star_atom failed! + - star_targets[9-9]: star_target !',' failed! + > star_targets[9-9]: star_target ((',' star_target))* ','? + - star_targets[9-9]: star_target ((',' star_target))* ','? failed! + - _tmp_137[9-9]: star_targets '=' failed! + - _loop1_22[9-9]: (star_targets '=') failed! + - assignment[9-9]: ((star_targets '='))+ (yield_expr | star_expressions) !'=' TYPE_COMMENT? failed! + > assignment[9-9]: single_target augassign ~ (yield_expr | star_expressions) + > single_target[9-9]: single_subscript_attribute_target + > single_subscript_attribute_target[9-9]: t_primary '.' NAME !t_lookahead + - single_subscript_attribute_target[9-9]: t_primary '.' NAME !t_lookahead failed! + > single_subscript_attribute_target[9-9]: t_primary '[' slices ']' !t_lookahead + - single_subscript_attribute_target[9-9]: t_primary '[' slices ']' !t_lookahead failed! + - single_target[9-9]: single_subscript_attribute_target failed! + > single_target[9-9]: NAME + - single_target[9-9]: NAME failed! + > single_target[9-9]: '(' single_target ')' + - single_target[9-9]: '(' single_target ')' failed! + - assignment[9-9]: single_target augassign ~ (yield_expr | star_expressions) failed! + - small_stmt[9-9]: assignment failed! + > small_stmt[9-9]: star_expressions + > star_expressions[9-9]: star_expression ((',' star_expression))+ ','? + > star_expression[9-9]: '*' bitwise_or + - star_expression[9-9]: '*' bitwise_or failed! + > star_expression[9-9]: expression + > expression[9-9]: disjunction 'if' disjunction 'else' expression + > disjunction[9-9]: conjunction (('or' conjunction))+ + > conjunction[9-9]: inversion (('and' inversion))+ + > inversion[9-9]: 'not' inversion + - inversion[9-9]: 'not' inversion failed! + > inversion[9-9]: comparison + > comparison[9-9]: bitwise_or compare_op_bitwise_or_pair+ + > bitwise_or[9-9]: bitwise_or '|' bitwise_xor + - bitwise_or[9-9]: bitwise_or '|' bitwise_xor failed! + > bitwise_or[9-9]: bitwise_xor + > bitwise_xor[9-9]: bitwise_xor '^' bitwise_and + - bitwise_xor[9-9]: bitwise_xor '^' bitwise_and failed! + > bitwise_xor[9-9]: bitwise_and + > bitwise_and[9-9]: bitwise_and '&' shift_expr + - bitwise_and[9-9]: bitwise_and '&' shift_expr failed! + > bitwise_and[9-9]: shift_expr + > shift_expr[9-9]: shift_expr '<<' sum + - shift_expr[9-9]: shift_expr '<<' sum failed! + > shift_expr[9-9]: shift_expr '>>' sum + - shift_expr[9-9]: shift_expr '>>' sum failed! + > shift_expr[9-9]: sum + > sum[9-9]: sum '+' term + - sum[9-9]: sum '+' term failed! + > sum[9-9]: sum '-' term + - sum[9-9]: sum '-' term failed! + > sum[9-9]: term + > term[9-9]: term '*' factor + - term[9-9]: term '*' factor failed! + > term[9-9]: term '/' factor + - term[9-9]: term '/' factor failed! + > term[9-9]: term '//' factor + - term[9-9]: term '//' factor failed! + > term[9-9]: term '%' factor + - term[9-9]: term '%' factor failed! + > term[9-9]: term '@' factor + - term[9-9]: term '@' factor failed! + > term[9-9]: factor + > factor[9-9]: '+' factor + - factor[9-9]: '+' factor failed! + > factor[9-9]: '-' factor + - factor[9-9]: '-' factor failed! + > factor[9-9]: '~' factor + - factor[9-9]: '~' factor failed! + > factor[9-9]: power + > power[9-9]: await_primary '**' factor + > await_primary[9-9]: AWAIT primary + - await_primary[9-9]: AWAIT primary failed! + > await_primary[9-9]: primary + > primary[9-9]: primary '.' NAME + - primary[9-9]: primary '.' NAME failed! + > primary[9-9]: primary genexp + - primary[9-9]: primary genexp failed! + > primary[9-9]: primary '(' arguments? ')' + - primary[9-9]: primary '(' arguments? ')' failed! + > primary[9-9]: primary '[' slices ']' + - primary[9-9]: primary '[' slices ']' failed! + > primary[9-9]: atom + > atom[9-9]: NAME + - atom[9-9]: NAME failed! + > atom[9-9]: 'True' + - atom[9-9]: 'True' failed! + > atom[9-9]: 'False' + - atom[9-9]: 'False' failed! + > atom[9-9]: 'None' + - atom[9-9]: 'None' failed! + > atom[9-9]: '__peg_parser__' + - atom[9-9]: '__peg_parser__' failed! + > atom[9-9]: &STRING strings + - atom[9-9]: &STRING strings failed! + > atom[9-9]: NUMBER + - atom[9-9]: NUMBER failed! + > atom[9-9]: &'(' (tuple | group | genexp) + - atom[9-9]: &'(' (tuple | group | genexp) failed! + > atom[9-9]: &'[' (list | listcomp) + - atom[9-9]: &'[' (list | listcomp) failed! + > atom[9-9]: &'{' (dict | set | dictcomp | setcomp) + - atom[9-9]: &'{' (dict | set | dictcomp | setcomp) failed! + > atom[9-9]: '...' + - atom[9-9]: '...' failed! + - primary[9-9]: atom failed! + - await_primary[9-9]: primary failed! + - power[9-9]: await_primary '**' factor failed! + > power[9-9]: await_primary + - power[9-9]: await_primary failed! + - factor[9-9]: power failed! + - term[9-9]: factor failed! + - sum[9-9]: term failed! + - shift_expr[9-9]: sum failed! + - bitwise_and[9-9]: shift_expr failed! + - bitwise_xor[9-9]: bitwise_and failed! + - bitwise_or[9-9]: bitwise_xor failed! + - comparison[9-9]: bitwise_or compare_op_bitwise_or_pair+ failed! + > comparison[9-9]: bitwise_or + - comparison[9-9]: bitwise_or failed! + - inversion[9-9]: comparison failed! + - conjunction[9-9]: inversion (('and' inversion))+ failed! + > conjunction[9-9]: inversion + - conjunction[9-9]: inversion failed! + - disjunction[9-9]: conjunction (('or' conjunction))+ failed! + > disjunction[9-9]: conjunction + - disjunction[9-9]: conjunction failed! + - expression[9-9]: disjunction 'if' disjunction 'else' expression failed! + > expression[9-9]: disjunction + - expression[9-9]: disjunction failed! + > expression[9-9]: lambdef + > lambdef[9-9]: 'lambda' lambda_params? ':' expression + - lambdef[9-9]: 'lambda' lambda_params? ':' expression failed! + - expression[9-9]: lambdef failed! + - star_expression[9-9]: expression failed! + - star_expressions[9-9]: star_expression ((',' star_expression))+ ','? failed! + > star_expressions[9-9]: star_expression ',' + - star_expressions[9-9]: star_expression ',' failed! + > star_expressions[9-9]: star_expression + - star_expressions[9-9]: star_expression failed! + - small_stmt[9-9]: star_expressions failed! + > small_stmt[9-9]: &'return' return_stmt + - small_stmt[9-9]: &'return' return_stmt failed! + > small_stmt[9-9]: &('import' | 'from') import_stmt + > _tmp_14[9-9]: 'import' + - _tmp_14[9-9]: 'import' failed! + > _tmp_14[9-9]: 'from' + - _tmp_14[9-9]: 'from' failed! + - small_stmt[9-9]: &('import' | 'from') import_stmt failed! + > small_stmt[9-9]: &'raise' raise_stmt + - small_stmt[9-9]: &'raise' raise_stmt failed! + > small_stmt[9-9]: 'pass' + - small_stmt[9-9]: 'pass' failed! + > small_stmt[9-9]: &'del' del_stmt + - small_stmt[9-9]: &'del' del_stmt failed! + > small_stmt[9-9]: &'yield' yield_stmt + - small_stmt[9-9]: &'yield' yield_stmt failed! + > small_stmt[9-9]: &'assert' assert_stmt + - small_stmt[9-9]: &'assert' assert_stmt failed! + > small_stmt[9-9]: 'break' + - small_stmt[9-9]: 'break' failed! + > small_stmt[9-9]: 'continue' + - small_stmt[9-9]: 'continue' failed! + > small_stmt[9-9]: &'global' global_stmt + - small_stmt[9-9]: &'global' global_stmt failed! + > small_stmt[9-9]: &'nonlocal' nonlocal_stmt + - small_stmt[9-9]: &'nonlocal' nonlocal_stmt failed! + - simple_stmt[9-9]: small_stmt !';' NEWLINE failed! + > simple_stmt[9-9]: ';'.small_stmt+ ';'? NEWLINE + > _gather_12[9-9]: small_stmt _loop0_13 + - _gather_12[9-9]: small_stmt _loop0_13 failed! + - simple_stmt[9-9]: ';'.small_stmt+ ';'? NEWLINE failed! + - statement[9-9]: simple_stmt failed! + - _loop1_11[9-9]: statement failed! + + statements[7-9]: statement+ succeeded! + + block[5-10]: NEWLINE INDENT statements DEDENT succeeded! + + function_def_raw[0-10]: 'def' NAME '(' params? ')' ['->' expression] ':' func_type_comment? block succeeded! + + function_def[0-10]: function_def_raw succeeded! + + compound_stmt[0-10]: &('def' | '@' | ASYNC) function_def succeeded! + + statement[0-10]: compound_stmt succeeded! + > statement[10-10]: compound_stmt + > compound_stmt[10-10]: &('def' | '@' | ASYNC) function_def + > _tmp_15[10-10]: 'def' + - _tmp_15[10-10]: 'def' failed! + > _tmp_15[10-10]: '@' + - _tmp_15[10-10]: '@' failed! + > _tmp_15[10-10]: ASYNC + - _tmp_15[10-10]: ASYNC failed! + - compound_stmt[10-10]: &('def' | '@' | ASYNC) function_def failed! + > compound_stmt[10-10]: &'if' if_stmt + - compound_stmt[10-10]: &'if' if_stmt failed! + > compound_stmt[10-10]: &('class' | '@') class_def + > _tmp_16[10-10]: 'class' + - _tmp_16[10-10]: 'class' failed! + > _tmp_16[10-10]: '@' + - _tmp_16[10-10]: '@' failed! + - compound_stmt[10-10]: &('class' | '@') class_def failed! + > compound_stmt[10-10]: &('with' | ASYNC) with_stmt + > _tmp_17[10-10]: 'with' + - _tmp_17[10-10]: 'with' failed! + > _tmp_17[10-10]: ASYNC + - _tmp_17[10-10]: ASYNC failed! + - compound_stmt[10-10]: &('with' | ASYNC) with_stmt failed! + > compound_stmt[10-10]: &('for' | ASYNC) for_stmt + > _tmp_18[10-10]: 'for' + - _tmp_18[10-10]: 'for' failed! + > _tmp_18[10-10]: ASYNC + - _tmp_18[10-10]: ASYNC failed! + - compound_stmt[10-10]: &('for' | ASYNC) for_stmt failed! + > compound_stmt[10-10]: &'try' try_stmt + - compound_stmt[10-10]: &'try' try_stmt failed! + > compound_stmt[10-10]: &'while' while_stmt + - compound_stmt[10-10]: &'while' while_stmt failed! + - statement[10-10]: compound_stmt failed! + > statement[10-10]: simple_stmt + > simple_stmt[10-10]: small_stmt !';' NEWLINE + > small_stmt[10-10]: assignment + > assignment[10-10]: NAME ':' expression ['=' annotated_rhs] + - assignment[10-10]: NAME ':' expression ['=' annotated_rhs] failed! + > assignment[10-10]: ('(' single_target ')' | single_subscript_attribute_target) ':' expression ['=' annotated_rhs] + > _tmp_20[10-10]: '(' single_target ')' + - _tmp_20[10-10]: '(' single_target ')' failed! + > _tmp_20[10-10]: single_subscript_attribute_target + > single_subscript_attribute_target[10-10]: t_primary '.' NAME !t_lookahead + > t_primary[10-10]: t_primary '.' NAME &t_lookahead + - t_primary[10-10]: t_primary '.' NAME &t_lookahead failed! + > t_primary[10-10]: t_primary '[' slices ']' &t_lookahead + - t_primary[10-10]: t_primary '[' slices ']' &t_lookahead failed! + > t_primary[10-10]: t_primary genexp &t_lookahead + - t_primary[10-10]: t_primary genexp &t_lookahead failed! + > t_primary[10-10]: t_primary '(' arguments? ')' &t_lookahead + - t_primary[10-10]: t_primary '(' arguments? ')' &t_lookahead failed! + > t_primary[10-10]: atom &t_lookahead + > atom[10-10]: NAME + - atom[10-10]: NAME failed! + > atom[10-10]: 'True' + - atom[10-10]: 'True' failed! + > atom[10-10]: 'False' + - atom[10-10]: 'False' failed! + > atom[10-10]: 'None' + - atom[10-10]: 'None' failed! + > atom[10-10]: '__peg_parser__' + - atom[10-10]: '__peg_parser__' failed! + > atom[10-10]: &STRING strings + - atom[10-10]: &STRING strings failed! + > atom[10-10]: NUMBER + - atom[10-10]: NUMBER failed! + > atom[10-10]: &'(' (tuple | group | genexp) + - atom[10-10]: &'(' (tuple | group | genexp) failed! + > atom[10-10]: &'[' (list | listcomp) + - atom[10-10]: &'[' (list | listcomp) failed! + > atom[10-10]: &'{' (dict | set | dictcomp | setcomp) + - atom[10-10]: &'{' (dict | set | dictcomp | setcomp) failed! + > atom[10-10]: '...' + - atom[10-10]: '...' failed! + - t_primary[10-10]: atom &t_lookahead failed! + - single_subscript_attribute_target[10-10]: t_primary '.' NAME !t_lookahead failed! + > single_subscript_attribute_target[10-10]: t_primary '[' slices ']' !t_lookahead + - single_subscript_attribute_target[10-10]: t_primary '[' slices ']' !t_lookahead failed! + - _tmp_20[10-10]: single_subscript_attribute_target failed! + - assignment[10-10]: ('(' single_target ')' | single_subscript_attribute_target) ':' expression ['=' annotated_rhs] failed! + > assignment[10-10]: ((star_targets '='))+ (yield_expr | star_expressions) !'=' TYPE_COMMENT? + > _loop1_22[10-10]: (star_targets '=') + > _tmp_137[10-10]: star_targets '=' + > star_targets[10-10]: star_target !',' + > star_target[10-10]: '*' (!'*' star_target) + - star_target[10-10]: '*' (!'*' star_target) failed! + > star_target[10-10]: target_with_star_atom + > target_with_star_atom[10-10]: t_primary '.' NAME !t_lookahead + - target_with_star_atom[10-10]: t_primary '.' NAME !t_lookahead failed! + > target_with_star_atom[10-10]: t_primary '[' slices ']' !t_lookahead + - target_with_star_atom[10-10]: t_primary '[' slices ']' !t_lookahead failed! + > target_with_star_atom[10-10]: star_atom + > star_atom[10-10]: NAME + - star_atom[10-10]: NAME failed! + > star_atom[10-10]: '(' target_with_star_atom ')' + - star_atom[10-10]: '(' target_with_star_atom ')' failed! + > star_atom[10-10]: '(' star_targets_tuple_seq? ')' + - star_atom[10-10]: '(' star_targets_tuple_seq? ')' failed! + > star_atom[10-10]: '[' star_targets_list_seq? ']' + - star_atom[10-10]: '[' star_targets_list_seq? ']' failed! + - target_with_star_atom[10-10]: star_atom failed! + - star_target[10-10]: target_with_star_atom failed! + - star_targets[10-10]: star_target !',' failed! + > star_targets[10-10]: star_target ((',' star_target))* ','? + - star_targets[10-10]: star_target ((',' star_target))* ','? failed! + - _tmp_137[10-10]: star_targets '=' failed! + - _loop1_22[10-10]: (star_targets '=') failed! + - assignment[10-10]: ((star_targets '='))+ (yield_expr | star_expressions) !'=' TYPE_COMMENT? failed! + > assignment[10-10]: single_target augassign ~ (yield_expr | star_expressions) + > single_target[10-10]: single_subscript_attribute_target + > single_subscript_attribute_target[10-10]: t_primary '.' NAME !t_lookahead + - single_subscript_attribute_target[10-10]: t_primary '.' NAME !t_lookahead failed! + > single_subscript_attribute_target[10-10]: t_primary '[' slices ']' !t_lookahead + - single_subscript_attribute_target[10-10]: t_primary '[' slices ']' !t_lookahead failed! + - single_target[10-10]: single_subscript_attribute_target failed! + > single_target[10-10]: NAME + - single_target[10-10]: NAME failed! + > single_target[10-10]: '(' single_target ')' + - single_target[10-10]: '(' single_target ')' failed! + - assignment[10-10]: single_target augassign ~ (yield_expr | star_expressions) failed! + - small_stmt[10-10]: assignment failed! + > small_stmt[10-10]: star_expressions + > star_expressions[10-10]: star_expression ((',' star_expression))+ ','? + > star_expression[10-10]: '*' bitwise_or + - star_expression[10-10]: '*' bitwise_or failed! + > star_expression[10-10]: expression + > expression[10-10]: disjunction 'if' disjunction 'else' expression + > disjunction[10-10]: conjunction (('or' conjunction))+ + > conjunction[10-10]: inversion (('and' inversion))+ + > inversion[10-10]: 'not' inversion + - inversion[10-10]: 'not' inversion failed! + > inversion[10-10]: comparison + > comparison[10-10]: bitwise_or compare_op_bitwise_or_pair+ + > bitwise_or[10-10]: bitwise_or '|' bitwise_xor + - bitwise_or[10-10]: bitwise_or '|' bitwise_xor failed! + > bitwise_or[10-10]: bitwise_xor + > bitwise_xor[10-10]: bitwise_xor '^' bitwise_and + - bitwise_xor[10-10]: bitwise_xor '^' bitwise_and failed! + > bitwise_xor[10-10]: bitwise_and + > bitwise_and[10-10]: bitwise_and '&' shift_expr + - bitwise_and[10-10]: bitwise_and '&' shift_expr failed! + > bitwise_and[10-10]: shift_expr + > shift_expr[10-10]: shift_expr '<<' sum + - shift_expr[10-10]: shift_expr '<<' sum failed! + > shift_expr[10-10]: shift_expr '>>' sum + - shift_expr[10-10]: shift_expr '>>' sum failed! + > shift_expr[10-10]: sum + > sum[10-10]: sum '+' term + - sum[10-10]: sum '+' term failed! + > sum[10-10]: sum '-' term + - sum[10-10]: sum '-' term failed! + > sum[10-10]: term + > term[10-10]: term '*' factor + - term[10-10]: term '*' factor failed! + > term[10-10]: term '/' factor + - term[10-10]: term '/' factor failed! + > term[10-10]: term '//' factor + - term[10-10]: term '//' factor failed! + > term[10-10]: term '%' factor + - term[10-10]: term '%' factor failed! + > term[10-10]: term '@' factor + - term[10-10]: term '@' factor failed! + > term[10-10]: factor + > factor[10-10]: '+' factor + - factor[10-10]: '+' factor failed! + > factor[10-10]: '-' factor + - factor[10-10]: '-' factor failed! + > factor[10-10]: '~' factor + - factor[10-10]: '~' factor failed! + > factor[10-10]: power + > power[10-10]: await_primary '**' factor + > await_primary[10-10]: AWAIT primary + - await_primary[10-10]: AWAIT primary failed! + > await_primary[10-10]: primary + > primary[10-10]: primary '.' NAME + - primary[10-10]: primary '.' NAME failed! + > primary[10-10]: primary genexp + - primary[10-10]: primary genexp failed! + > primary[10-10]: primary '(' arguments? ')' + - primary[10-10]: primary '(' arguments? ')' failed! + > primary[10-10]: primary '[' slices ']' + - primary[10-10]: primary '[' slices ']' failed! + > primary[10-10]: atom + > atom[10-10]: NAME + - atom[10-10]: NAME failed! + > atom[10-10]: 'True' + - atom[10-10]: 'True' failed! + > atom[10-10]: 'False' + - atom[10-10]: 'False' failed! + > atom[10-10]: 'None' + - atom[10-10]: 'None' failed! + > atom[10-10]: '__peg_parser__' + - atom[10-10]: '__peg_parser__' failed! + > atom[10-10]: &STRING strings + - atom[10-10]: &STRING strings failed! + > atom[10-10]: NUMBER + - atom[10-10]: NUMBER failed! + > atom[10-10]: &'(' (tuple | group | genexp) + - atom[10-10]: &'(' (tuple | group | genexp) failed! + > atom[10-10]: &'[' (list | listcomp) + - atom[10-10]: &'[' (list | listcomp) failed! + > atom[10-10]: &'{' (dict | set | dictcomp | setcomp) + - atom[10-10]: &'{' (dict | set | dictcomp | setcomp) failed! + > atom[10-10]: '...' + - atom[10-10]: '...' failed! + - primary[10-10]: atom failed! + - await_primary[10-10]: primary failed! + - power[10-10]: await_primary '**' factor failed! + > power[10-10]: await_primary + - power[10-10]: await_primary failed! + - factor[10-10]: power failed! + - term[10-10]: factor failed! + - sum[10-10]: term failed! + - shift_expr[10-10]: sum failed! + - bitwise_and[10-10]: shift_expr failed! + - bitwise_xor[10-10]: bitwise_and failed! + - bitwise_or[10-10]: bitwise_xor failed! + - comparison[10-10]: bitwise_or compare_op_bitwise_or_pair+ failed! + > comparison[10-10]: bitwise_or + - comparison[10-10]: bitwise_or failed! + - inversion[10-10]: comparison failed! + - conjunction[10-10]: inversion (('and' inversion))+ failed! + > conjunction[10-10]: inversion + - conjunction[10-10]: inversion failed! + - disjunction[10-10]: conjunction (('or' conjunction))+ failed! + > disjunction[10-10]: conjunction + - disjunction[10-10]: conjunction failed! + - expression[10-10]: disjunction 'if' disjunction 'else' expression failed! + > expression[10-10]: disjunction + - expression[10-10]: disjunction failed! + > expression[10-10]: lambdef + > lambdef[10-10]: 'lambda' lambda_params? ':' expression + - lambdef[10-10]: 'lambda' lambda_params? ':' expression failed! + - expression[10-10]: lambdef failed! + - star_expression[10-10]: expression failed! + - star_expressions[10-10]: star_expression ((',' star_expression))+ ','? failed! + > star_expressions[10-10]: star_expression ',' + - star_expressions[10-10]: star_expression ',' failed! + > star_expressions[10-10]: star_expression + - star_expressions[10-10]: star_expression failed! + - small_stmt[10-10]: star_expressions failed! + > small_stmt[10-10]: &'return' return_stmt + - small_stmt[10-10]: &'return' return_stmt failed! + > small_stmt[10-10]: &('import' | 'from') import_stmt + > _tmp_14[10-10]: 'import' + - _tmp_14[10-10]: 'import' failed! + > _tmp_14[10-10]: 'from' + - _tmp_14[10-10]: 'from' failed! + - small_stmt[10-10]: &('import' | 'from') import_stmt failed! + > small_stmt[10-10]: &'raise' raise_stmt + - small_stmt[10-10]: &'raise' raise_stmt failed! + > small_stmt[10-10]: 'pass' + - small_stmt[10-10]: 'pass' failed! + > small_stmt[10-10]: &'del' del_stmt + - small_stmt[10-10]: &'del' del_stmt failed! + > small_stmt[10-10]: &'yield' yield_stmt + - small_stmt[10-10]: &'yield' yield_stmt failed! + > small_stmt[10-10]: &'assert' assert_stmt + - small_stmt[10-10]: &'assert' assert_stmt failed! + > small_stmt[10-10]: 'break' + - small_stmt[10-10]: 'break' failed! + > small_stmt[10-10]: 'continue' + - small_stmt[10-10]: 'continue' failed! + > small_stmt[10-10]: &'global' global_stmt + - small_stmt[10-10]: &'global' global_stmt failed! + > small_stmt[10-10]: &'nonlocal' nonlocal_stmt + - small_stmt[10-10]: &'nonlocal' nonlocal_stmt failed! + - simple_stmt[10-10]: small_stmt !';' NEWLINE failed! + > simple_stmt[10-10]: ';'.small_stmt+ ';'? NEWLINE + > _gather_12[10-10]: small_stmt _loop0_13 + - _gather_12[10-10]: small_stmt _loop0_13 failed! + - simple_stmt[10-10]: ';'.small_stmt+ ';'? NEWLINE failed! + - statement[10-10]: simple_stmt failed! + - _loop1_11[10-10]: statement failed! + + statements[0-10]: statement+ succeeded! + + file[0-11]: statements? $ succeeded! +``` -![코드 token화 예시](../images/4_grammar/code_tokenized.png) +
diff --git a/_sources/docs/5_0_config_and_input.md b/_sources/docs/5_0_config_and_input.md index e8dfab5..b035d8d 100644 --- a/_sources/docs/5_0_config_and_input.md +++ b/_sources/docs/5_0_config_and_input.md @@ -1 +1 @@ -# 구성과 입력 \ No newline at end of file +# 5. 구성과 입력 \ No newline at end of file diff --git a/_sources/docs/6_0_rexing_and_parsing.md b/_sources/docs/6_0_rexing_and_parsing.md index 6d1a4bc..a18705b 100644 --- a/_sources/docs/6_0_rexing_and_parsing.md +++ b/_sources/docs/6_0_rexing_and_parsing.md @@ -1,4 +1,4 @@ -# 렉싱과 파싱 +# 6. 렉싱과 파싱 - [렉싱과 파싱](#렉싱과-파싱) - [6.0 개요](#60-개요) - [6.1 CST 생성](#61-cst-생성) diff --git a/_sources/docs/7_0_compiler.md b/_sources/docs/7_0_compiler.md index 2e0f22b..5e6ca7a 100644 --- a/_sources/docs/7_0_compiler.md +++ b/_sources/docs/7_0_compiler.md @@ -1,4 +1,4 @@ -# 컴파일러 +# 7. 컴파일러 ![컴파일 과정](../images/7_compiler/00_compile_process.png) 파이썬 코드를 파싱하면 연산자, 함수, 클래스, 이름 공간을 포함하는 AST가 생성 AST를 CPU 명령으로 바꾸는 것이 **컴파일러** diff --git a/_sources/docs/8_0_eval_loop.md b/_sources/docs/8_0_eval_loop.md index bcbfc67..0a041dc 100644 --- a/_sources/docs/8_0_eval_loop.md +++ b/_sources/docs/8_0_eval_loop.md @@ -1,4 +1,4 @@ -# 평가 루프 +# 8. 평가 루프 - [평가 루프](#평가-루프) - [8.0 개요](#80-개요) diff --git a/_sources/docs/9_0_memory.md b/_sources/docs/9_0_memory.md index bc2043c..6dbe5cb 100644 --- a/_sources/docs/9_0_memory.md +++ b/_sources/docs/9_0_memory.md @@ -1,4 +1,4 @@ -# 메모리 관리 +# 9. 메모리 관리 - [메모리 관리](#메모리-관리) - [9.0 개요](#90-개요) diff --git a/_sources/intro.md b/_sources/intro.md index cc80f3b..fd30c38 100644 --- a/_sources/intro.md +++ b/_sources/intro.md @@ -1,9 +1,11 @@ # CPython Guide for PseudoLab +가짜연구소 CPython 파헤치기 스터디팀에서 작성하는 CPython Guide 페이지 입니다. + ### [CPython Github](https://github.com/python/cpython) 스터디에 활용되는 CPython Github 저장소 입니다. -### [CPython 파헤치기 Notion 페이지](https://www.notion.so/chanrankim/CPython-868604c8879341808b85d4321bb07501?pvs=4) -스터디에 진행 기록을 저장하는 Notion 페이지 입니다. - -가짜연구소 CPython 파헤치기 스터디팀에서 작성하는 CPython Guide 페이지 입니다. \ No newline at end of file +### CPython 파헤치기 Notion 페이지 +스터디 진행 기록을 저장하는 Notion 페이지 입니다. +- [6기 (2023.03~2023.07)](https://www.notion.so/chanrankim/CPython-868604c8879341808b85d4321bb07501?pvs=4) +- [8기 (2024.03~2024.06)](https://www.notion.so/chanrankim/Python-CPython-eb832e65c4b1443ba3b9be8d5fc5883a?pvs=4) diff --git a/docs/0_0_dev_env_setup.html b/docs/0_0_dev_env_setup.html index 04a5744..a5a6532 100644 --- a/docs/0_0_dev_env_setup.html +++ b/docs/0_0_dev_env_setup.html @@ -66,8 +66,6 @@ - - @@ -159,30 +157,29 @@

◽ CPython 가이드

-