A robust tool to transpile Python source code into V(vlang) code.
This document describes the internal architecture of the Python to Vlang Transpiler.
The transpiler follows a pipeline architecture with distinct phases:
Python Source → Parser → AST → Analyzer → Typed AST → Translator → V AST → Generator → V Source
core/parser.py)Purpose: Parses Python source code into an Abstract Syntax Tree (AST).
Implementation:
ast moduleKey Classes:
class PyASTParser:
def parse(self, source: str) -> ast.AST
def parse_file(self, file_path: str) -> ast.AST
def dump_tree(self, tree: ast.AST) -> str # Debug output
Example:
from py2v_transpiler.core.parser import PyASTParser
parser = PyASTParser()
tree = parser.parse("def foo(): pass")
print(parser.dump_tree(tree))
core/analyzer.py)Purpose: Performs static type inference using mypy.
Implementation:
Key Classes:
class TypeInference:
def analyze(self, tree: ast.AST) -> None
def get_type(self, node: ast.AST) -> Optional[str]
def infer_alias_types(self, tree: ast.AST) -> Dict[str, str]
Type Inference Process:
.pyi stub files)core/translator/)Purpose: Visits AST nodes and translates them to V constructs.
Implementation:
Module Structure:
core/translator/
├── __init__.py # VNodeVisitor main class
├── base.py # TranslatorBase with shared state
├── module.py # Module-level handling
├── imports.py # Import statements
├── expressions.py # Expressions and operators
├── literals.py # Literals (strings, numbers)
├── variables.py # Variable assignments
├── control_flow.py # if, for, while, match
├── functions.py # Function definitions
└── classes.py # Class definitions
Key Classes:
class VNodeVisitor(
ModuleMixin,
ImportsMixin,
ExpressionsMixin,
ClassesMixin,
FunctionsMixin,
ControlFlowMixin,
VariablesMixin,
LiteralsMixin,
TranslatorBase
):
# Visits AST nodes and emits V code
Translation Process:
stdlib_map/mapper.py)Purpose: Maps Python stdlib calls to V equivalents.
Implementation:
Key Classes:
class StdLibMapper:
def __init__(self):
self.mappings: Dict[str, Dict[str, Union[str, Callable]]]
def map(self, module: str, function: str, args: List[str]) -> str
Mapping Types:
math.sqrt → math.sqrtrandom.randint(a, b) → rand.int(a..b)core/generator.py)Purpose: Emits final V source code with proper formatting.
Implementation:
Key Classes:
class VCodeEmitter:
def __init__(self):
self.imports: List[str]
self.structs: List[str]
self.functions: List[str]
self.main_body: List[str]
def emit_global_helpers(...) -> str
Output Structure:
// Imports
import os
import math
// Structs (from classes)
struct Point {
x int
y int
}
// Functions
fn foo() int {
return 42
}
// Main
fn main() {
// Program entry point
}
┌─────────────┐
│ Python File │
└──────┬──────┘
│
▼
┌─────────────┐
│ Parser │
└──────┬──────┘
│
▼
┌─────────────┐
│ Raw AST │
└──────┬──────┘
│
▼
┌─────────────┐
│ Analyzer │
│ (mypy) │
└──────┬──────┘
│
▼
┌─────────────┐
│ Typed AST │
└──────┬──────┘
│
▼
┌─────────────┐
│ Translator │
│ (Visitor) │
└──────┬──────┘
│
▼
┌─────────────┐
│ V Code │
│ (buffer) │
└──────┬──────┘
│
▼
┌─────────────┐
│ Generator │
└──────┬──────┘
│
▼
┌─────────────┐
│ V File │
└─────────────┘
| Python | V |
|---|---|
int |
int |
float |
f64 |
bool |
bool |
str |
string |
None |
none |
Any |
Any |
| Python | V |
|---|---|
list[T] |
[]T |
dict[K, V] |
map[K]V |
set[T] |
map[T]bool |
tuple[A, B] |
[]A (homogeneous) |
Optional[T] |
?T |
Union[A, B] |
A \| B or Any |
| Python | V |
|---|---|
Callable[[int], str] |
fn (int) string |
Callable[..., Any] |
fn |
Python’s exception handling is mapped to V’s error handling:
# Python
try:
risky_operation()
except ValueError as e:
print(f"Error: {e}")
// V
result := risky_operation() or {
println('Error: ${err}')
return
}
| Python | V |
|---|---|
ValueError |
Custom error |
TypeError |
Type mismatch |
KeyError |
Map access error |
IndexError |
Array bounds check |
RuntimeError |
Generic error |
The transpiler generates helper functions for Python features without direct V equivalents:
py2v_helpers.vGenerated Helpers:
enumerate() - Index iterationzip() - Parallel iterationsorted() - Sortingreversed() - Reverse iterationany() / all() - Boolean aggregationmap() / filter() - Functional operationsConditional Generation:
used_builtins set in translatorclass TranspilerConfig:
strict_types: bool # Enable strict type checking
output_dir: str # Output directory
mypy_enabled: bool # Enable mypy inference
warn_dynamic: bool # Warn about Any types
no_helpers: bool # Skip helper generation
helpers_only: bool # Generate only helpers
stdlib_map/mapper.py
self.mappings["new_module"] = {
"function": "v_function"
}
models/v_types.py
def map_python_type_to_v(py_type: str) -> str:
if py_type == "NewType":
return "v_type"
def visit_NewNode(self, node: ast.AST) -> str:
# Translation logic
tests/
├── test_parser.py # Parser tests
├── test_analyzer.py # Type inference tests
├── test_generator.py # Code generation tests
├── test_dependencies.py # Dependency analysis tests
├── test_v2_features.py # New feature tests
└── translator/ # Translation tests
├── test_classes.py
├── test_functions.py
├── test_control_flow.py
└── ...
Test Pattern:
def test_feature():
python_code = """
def foo() -> int:
return 42
"""
expected_v = """
fn foo() int {
return 42
}
"""
assert transpile(python_code) == expected_v
See TODO.md and todo2.md for planned enhancements: