Skip to content

Implement py2rust: Python-to-Rust subset compiler - #1

Merged
djmahe4 merged 87 commits into
mainfrom
copilot/create-python-to-rust-compiler
May 28, 2026
Merged

djmahe4 merged 87 commits into
mainfrom
copilot/create-python-to-rust-compiler

Conversation

Copilot AI commented Apr 12, 2026 •

Copy link
Copy Markdown
Contributor

Builds py2rust from scratch — a compiler that translates a statically typed Python subset into idiomatic, safe Rust following a formal pipeline: Python AST → Custom AST → Symbol Table + Type Checking → High-Level IR → Rust codegen.

Pipeline stages

  • Frontend (frontend/): Python ast → frozen-dataclass custom AST with source locations; rejects unsupported features (classes, imports, lambdas, missing type hints, eval/exec, etc.) with UnsupportedFeatureError
  • Middle-end (middleend/): scoped symbol table, strict bidirectional type checker, literal type inferencer, IR builder (custom AST → typed IR)
  • IR (ir/): strongly-typed frozen-dataclass nodes — IRFunction, IRAssign, IRIf, IRWhile, IRForRange, IRReturn, IRPrint, etc.
  • Backend (backend/): Rust codegen + rustfmt integration

Type mapping

Python Rust
int i32
float f64
bool bool
str String
list[T] Vec<T>

Codegen correctness

Three non-obvious correctness issues fixed vs. naïve output:

let mut inference — codegen scans the full function body (including nested loops/branches) for IRAssign/IRAugAssign targets and emits let mut only for variables that are actually reassigned after declaration.

fn main() return type — Rust's main must return () or a Termination impl. If the user writes def main() -> int, codegen emits fn main() (no return type) and converts return <expr>; to return;.

--verify temp file — rustc -o /dev/null fails in sandboxed environments; replaced with a proper tempfile.NamedTemporaryFile.

Example

# fibonacci.py
def fib(n: int) -> int:
    a: int = 0
    b: int = 1
    i: int = 2
    while i <= n:
        temp: int = a + b
        a = b      # triggers let mut a
        b = temp   # triggers let mut b
        i += 1     # triggers let mut i
    return b
// fibonacci.rs (generated)
fn fib(n: i32) -> i32 {
    let mut a: i32 = 0;
    let mut b: i32 = 1;
    let mut i: i32 = 2;
    while i <= n {
        let temp: i32 = a + b;
        a = b;
        b = temp;
        i += 1;
    }
    return b;
}

CLI

py2rust input.py -o output.rs [--emit-ast] [--emit-ir] [--check-only] [--verbose] [--verify]
Original prompt

🛠️ SYSTEM ROLE

You are a senior compiler engineer and Rust systems programmer with extensive experience building production compilers (similar to rustc frontend or mypy + codegen pipelines).

Your task is to build py2rust — a correct, safe, and idiomatic Python-to-Rust subset compiler.

You must treat this as a real compiler project, not a quick transpiler. Every stage must follow formal compiler design principles: frontend, middle-end, backend, with clear separation of concerns.


🚨 CRITICAL RULES — YOU MUST OBEY THESE AT ALL TIMES

  1. Never hallucinate features, APIs, or Rust syntax. Only use standard, stable Rust.
  2. Strictly follow the supported subset. Reject everything else immediately.
  3. Never skip phases or combine multiple stages into one response.
  4. Every module must be independently testable with clear unit tests.
  5. All generated Rust code must be valid, compile cleanly with rustc (stable), contain no unsafe, and follow idiomatic Rust style.
  6. Fail fast on unsupported Python features with a clear UnsupportedFeatureError.
  7. Always perform type checking before any code generation.
  8. Use only Python 3.11+ features and standard library (ast, dataclasses, etc.).
  9. Never deviate from the exact project structure provided.
  10. After each major phase, stop and wait for explicit user instruction to proceed.

🎯 PROJECT NAME & GOAL

Project: py2rust

Goal: Translate a strictly defined, statically typed subset of Python into clean, safe, zero-unsafe Rust code.

Pipeline (mandatory):
Python Source → Python AST → Custom AST → Symbol Table + Semantic Analysis → Type Checking & Inference → High-Level IR → Rust Code Generation → Formatted Rust


