Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions detailed_transpilation_report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Отчет о трансляции (py2v_transpiler)

В данном отчете проанализированы результаты трансляции пяти файлов из директории `pythontovlang/py2v_transpiler/tests/input/transpile`.

## 1. test_bitwise_ops.py

### Ошибки и проблемы:
- **Отсутствие поддержки операторов комбинированного присваивания (AugAssign)**:
Для битовых операций (`|=`, `&=`, `^=`, `<<=`, `>>=`) транслятор выдает комментарий `// Unsupported AugAssign operator`, оставляя переменную без изменений.
*Пример:*
```v
// Unsupported AugAssign operator: <class 'ast.BitOr'>
println('New permissions: ${permissions}')
```
- **Типизация math.powi**: Используется `math.powi(base, exp)` для целых чисел, что корректно для V, но требует уверенности, что `base` и `exp` всегда `int`.

---

## 2. test_boolean_ops.py

### Ошибки и проблемы:
- **Несоответствие типов в анонимных функциях**:
В тесте `test_boolean_short_circuit_and` генерируется функция, которая должна возвращать `int` (так как в Python `True` это 1), но тело функции возвращает `true` (bool).
*Ошибка в V:*
```v
mut should_not_run := fn () int {
println('This should not print')
return true // Ошибка: возвращает bool вместо int
}
```
- **Подмена идентичности (`is`) на равенство (`==`)**:
В V `a == b` для массивов проверяет равенство значений. В Python `is` проверяет идентичность объектов. Транслятор заменяет `is` на `==`, что меняет семантику теста.
- **Сложные логические выражения (Short-circuiting)**:
Для выражений `a and b`, где `a` или `b` не являются строго `bool`, генерируются `if`-выражения с приведением к `Any`. Это усложняет код, хотя и сохраняет логику Python.

---

## 3. test_builtin_modules.py

### Ошибки и проблемы:
- **Некорректный маппинг имен в модуле `rand`**:
Python модуль `random` транслируется в V модуль `rand`, но вызовы методов часто сохраняют префикс `random`, который не импортирован.
*Ошибка в V:*
```v
import rand
// ...
println('Sample: ${random.sample(choices, 2)}') // Ошибка: random не определен
```
- **Проблемы с `os.path`**:
Вызовы `os.path.split` и `os.path.splitext` транслируются как есть, но в стандартной библиотеке V `os` обычно нет подмодуля `path` с такими методами (в V это `os.split_path` и т.д.).
- **Отсутствующие хелперы для встроенных функций**:
Для функций `range`, `sum`, `min`, `max`, `zip`, `enumerate` вызовы генерируются, но соответствующие определения отсутствуют в `helpers.v` для этого модуля.
- **Использование `.all(it)` и `.any(it)`**:
Для массивов вызываются методы `.all` и `.any`, которые не являются встроенными в V для обычных массивов и требуют дополнительных generic-расширений.

---

## 4. test_while_loop.py

### Ошибки и проблемы:
- **Логика `while-else`**:
Транспилятор использует флаг `py_loop_completed_N`. Однако в тестах без `break` этот флаг инициализируется `true` и никогда не меняется, что формально верно, но избыточно.
- **Аргумент `end` в `print`**:
Python `print(..., end=" ")` транслируется в `print('... ')`, что добавляет пробел в конец строки, но не учитывает, что последующие вызовы `print` в V также могут добавлять переводы строк, если не используются осторожно.

---

## 5. test_set_operations.py

### Ошибки и проблемы:
- **Некорректная инициализация множеств (Set)**:
Множества транслируются как `map[K]bool`.
*Ошибка в V:*
```v
s3 := map[string]bool([1, 2, 2, 3, 3, 3]) // V не поддерживает инициализацию карты из массива таким образом
```
- **Отсутствие методов `.add()`, `.remove()`, `.discard()`, `.pop()` для карт**:
В V для `map` используются другие синтаксические конструкции. Транслятор генерирует вызовы методов, которых нет у встроенного типа `map`.
- **Операторы сравнения множеств**:
Выражения `b <= a` и `a >= b` (проверка подмножества) не поддерживаются для `map` в V.
- **Методы `.union()`, `.intersection()` и др.**:
Транслятор пытается вызывать их на объекте карты (`a.py_union(b)`), но они должны быть либо хелперами, либо расширениями, которых нет.

## Общие выводы

