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
179 changes: 179 additions & 0 deletions py2v_transpiler/tests/input/transpile/test_global_nonlocal.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
module main

// @line: test_global_nonlocal.py:1:0
pub fn test_global_variable() {
mut counter := 0
// @line: test_global_nonlocal.py:4:4
mut increment := fn () int {
//##LLM@@ Python 'global' or 'nonlocal' scope modification detected. V heavily discourages global state and has strict mutability rules for closures. Please refactor state management, possibly by passing mutable parameters (mut) explicitly.
// nonlocal counter
counter += 1
return counter
}
println('${increment()}')
println('${increment()}')
println('${increment()}')
}
// @line: test_global_nonlocal.py:13:0
pub fn test_global_in_multiple_functions() {
mut total := 100
// @line: test_global_nonlocal.py:16:4
mut add := fn (x int) []Any {
//##LLM@@ Python 'global' or 'nonlocal' scope modification detected. V heavily discourages global state and has strict mutability rules for closures. Please refactor state management, possibly by passing mutable parameters (mut) explicitly.
// nonlocal total
total += x
}
// @line: test_global_nonlocal.py:20:4
mut subtract := fn (x int) {
//##LLM@@ Python 'global' or 'nonlocal' scope modification detected. V heavily discourages global state and has strict mutability rules for closures. Please refactor state management, possibly by passing mutable parameters (mut) explicitly.
// nonlocal total
total -= x
}
// @line: test_global_nonlocal.py:24:4
mut get_total := fn [total] () int {
return total
}
add(50)
println('${get_total()}')
subtract(30)
println('${get_total()}')
}
// @line: test_global_nonlocal.py:32:0
pub fn test_nested_function() {
// @line: test_global_nonlocal.py:33:4
mut outer := fn (x int) Any {
// @line: test_global_nonlocal.py:34:8
mut inner := fn [x] (y int) int {
return x + y
}
return inner
}
add_5 := outer(5)
println('${add_5(10)}')
add_10 := outer(10)
println('${add_10(20)}')
}
// @line: test_global_nonlocal.py:44:0
pub fn test_closure_with_state() {
// @line: test_global_nonlocal.py:45:4
mut make_accumulator := fn () Any {
mut total := 0
// @line: test_global_nonlocal.py:48:8
mut accumulate := fn (value int) int {
//##LLM@@ Python 'global' or 'nonlocal' scope modification detected. V heavily discourages global state and has strict mutability rules for closures. Please refactor state management, possibly by passing mutable parameters (mut) explicitly.
// nonlocal total
total += value
return total
}
return accumulate
}
acc := make_accumulator()
println('${acc(5)}')
println('${acc(10)}')
println('${acc(15)}')
}
// @line: test_global_nonlocal.py:60:0
pub fn test_closure_in_loop() {
mut funcs := []Any{}
for i in 0..5 {
// @line: test_global_nonlocal.py:63:8
mut func := fn [i] (x Any) Any {
return x
}
(funcs as string).append(func)
}
for f in funcs {
println('${f()}')
}
}
// @line: test_global_nonlocal.py:70:0
pub fn test_closure_proper_capture() {
mut funcs := []fn (...Any) Any{}
for i in 0..5 {
// @line: test_global_nonlocal.py:73:8
mut func := fn [i] () Any {
nonlocal_i := i
return nonlocal_i
}
funcs << func
}
println('Closure in loop (all return last value):')
}
// @line: test_global_nonlocal.py:84:0
pub fn test_multiple_closures() {
// @line: test_global_nonlocal.py:85:4
mut make_counters := fn () Any {
mut count_a := 0
mut count_b := 0
// @line: test_global_nonlocal.py:89:8
mut increment_a := fn () int {
//##LLM@@ Python 'global' or 'nonlocal' scope modification detected. V heavily discourages global state and has strict mutability rules for closures. Please refactor state management, possibly by passing mutable parameters (mut) explicitly.
// nonlocal count_a
count_a += 1
return count_a
}
// @line: test_global_nonlocal.py:94:8
mut increment_b := fn () int {
//##LLM@@ Python 'global' or 'nonlocal' scope modification detected. V heavily discourages global state and has strict mutability rules for closures. Please refactor state management, possibly by passing mutable parameters (mut) explicitly.
// nonlocal count_b
count_b += 1
return count_b
}
// @line: test_global_nonlocal.py:99:8
mut get_counts := fn [count_a, count_b] () Any {
return [count_a, count_b]
}
return [increment_a, increment_b, get_counts]
}
py_destruct_0 := make_counters()
inc_a := py_destruct_0[0]
inc_b := py_destruct_0[1]
get := py_destruct_0[2]
println('${inc_a()}')
println('${inc_a()}')
println('${inc_b()}')
println('${inc_a()}')
println('${get()}')
}
// @line: test_global_nonlocal.py:111:0
pub fn test_closure_with_list() {
// @line: test_global_nonlocal.py:112:4
mut make_history := fn () Any {
mut history := []Any{}
// @line: test_global_nonlocal.py:115:8
mut add := fn [history] (item Any) []Any {
//##LLM@@ Python 'global' or 'nonlocal' scope modification detected. V heavily discourages global state and has strict mutability rules for closures. Please refactor state management, possibly by passing mutable parameters (mut) explicitly.
// nonlocal history
history << item
return history
}
// @line: test_global_nonlocal.py:120:8
mut get_history := fn [history] () Any {
return history.copy()
}
return [add, get_history]
}
py_destruct_1 := make_history()
add := py_destruct_1[0]
get := py_destruct_1[1]
add(1)
add(2)
add(3)
println('${get()}')
}
// @line: test_global_nonlocal.py:131:0
pub fn test() {
test_global_variable()
test_global_in_multiple_functions()
test_nested_function()
test_closure_with_state()
test_closure_in_loop()
test_multiple_closures()
test_closure_with_list()
}

fn main() {
// @line: test_global_nonlocal.py:140:0
// if __name__ == '__main__':
test()
}
125 changes: 125 additions & 0 deletions py2v_transpiler/tests/input/transpile/test_global_nonlocal_helpers.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
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()
}
fn py_range(args ...int) []int { mut res := []int{}; if args.len == 1 { for i in 0..args[0] { res << i } } else if args.len == 2 { for i in args[0]..args[1] { res << i } } else if args.len == 3 { start := args[0]; stop := args[1]; step := args[2]; if step > 0 { for i := start; i < stop; i += step { res << i } } else if step < 0 { for i := start; i > stop; i += step { res << i } } }; return res }
Loading
Loading