📁 PROJECT STRUCTURE (EXACT — NO CHANGES ALLOWED)

py2rust/
├── py2rust/
│   ├── __init__.py
│   ├── main.py
│   ├── cli.py
│   ├── config.py
│   │
│   ├── frontend/
│   │   ├── __init__.py
│   │   ├── ast_nodes.py
│   │   └── parser.py
│   │
│   ├── middleend/
│   │   ├── __init__.py
│   │   ├── symbol_table.py
│   │   ├── type_checker.py
│   │   ├── type_inferencer.py
│   │   └── ir_builder.py
│   │
│   ├── ir/
│   │   ├── __init__.py
│   │   └── ir_nodes.py
│   │
│   ├── backend/
│   │   ├── __init__.py
│   │   ├── rust_codegen.py
│   │   └── rust_formatter.py
│   │
│   ├── utils/
│   │   ├── __init__.py
│   │   ├── errors.py
│   │   ├── logger.py
│   │   └── visitor.py
│   │
│   └── tests/
│       ├── __init__.py
│       ├── test_parser.py
│       ├── test_semantic.py
│       ├── test_ir.py
│       ├── test_codegen.py
│       └── test_cases/
│           ├── valid/
│           └── invalid/
│
├── pyproject.toml
├── README.md
└── examples/

🔒 STRICTLY SUPPORTED PYTHON SUBSET (Phase 1 MVP)

Only these features are allowed. Anything else must raise UnsupportedFeatureError with line number and helpful message.

✅ Supported:

  • Function definitions with mandatory type hints on all parameters and return type
  • Variable declarations with type annotations or inferable literals
  • Primitive types: int, float, bool, str
  • Arithmetic operators: +, -, *, /, //, %
  • Comparison operators and boolean logic (and, or, not)
  • if / elif / else
  • while loops
  • for loops only in the form for i in range(start, stop) or range(start, stop, step) where arguments are simple
  • return statements
  • Homogeneous lists: list[int], list[float], etc. → Vec<T>
  • print(expr) with simple arguments

❌ Forbidden (immediate error):

  • Classes, methods, inheritance
  • Any missing type hints on function parameters/returns
  • Dynamic typing, Any, typing.Any
  • eval, exec, globals, locals
  • Decorators, lambdas, comprehensions
  • Async, generators, yield
  • Import statements
  • Exceptions / try-except
  • Recursion (optional restriction for Phase 1)

Type Mapping:

  • int → i32
  • float → f64
  • bool → bool
  • str → String
  • list[T] → Vec<T>

🧩 DETAILED PHASE REQUIREMENTS

Frontend

  • Use Python’s ast module + Visitor pattern (utils/visitor.py)
  • Define all nodes as frozen dataclasses in frontend/ast_nodes.py with source location
  • Convert Python AST to Custom AST, rejecting unsupported nodes early

Middle-end

  • Scoped symbol table supporting global and function scopes
  • Strict type checker with bidirectional checking where possible
  • Limited type inference only from literals and simple expressions
  • Full semantic validation before IR generation

IR (High-Level)

  • Define clean, strongly-typed IR nodes in ir/ir_nodes.py
  • Include: IRFunction, IRBlock, IRAssign, IRBinaryOp, IRIf, IRWhile, IRForRange, IRReturn, IRPrint

Backend (Rust Codegen)

  • Generate idiomatic, readable Rust code
  • Use explicit types on let bindings when needed
  • Map control flow correctly (if, while, for i in start..end)
  • Use println! for print()
  • Ensure correct semic...

Copilot AI and others added 4 commits April 12, 2026 03:34
- Frontend parser: supports typed Python subset (int/float/bool/str/list,
  functions with mandatory type hints, if/elif/else, while, for-range,
  return, print, arithmetic/comparison/bool ops)
- Middle-end: symbol table with scoping, type checker, type inferencer,
  IR builder lowering Python AST to typed IR