1. **AugAssign**: Серьезная недоработка в поддержке битовых операций.
2. **Standard Library Mapping**: Несоответствия между Python `random`/`os` и V `rand`/`os`.
3. **Set Support**: Реализация множеств через `map[K]bool` требует значительно большего количества хелперов или методов-расширений для корректной работы (add, remove, pop, subset и т.д.).
4. **Type Consistency**: Возникают ошибки в генерируемом V-коде из-за несоответствия типов (bool vs int в возвращаемых значениях).
146 changes: 146 additions & 0 deletions py2v_transpiler/tests/input/transpile/test_bitwise_ops.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
module main

import math

// @line: test_bitwise_ops.py:1:0
pub fn test_bitwise_and() {
mut a := 12
mut b := 10
mut result := a & b
println('${a} & ${b} = ${result}')
}
// @line: test_bitwise_ops.py:7:0
pub fn test_bitwise_or() {
mut a := 12
mut b := 10
mut result := a | b
println('${a} | ${b} = ${result}')
}
// @line: test_bitwise_ops.py:13:0
pub fn test_bitwise_xor() {
mut a := 12
mut b := 10
mut result := a ^ b
println('${a} ^ ${b} = ${result}')
}
// @line: test_bitwise_ops.py:19:0
pub fn test_bitwise_not() {
mut a := 5
mut result := ~a
println('~${a} = ${result}')
}
// @line: test_bitwise_ops.py:24:0
pub fn test_bitwise_shift_left() {
mut a := 4
mut result := a << 2
println('${a} << 2 = ${result}')
}
// @line: test_bitwise_ops.py:29:0
pub fn test_bitwise_shift_right() {
mut a := 16
mut result := a >> 2
println('${a} >> 2 = ${result}')
}
// @line: test_bitwise_ops.py:34:0
pub fn test_bitwise_operations() {
mut num := 13
bit_mask := 4
is_set := num & bit_mask != 0
println('Bit 2 is set in ${num}: ${is_set}')
mut result := num | 2
println('Set bit 1 in ${num}: ${result}')
result = num & ~4
println('Clear bit 2 in ${num}: ${result}')
result = num ^ 1
println('Toggle bit 0 in ${num}: ${result}')
}
// @line: test_bitwise_ops.py:53:0
pub fn test_bitwise_flags() {
read := 1
write := 2
execute := 4
mut permissions := read | write
println('Permissions: ${permissions}')
has_read := permissions & read != 0
has_execute := permissions & execute != 0
println('Has read: ${has_read}, Has execute: ${has_execute}')
// Unsupported AugAssign operator: <class 'ast.BitOr'>
println('New permissions: ${permissions}')
// Unsupported AugAssign operator: <class 'ast.BitAnd'>
println('Final permissions: ${permissions}')
}
// @line: test_bitwise_ops.py:74:0
pub fn test_floor_division() {
mut a := 17
mut b := 5
mut result := int(math.floor(f64(a) / f64(b)))
println('${a} // ${b} = ${result}')
result_neg := int(math.floor(f64(-17) / f64(5)))
println('-17 // 5 = ${result_neg}')
}
// @line: test_bitwise_ops.py:84:0
pub fn test_modulo() {
mut a := 17
mut b := 5
mut result := a % b
println('${a} % ${b} = ${result}')
mut num := 10
is_even := num % 2 == 0
println('${num} is even: ${is_even}')
}
// @line: test_bitwise_ops.py:95:0
pub fn test_power() {
base := 2
exp := 10
mut result := math.powi(base, exp)
println('${base} ** ${exp} = ${result}')
result_sqrt := math.pow(f64(16), 0.5)
println('16 ** 0.5 = ${result_sqrt}')
}
// @line: test_bitwise_ops.py:105:0
pub fn test_augmented_assignment() {
mut x := 10
x += 5
println('x += 5: ${x}')
x -= 3
println('x -= 3: ${x}')
x *= 2
println('x *= 2: ${x}')
x = int(math.floor(f64(x) / f64(3)))
println('x //= 3: ${x}')
x = int(math.pow(x, 2))
println('x **= 2: ${x}')
x %= 7
println('x %= 7: ${x}')
// Unsupported AugAssign operator: <class 'ast.BitAnd'>
println('x &= 3: ${x}')
// Unsupported AugAssign operator: <class 'ast.BitOr'>
println('x |= 5: ${x}')
// Unsupported AugAssign operator: <class 'ast.BitXor'>
println('x ^= 2: ${x}')
// Unsupported AugAssign operator: <class 'ast.RShift'>
println('x >>= 1: ${x}')
// Unsupported AugAssign operator: <class 'ast.LShift'>
println('x <<= 2: ${x}')
}
// @line: test_bitwise_ops.py:140:0
pub fn test() {
test_bitwise_and()
test_bitwise_or()
test_bitwise_xor()
test_bitwise_not()
test_bitwise_shift_left()
test_bitwise_shift_right()
test_bitwise_operations()
test_bitwise_flags()
test_floor_division()
test_modulo()
test_power()
test_augmented_assignment()
}

