This project is a proof-of-concept (PoC) transpiler for PWV with Multi-Version Objects.
The transpiler orchestrates a full transpile-and-run pipeline, driven by the main entry point (main.py).
- Parse: Parses all
.pyfiles within a specified test case directory into ASTs using theastmodule. - Transform: Traverses and transforms the ASTs in multiple passes:
- Pass 1 (
SymbolTableBuilderVisitor): Builds aSymbolTablecontaining information about all classes, methods, fields, and variables. - Pass 2 (
UnifiedClassBuilder): Merges the versioned class ASTs (e.g.,Test__1__,Test__2__) into a new, unified class AST that implements the State Pattern.
- Pass 1 (
- Generate Code: Converts the final, transformed ASTs back into well-formatted Python source code.
- Execute: The test pipeline runs the generated
main.pyto verify its runtime behavior.
- Python 3.8 or higher
- uv: A fast Python package installer and resolver. See the installation guide.
This project uses uv for dependency management and reproducibility.
The environment is defined by pyproject.toml and uv.lock. Both should be committed to Git.
# Pin Python version (creates .python-version)
uv python pin 3.12
# Install dependencies (creates .venv and uv.lock if missing)
uv syncuv sync will:
- Create a virtual environment in .venv
- Install project dependencies
- Install the project itself in editable mode (so
src/mylang_compilercan be imported from anywhere)
# macOS/Linux
source .venv/bin/activate
# Windows PowerShell
.venv\Scripts\activate
# deactivate
deactivateYou can run the transpiler on a specific test case directory using main.py.
# Example: Run the 'basic_cases/basic_01' test case
python main.py basic_cases/basic_01
# Run with debug logs enabled
python main.py basic_cases/basic_01 --debugFor the transpiler to work correctly, your source code must follow a few specific conventions:
All versions of a class that you intend to unify must be defined within the same Python file. Each versioned class must be named with a double-underscore suffix __<number>__.
Example: point.py
# All versions of 'Point' must be in this single file.
class Point__1__:
def __init__(self, x: int):
self.x = x
class Point__2__:
def __init__(self, r: float):
self.r = rIf you need to define state transformation logic between versions, you must create a corresponding synchronization module.
- Naming: The sync module must be named after the base class, with a
_syncsuffix (e.g.,Point_sync.py). - Location: No restriction.
Functions within a sync module are used to transform the state from one version to another. They must follow a strict naming convention and signature.
- Naming:
sync_from_v<source_number>_to_v<target_number> - Signature: Each function must accept two arguments: the source implementation instance and the target implementation instance.
Example: Point_sync.py
def sync_from_v1_to_v2(v1_impl, v2_impl):
# This function is called when switching from v1 to v2.
# It should read from v1_impl and write to v2_impl.
v2_impl.r = v1_impl.x # Example transformationThis project features a fully automated test suite powered by pytest.
-
Input Files (
test/resources/samples/): Each subdirectory (e.g.,basic_cases/basic_01/) represents a self-contained test case and should include all necessary source files. -
Expected Output (
test/resources/expected_output/): This directory mirrors the parent structure ofsamples/. The expected runtime output for a given test case is stored in a.txtfile that shares the same name as the test case directory.- Example: The expected output for the test case in
.../samples/basic_cases/basic_01/should be placed in.../expected_output/basic_cases/basic_01.txt.
- Example: The expected output for the test case in
-
Run all tests:
pytest
-
Run a specific test case: Use the
--target_diroption to specify the relative path to a single test case.# Runs only the tests in the 'basic_cases/basic_01/' directory pytest --target_dir=basic_cases/basic_01 -
Run with Debug Logs: To see the transpiler's internal logging, add the
--debugflag.pytest --debug --target_dir=basic_cases/basic_01/
A brief overview of the key directories and files in this project.
.
├── main.py : The main entry point
├── pyproject.toml
├── src/ : Contains all the source code for the transpiler library
│ └── mylang_compiler/ : The main package for the transpiler
│ ├── run.py
│ ├── my_lang_transformer.py
│ ├── builder/ : A package containing specialized builder classes
│ ├── symbol_table/ : Contains the data structures for the symbol table
│ └── util/ : Contains shared helper modules like the `logger`
└── tests/ : Contains all files related to the test suite
├── test_transformer.py
└── resources/ : Holds all the data required for the tests
├── samples/ : Contains the input `.py` source files for each test case
└── expected_output/ : Contains the expected output for each corresponding test case