- IR: typed intermediate representation nodes
- Backend: Rust code generator + optional rustfmt formatter
- Utils: error hierarchy, visitor pattern, logger
- CLI: py2rust command-line tool
- Tests: 66 tests (parser, semantic, IR, codegen) — all passing
- Examples: fibonacci and simple_math in Python and Rust

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Co-authored-by: djmahe4 <137691824+djmahe4@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Co-authored-by: djmahe4 <137691824+djmahe4@users.noreply.github.com>
Copilot AI changed the title [WIP] Add initial implementation of Python-to-Rust subset compiler Implement py2rust: Python-to-Rust subset compiler Apr 12, 2026
Copilot AI requested a review from djmahe4 April 12, 2026 03:44
@djmahe4

djmahe4 commented Apr 12, 2026

Copy link
Copy Markdown
Owner

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements py2rust, a subset compiler for translating statically typed Python into Rust, featuring a complete pipeline from parsing to code generation. The review identifies several functional and semantic issues: the AST visitor fails to traverse nodes stored in tuples, and the Rust code generation incorrectly handles floor division, negative range steps, and operator precedence. Furthermore, the type checker lacks necessary validations for augmented assignments and range arguments, and the print implementation will cause compilation errors for list types. Refactoring the type-dispatching logic to use isinstance is also recommended for better robustness.

Comment thread py2rust/utils/visitor.py Outdated
Comment thread py2rust/backend/rust_codegen.py Outdated
Comment thread py2rust/backend/rust_codegen.py Outdated
Comment thread py2rust/backend/rust_codegen.py Outdated
Comment thread py2rust/backend/rust_codegen.py Outdated
Comment thread py2rust/middleend/type_checker.py Outdated
Comment thread py2rust/middleend/type_checker.py Outdated
Comment thread py2rust/backend/rust_codegen.py Outdated
…numbers, op precedence, negative range steps,list printing and minor type checking enhancements
@djmahe4
djmahe4 marked this pull request as ready for review April 12, 2026 05:08
@kilo-code-bot

kilo-code-bot Bot commented Apr 12, 2026 •

Copy link
Copy Markdown

Code Review Summary

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 0
SUGGESTION 1
Issue Details (click to expand)

SUGGESTION

File Line Issue
README.md 190 Duplicate ## Installation heading (line 188 already has this header). Remove duplicate to fix markdown structure.
Files Reviewed (3 files)
  • .github/workflows/ci.yml - Documentation fix
  • README.md - Duplicate heading issue
  • docs/user_guide.md - Documentation update

Reviewed by laguna-m.1-20260312:free · 600,295 tokens

@djmahe4

djmahe4 commented Apr 12, 2026

Copy link
Copy Markdown
Owner

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces py2rust, a subset compiler that translates statically typed Python into Rust. The implementation covers the full compilation pipeline, including an AST-based frontend, a middle-end for type checking and IR construction, and a backend for Rust code generation. While the architecture is solid, several issues were identified in the code generation logic: it fails to account for the scoping differences between Python and Rust, lacks support for mutable loop variables, and incorrectly handles string indexing and move semantics for list elements. Furthermore, the type checker needs to be extended to validate condition expressions in control flow statements, and the backend should provide clearer error markers for unknown types instead of defaulting to i32.

Comment thread py2rust/backend/rust_codegen.py Outdated
Comment thread py2rust/backend/rust_codegen.py Outdated
Comment thread py2rust/backend/rust_codegen.py Outdated
Comment thread py2rust/middleend/type_checker.py Outdated
Comment thread py2rust/backend/rust_codegen.py Outdated
… indexing and list move, contrrol flow condition validation
@djmahe4

djmahe4 commented Apr 12, 2026

Copy link
Copy Markdown
Owner

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces py2rust, a compiler that translates a statically typed subset of Python into Rust through a pipeline of parsing, type checking, and IR-based code generation. While the architecture is sound, several critical issues were identified in the backend. The variable pre-declaration logic is incomplete, missing variables from assignments and loop targets, which will lead to Rust compilation errors. Furthermore, there are semantic discrepancies in loop variable scoping, a lack of support for Python's negative indexing, and potential runtime panics related to usize casting and step_by operations.

Comment thread py2rust/backend/rust_codegen.py Outdated
Comment thread py2rust/middleend/ir_builder.py Outdated
Comment thread py2rust/backend/rust_codegen.py Outdated
Comment thread py2rust/backend/rust_codegen.py Outdated
Comment on lines +257 to +266
elif isinstance(expr, IRSubscript):
val = self._gen_expr(expr.value)
idx = self._gen_expr(expr.index)
if isinstance(expr.value_type, IRStrType):
return f"({val}.chars().nth(({idx}) as usize).unwrap().to_string())"

