/// Enhanced random program generator - based on csmith approach, focused on generating complex type-safe MiniMoonbit programs
/// Environment management - used to track variable and type bindings
struct Env[K, V] {
map : Map[K, V]
parent : Env[K, V]?
}
/// Create a new environment
fn[K, V] Env::new() -> Env[K, V] {
{ map: Map::new(), parent: None }
}
/// Create a sub-environment
fn[K, V] Env::sub_env(self : Self[K, V]) -> Env[K, V] {
{ map: Map::new(), parent: Some(self) }
}
/// Get value from environment (searches parent environments if needed)
fn[K : Eq + Hash, V] Env::get(self : Self[K, V], key : K) -> V? {
match self.map.get(key) {
Some(value) => Some(value)
None =>
match self.parent {
Some(parent) => parent.get(key)
None => None
}
}
}
/// Set value in current environment
fn[K : Eq + Hash, V] Env::set(self : Self[K, V], key : K, value : V) -> Unit {
self.map.set(key, value)
}
/// Collect all variables of a specific type from environment
fn[K, V : Eq] Env::collect_vars_of_type(
self : Self[K, V],
target_type : V,
) -> Array[K] {
let result = Array::new()
self.map.each(fn(key, value) { if value == target_type { result.push(key) } })
if self.parent is Some(parent) {
result.append(parent.collect_vars_of_type(target_type))
}
result
}
/// Generator state and configuration
pub struct RandProgGenerator {
rand : @random.Rand
// Enhanced configuration parameters for generating complex programs
max_depth : Int
max_stmt_count : Int
max_array_size : Int
max_tuple_size : Int
max_func_params : Int
max_nested_level : Int
total_lines_target : Int
// Environment tracking
mut var_env : Env[Ident, Type] // Variable type environment
mut mutable_vars : Env[Ident, Type] // Mutable variable environment
type_env : Env[Upper, Type] // Custom type environment
// Track all defined variables and their usage
mut all_defined_vars : Map[Ident, Type] // All defined variables
mut used_vars : Map[Ident, Bool] // Used variables
// Defined types and functions
struct_defs : Map[Upper, StructDef]
enum_defs : Map[Upper, EnumDef]
func_defs : Map[Ident, TopFuncDef]
// Name counter for uniqueness
mut name_counter : Int
// Current context
mut current_return_type : Type
mut current_depth : Int
mut current_nested_level : Int
// Line count tracking
mut current_lines : Int
}
/// Create new random program generator
pub fn RandProgGenerator::new(seed~ : Int? = None) -> RandProgGenerator {
let g = RandProgGenerator::{
rand: @random.Rand::new(),
max_depth: 4, // Reduce max depth to avoid stack overflow
max_stmt_count: 15, // Moderate statement count
max_array_size: 5, // Moderate array size
max_tuple_size: 4, // Moderate tuple size
max_func_params: 4, // Moderate function parameter count
max_nested_level: 3, // Reduce nesting level limit
total_lines_target: 2000, // Target line count
var_env: Env::new(),
mutable_vars: Env::new(),
type_env: Env::new(),
all_defined_vars: Map::new(),
used_vars: Map::new(),
struct_defs: Map::new(),
enum_defs: Map::new(),
func_defs: Map::new(),
name_counter: 0,
current_return_type: Unit,
current_depth: 0,
current_nested_level: 0,
current_lines: 0,
}
let seed = if seed is Some(s) {
s
} else {
(@env.now() % 100).to_int()
}
for i in 0.. Int {
if max <= 0 {
return 0
}
self.rand.int(limit=max)
}
/// Generate random boolean
fn RandProgGenerator::rand_bool(self : Self) -> Bool {
self.rand_int(2) == 0
}
/// Generate random double
fn RandProgGenerator::rand_double(self : Self) -> Double {
self.rand.double() * 1000.0 // Expand range to generate more diverse floating point numbers
}
/// Choose random element from array
fn[T] RandProgGenerator::choice(self : Self, choices : Array[T]) -> T? {
if choices.is_empty() {
None
} else {
Some(choices[self.rand_int(choices.length())])
}
}
/// Weighted random choice
fn[T] RandProgGenerator::weighted_choice(
self : Self,
choices : Array[(T, Int)],
) -> T? {
if choices.is_empty() {
return None
}
let total_weight = choices.fold(init=0, fn(acc, choice) { acc + choice.1 })
if total_weight <= 0 {
return self.choice(choices.map(fn(choice) { choice.0 }))
}
let mut current_weight = 0
let target_weight = self.rand_int(total_weight)
for choice in choices {
current_weight = current_weight + choice.1
if current_weight > target_weight {
return Some(choice.0)
}
}
// Fallback choice
self.choice(choices.map(fn(choice) { choice.0 }))
}
/// Generate identifier
fn RandProgGenerator::gen_ident(self : Self) -> Ident {
let names = [
"x", "y", "z", "a", "b", "c", "value", "temp", "result", "data", "item", "elem",
"i", "j", "k", "count", "sum", "index", "flag", "status", "info", "node", "next",
"prev", "head", "tail", "left", "right", "top", "bottom", "min", "max", "first",
"last", "current", "target",
]
let base_name = self.choice(names).unwrap()
self.name_counter = self.name_counter + 1
Ident(base_name + self.name_counter.to_string())
}
/// Generate uppercase identifier
fn RandProgGenerator::gen_upper(self : Self) -> Upper {
let names = [
"Point", "Node", "Item", "Data", "Result", "Option", "List", "Tree", "Value",
"Container", "Record", "Entry", "Element", "Structure", "Entity", "Object", "Instance",
"State", "Config", "Context", "Buffer", "Cache", "Queue", "Stack", "Matrix",
"Vector", "Complex", "Wrapper",
]
let base_name = self.choice(names).unwrap()
self.name_counter = self.name_counter + 1
Upper(base_name + self.name_counter.to_string())
}
/// Generate basic types
fn RandProgGenerator::gen_basic_type(self : Self) -> Type {
match self.rand_int(4) {
0 => Unit
1 => Bool
2 => Int
_ => Double
}
}
/// Enhanced type generator supporting more complex nested types
fn RandProgGenerator::gen_type(self : Self, allow_complex : Bool) -> Type {
if self.current_nested_level >= self.max_nested_level ||
!allow_complex ||
self.current_depth >= self.max_depth - 1 {
return self.gen_basic_type()
}
// Use weighted selection, basic types have higher weight to ensure compilable programs
let choices = [
(0, 80), // Basic types - significantly increased weight
(1, 10), // Array types - reduced weight
(2, 8), // Tuple types - reduced weight
(3, 1), // Custom struct types - greatly reduced weight
(4, 1),
] // Custom enum types - greatly reduced weight
match self.weighted_choice(choices) {
Some(0) => self.gen_basic_type()
Some(1) => self.gen_array_type()
Some(2) => self.gen_tuple_type()
Some(3) => self.gen_custom_struct_type()
Some(4) => self.gen_custom_enum_type()
_ => self.gen_basic_type()
}
}
/// Generate array type
fn RandProgGenerator::gen_array_type(self : Self) -> Type {
self.current_nested_level = self.current_nested_level + 1
let element_type = self.gen_type(true)
self.current_nested_level = self.current_nested_level - 1
Array(element_type)
}
/// Generate tuple type
fn RandProgGenerator::gen_tuple_type(self : Self) -> Type {
let size = self.rand_int(self.max_tuple_size - 1) + 2 // At least 2 elements
let types = Array::new()
self.current_nested_level = self.current_nested_level + 1
for i = 0; i < size; i = i + 1 {
types.push(
self.gen_type(self.current_nested_level < self.max_nested_level - 1),
)
}
self.current_nested_level = self.current_nested_level - 1
Tuple(types)
}
/// Generate custom struct type
fn RandProgGenerator::gen_custom_struct_type(self : Self) -> Type {
// Randomly select from defined structs
let available_structs = Array::new()
self.struct_defs.each(fn(name, _) { available_structs.push(name) })
match self.choice(available_structs) {
Some(struct_name) =>
match self.struct_defs.get(struct_name) {
Some(struct_def) => struct_def.type_of()
None => self.gen_basic_type() // Fallback
}
None => self.gen_basic_type() // If no structs available, return basic type
}
}
/// Generate custom enum type
fn RandProgGenerator::gen_custom_enum_type(self : Self) -> Type {
// Randomly select from defined enums
let available_enums = Array::new()
self.enum_defs.each(fn(name, _) { available_enums.push(name) })
match self.choice(available_enums) {
Some(enum_name) =>
match self.enum_defs.get(enum_name) {
Some(enum_def) => enum_def.type_of()
None => self.gen_basic_type() // Fallback
}
None => self.gen_basic_type() // If no enums available, return basic type
}
}
/// Find all variables of specified type
fn RandProgGenerator::find_all_vars_of_type(
self : Self,
target_type : Type,
) -> Array[Ident] {
self.var_env.collect_vars_of_type(target_type)
}
// Removed: mark_mutable_var_used - no longer needed with immediate assignment approach
/// Record variable definition
fn RandProgGenerator::record_var_definition(
self : Self,
var_name : Ident,
var_type : Type,
) -> Unit {
self.all_defined_vars = {
let new_map = Map::new()
self.all_defined_vars.each(fn(k, v) { new_map.set(k, v) })
new_map.set(var_name, var_type)
new_map
}
self.used_vars = {
let new_map = Map::new()
self.used_vars.each(fn(k, v) { new_map.set(k, v) })
new_map.set(var_name, false) // Initially mark as unused
new_map
}
}
/// Mark variable as used
fn RandProgGenerator::mark_var_used(self : Self, var_name : Ident) -> Unit {
self.used_vars = {
let new_map = Map::new()
self.used_vars.each(fn(k, v) { new_map.set(k, v) })
new_map.set(var_name, true)
new_map
}
}
// This function has been moved into gen_block_expr_with_usage_tracking
/// Generate complex literal expressions
fn RandProgGenerator::gen_literal_expr(self : Self, ty : Type) -> Expr {
match ty {
Unit => IfLevelExpr(ApplyExpr(ValueExpr(UnitExpr)))
Bool => IfLevelExpr(ApplyExpr(ValueExpr(BoolExpr(self.rand_bool()))))
Int => {
// Generate more diverse integers
let value = match self.rand_int(4) {
0 => self.rand_int(10) // Small integers 0-9
1 => self.rand_int(1000) // Medium integers 0-999
2 => self.rand_int(100000) // Large integers 0-99999
_ => self.rand_int(2) * 2 - 1 // -1 or 1
}
IfLevelExpr(ApplyExpr(ValueExpr(IntExpr(value))))
}
Double => {
let value = self.rand_double()
IfLevelExpr(ApplyExpr(ValueExpr(FloatExpr(value))))
}
Array(elem_type) => self.gen_array_expr(elem_type)
Tuple(elem_types) => self.gen_tuple_expr(elem_types)
Struct(name, fields) => self.gen_struct_construct_expr(name, fields)
Enum(name, variants) => self.gen_enum_construct_expr(name, variants)
_ => IfLevelExpr(ApplyExpr(ValueExpr(UnitExpr))) // For other types, return Unit
}
}
/// Generate struct constructor expression
fn RandProgGenerator::gen_struct_construct_expr(
self : Self,
name : Upper,
fields : Array[(Ident, Type)],
) -> Expr {
let field_assignments = Array::new()
for field in fields {
let (field_name, field_type) = field
let field_value = self.gen_expr(field_type, true) // Use simple expressions for field values
field_assignments.push((field_name, field_value))
}
IfLevelExpr(ApplyExpr(ValueExpr(StructConstruct(name, field_assignments))))
}
/// Generate enum constructor expression
fn RandProgGenerator::gen_enum_construct_expr(
self : Self,
name : Upper,
variants : Array[(Upper, Array[Type])],
) -> Expr {
match self.choice(variants) {
Some((variant_name, variant_types)) => {
let field_values = Array::new()
for variant_type in variant_types {
field_values.push(self.gen_expr(variant_type, true))
}
IfLevelExpr(
ApplyExpr(
ValueExpr(EnumConstruct(Some(name), variant_name, field_values)),
),
)
}
None => IfLevelExpr(ApplyExpr(ValueExpr(UnitExpr))) // If no variants, return Unit
}
}
/// Generate variable reference expression - ensure referenced variables actually exist in current environment
fn RandProgGenerator::gen_var_expr(self : Self, ty : Type) -> Expr? {
// First find variables of specified type in current environment
let available_vars = self.var_env.collect_vars_of_type(ty)
if available_vars.is_empty() {
return None
}
// Randomly select from available variables
match self.choice(available_vars) {
Some(v) =>
// Verify variable actually exists
match self.var_env.get(v) {
Some(_) => {
// Mark variable as used
self.mark_var_used(v)
Some(IfLevelExpr(ApplyExpr(ValueExpr(IdentExpr(v)))))
}
None => None
}
None => None
}
}
/// Generate complex array expressions
fn RandProgGenerator::gen_array_expr(self : Self, elem_type : Type) -> Expr {
match self.rand_int(2) {
0 => {
// Array::make(size, init_value)
let size_val = self.rand_int(self.max_array_size) + 1
let size_expr = IfLevelExpr(ApplyExpr(ValueExpr(IntExpr(size_val))))
let init_expr = self.gen_expr(elem_type, true)
IfLevelExpr(ApplyExpr(ValueExpr(ArrayMake(size_expr, init_expr))))
}
_ => {
// [elem1, elem2, ...] - ensure at least one element
let size = self.rand_int(self.max_array_size) + 1 // At least 1 element
let elements = Array::new()
for i = 0; i < size; i = i + 1 {
elements.push(self.gen_expr(elem_type, true))
}
IfLevelExpr(ApplyExpr(ValueExpr(ArrayExpr(elements))))
}
}
}
/// Generate complex tuple expressions
fn RandProgGenerator::gen_tuple_expr(
self : Self,
elem_types : Array[Type],
) -> Expr {
let elements = Array::new()
for elem_type in elem_types {
elements.push(self.gen_expr(elem_type, true))
}
IfLevelExpr(ApplyExpr(ValueExpr(TupleExpr(elements))))
}
/// Generate function call expression - ensure only calling actually existing and accessible functions
fn RandProgGenerator::gen_function_call_expr(
self : Self,
expected_return_type : Type,
) -> Expr? {
// Find functions with matching return type (including top-level and local functions in current scope)
let available_funcs = Array::new()
// Find function type variables in current environment (local functions) - only check currently accessible ones
self.var_env.map.each(fn(var_name, var_type) {
match var_type {
Func(param_types, return_type) =>
if return_type == expected_return_type {
// Verify function actually exists in current environment
match self.var_env.get(var_name) {
Some(_) => available_funcs.push((var_name, param_types))
None => ()
}
}
_ => ()
}
})
// Only consider top-level functions when there are few available functions, to avoid complexity
if available_funcs.length() < 2 {
self.func_defs.each(fn(func_name, func_def) {
if func_def.ret_ty == expected_return_type &&
func_def.params.length() <= 2 {
available_funcs.push((func_name, func_def.params.map(fn(p) { p.1 })))
}
})
}
match self.choice(available_funcs) {
Some((func_name, param_types)) => {
let args = Array::new()
for param_type in param_types {
args.push(self.gen_expr(param_type, true)) // Use simple expressions
}
let func_apply = ApplyExpr::ValueExpr(ValueExpr::IdentExpr(func_name))
Some(IfLevelExpr(ApplyExpr(Call(func_apply, args))))
}
None => None
}
}
/// Generate array access expression
fn RandProgGenerator::gen_array_access_expr(
self : Self,
elem_type : Type,
) -> Expr? {
// Find array type variables
let array_vars = self.find_all_vars_of_type(Array(elem_type))
match self.choice(array_vars) {
Some(array_var) => {
let index_expr = self.gen_expr(Int, true)
let array_apply = ApplyExpr::ValueExpr(ValueExpr::IdentExpr(array_var))
Some(IfLevelExpr(ApplyExpr(ArrAcc(array_apply, index_expr))))
}
None => None
}
}
/// Generate dot access expression (struct field access)
fn RandProgGenerator::gen_dot_access_expr(
self : Self,
expected_type : Type,
) -> Expr? {
// Find struct variables with matching field types
let candidates = Array::new()
self.var_env.map.each(fn(var_name, var_type) {
match var_type {
Struct(_, fields) =>
for field in fields {
let (field_name, field_type) = field
if field_type == expected_type {
candidates.push((var_name, field_name))
}
}
_ => ()
}
})
match self.choice(candidates) {
Some((var_name, field_name)) => {
let struct_apply = ApplyExpr::ValueExpr(ValueExpr::IdentExpr(var_name))
Some(IfLevelExpr(ApplyExpr(DotAcc(struct_apply, field_name))))
}
None => None
}
}
/// Enhanced expression generator supporting more complex expression structures
pub fn RandProgGenerator::gen_expr(self : Self, ty : Type, simple : Bool) -> Expr {
if self.current_depth >= self.max_depth || simple {
// At max depth or when simple expressions required, prioritize literals or variable references
let choices = [
(0, 60), // Literals - significantly increased weight
(1, 35), // Variable references - increased weight
(2, 3), // Function calls - significantly reduced weight
(3, 2),
] // Field access - significantly reduced weight
match self.weighted_choice(choices) {
Some(0) => self.gen_literal_expr(ty)
Some(1) =>
match self.gen_var_expr(ty) {
Some(expr) => expr
None => self.gen_literal_expr(ty)
}
Some(2) =>
match self.gen_function_call_expr(ty) {
Some(expr) => expr
None => self.gen_literal_expr(ty)
}
Some(3) =>
match self.gen_dot_access_expr(ty) {
Some(expr) => expr
None => self.gen_literal_expr(ty)
}
_ => self.gen_literal_expr(ty)
}
} else {
self.current_depth = self.current_depth + 1
let result = match ty {
Unit => self.gen_complex_unit_expr()
Bool => self.gen_complex_bool_expr()
Int => self.gen_complex_int_expr()
Double => self.gen_complex_double_expr()
Array(elem_type) => self.gen_complex_array_expr(elem_type)
Tuple(elem_types) => self.gen_complex_tuple_expr(elem_types)
Struct(name, fields) => self.gen_complex_struct_expr(name, fields)
Enum(name, variants) => self.gen_complex_enum_expr(name, variants)
_ => self.gen_literal_expr(ty)
}
self.current_depth = self.current_depth - 1
result
}
}
/// Generate complex Unit expressions
fn RandProgGenerator::gen_complex_unit_expr(self : Self) -> Expr {
let choices = [
(0, 40), // Literal Unit
(1, 20), // Variable reference
(2, 15), // Function call
(3, 15), // If expression
(4, 10),
] // Expression statement
match self.weighted_choice(choices) {
Some(0) => self.gen_literal_expr(Unit)
Some(1) =>
match self.gen_var_expr(Unit) {
Some(expr) => expr
None => self.gen_literal_expr(Unit)
}
Some(2) =>
match self.gen_function_call_expr(Unit) {
Some(expr) => expr
None => self.gen_literal_expr(Unit)
}
Some(3) =>
match self.gen_if_expr(Unit) {
Some(expr) => expr
None => self.gen_literal_expr(Unit)
}
Some(4) => {
// Generate a compound expression containing Unit expression
let inner_expr = self.gen_expr(Unit, true)
IfLevelExpr(ApplyExpr(ValueExpr(GroupExpr(inner_expr))))
}
_ => self.gen_literal_expr(Unit)
}
}
/// Generate complex Bool expressions
fn RandProgGenerator::gen_complex_bool_expr(self : Self) -> Expr {
let choices = [
(0, 20), // Literal Bool
(1, 18), // Variable reference
(2, 18), // Comparison expression
(3, 15), // Logical expression
(4, 12), // If expression
(5, 10), // Function call
(6, 7),
] // Negation expression
match self.weighted_choice(choices) {
Some(0) => self.gen_literal_expr(Bool)
Some(1) =>
match self.gen_var_expr(Bool) {
Some(expr) => expr
None => self.gen_literal_expr(Bool)
}
Some(2) => self.gen_comparison_expr()
Some(3) => self.gen_logical_expr()
Some(4) =>
match self.gen_if_expr(Bool) {
Some(expr) => expr
None => self.gen_literal_expr(Bool)
}
Some(5) =>
match self.gen_function_call_expr(Bool) {
Some(expr) => expr
None => self.gen_literal_expr(Bool)
}
Some(6) => {
let inner_expr = self.gen_expr(Bool, true)
IfLevelExpr(ApplyExpr(ValueExpr(NotExpr(inner_expr))))
}
_ => self.gen_literal_expr(Bool)
}
}
/// Generate complex Int expressions
fn RandProgGenerator::gen_complex_int_expr(self : Self) -> Expr {
let choices = [
(0, 35), // Literal Int
(1, 30), // Variable reference
(2, 15), // Arithmetic expression
(3, 8), // If expression
(4, 5), // Function call
(5, 4), // Match expression
(6, 2), // Array access
(7, 1), // Field access
]
match self.weighted_choice(choices) {
Some(0) => self.gen_literal_expr(Int)
Some(1) =>
match self.gen_var_expr(Int) {
Some(expr) => expr
None => self.gen_literal_expr(Int)
}
Some(2) => self.gen_arithmetic_expr(Int)
Some(3) =>
match self.gen_if_expr(Int) {
Some(expr) => expr
None => self.gen_literal_expr(Int)
}
Some(4) =>
match self.gen_function_call_expr(Int) {
Some(expr) => expr
None => self.gen_literal_expr(Int)
}
Some(5) =>
match self.gen_match_expr(Int) {
Some(expr) => expr
None => self.gen_literal_expr(Int)
}
Some(6) =>
match self.gen_array_access_expr(Int) {
Some(expr) => expr
None => self.gen_literal_expr(Int)
}
Some(7) =>
match self.gen_dot_access_expr(Int) {
Some(expr) => expr
None => self.gen_literal_expr(Int)
}
_ => self.gen_literal_expr(Int)
}
}
/// Generate complex Double expressions
fn RandProgGenerator::gen_complex_double_expr(self : Self) -> Expr {
let choices = [
(0, 25), // Literal Double
(1, 20), // Variable reference
(2, 20), // Arithmetic expression
(3, 12), // If expression
(4, 10), // Function call
(5, 8), // Match expression
(6, 3), // Array access
(7, 2), // Field access
]
match self.weighted_choice(choices) {
Some(0) => self.gen_literal_expr(Double)
Some(1) =>
match self.gen_var_expr(Double) {
Some(expr) => expr
None => self.gen_literal_expr(Double)
}
Some(2) => self.gen_arithmetic_expr(Double)
Some(3) =>
match self.gen_if_expr(Double) {
Some(expr) => expr
None => self.gen_literal_expr(Double)
}
Some(4) =>
match self.gen_function_call_expr(Double) {
Some(expr) => expr
None => self.gen_literal_expr(Double)
}
Some(5) =>
match self.gen_match_expr(Double) {
Some(expr) => expr
None => self.gen_literal_expr(Double)
}
Some(6) =>
match self.gen_array_access_expr(Double) {
Some(expr) => expr
None => self.gen_literal_expr(Double)
}
Some(7) =>
match self.gen_dot_access_expr(Double) {
Some(expr) => expr
None => self.gen_literal_expr(Double)
}
_ => self.gen_literal_expr(Double)
}
}
/// Generate complex Array expressions
fn RandProgGenerator::gen_complex_array_expr(
self : Self,
elem_type : Type,
) -> Expr {
let choices = [
(0, 30), // Array literal
(1, 25), // Variable reference
(2, 20), // Array::make
(3, 15), // Function call
(4, 10),
] // Field access
match self.weighted_choice(choices) {
Some(0) => self.gen_array_expr(elem_type)
Some(1) =>
match self.gen_var_expr(Array(elem_type)) {
Some(expr) => expr
None => self.gen_array_expr(elem_type)
}
Some(2) => {
// Ensure Array::make first parameter is at least 1
let size_val = self.rand_int(self.max_array_size) + 1
let size_expr = IfLevelExpr(ApplyExpr(ValueExpr(IntExpr(size_val))))
let init_expr = self.gen_expr(elem_type, false)
IfLevelExpr(ApplyExpr(ValueExpr(ArrayMake(size_expr, init_expr))))
}
Some(3) =>
match self.gen_function_call_expr(Array(elem_type)) {
Some(expr) => expr
None => self.gen_array_expr(elem_type)
}
Some(4) =>
match self.gen_dot_access_expr(Array(elem_type)) {
Some(expr) => expr
None => self.gen_array_expr(elem_type)
}
_ => self.gen_array_expr(elem_type)
}
}
/// Generate complex Tuple expressions
fn RandProgGenerator::gen_complex_tuple_expr(
self : Self,
elem_types : Array[Type],
) -> Expr {
let choices = [
(0, 40), // Tuple literal
(1, 25), // Variable reference
(2, 20), // Function call
(3, 15),
] // Field access
match self.weighted_choice(choices) {
Some(0) => self.gen_tuple_expr(elem_types)
Some(1) =>
match self.gen_var_expr(Tuple(elem_types)) {
Some(expr) => expr
None => self.gen_tuple_expr(elem_types)
}
Some(2) =>
match self.gen_function_call_expr(Tuple(elem_types)) {
Some(expr) => expr
None => self.gen_tuple_expr(elem_types)
}
Some(3) =>
match self.gen_dot_access_expr(Tuple(elem_types)) {
Some(expr) => expr
None => self.gen_tuple_expr(elem_types)
}
_ => self.gen_tuple_expr(elem_types)
}
}
/// Generate complex Struct expressions
fn RandProgGenerator::gen_complex_struct_expr(
self : Self,
name : Upper,
fields : Array[(Ident, Type)],
) -> Expr {
let choices = [
(0, 40), // Struct constructor
(1, 30), // Variable reference
(2, 20), // Function call
(3, 10),
] // Field access
match self.weighted_choice(choices) {
Some(0) => self.gen_struct_construct_expr(name, fields)
Some(1) =>
match self.gen_var_expr(Struct(name, fields)) {
Some(expr) => expr
None => self.gen_struct_construct_expr(name, fields)
}
Some(2) =>
match self.gen_function_call_expr(Struct(name, fields)) {
Some(expr) => expr
None => self.gen_struct_construct_expr(name, fields)
}
Some(3) =>
match self.gen_dot_access_expr(Struct(name, fields)) {
Some(expr) => expr
None => self.gen_struct_construct_expr(name, fields)
}
_ => self.gen_struct_construct_expr(name, fields)
}
}
/// Generate complex Enum expressions
fn RandProgGenerator::gen_complex_enum_expr(
self : Self,
name : Upper,
variants : Array[(Upper, Array[Type])],
) -> Expr {
let choices = [
(0, 40), // Enum constructor
(1, 30), // Variable reference
(2, 20), // Function call
(3, 10),
] // Field access
match self.weighted_choice(choices) {
Some(0) => self.gen_enum_construct_expr(name, variants)
Some(1) =>
match self.gen_var_expr(Enum(name, variants)) {
Some(expr) => expr
None => self.gen_enum_construct_expr(name, variants)
}
Some(2) =>
match self.gen_function_call_expr(Enum(name, variants)) {
Some(expr) => expr
None => self.gen_enum_construct_expr(name, variants)
}
Some(3) =>
match self.gen_dot_access_expr(Enum(name, variants)) {
Some(expr) => expr
None => self.gen_enum_construct_expr(name, variants)
}
_ => self.gen_enum_construct_expr(name, variants)
}
}
/// Generate arithmetic expressions (only for Int and Double)
fn RandProgGenerator::gen_arithmetic_expr(self : Self, ty : Type) -> Expr {
// Always generate simple binary expressions to avoid infinite recursion
let left = self.gen_expr(ty, true)
let right = self.gen_expr(ty, true)
match self.rand_int(5) {
0 => AddExpr(left, right)
1 => SubExpr(left, right)
2 => MulExpr(left, right)
3 => DivExpr(left, right)
_ => ModExpr(left, right)
}
}
/// Generate comparison expressions (returns Bool)
fn RandProgGenerator::gen_comparison_expr(self : Self) -> Expr {
let ty = if self.rand_bool() { Type::Int } else { Type::Double }
// Generate simple comparison to avoid recursive complexity
let left = self.gen_expr(ty, true)
let right = self.gen_expr(ty, true)
self.make_comparison(left, right)
}
/// Helper function to create comparison
fn RandProgGenerator::make_comparison(
self : Self,
left : Expr,
right : Expr,
) -> Expr {
let op = match self.rand_int(6) {
0 => Eq
1 => Ne
2 => Lt
3 => Le
4 => Gt
_ => Ge
}
CmpExpr(op, left, right)
}
/// Generate logical expressions (returns Bool)
fn RandProgGenerator::gen_logical_expr(self : Self) -> Expr {
match self.rand_int(2) {
0 => {
// AND expression
let left = self.gen_expr(Bool, true) // Use simple expressions
let right = self.gen_expr(Bool, true)
AndExpr(left, right)
}
_ => {
// OR expression
let left = self.gen_expr(Bool, true) // Use simple expressions
let right = self.gen_expr(Bool, true)
OrExpr(left, right)
}
}
}
/// Generate if expressions
pub fn RandProgGenerator::gen_if_expr(self : Self, expected_type : Type) -> Expr? {
// Prevent overly deep nesting
if self.current_depth >= self.max_depth - 1 {
return None
}
// Generate condition expression (use current environment, don't introduce new variables)
let cond = self.gen_expr(Bool, true)
// Generate then block, important: don't create new sub-environment, since if expressions shouldn't introduce new scope
let old_depth = self.current_depth
self.current_depth = self.current_depth + 1
// Generate then block - only use expressions, don't add new variable declarations
let then_block = if expected_type == Unit {
let block = BlockExpr::new(nested_level=self.current_depth - 1)
let unit_expr = self.gen_expr(Unit, true)
block.set_last_expr(unit_expr)
block
} else {
let block = BlockExpr::new(nested_level=self.current_depth - 1)
// Directly generate return expression, don't generate statements to avoid scope issues
let return_expr = self.gen_expr(expected_type, true) // Use simple expressions
block.set_last_expr(return_expr)
block
}
// Generate else block - also don't create new scope
let else_part = if self.rand_bool() == true &&
self.current_depth < self.max_depth - 2 {
// Generate else if, but be careful with recursion depth
match self.gen_if_expr(expected_type) {
Some(nested_if) =>
match nested_if {
IfLevelExpr(IfExpr(if_expr)) => Either::Left(if_expr)
_ => {
// If not an if expression, create simple else block
let else_block = BlockExpr::new(nested_level=self.current_depth - 1)
let else_expr = self.gen_expr(expected_type, true)
else_block.set_last_expr(else_expr)
Either::Right(else_block)
}
}
None => {
// Generate simple else block
let else_block = BlockExpr::new(nested_level=self.current_depth - 1)
let else_expr = self.gen_expr(expected_type, true)
else_block.set_last_expr(else_expr)
Either::Right(else_block)
}
}
} else {
// Generate simple else block
let else_block = BlockExpr::new(nested_level=self.current_depth - 1)
let else_expr = self.gen_expr(expected_type, true)
else_block.set_last_expr(else_expr)
Either::Right(else_block)
}
// Restore depth
self.current_depth = old_depth
let if_expr = IfExpr::{ cond, then_: then_block, else_: else_part }
Some(IfLevelExpr(IfExpr(if_expr)))
}
/// Generate match expressions
pub fn RandProgGenerator::gen_match_expr(
self : Self,
expected_type : Type,
) -> Expr? {
// Prevent overly deep nesting
if self.current_depth >= self.max_depth - 1 {
return None
}
// Select appropriate type for matching
let match_type = match self.rand_int(4) {
0 => Type::Bool
1 => Type::Int
2 => {
// Try to use defined enum types
let available_enums = Array::new()
self.enum_defs.each(fn(_, enum_def) {
available_enums.push(enum_def.type_of())
})
match self.choice(available_enums) {
Some(enum_type) => enum_type
None => Type::Bool // Fallback
}
}
_ =>
// Simple tuple type
Type::Tuple([Type::Int, Type::Bool])
}
// Generate match expression
let match_expr_val = self.gen_expr(match_type, true)
// Create sub-environment
let old_var_env = self.var_env
let old_mut_env = self.mutable_vars
let old_depth = self.current_depth
self.var_env = old_var_env.sub_env()
self.mutable_vars = old_mut_env.sub_env()
self.current_depth = self.current_depth + 1
// Generate match arms
let arms = self.gen_match_arms(match_type, expected_type)
// Restore environment
self.var_env = old_var_env
self.mutable_vars = old_mut_env
self.current_depth = old_depth
if arms.is_empty() {
None
} else {
let match_expr = MatchExpr::{
nested_level: self.current_depth,
expr: match_expr_val,
arms,
}
Some(IfLevelExpr(MatchExpr(match_expr)))
}
}
/// Generate match arms
fn RandProgGenerator::gen_match_arms(
self : Self,
match_type : Type,
result_type : Type,
) -> Array[(Pattern, Expr)] {
let arms = Array::new()
match match_type {
Bool => {
// Boolean type matching
let true_expr = self.gen_expr(result_type, true)
let false_expr = self.gen_expr(result_type, true)
arms.push((Pattern::Bool(true), true_expr))
arms.push((Pattern::Bool(false), false_expr))
}
Int => {
// Integer type matching
let arm_count = self.rand_int(3) + 2 // 2-4 arms
for i = 0; i < arm_count - 1; i = i + 1 {
let pattern_val = self.rand_int(10)
let arm_expr = self.gen_expr(result_type, true)
arms.push((Pattern::Number(pattern_val), arm_expr))
}
// Add wildcard arm
let wildcard_expr = self.gen_expr(result_type, true)
arms.push((Pattern::WildCard, wildcard_expr))
}
Enum(enum_name, variants) =>
// Enum type matching
for variant in variants {
let (variant_name, variant_types) = variant
let patterns = Array::new()
for variant_type in variant_types {
// Generate simple patterns
match variant_type {
Int => patterns.push(Pattern::WildCard) // Simplify to wildcards
Bool => patterns.push(Pattern::WildCard)
_ => patterns.push(Pattern::WildCard)
}
}
let arm_expr = self.gen_expr(result_type, true)
arms.push(
(
Pattern::EnumPattern(Some(enum_name), variant_name, patterns),
arm_expr,
),
)
}
Tuple(elem_types) => {
// Tuple type matching
let patterns = Array::new()
for elem_type in elem_types {
// Generate simple patterns
match elem_type {
Int =>
if self.rand_bool() == true {
patterns.push(Pattern::Number(self.rand_int(5)))
} else {
patterns.push(Pattern::WildCard)
}
Bool =>
if self.rand_bool() == true {
patterns.push(Pattern::Bool(self.rand_bool()))
} else {
patterns.push(Pattern::WildCard)
}
_ => patterns.push(Pattern::WildCard)
}
}
let arm_expr = self.gen_expr(result_type, true)
arms.push((Pattern::Tuple(patterns), arm_expr))
// Add wildcard arm
let wildcard_expr = self.gen_expr(result_type, true)
arms.push((Pattern::WildCard, wildcard_expr))
}
_ => {
// Other types use wildcards
let wildcard_expr = self.gen_expr(result_type, true)
arms.push((Pattern::WildCard, wildcard_expr))
}
}
arms
}
/// Enhanced statement generator supporting more statement types
pub fn RandProgGenerator::gen_stmt(self : Self) -> Stmt {
// Adjust statement complexity based on depth and line count target
if self.current_depth >= self.max_depth - 1 {
// At greater depth, generate simple statements
let choices = [
(0, 50), // Let statements - increased weight
(1, 30), // Let mut statements - increased weight
(2, 15), // Assignment statements
(3, 5),
] // Expression statements - significantly reduced weight
match self.weighted_choice(choices) {
Some(0) => self.gen_let_stmt()
Some(1) => self.gen_expr_stmt()
Some(2) => self.gen_let_mut_stmt()
Some(3) => self.gen_assign_stmt()
_ => self.gen_let_stmt()
}
} else {
// At shallower depth, can generate more complex statements, ensure mutable variables get used
let choices = [
(0, 35), // Let statements - moderate weight
(1, 20), // Let mut statements - reduced weight to avoid too many unused mutable variables
(2, 25), // Assignment statements - increased weight to ensure mutable variables are used
(3, 8), // Expression statements - reduced weight
(4, 5), // While loops - normal weight
(5, 3), // Tuple destructuring let - reduced weight
(6, 1), // Return statements - reduced weight
(7, 1), // Local function definitions - greatly reduced weight
]
match self.weighted_choice(choices) {
Some(0) => self.gen_let_stmt()
Some(1) => self.gen_let_mut_stmt()
Some(2) => self.gen_assign_stmt()
Some(3) => self.gen_expr_stmt()
Some(4) => self.gen_while_stmt()
Some(5) => self.gen_let_tuple_stmt()
Some(6) => self.gen_return_stmt()
Some(7) => self.gen_local_func_def_stmt()
_ => self.gen_let_stmt()
}
}
}
/// Generate let statement
pub fn RandProgGenerator::gen_let_stmt(self : Self) -> Stmt {
let var_name = self.gen_ident()
let var_type = self.gen_type(true)
let init_expr = self.gen_expr(var_type, false)
// Add variable to environment
self.var_env.set(var_name, var_type)
// Record variable definition
self.record_var_definition(var_name, var_type)
// Generate type annotations more frequently to improve code readability
let type_annotation = if self.rand_int(10) < 7 {
Some(var_type)
} else {
None
}
Let(var_name, type_annotation, init_expr)
}
/// Generate let mut statement with immediate assignment to ensure mutability is used
pub fn RandProgGenerator::gen_let_mut_stmt(self : Self) -> Stmt {
let var_name = self.gen_ident()
let var_type = self.gen_type(true)
let init_expr = self.gen_expr(var_type, false)
// Add variable to environment (including mutable variable environment)
self.var_env.set(var_name, var_type)
self.mutable_vars.set(var_name, var_type)
// Record variable definition
self.record_var_definition(var_name, var_type)
let type_annotation = if self.rand_int(10) < 7 {
Some(var_type)
} else {
None
}
// Generate the let mut statement, which will be followed by an assignment
LetMut(var_name, type_annotation, init_expr)
}
// Removed: gen_let_mut_with_assignment - functionality moved to gen_block_expr
/// Generate tuple destructuring let statement
pub fn RandProgGenerator::gen_let_tuple_stmt(self : Self) -> Stmt {
let tuple_size = self.rand_int(self.max_tuple_size - 1) + 2 // At least 2 elements
let bindings = Array::new()
let types = Array::new()
// First determine all types
for i = 0; i < tuple_size; i = i + 1 {
let elem_type = self.gen_type(false)
types.push(elem_type)
}
// Generate tuple expression (cannot reference variables that are about to be bound)
let tuple_type = Type::Tuple(types)
let tuple_expr = self.gen_expr(tuple_type, false)
// Then generate bindings and add variables to environment (after generating expression)
for i = 0; i < tuple_size; i = i + 1 {
let elem_type = types[i]
if self.rand_bool() == true {
// Generate identifier binding
let var_name = self.gen_ident()
bindings.push(Binding::Ident(var_name))
// Only add to environment after generating expression to avoid circular reference
self.var_env.set(var_name, elem_type)
// Record variable definition
self.record_var_definition(var_name, elem_type)
} else {
// Generate wildcard binding
bindings.push(Binding::WhileCard)
}
}
let type_annotation = if self.rand_bool() == true {
Some(tuple_type)
} else {
None
}
LetTuple(bindings, type_annotation, tuple_expr)
}
/// Generate assignment statement
pub fn RandProgGenerator::gen_assign_stmt(self : Self) -> Stmt {
// Get all mutable variables (including those in parent environments)
let mut_vars = Array::new()
self.collect_mutable_vars_recursive(self.mutable_vars, mut_vars)
if mut_vars.is_empty() {
// If no mutable variables, generate a let statement
return self.gen_let_stmt()
}
let (var_name, var_type) = self.choice(mut_vars).unwrap()
// Verify variable actually exists in currently accessible environment
match self.var_env.get(var_name) {
Some(_) => {
// Variable actually exists, can safely assign
// Generate appropriate left value based on variable type, but ensure simplicity to avoid complex access patterns
let left_value = LeftValue::Ident(var_name) // Always use simple variable assignment
let new_value = self.gen_expr(var_type, true) // Use simple expressions to avoid complexity
Assign(left_value, new_value)
}
None =>
// Variable doesn't exist, generate let statement instead
self.gen_let_stmt()
}
}
// Helper function: recursively collect mutable variables
/// Recursively collect mutable variables
fn RandProgGenerator::collect_mutable_vars_recursive(
self : Self,
env : Env[Ident, Type],
result : Array[(Ident, Type)],
) -> Unit {
env.map.each(fn(var_name, var_type) {
// Only add variables that actually exist in current variable environment
match self.var_env.get(var_name) {
Some(_) => result.push((var_name, var_type))
None => ()
}
})
match env.parent {
Some(parent) => self.collect_mutable_vars_recursive(parent, result)
None => ()
}
}
/// Generate while statement
pub fn RandProgGenerator::gen_while_stmt(self : Self) -> Stmt {
// Generate a while loop with definite termination condition
// Use pattern: let mut counter = 0; while counter < limit { ... counter = counter + 1 }
// Create sub-environment
let old_var_env = self.var_env
let old_mut_env = self.mutable_vars
self.var_env = old_var_env.sub_env()
self.mutable_vars = old_mut_env.sub_env()
// Generate loop counter variable
let counter_name = self.gen_ident()
let counter_type = Int
let initial_value = IfLevelExpr(ApplyExpr(ValueExpr(IntExpr(0)))) // Start from 0
// Add counter to environment
self.var_env.set(counter_name, counter_type)
self.mutable_vars.set(counter_name, counter_type)
// Generate loop limit
let limit = self.rand_int(10) + 1 // 1-10 iterations
let limit_expr = IfLevelExpr(ApplyExpr(ValueExpr(IntExpr(limit))))
// Generate condition: counter < limit
let counter_ref = IfLevelExpr(ApplyExpr(ValueExpr(IdentExpr(counter_name))))
let cond = CmpExpr(Lt, counter_ref, limit_expr)
// Generate loop body and add counter increment at the end
let body = self.gen_block_expr_with_usage_tracking(Unit)
// Add counter increment statement in loop body
let increment_expr = AddExpr(
IfLevelExpr(ApplyExpr(ValueExpr(IdentExpr(counter_name)))),
IfLevelExpr(ApplyExpr(ValueExpr(IntExpr(1)))),
)
let increment_stmt = Assign(LeftValue::Ident(counter_name), increment_expr)
body.push(increment_stmt)
// Restore environment
self.var_env = old_var_env
self.mutable_vars = old_mut_env
// Create a compound statement block containing let mut and while
let wrapper_block = BlockExpr::new(nested_level=self.current_depth)
// Add let mut statement
let let_mut_stmt = LetMut(counter_name, Some(counter_type), initial_value)
wrapper_block.push(let_mut_stmt)
// Add while statement
let while_stmt = While(cond, body)
wrapper_block.push(while_stmt)
// Return expression statement wrapping this block
ExprStmt(IfLevelExpr(ApplyExpr(ValueExpr(BlockExpr(wrapper_block)))))
}
/// Generate return statement
pub fn RandProgGenerator::gen_return_stmt(self : Self) -> Stmt {
let return_expr = self.gen_expr(self.current_return_type, false)
Return(return_expr)
}
/// Generate local function definition statement
pub fn RandProgGenerator::gen_local_func_def_stmt(self : Self) -> Stmt {
// Reduce local function generation as they easily cause scope issues
if self.current_depth >= self.max_depth - 2 {
return self.gen_let_stmt() // Don't generate local functions in deep nesting
}
let param_count = self.rand_int(3) // 0-2 parameters, reduce complexity
let params = Array::new()
// Generate function name and type
let func_name = self.gen_ident()
let ret_ty = self.gen_basic_type() // Use basic types to ensure safety
// Generate parameter types
let param_types = Array::new()
for i = 0; i < param_count; i = i + 1 {
let param_type = self.gen_basic_type() // Use basic types to ensure safety
param_types.push(param_type)
}
// Add function type to current environment (before generating function body)
let func_type = Type::Func(param_types, ret_ty)
self.var_env.set(func_name, func_type)
// Create completely independent function scope, don't inherit external variables
let old_var_env = self.var_env
let old_mut_env = self.mutable_vars
self.var_env = Env::new() // Brand new environment, don't inherit any external variables
self.mutable_vars = Env::new()
// Generate parameters and add to function scope
for i = 0; i < param_count; i = i + 1 {
let param_name = self.gen_ident()
let param_type = param_types[i]
params.push((param_name, Some(param_type)))
// Add parameters to function internal environment
self.var_env.set(param_name, param_type)
// Record parameters as defined variables
self.record_var_definition(param_name, param_type)
// Parameters are used when defined
self.mark_var_used(param_name)
}
// Generate function body - use variable tracking
let old_return_type = self.current_return_type
self.current_return_type = ret_ty
let body = self.gen_block_expr_with_usage_tracking(ret_ty)
// Restore environment
self.current_return_type = old_return_type
self.var_env = old_var_env
self.mutable_vars = old_mut_env
LocalFuncDef(func_name, params, Some(ret_ty), body)
}
/// Generate expression statement
pub fn RandProgGenerator::gen_expr_stmt(self : Self) -> Stmt {
// Expression statements should only generate Unit type or if/match expressions, avoid cases requiring let _ = prefix
let expr = match self.rand_int(3) {
0 =>
// Generate Unit expression
self.gen_expr(Unit, true)
1 =>
// Generate if expression (doesn't need let _ = prefix)
match self.gen_if_expr(Unit) {
Some(expr) => expr
None => self.gen_expr(Unit, true)
}
_ =>
// Generate match expression (doesn't need let _ = prefix)
match self.gen_match_expr(Unit) {
Some(expr) => expr
None => self.gen_expr(Unit, true)
}
}
ExprStmt(expr)
}
/// Generate constructor and usage statements for unused types
fn RandProgGenerator::gen_force_use_unused_types(
self : Self,
block : BlockExpr,
) -> Unit {
// Force use of all struct types
self.struct_defs.each(fn(struct_name, struct_def) {
if true { // Use all structs
// Generate struct constructor expression and assign to variable
let var_name = self.gen_ident()
let struct_expr = self.gen_struct_construct_expr(
struct_name,
struct_def.fields,
)
let let_stmt = Let(var_name, Some(struct_def.type_of()), struct_expr)
block.push(let_stmt)
// Access all struct fields
for field in struct_def.fields {
let (field_name, field_type) = field
let field_access = IfLevelExpr(
ApplyExpr(
DotAcc(
ApplyExpr::ValueExpr(ValueExpr::IdentExpr(var_name)),
field_name,
),
),
)
match field_type {
Int => {
// Generate println call for Int type
let println_call = IfLevelExpr(
ApplyExpr(
Call(
ApplyExpr::ValueExpr(ValueExpr::IdentExpr(Ident("println"))),
[field_access],
),
),
)
block.push(ExprStmt(println_call))
}
_ =>
// Generate simple expression statement for other types
block.push(ExprStmt(field_access))
}
}
// Use entire struct
let usage_expr = IfLevelExpr(ApplyExpr(ValueExpr(IdentExpr(var_name))))
block.push(ExprStmt(usage_expr))
}
})
// Force use of all enum types through match expressions
self.enum_defs.each(fn(enum_name, enum_def) {
if true { // Use all enums
// Generate enum constructor expression and assign to variable
let var_name = self.gen_ident()
let enum_expr = self.gen_enum_construct_expr(enum_name, enum_def.variants)
let let_stmt = Let(var_name, Some(enum_def.type_of()), enum_expr)
block.push(let_stmt)
// Generate match expression using all variants
if !enum_def.variants.is_empty() {
let match_arms = Array::new()
for variant in enum_def.variants {
let (variant_name, variant_types) = variant
let patterns = Array::new()
for _ in variant_types {
patterns.push(Pattern::WildCard) // Use wildcard patterns
}
let pattern = Pattern::EnumPattern(
Some(enum_name),
variant_name,
patterns,
)
let arm_expr = IfLevelExpr(ApplyExpr(ValueExpr(UnitExpr)))
match_arms.push((pattern, arm_expr))
}
let var_expr = IfLevelExpr(ApplyExpr(ValueExpr(IdentExpr(var_name))))
let match_expr = MatchExpr::{
nested_level: self.current_depth + 1,
expr: var_expr,
arms: match_arms,
}
let match_stmt = ExprStmt(IfLevelExpr(MatchExpr(match_expr)))
block.push(match_stmt)
}
// Use entire enum
let usage_expr = IfLevelExpr(ApplyExpr(ValueExpr(IdentExpr(var_name))))
block.push(ExprStmt(usage_expr))
}
})
// Force call all functions
self.func_defs.each(fn(func_name, func_def) {
if true { // Call all functions
// Generate function call
let args = Array::new()
for param in func_def.params {
let (_, param_type) = param
args.push(self.gen_expr(param_type, true))
}
let func_call = IfLevelExpr(
ApplyExpr(
Call(ApplyExpr::ValueExpr(ValueExpr::IdentExpr(func_name)), args),
),
)
if func_def.ret_ty == Unit {
// Unit return type, directly as expression statement
block.push(ExprStmt(func_call))
} else {
// Non-Unit return type, assign to variable then use
let var_name = self.gen_ident()
let let_stmt = Let(var_name, Some(func_def.ret_ty), func_call)
block.push(let_stmt)
// Decide how to use based on return type
match func_def.ret_ty {
Int => {
let var_expr = IfLevelExpr(
ApplyExpr(ValueExpr(IdentExpr(var_name))),
)
let println_call = IfLevelExpr(
ApplyExpr(
Call(
ApplyExpr::ValueExpr(ValueExpr::IdentExpr(Ident("println"))),
[var_expr],
),
),
)
block.push(ExprStmt(println_call))
}
_ => {
let usage_expr = IfLevelExpr(
ApplyExpr(ValueExpr(IdentExpr(var_name))),
)
block.push(ExprStmt(usage_expr))
}
}
}
}
})
// Force use all top-level variables
self.var_env.map.each(fn(var_name, var_type) {
// Check if this variable is in global scope (not function parameter)
if self.current_depth <= 1 { // At top level of main function
match var_type {
Int => {
// Generate println call for Int type
let var_expr = IfLevelExpr(ApplyExpr(ValueExpr(IdentExpr(var_name))))
let println_call = IfLevelExpr(
ApplyExpr(
Call(
ApplyExpr::ValueExpr(ValueExpr::IdentExpr(Ident("println"))),
[var_expr],
),
),
)
block.push(ExprStmt(println_call))
}
_ => {
// Generate simple expression statement for other types
let var_expr = IfLevelExpr(ApplyExpr(ValueExpr(IdentExpr(var_name))))
block.push(ExprStmt(var_expr))
}
}
}
})
}
/// Generate code block and handle unused variables at the end
fn RandProgGenerator::gen_block_expr_with_usage_tracking(
self : Self,
return_type : Type,
) -> BlockExpr {
// Save current defined variables state
let scope_start_vars = Map::new()
self.all_defined_vars.each(fn(k, v) { scope_start_vars.set(k, v) })
// Generate normal code block
let block = self.gen_block_expr(return_type)
// Generate usage statements for variables defined but unused in current scope
self.all_defined_vars.each(fn(var_name, var_type) {
// Check if this variable is newly defined in current scope
match scope_start_vars.get(var_name) {
None =>
// This is a newly defined variable, check if unused
match self.used_vars.get(var_name) {
Some(false) =>
// Variable unused, generate usage statement
match self.var_env.get(var_name) {
Some(_) => {
// Variable visible in current environment, generate usage statement
match var_type {
Int => {
// Generate println call for Int type
let var_expr = IfLevelExpr(
ApplyExpr(ValueExpr(IdentExpr(var_name))),
)
let println_call = IfLevelExpr(
ApplyExpr(
Call(
ApplyExpr::ValueExpr(
ValueExpr::IdentExpr(Ident("println")),
),
[var_expr],
),
),
)
block.push(ExprStmt(println_call))
}
_ => {
// Generate simple expression statement for other types
let var_expr = IfLevelExpr(
ApplyExpr(ValueExpr(IdentExpr(var_name))),
)
block.push(ExprStmt(var_expr))
}
}
// Mark variable as used
self.mark_var_used(var_name)
}
None => () // Variable not visible, skip
}
_ => () // Variable already used or undefined, skip
}
Some(_) => () // Variable not defined in current scope, skip
}
})
// Additional enhancement: for any variable visible in current environment but marked as unused, force use
self.var_env.map.each(fn(var_name, var_type) {
match self.used_vars.get(var_name) {
Some(false) => {
// Unused variable, force generate usage statement
match var_type {
Int => {
let var_expr = IfLevelExpr(
ApplyExpr(ValueExpr(IdentExpr(var_name))),
)
let println_call = IfLevelExpr(
ApplyExpr(
Call(
ApplyExpr::ValueExpr(ValueExpr::IdentExpr(Ident("println"))),
[var_expr],
),
),
)
block.push(ExprStmt(println_call))
}
_ => {
let var_expr = IfLevelExpr(
ApplyExpr(ValueExpr(IdentExpr(var_name))),
)
block.push(ExprStmt(var_expr))
}
}
self.mark_var_used(var_name)
}
_ => ()
}
})
// Note: mutable variables now get immediate assignments in gen_block_expr
// Force use some top-level definitions in main function
if self.current_depth <= 1 { // Only generate in top-level block
self.gen_force_use_unused_types(block)
}
block
}
/// Enhanced code block generator supporting more complex code structures
pub fn RandProgGenerator::gen_block_expr(
self : Self,
return_type : Type,
) -> BlockExpr {
let block = BlockExpr::new(nested_level=self.current_depth)
// Check recursion depth to avoid infinite recursion
if self.current_depth >= self.max_depth {
// At max depth, only generate simple return expression
if return_type != Unit {
let last_expr = self.gen_literal_expr(return_type)
block.set_last_expr(last_expr)
}
return block
}
// Create sub-environment
let old_var_env = self.var_env
let old_mut_env = self.mutable_vars
let old_depth = self.current_depth
self.var_env = old_var_env.sub_env()
self.mutable_vars = old_mut_env.sub_env()
self.current_depth = self.current_depth + 1
// Dynamically adjust statement count based on target line count
let base_stmt_count = if self.current_lines < self.total_lines_target / 2 {
// If current lines less than half of target, generate more statements
self.rand_int(25) + 15 // 15-39 statements
} else if self.current_lines < self.total_lines_target * 3 / 4 {
// If approaching target, moderate amount
self.rand_int(15) + 10 // 10-24 statements
} else {
// If approaching or exceeding target, fewer statements
self.rand_int(8) + 5 // 5-12 statements
}
let stmt_count = if self.current_depth <= 2 {
base_stmt_count
} else {
base_stmt_count / (self.current_depth - 1) // Greater depth, fewer statements
}
for i = 0; i < stmt_count; i = i + 1 {
let stmt = self.gen_stmt()
block.push(stmt)
self.current_lines = self.current_lines + self.estimate_stmt_lines(stmt)
// If we just generated a let mut statement, immediately generate an assignment for it
match stmt {
LetMut(var_name, _, _) => {
// Get the variable type from var_env
match self.var_env.get(var_name) {
Some(var_type) => {
let assign_value = self.gen_expr(var_type, true)
let assign_stmt = Assign(LeftValue::Ident(var_name), assign_value)
block.push(assign_stmt)
self.current_lines = self.current_lines + 1
}
None => () // Should not happen, but skip if it does
}
}
_ => () // Not a let mut statement, do nothing
}
// If target line count reached, stop generating more statements
if self.current_lines >= self.total_lines_target {
break
}
}
// Note: forced assignments for unused mutable variables are handled
// in gen_block_expr_with_usage_tracking when that function is used
// Generate return expression (if needed)
if return_type != Unit {
let last_expr = if self.rand_bool() == true {
self.gen_literal_expr(return_type) // Sometimes generate literals
} else {
self.gen_expr(return_type, false) // Sometimes generate complex expressions
}
block.set_last_expr(last_expr)
self.current_lines = self.current_lines + 1
}
// Restore environment
self.var_env = old_var_env
self.mutable_vars = old_mut_env
self.current_depth = old_depth
block
}
/// Estimate statement line count (for controlling total line count)
fn RandProgGenerator::estimate_stmt_lines(self : Self, stmt : Stmt) -> Int {
match stmt {
Let(_, _, _) => 1
LetMut(_, _, _) => 1
LetTuple(_, _, _) => 1
Assign(_, _) => 1
ExprStmt(_) => 1
Return(_) => 1
LocalFuncDef(_, params, _, body) =>
2 + params.length() + self.estimate_block_lines(body)
While(_, body) => 1 + self.estimate_block_lines(body)
}
}
/// Estimate code block line count
fn RandProgGenerator::estimate_block_lines(self : Self, block : BlockExpr) -> Int {
let lines = 2 // { and }
let stmt_lines = block.stmts.fold(init=0, fn(acc, stmt) {
acc + self.estimate_stmt_lines(stmt)
})
let expr_lines = match block.last_expr {
Some(_) => 1
None => 0
}
lines + stmt_lines + expr_lines
}
/// Enhanced top-level definition generator
pub fn RandProgGenerator::gen_top_let(self : Self) -> TopLet {
let name = self.gen_ident()
let ty = self.gen_type(true)
let value = self.gen_expr(ty, false)
// Add global variable to environment
self.var_env.set(name, ty)
// Always generate type annotation to ensure type safety
let type_annotation = Some(ty)
{ name, ty: type_annotation, value }
}
/// Generate struct definition
pub fn RandProgGenerator::gen_struct_def(self : Self) -> StructDef {
let name = self.gen_upper()
let field_count = self.rand_int(5) + 1 // 1-5 fields, reduce complexity
let fields = Array::new()
for i = 0; i < field_count; i = i + 1 {
let field_name = self.gen_ident()
// For struct fields, mainly use basic types or simple composite types
let field_type = if self.rand_int(10) < 7 {
self.gen_basic_type() // 70% probability use basic types
} else {
// 30% probability use simple composite types
match self.rand_int(2) {
0 => Array(self.gen_basic_type())
_ => {
let tuple_size = self.rand_int(3) + 2
let tuple_types = Array::new()
for j = 0; j < tuple_size; j = j + 1 {
tuple_types.push(self.gen_basic_type())
}
Tuple(tuple_types)
}
}
}
fields.push((field_name, field_type))
}
let struct_def = { generic_param: None, name, fields }
// Register struct definition
self.struct_defs.set(name, struct_def)
// Add struct type to type environment
self.type_env.set(name, struct_def.type_of())
struct_def
}
/// Generate enum definition
pub fn RandProgGenerator::gen_enum_def(self : Self) -> EnumDef {
let name = self.gen_upper()
let variant_count = self.rand_int(4) + 1 // 1-4 variants, reduce complexity
let variants = Array::new()
for i = 0; i < variant_count; i = i + 1 {
let variant_name = self.gen_upper()
let field_count = self.rand_int(4) // 0-3 fields, reduce complexity
let variant_fields = Array::new()
for j = 0; j < field_count; j = j + 1 {
// For enum variants, mainly use basic types
let field_type = if self.rand_int(10) < 8 {
self.gen_basic_type() // 80% probability use basic types
} else {
Array(self.gen_basic_type()) // 20% probability use basic type arrays
}
variant_fields.push(field_type)
}
variants.push((variant_name, variant_fields))
}
let enum_def = { generic_param: None, name, variants }
// Register enum definition
self.enum_defs.set(name, enum_def)
// Add enum type to type environment
self.type_env.set(name, enum_def.type_of())
enum_def
}
/// Generate top-level function definition
pub fn RandProgGenerator::gen_top_func_def(self : Self) -> TopFuncDef {
let name = self.gen_ident()
let param_count = self.rand_int(self.max_func_params)
let params = Array::new()
// Create new environment scope
let old_var_env = self.var_env
let old_mut_env = self.mutable_vars
self.var_env = old_var_env.sub_env()
self.mutable_vars = old_mut_env.sub_env()
// Generate parameters, use basic types to ensure type safety
for i = 0; i < param_count; i = i + 1 {
let param_name = self.gen_ident()
let param_type = self.gen_basic_type() // Use basic types to ensure safety
params.push((param_name, param_type))
// Add parameters to environment
self.var_env.set(param_name, param_type)
// Record parameters as defined variables
self.record_var_definition(param_name, param_type)
// Parameters are used when defined
self.mark_var_used(param_name)
}
// Generate return type and function body
let ret_ty = self.gen_basic_type() // Use basic types to ensure safety
let old_return_type = self.current_return_type
self.current_return_type = ret_ty
// Use variable tracking code block generation
let body = self.gen_block_expr_with_usage_tracking(ret_ty)
// Restore environment and return type
self.current_return_type = old_return_type
self.var_env = old_var_env
self.mutable_vars = old_mut_env
let func_def = { generic_param: None, name, params, ret_ty, body }
// Register function definition
self.func_defs.set(name, func_def)
func_def
}
/// Generate main function (without parameters and generic parameters)
pub fn RandProgGenerator::gen_main_func(self : Self) -> TopFuncDef {
let name : Ident = Ident("main")
let params : Array[(Ident, Type)] = [] // main function has no parameters
let ret_ty = Unit // main function returns Unit
// Create new environment scope
let old_var_env = self.var_env
let old_mut_env = self.mutable_vars
self.var_env = old_var_env.sub_env()
self.mutable_vars = old_mut_env.sub_env()
let old_return_type = self.current_return_type
self.current_return_type = Unit
// Generate a larger function body with more statements
let body = self.gen_block_expr_with_usage_tracking(Unit)
// Restore environment and return type
self.current_return_type = old_return_type
self.var_env = old_var_env
self.mutable_vars = old_mut_env
{ generic_param: None, name, params, ret_ty, body }
}
/// Generate top-level declaration
pub fn RandProgGenerator::gen_top_decl(self : Self) -> TopDecl {
let choices = [
(0, 30), // Top-level let
(1, 25), // Struct definition
(2, 25), // Function definition
(3, 20),
] // Enum definition
match self.weighted_choice(choices) {
Some(0) => TopDecl::TopLet(self.gen_top_let())
Some(1) => TopDecl::StructDef(self.gen_struct_def())
Some(2) => TopDecl::TopFuncDef(self.gen_top_func_def())
Some(3) => TopDecl::EnumDef(self.gen_enum_def())
_ => TopDecl::TopLet(self.gen_top_let())
}
}
/// Program generator ensuring main function inclusion and reasonable program length
pub fn RandProgGenerator::gen_program(self : Self) -> Program {
let top_decls = Array::new()
// First generate appropriate amount of basic type definitions
let struct_count = self.rand_int(5) + 3 // 3-7 structs
for i = 0; i < struct_count; i = i + 1 {
top_decls.push(TopDecl::StructDef(self.gen_struct_def()))
self.current_lines = self.current_lines + 5
}
let enum_count = self.rand_int(4) + 2 // 2-5 enums
for i = 0; i < enum_count; i = i + 1 {
top_decls.push(TopDecl::EnumDef(self.gen_enum_def()))
self.current_lines = self.current_lines + 6
}
// Generate appropriate amount of functions and top-level variables
let decl_count = self.rand_int(40) + 40 // 40-79 declarations
for i = 0; i < decl_count; i = i + 1 {
let decl = self.gen_top_decl()
top_decls.push(decl)
// Estimate line count
match decl {
TopDecl::TopLet(_) => self.current_lines = self.current_lines + 1
TopDecl::TopFuncDef(func_def) =>
self.current_lines = self.current_lines +
3 +
self.estimate_block_lines(func_def.body)
TopDecl::StructDef(_) => self.current_lines = self.current_lines + 5
TopDecl::EnumDef(_) => self.current_lines = self.current_lines + 6
}
}
// Finally generate main function (required)
let main_func = self.gen_main_func()
top_decls.push(TopDecl::TopFuncDef(main_func))
self.current_lines = self.current_lines +
self.estimate_block_lines(main_func.body) +
2
{ top_decls, }
}