fn main() {
// @line: test_bitwise_ops.py:154:0
// if __name__ == '__main__':
test()
}
124 changes: 124 additions & 0 deletions py2v_transpiler/tests/input/transpile/test_bitwise_ops_helpers.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
module main

pub struct NoneType {}

pub fn (n NoneType) str() string {
return 'None'
}

pub struct Interpolation {
pub:
value Any
expression string
conversion string
format_spec string
}

pub struct Template {
pub:
strings []string
interpolations []Interpolation
}

pub fn (t Template) values() []Any {
mut res := []Any{cap: t.interpolations.len}
for i in t.interpolations {
res << i.value
}
return res
}

pub fn (t1 Template) + (t2 Template) Template {
if t1.strings.len == 0 { return t2 }
if t2.strings.len == 0 { return t1 }
mut new_strings := t1.strings[..t1.strings.len - 1].clone()
new_strings << t1.strings.last() + t2.strings[0]
if t2.strings.len > 1 {
new_strings << t2.strings[1..]
}
mut new_interpolations := t1.interpolations.clone()
new_interpolations << t2.interpolations
return Template{
strings: new_strings
interpolations: new_interpolations
}
}

pub type Any = Interpolation | NoneType | Template | []Any | []u8 | bool | f64 | i64 | int | map[string]Any | string

pub enum PyAnnotationFormat { value forwardref string }

pub fn py_get_type_hints[T]() map[string]string {
mut hints := map[string]string{}
$for field in T.fields {
hints[field.name] = field.typ
}
return hints
}

pub fn py_get_type_hints_generic(obj Any) map[string]string {
return map[string]string{}
}

struct PyGeneratorInput {
val Any
is_exc bool
exc_msg string
}
struct PyGenerator[T] {
mut:
out chan T
in_ chan PyGeneratorInput
open bool = true
}

fn (mut g PyGenerator[T]) next() ?T {
if !g.open { return none }
g.in_ <- PyGeneratorInput{val: 0} // Send dummy value
res := <-g.out
if res == none { g.open = false }
return res
}
fn (mut g PyGenerator[T]) send(val Any) ?T {
if !g.open { panic('StopIteration') }
g.in_ <- PyGeneratorInput{val: val}
res := <-g.out
if res == none { g.open = false }
return res
}
fn (mut g PyGenerator[T]) throw(msg string) ?T {
if !g.open { panic('StopIteration') }
g.in_ <- PyGeneratorInput{is_exc: true, exc_msg: msg}
res := <-g.out
if res == none { g.open = false }
return res
}
fn (mut g PyGenerator[T]) close() {
g.open = false
g.in_.close()
// g.out will be closed by the generator function loop when it detects in_ closed or panic
}
fn py_yield[T](ch_out chan T, ch_in chan PyGeneratorInput, val T) Any {
ch_out <- val
inp := <-ch_in
if inp.is_exc {
panic(inp.exc_msg)
}
return inp.val
}
//##LLM@@ String formatting for bytes is stubbed and might be incorrect. Please implement proper bytes formatting or use V string interpolation.
fn py_bytes_format(fmt []u8, args Any) []u8 {
// Simplistic implementation for b'%s' % b'val'
// Converts bytes to string, formats, and converts back.
// This is not efficient or correct for non-ASCII bytes but works for simple cases.
fmt_str := fmt.bytestr()
// TODO: handle args properly. V's string interpolation/formatting expects distinct args.
// If args is []u8, treat as string.
arg_str := if args is []u8 { args.bytestr() } else { '${args}' }

// Manual substitution of %s
// V does not have sprintf for runtime strings easily available in core without C interop.
// Simple replace for %s
res := fmt_str.replace('%s', arg_str)
return res.bytes()
}
Loading
Loading