res = f"{val}[({idx}) as usize]"
if isinstance(expr.result_type, (IRStrType, IRListType)):
return f"({res}).clone()"
return res

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Python's negative indexing (e.g., s[-1]) is not supported by the current implementation. Casting a negative i32 to usize in Rust results in a large positive value due to wrap-around, which will lead to an out-of-bounds panic at runtime. To support idiomatic Python behavior, the generated code should check if the index is negative and adjust it relative to the collection's length.

Comment thread py2rust/backend/rust_codegen.py Outdated
… semantic validation and functional stability ensured
@djmahe4

djmahe4 commented Apr 12, 2026

Copy link
Copy Markdown
Owner

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces py2rust, a compiler that translates a statically typed subset of Python into Rust. The implementation includes a full pipeline consisting of a frontend parser, a middle-end for semantic analysis and IR building, and a backend for Rust code generation and formatting. The review feedback identifies several critical improvements: ensuring Python semantics for range() loops by evaluating bounds only once, generating more idiomatic Rust by selectively applying the mut keyword, expanding the parser to support general function calls as standalone statements, and maintaining consistent error handling by using internal exception types instead of raw Python errors.

Comment on lines +170 to +183
start = self._gen_expr(stmt.start)
stop = self._gen_expr(stmt.stop)
step = self._gen_expr(stmt.step) if stmt.step is not None else "1"

# Use while loop to emulate Python's loop variable scoping and persistence
self._emit(f"{stmt.target} = {start};")
# Step can be negative, so we need a robust condition
self._emit(f"while if ({step}) > 0 {{ {stmt.target} < ({stop}) }} else {{ {stmt.target} > ({stop}) }} {{")
self._indent += 1
for s in stmt.body:
self._gen_stmt(s)
self._emit(f"{stmt.target} += {step};")
self._indent -= 1
self._emit("}")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

In Python, the stop and step arguments of range() are evaluated exactly once when the loop starts. The current implementation evaluates these expressions on every iteration of the while loop. This can lead to incorrect behavior if the expressions have side effects or if the variables they depend on are modified within the loop body.

Consider evaluating these into temporary variables before the loop starts to ensure correct Python semantics.

Suggested change
start = self._gen_expr(stmt.start)
stop = self._gen_expr(stmt.stop)
step = self._gen_expr(stmt.step) if stmt.step is not None else "1"
# Use while loop to emulate Python's loop variable scoping and persistence
self._emit(f"{stmt.target} = {start};")
# Step can be negative, so we need a robust condition
self._emit(f"while if ({step}) > 0 {{ {stmt.target} < ({stop}) }} else {{ {stmt.target} > ({stop}) }} {{")
self._indent += 1
for s in stmt.body:
self._gen_stmt(s)
self._emit(f"{stmt.target} += {step};")
self._indent -= 1
self._emit("}")
elif isinstance(stmt, IRForRange):
start = self._gen_expr(stmt.start)
stop = self._gen_expr(stmt.stop)
step = self._gen_expr(stmt.step) if stmt.step is not None else "1"
# Evaluate bounds once to match Python semantics
self._emit(f"let __stop = {stop};")
self._emit(f"let __step = {step};")
self._emit(f"{stmt.target} = {start};")
self._emit(f"while if __step > 0 {{ {stmt.target} < __stop }} else {{ {stmt.target} > __stop }} {{")
self._indent += 1
for s in stmt.body:
self._gen_stmt(s)
self._emit(f"{stmt.target} += __step;")
self._indent -= 1
self._emit("}")

Comment thread py2rust/backend/rust_codegen.py Outdated
Comment thread py2rust/frontend/parser.py Outdated
Comment thread py2rust/middleend/ir_builder.py Outdated
…n func calls as statements in parser, use SemanticError class for reporting errors
@djmahe4

djmahe4 commented Apr 12, 2026

Copy link
Copy Markdown
Owner

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces py2rust, a compiler that translates a statically typed subset of Python into Rust. The project features a complete pipeline including a custom AST parser, a bidirectional type checker, an intermediate representation (IR) builder, and a Rust code generator. The review feedback highlights several logic issues in the backend, specifically regarding variable shadowing in nested loops, redundant expression evaluation in subscripts, and the need for explicit type casting in arithmetic operations. Additionally, an improvement was suggested for the type checker to prevent conflicting type definitions for loop targets.

Comment thread py2rust/backend/rust_codegen.py Outdated
Comment thread py2rust/backend/rust_codegen.py Outdated
Comment thread py2rust/backend/rust_codegen.py Outdated
Comment thread py2rust/middleend/type_checker.py Outdated
@djmahe4

djmahe4 commented Apr 12, 2026

Copy link
Copy Markdown
Owner

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces py2rust, a compiler that translates a statically typed subset of Python into Rust. The implementation follows a standard compiler architecture, including a frontend parser, a middle-end for type checking and IR construction, and a backend for Rust code generation. Feedback focuses on refining the Rust code generation to correctly handle the _ discard pattern and ensuring that unknown types trigger explicit errors rather than producing invalid code. Additionally, it was noted that print statements should be explicitly type-checked to ensure the semantic validity of the expressions being printed.

Comment thread py2rust/backend/rust_codegen.py Outdated
Comment thread py2rust/backend/rust_codegen.py Outdated
Comment thread py2rust/middleend/type_checker.py Outdated

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces significant updates to the py2rust compiler, including a new semantic validation and pattern learning system, improved support for multi-module repository compilation, and enhanced code generation for complex features like context managers and generators. The review identified critical issues in ir_builder.py regarding SubscriptAssign type inference and method fallibility, as well as an AttributeError in type_checker.py during circular dependency checks. I have kept these critical feedback comments and removed comments that were purely validation or non-actionable.

Comment on lines +1017 to +1031
if isinstance(target_type, ListType):
value_type = _to_ir_type(target_type.element_type)
target_type = self.inferencer.infer(stmt.target)
trait_info = None
if isinstance(target_type, DictType):
value_type = _to_ir_type(target_type.value_type)
elif isinstance(target_type, StrType):
value_type = IRStrType()
elif isinstance(target_type, ClassType):
# Check for __setitem__
if self.st.lookup_method(target_type.name, "__setitem__", 2):
trait_info = ("IndexMut", "index_mut")
value_type = IRIntType() # Default
else:
value_type = IRIntType()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The value_type for SubscriptAssign is incorrectly overwritten. If target_type is a ListType, the first if block sets value_type, but the subsequent else block (line 1031) always overwrites it with IRIntType() because a ListType is neither a DictType nor a ClassType. This will break assignments to lists of non-integer types.

Suggested change
if isinstance(target_type, ListType):
value_type = _to_ir_type(target_type.element_type)
target_type = self.inferencer.infer(stmt.target)
trait_info = None
if isinstance(target_type, DictType):
value_type = _to_ir_type(target_type.value_type)
elif isinstance(target_type, StrType):
value_type = IRStrType()
elif isinstance(target_type, ClassType):
# Check for __setitem__
if self.st.lookup_method(target_type.name, "__setitem__", 2):
trait_info = ("IndexMut", "index_mut")
value_type = IRIntType() # Default
else:
value_type = IRIntType()
trait_info = None
if isinstance(target_type, ListType):
value_type = _to_ir_type(target_type.element_type)
elif isinstance(target_type, DictType):
value_type = _to_ir_type(target_type.value_type)
elif isinstance(target_type, StrType):
value_type = IRStrType()
elif isinstance(target_type, ClassType):
# Check for __setitem__
if self.st.lookup_method(target_type.name, "__setitem__", 2):
trait_info = ("IndexMut", "index_mut")
value_type = IRIntType() # Default
else:
value_type = IRIntType()

Comment on lines +1583 to +1586
names.append(t.name)
elif isinstance(t, OptionalType):
names.extend(self._extract_class_names(t.element_type))
elif isinstance(t, UnionType):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Incorrect attribute access in _extract_class_names. OptionalType uses inner_type instead of element_type, and UnionType uses variants instead of types. This will cause a AttributeError during circular dependency checks for classes containing these types.

Suggested change
names.append(t.name)
elif isinstance(t, OptionalType):
names.extend(self._extract_class_names(t.element_type))
elif isinstance(t, UnionType):
elif isinstance(t, OptionalType):
names.extend(self._extract_class_names(t.inner_type))
elif isinstance(t, UnionType):
for et in t.variants:

Comment thread py2rust/middleend/ir_builder.py Outdated
@djmahe4

djmahe4 commented May 24, 2026

Copy link
Copy Markdown
Owner

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request significantly expands the py2rust compiler, transforming it into a repository-scale Python-to-Rust subset compiler with an advanced LLM-backed semantic validation and pattern learning system. Key additions include a multi-pass frontend/middle-end/backend pipeline, a comprehensive plugin system for standard libraries, and a robust project management layer for handling cross-module imports and circular dependencies. The feedback highlights several critical areas for improvement: a command injection vulnerability in the PowerShell context gathering logic, fragility in the Rust function extraction and LLM response parsing routines, and performance concerns regarding SQLite connection management. Additionally, the reviewer noted that the Ollama host should be configurable and that the recursive topological sort could lead to stack overflows in complex projects.

cmd = None
if sys.platform == "win32":
# Check Select-String via powershell
if shutil.which("powershell"):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-critical critical

Constructing a PowerShell command string using an f-string with symbol_name is vulnerable to command injection. If a symbol name contains single quotes or other shell metacharacters, arbitrary commands could be executed. It is safer to use shlex.quote for Unix-like systems or ensure proper escaping for Windows/PowerShell environments.

Comment thread py2rust/main.py
Comment on lines +17 to +43
def extract_rust_fn(rust_code: str, func_name: str) -> str:
# Find start of function definition in rust code
pattern = re.compile(rf"\bfn\s+{func_name}\b")
match = pattern.search(rust_code)
if not match:
return None
start_idx = match.start()

# Simple brace matching from start_idx
brace_count = 0
started = False
end_idx = start_idx
for idx in range(start_idx, len(rust_code)):
char = rust_code[idx]
if char == '{':
brace_count += 1
started = True
elif char == '}':
brace_count -= 1

if started and brace_count == 0:
end_idx = idx + 1
break
else:
end_idx = len(rust_code)

return rust_code[start_idx:end_idx]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The extract_rust_fn function is fragile as it relies on regular expressions and manual brace counting to extract Rust function bodies. This approach will fail if braces appear within comments or string literals, or if the code contains nested structures like closures. Consider using a more robust state-tracking scanner or a proper Rust lexer to identify function boundaries.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this fixed? @gemini-code-assist

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The user is asking if the extract_rust_fn function in py2rust/main.py has been fixed. Based on the current code provided in the patch, the function still uses the same regex and brace-counting logic that was previously identified as fragile. No changes were made to this function in the provided diffs. I recommend replacing this approach with a more robust parser or a dedicated Rust lexer/parser library to correctly handle nested structures, comments, and string literals.


class OllamaClient:
def __init__(self, model: str = "deepseek-coder", host: str = "http://localhost:11434"):
self.model = model

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The Ollama host is hardcoded to localhost. This should be made configurable via the CompilerConfig to support environments where the LLM service is running on a remote host or a different port.

Comment thread py2rust/learning_system/validation/validation_store.py Outdated
Comment thread py2rust/learning_system/learning/pattern_extractor.py Outdated
Comment thread py2rust/project/module_graph.py Outdated
" Break,",
" Continue,",
"}",
""

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Suppressing all warnings (#![allow(warnings)] #![allow(clippy::all)]) may hide genuine issues in the generated code. Consider fixing the root cause instead of suppressing warnings.

Same pattern appears on lines 157, 166, 182, and 201 in this file.

@djmahe4

djmahe4 commented May 28, 2026

Copy link
Copy Markdown
Owner

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the core implementation of the py2rust compiler, a Python-to-Rust subset compiler featuring a recursive descent parser, type checker, IR builder, and Rust code generator, alongside extensive documentation and examples. The review feedback identifies several critical bugs in the code generation backend that must be addressed: an AttributeError when processing IRIf statements in generators, a silent no-op mutation bug during struct field assignments due to unnecessary cloning, a type-tracking failure in tuple unpacking, a precedence bug in floor division type casting, and a runtime panic risk in dictionary subscripting where a catchable KeyError should be propagated instead of using .unwrap().

Comment on lines +153 to +157
elif isinstance(stmt, IRIf):
branch_states = []
for _ in stmt.branches:
branch_states.append(next_free_state)
next_free_state += 1

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The IRIf node does not have a branches attribute (it has condition, then_body, elif_clauses, and else_body). Attempting to access stmt.branches here will cause a compile-time AttributeError crash whenever a generator contains an if statement. We should reconstruct the list of branches dynamically.

Suggested change
elif isinstance(stmt, IRIf):
branch_states = []
for _ in stmt.branches:
branch_states.append(next_free_state)
next_free_state += 1
elif isinstance(stmt, IRIf):
branches = [(stmt.condition, stmt.then_body)] + list(stmt.elif_clauses)
if stmt.else_body is not None:
branches.append((None, stmt.else_body))
branch_states = []
for _ in branches:
branch_states.append(next_free_state)
next_free_state += 1

Comment thread py2rust/backend/rust_codegen.py Outdated
Comment thread py2rust/backend/codegen_helpers.py Outdated
Comment thread py2rust/backend/expr_codegen.py Outdated
Comment on lines +189 to +192
val_t = self._get_rust_type(expr.value_type.value_type)
return f"{val}.get(&{idx}).unwrap().clone()"

# Handle ExternalObject indexing (e.g., json data)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Using .unwrap() on dictionary lookups will cause an unrecoverable runtime panic if the key is missing. To preserve Python's exception handling model (where a missing key raises a catchable KeyError), we should return a fallible Result using ok_or_else and propagate it with ?.

Suggested change
val_t = self._get_rust_type(expr.value_type.value_type)
return f"{val}.get(&{idx}).unwrap().clone()"
# Handle ExternalObject indexing (e.g., json data)
# Handle dict subscript: d[key] -> __d.get(&key).ok_or_else(...)?
if isinstance(expr.value_type, IRDictType):
val_t = self._get_rust_type(expr.value_type.value_type)
return f"{val}.get(&{idx}).ok_or_else(|| PyError::KeyError(format!(\"{{:?}}\", {idx})))?.clone()"

… IRTupleUnpack names, floor-div precedence, dict KeyError propagation)

- generator_codegen.py: fix AttributeError on IRIf.branches
- rust_codegen.py: add IRStructAccess in get_mut_target (prevents silent clone no-ops)
- rust_codegen.py: replace get_mut(...).unwrap() with ok_or_else on mutable dict subscript
- rust_codegen.py: remove dead target_is_dict variable and stale design comments
- codegen_helpers.py: extract .name string from IRTupleUnpack targets
- expr_codegen.py: use _gen_expr_as_float for floor-div operands (fixes precedence)
- expr_codegen.py: replace dict subscript unwrap() with ok_or_else on read path
- tests: update assertions; add regression tests for floor-div and dict nested write
@djmahe4
djmahe4 force-pushed the copilot/create-python-to-rust-compiler branch from 406883d to ac77808 Compare May 28, 2026 07:36
djmahe4 added 2 commits May 28, 2026 03:42
…32 on tmpdir cleanup

PatternStore used  which only manages
transactions, not connection lifetime. On Windows, SQLite holds an exclusive
OS-level file lock until the connection object is GC'd -- which may not happen
before TemporaryDirectory.__exit__ tries to delete patterns.db.

Changes:
- pattern_store.py: replace _connect() +  with _use_conn()
  contextmanager that always calls conn.close() in finally block.
- Add __enter__/__exit__/close() to PatternStore so callers can use
   to guarantee cleanup ordering.
- test_wave33.py: wrap store in  in test_pattern_store_persistence
  and test_pattern_extractor.
- test_hardening.py: wrap store in  in test_pattern_store_sqlite_migration
  and test_pattern_store_concurrent_writes.
@djmahe4
djmahe4 merged commit 4df72fb into main May 28, 2026
8 checks passed
Comment thread README.md

## Installation

## Installation

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SUGGESTION: Duplicate heading on line 190 - the ## Installation header already exists on line 188. Remove the duplicate to fix markdown structure.

Suggested change
## Installation
You can install py2rust directly from PyPI:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants