Files
agila_open_tool/tools/v/cmd/v2/test.v
T

5272 lines
113 KiB
V

const pi = 3
struct Point {
mut:
x int
y int
}
struct Rectangle {
mut:
width int
height int
origin Point
}
struct Node {
mut:
value int
left int
right int
}
// For testing array.clone() on nested selectors
struct ArrayHolder {
mut:
data []int
}
struct Wrapper {
mut:
holder &ArrayHolder
}
// For testing map indexing with push (map[key] << value)
struct PendingLabels {
mut:
labels map[int][]int
}
struct MapFieldIndexHolder {
mut:
values map[string]i64
}
// For testing array push in map iteration
struct Error76 {
msg string
val_id int
}
enum Color {
red
green
blue
yellow
}
enum Status {
pending = 0
active = 1
done = 2
}
// Flag enum for bitfield operations
@[flag]
enum Permissions {
read
write
execute
}
@[flag]
enum KeywordFlags {
read
unsigned
}
struct KeywordFlagBox {
flags KeywordFlags
}
// Enum for testing match with different return type
enum Operator {
plus
minus
mul
div
}
// Enum for binding power - return type differs from match expression type
enum BindingPower {
lowest
low
medium
high
}
// Interface declaration
interface Drawable {
draw() int
}
// Another interface with multiple methods
interface Shape {
area() int
perimeter() int
}
// Interface with methods that take parameters
interface Calculator {
add(a int, b int) int
multiply(x int) int
}
// Type alias
type MyInt = int
// Sum type
type Number = int | Point
// For testing nested smartcasts (outer sum type contains inner sum type)
type NestedOuter = Number | Rectangle
__global (
g_val int
g_count int
g_flag bool
g_point Point
)
// ===================== METHODS =====================
// Method that returns a different enum type than the receiver enum type
// Tests that match conditions use the correct enum (Operator) not the return type (BindingPower)
fn (op Operator) get_binding_power() BindingPower {
return match op {
.plus, .minus { .low }
.mul, .div { .medium }
}
}
fn (p Point) sum() int {
return p.x + p.y
}
// Implements Drawable interface
fn (p Point) draw() int {
// Return a unique identifier for drawing
return p.x * 1000 + p.y
}
fn (p Point) product() int {
return p.x * p.y
}
fn (p Point) scaled(factor int) Point {
return Point{
x: p.x * factor
y: p.y * factor
}
}
fn (mut p Point) double() {
p.x = p.x * 2
p.y = p.y * 2
}
// Implements Calculator interface
fn (p Point) add(a int, b int) int {
return p.x + p.y + a + b
}
fn (p Point) multiply(x int) int {
return (p.x + p.y) * x
}
fn (r Rectangle) area() int {
return r.width * r.height
}
fn (r Rectangle) perimeter() int {
return 2 * (r.width + r.height)
}
fn (n Node) total() int {
return n.value + n.left + n.right
}
// ===================== HELPER FUNCTIONS =====================
// For test 77: process_number takes a Number sum type and returns a value
// This tests that smartcasted variables inside match branches can be passed
// to functions expecting the original sum type
fn process_number(n Number) int {
match n {
int { return n }
Point { return n.x + n.y }
}
}
fn fib(n int) int {
if n < 2 {
return n
}
return fib(n - 1) + fib(n - 2)
}
fn factorial(n int) int {
if n <= 1 {
return 1
}
return n * factorial(n - 1)
}
fn sum_recursive(n int) int {
if n <= 0 {
return 0
}
return n + sum_recursive(n - 1)
}
fn gcd(a int, b int) int {
if b == 0 {
return a
}
return gcd(b, a % b)
}
// Multi-return functions
fn swap(a int, b int) (int, int) {
return b, a
}
fn divmod(a int, b int) (int, int) {
return a / b, a % b
}
fn min_max(a int, b int, c int) (int, int) {
mut min := a
mut max := a
if b < min {
min = b
}
if b > max {
max = b
}
if c < min {
min = c
}
if c > max {
max = c
}
return min, max
}
fn triple_return(x int) (int, int, int) {
return x, x * 2, x * 3
}
fn power(base int, exp int) int {
if exp == 0 {
return 1
}
return base * power(base, exp - 1)
}
fn sum_many(a int, b int, c int, d int, e int, f int, g int, h int) int {
return a + b + c + d + e + f + g + h
}
fn mul_many(a int, b int, c int, d int, e int, f int, g int, h int) int {
return a * b * c * d * e * f * g * h
}
fn max_of_eight(a int, b int, c int, d int, e int, f int, g int, h int) int {
mut m := a
if b > m {
m = b
}
if c > m {
m = c
}
if d > m {
m = d
}
if e > m {
m = e
}
if f > m {
m = f
}
if g > m {
m = g
}
if h > m {
m = h
}
return m
}
fn weighted_sum(a int, b int, c int, d int, e int, f int, g int, h int) int {
return a * 1 + b * 2 + c * 3 + d * 4 + e * 5 + f * 6 + g * 7 + h * 8
}
fn modify_struct(mut p Point) {
p.x = 999
p.y = 888
}
fn swap_point(mut p Point) {
tmp := p.x
p.x = p.y
p.y = tmp
}
fn scale_point(mut p Point, factor int) {
p.x = p.x * factor
p.y = p.y * factor
}
fn translate_point(mut p Point, dx int, dy int) {
p.x = p.x + dx
p.y = p.y + dy
}
fn reset_point(mut p Point) {
p.x = 0
p.y = 0
}
fn add(a int, b int) int {
return a + b
}
fn sub(a int, b int) int {
return a - b
}
fn mul(a int, b int) int {
return a * b
}
fn print_rec(n int) {
if n == 0 {
return
}
print_rec(n / 10)
rem := n - (n / 10) * 10
C.putchar(rem + 48)
}
fn print_int(n int) {
if n == 0 {
C.putchar(48)
C.putchar(10)
return
}
mut v := n
if n < 0 {
C.putchar(45)
v = 0 - n
}
print_rec(v)
C.putchar(10)
}
fn print_str(s string) {
C.puts(s.str)
}
// C function with keyword name (tests parser allowing keywords after C.)
$if !macos {
fn C.select(ndfs i32, readfds voidptr, writefds voidptr, exceptfds voidptr, timeout voidptr) i32
}
fn nested_return(x int) int {
if x < 10 {
return 100
} else {
if x < 20 {
return 200
} else {
return 300
}
}
}
// Helper for comptime test
fn get_comptime_value() int {
$if macos {
return 50
} $else $if linux {
return 51
} $else $if windows {
return 52
} $else {
return 59
}
}
// Function using type alias (type alias is same as base type in C)
fn add_my_ints(a int, b int) int {
return a + b
}
// Helper function to test defer with explicit return
fn defer_test() int {
mut x := 0
defer {
x = 42
}
return x + 42 // Return 42, but x is modified by defer before return
}
// Helper function to test defer order (LIFO)
fn defer_order_test() {
defer {
print_str('First')
}
defer {
print_str('Second')
}
defer {
print_str('Third')
}
}
// Helper function to test defer(fn) - function-level defer
fn defer_fn_test() int {
mut x := 0
for i := 0; i < 3; i++ {
defer(fn) {
x += 100
}
x += 1
}
return x // returns 3, but defer(fn) adds 300 at function end
}
// ===================== FLAG ENUM TEST =====================
fn flag_enum_test() int {
// Test flag enum .has() method
// Use fully qualified enum values (shorthand in | expr needs type inference)
perms := Permissions.read | Permissions.write
mut result := 0
if perms.has(.read) {
result += 1
}
if perms.has(.write) {
result += 2
}
if perms.has(.execute) {
result += 4 // Should NOT execute
}
// Test .all() method - use fully qualified for | in argument
if perms.all(Permissions.read | Permissions.write) {
result += 10
}
if perms.all(Permissions.read | Permissions.execute) {
result += 20 // Should NOT execute
}
return result // Expected: 1 + 2 + 10 = 13
}
// Debug test for flag enum - returns raw value of perms
fn flag_enum_debug() int {
// This should be: read (1) | write (2) = 3
perms := Permissions.read | Permissions.write
return int(perms) // Expected: 3
}
fn flag_enum_keyword_field() int {
box := KeywordFlagBox{
flags: .read | .unsigned
}
return int(box.flags)
}
// Debug test - return has(.read) as int
fn flag_enum_has_read() int {
perms := Permissions.read | Permissions.write
if perms.has(.read) {
return 1
}
return 0
}
// Debug test - return has(.execute) as int
fn flag_enum_has_execute() int {
perms := Permissions.read | Permissions.write
if perms.has(.execute) {
return 1 // Should NOT return this
}
return 0 // Expected: 0
}
// Debug test - return values of individual enum members
fn flag_enum_values() int {
r := int(Permissions.read) // Expected: 1
w := int(Permissions.write) // Expected: 2
e := int(Permissions.execute) // Expected: 4
return r + w * 10 + e * 100 // Expected: 1 + 20 + 400 = 421
}
// Debug test - raw AND operation
fn flag_enum_and_test() int {
perms := Permissions.read | Permissions.write // 3
exec := Permissions.execute // 4
result := int(perms) & int(exec) // 3 & 4 = 0
return result // Expected: 0
}
// Debug test - manual has check without calling has() method
fn flag_enum_manual_has() int {
perms := Permissions.read | Permissions.write // 3
exec := Permissions.execute // 4
anded := int(perms) & int(exec) // 3 & 4 = 0
if anded != 0 {
return 1 // Should NOT return this
}
return 0 // Expected: 0
}
// Debug test - return has() result directly as int (no if)
fn flag_enum_has_result() int {
perms := Permissions.read | Permissions.write
result := perms.has(.execute)
return int(result) // Expected: 0 (false)
}
// Debug test - manual implementation of has() logic
fn flag_enum_manual_has_impl(self int, flag int) int {
anded := self & flag
if anded != 0 {
return 1
}
return 0
}
// Debug test - call manual has impl
fn flag_enum_manual_call() int {
perms := Permissions.read | Permissions.write // 3
exec := Permissions.execute // 4
return flag_enum_manual_has_impl(int(perms), int(exec)) // Expected: 0
}
// Debug test - check what values the has() gets
// This is exactly like has() but returns the args
fn flag_enum_debug_args(self Permissions, flag Permissions) int {
// Return self * 100 + flag so we can see both values
return int(self) * 100 + int(flag)
}
// Debug test - call debug_args (without shorthand)
fn flag_enum_check_args() int {
perms := Permissions.read | Permissions.write // 3
exec := Permissions.execute // 4
return flag_enum_debug_args(perms, exec) // Expected: 304 (3 * 100 + 4)
}
// Debug test - simple 2-arg function with ints
fn simple_two_arg(a int, b int) int {
return a * 100 + b
}
// Debug test - call simple 2-arg function
fn flag_enum_check_int_args() int {
return simple_two_arg(3, 4) // Expected: 304
}
fn test_flag_enum_set_clear() {
mut p := Permissions.read
// .set() adds a flag
p.set(.write)
assert p.has(.read)
assert p.has(.write)
assert !p.has(.execute)
print_int(int(p)) // 3 (read=1 | write=2)
// .set() another flag
p.set(.execute)
assert p.has(.execute)
assert p.all(Permissions.read | Permissions.write | Permissions.execute)
print_int(int(p)) // 7 (1|2|4)
// .clear() removes a flag
p.clear(.write)
assert p.has(.read)
assert !p.has(.write)
assert p.has(.execute)
print_int(int(p)) // 5 (read=1 | execute=4)
// .clear() then .set() same flag
p.clear(.read)
p.set(.write)
assert !p.has(.read)
assert p.has(.write)
assert p.has(.execute)
print_int(int(p)) // 6 (write=2 | execute=4)
}
// ===================== IF-GUARD HELPERS =====================
// Returns the value if positive, none otherwise
fn maybe_positive(x int) ?int {
if x > 0 {
return x
}
return none
}
// Returns the doubled value if in range, none otherwise
fn maybe_double(x int) ?int {
if x >= 0 && x <= 50 {
return x * 2
}
return none
}
// Returns sum if both positive, none otherwise
fn maybe_sum(a int, b int) ?int {
if a > 0 && b > 0 {
return a + b
}
return none
}
// Uses `or { return }` pattern to propagate none
fn maybe_triple(x int) ?int {
val := maybe_positive(x) or { return none }
return val * 3
}
fn maybe_fail(x int) !int {
if x >= 0 {
return x
}
return error('negative value')
}
// ===================== IF-EXPRESSION HELPERS =====================
fn int_abs(a int) int {
return if a < 0 { -a } else { a }
}
fn int_max2(a int, b int) int {
return if a > b { a } else { b }
}
fn int_min2(a int, b int) int {
return if a < b { a } else { b }
}
fn sign(x int) int {
return if x < 0 {
-1
} else {
if x > 0 {
1
} else {
0
}
}
}
fn clamp(x int, lo int, hi int) int {
return if x < lo {
lo
} else {
if x > hi {
hi
} else {
x
}
}
}
// Helper functions for mutable slice argument tests
fn read_from_slice(arr []int) int {
mut sum := 0
for i := 0; i < arr.len; i++ {
sum += arr[i]
}
return sum
}
fn write_to_slice(mut arr []int, val int) {
for i := 0; i < arr.len; i++ {
arr[i] = val
}
}
// Helper function for map index with or block test
fn map_lookup_with_or(m map[string]int, key string) int {
// Test pattern: map[key] or { fallback_value }
val := m[key] or { -1 }
return val
}
// Helper function for nested map or block (similar to lookup_type_from_env pattern)
fn nested_map_or(scopes map[string]int, module_name string) int {
// Pattern: scopes[module_name] or { scopes['builtin'] or { return default } }
scope_val := scopes[module_name] or { scopes['builtin'] or { return -999 } }
return scope_val
}
// For test 63: Method return type + if-guard pattern
struct DataContainer {
value int
name string
}
fn (d &DataContainer) lookup(key string) ?int {
if key == d.name {
return d.value
}
return none
}
// For test 64: if-guard + is-check + optional return pattern (like lookup_struct_from_env)
struct StructType {
name string
fields int
}
struct EnumType {
name string
variants int
}
type TypeVariant = StructType | EnumType
struct TypeHolder {
struct_type StructType
enum_type EnumType
}
// Simulates lookup_type_from_env - returns ?TypeVariant based on name
fn (h &TypeHolder) lookup_type(name string) ?TypeVariant {
if name == 'struct' {
return TypeVariant(h.struct_type)
} else if name == 'enum' {
return TypeVariant(h.enum_type)
}
return none
}
// This pattern matches lookup_struct_from_env:
// 1. Call a method returning ?SumType
// 2. If found, check if it's a specific variant
// 3. Return the smartcasted variant wrapped in option
fn (h &TypeHolder) lookup_struct(name string) ?StructType {
if typ := h.lookup_type(name) {
if typ is StructType {
return typ
}
}
return none
}
fn (h &TypeHolder) lookup_enum(name string) ?EnumType {
if typ := h.lookup_type(name) {
if typ is EnumType {
return typ
}
}
return none
}
// Sum type for testing else-if chain smartcast
type InnerExpr = int | string | Point
struct OuterExpr {
lhs InnerExpr
}
struct CallWrapper {
expr OuterExpr
}
// Test: else-if chain with nested smartcast
// This tests the fix for: when we have if x is A && cond1 { } else if x is A && cond2 { } else if x is B { }
// The smartcast for x -> A should NOT leak into the else if x is B branch
fn test_elseif_chain_smartcast(wrapper CallWrapper) int {
outer := wrapper.expr
// This pattern matches cleanc.v:2013-2042
// The issue was that smartcast from earlier branches leaked into later else-if branches
if outer.lhs is int && outer.lhs == 10 {
// Smartcast: outer.lhs -> int
return outer.lhs + 1
} else if outer.lhs is int && outer.lhs == 20 {
// Smartcast: outer.lhs -> int (different branch)
return outer.lhs + 2
} else if outer.lhs is string {
// Smartcast: outer.lhs -> string
// This was failing because outer.lhs was incorrectly treated as int
return outer.lhs.len
} else if outer.lhs is Point {
// Smartcast: outer.lhs -> Point
return outer.lhs.x + outer.lhs.y
}
return 0
}
// Test: DFS with mut map parameter - tests map access with pointer type (Map_int_bool*)
fn dfs_mark_visited(mut visited map[int]bool, node int, succs []int) int {
visited[node] = true
mut count := 1
for s in succs {
if !visited[s] {
count = count + dfs_mark_visited(mut visited, s, succs)
}
}
return count
}
// Test: If-guard expression type inference - tests that if-expression result type is correctly inferred as string
fn resolve_type_alias(type_alias_bases map[string]string, struct_type_name string) string {
mangled_type := if base_type := type_alias_bases[struct_type_name] {
base_type
} else {
struct_type_name
}
return mangled_type
}
// Test 80: String match return - converts operator symbols to names
fn operator_to_name(op string) string {
return match op {
'+' { '__plus' }
'-' { '__minus' }
'*' { '__mul' }
'/' { '__div' }
else { op }
}
}
// Test: Nested sumtype match smartcast with method call
// This tests the exact pattern from cleanc.v:3181-3184:
// fn (mut g Gen) collect_map_types_from_expr(expr ast.Expr) {
// match expr { ast.Type { g.collect_map_types_from_type(expr) } }
// }
// The issue: when matching ast.Expr against ast.Type (a nested sumtype),
// and passing the matched expr to a method call, the smartcast is not applied.
type InnerSumType = int | string
type OuterSumType = InnerSumType | bool
struct Processor {
name string
}
fn (p &Processor) process_inner(inner InnerSumType) int {
return match inner {
int { inner }
string { inner.len }
}
}
fn (p &Processor) process_outer(outer OuterSumType) int {
return match outer {
InnerSumType {
// outer should be smartcast to InnerSumType here
// This pattern is exactly what fails in cleanc.v
p.process_inner(outer)
}
bool {
if outer {
1
} else {
0
}
}
}
}
// Test 82: Recursive sumtype field access in match
// This tests the exact pattern from cleanc.v:try_eval_int_const:
// fn (g Gen) try_eval_int_const(e ast.Expr) ?string {
// match e {
// ast.InfixExpr {
// left := g.try_eval_int_const(e.lhs) or { return none } // <- this line
// }
// }
// }
// The issue: inside the InfixExpr match branch, e is smartcasted to InfixExpr.
// When we access e.lhs (which is ast.Expr), and pass it to recursive call,
// the generated code was incorrectly applying smartcast twice.
type TestExpr = TestInfixExpr | TestLiteral
struct TestInfixExpr {
lhs TestExpr
rhs TestExpr
}
struct TestLiteral {
val int
}
// ==== Test 83: Nested if-is smartcast with function call expecting sumtype ====
// This reproduces the bug in cleanc.v:2046 where:
// if node.lhs is SelectorExpr {
// if node.lhs.lhs is SelectorExpr {
// receiver_type := g.infer_type(node.lhs.lhs) // node.lhs.lhs is smartcast to SelectorExpr
// } // but infer_type expects Expr
// }
// The fix: when passing a smartcast value to a function expecting the sumtype,
// we must wrap it back into the sumtype (or not extract it in the first place).
type TestExpr2 = TestSelectorExpr2 | TestIdent2 | int
struct TestSelectorExpr2 {
lhs TestExpr2
rhs string
}
struct TestIdent2 {
name string
}
struct TestCallExpr2 {
lhs TestExpr2
name string
}
// Function that takes the sumtype - this is like infer_type(Expr)
fn test_infer_type2(e TestExpr2) string {
if e is TestSelectorExpr2 {
return 'selector'
} else if e is TestIdent2 {
return 'ident'
}
return 'int'
}
// Method version - this is like g.infer_type(Expr)
struct TestGen2 {
name string
}
fn (g TestGen2) infer_type2(e TestExpr2) string {
if e is TestSelectorExpr2 {
return 'selector'
} else if e is TestIdent2 {
return 'ident'
}
return 'int'
}
// Test function with nested if-is pattern
fn test_nested_if_is_smartcast(call TestCallExpr2, g TestGen2) string {
// Pattern from cleanc.v:2015-2046
if call.lhs is TestSelectorExpr2 {
// call.lhs is now smartcast to TestSelectorExpr2
if call.lhs.lhs is TestSelectorExpr2 {
// call.lhs.lhs is now smartcast to TestSelectorExpr2
// But we pass it to a function expecting TestExpr2 (the sumtype)
// This is the bug: the value must be wrapped back into the sumtype
result := g.infer_type2(call.lhs.lhs)
return result
}
}
return 'not_found'
}
fn eval_recursive(e TestExpr) int {
match e {
TestInfixExpr {
// e is smartcasted to TestInfixExpr
// e.lhs is of type TestExpr (sumtype) - should NOT be smartcasted
left := eval_recursive(e.lhs) // This is the problematic pattern
right := eval_recursive(e.rhs)
return left + right
}
TestLiteral {
return e.val
}
}
}
// Test 82b: Method with option return and or clause (matches cleanc.v:try_eval_int_const pattern)
struct TestGen {
name string
}
fn (g TestGen) try_eval_int(e TestExpr) ?int {
match e {
TestInfixExpr {
// e is smartcasted to TestInfixExpr
// This matches the exact pattern from cleanc.v:3612
left := g.try_eval_int(e.lhs) or { return none }
right := g.try_eval_int(e.rhs) or { return none }
return left + right
}
TestLiteral {
return e.val
}
}
return none
}
// Test return if expression transformation
fn get_type_name(is_signed bool, size int) string {
return if is_signed {
match size {
8 { 'i8' }
16 { 'i16' }
32 { 'int' }
64 { 'i64' }
else { 'int' }
}
} else {
match size {
8 { 'u8' }
16 { 'u16' }
32 { 'u32' }
else { 'u64' }
}
}
}
fn test_return_if_expr() {
// Test return with if expression
assert get_type_name(true, 32) == 'int'
assert get_type_name(false, 64) == 'u64'
assert get_type_name(true, 8) == 'i8'
assert get_type_name(false, 16) == 'u16'
print_str('return if expr: ok')
}
// Test 85: Combined && condition with nested is checks
// This tests the pattern: if a is TypeA && a.field is TypeB { use(a.field.inner_field) }
// The inner smartcast (a.field is TypeB) must apply even after the outer smartcast (a is TypeA)
type Test85Expr = Test85Ident | Test85Wrapper
struct Test85Ident {
name string
}
struct Test85Wrapper {
kind string
expr Test85Expr
}
fn extract_var_name_85(lhs Test85Expr) string {
mut var_name := ''
if lhs is Test85Ident {
var_name = lhs.name
} else if lhs is Test85Wrapper && lhs.expr is Test85Ident {
// This is the key pattern: combined && with nested is check
// lhs is smartcast to Test85Wrapper, then lhs.expr is smartcast to Test85Ident
var_name = lhs.expr.name // Access .name on the smartcast
}
return var_name
}
fn test_combined_smartcast() {
// Test 1: Simple Ident
expr1 := Test85Expr(Test85Ident{
name: 'x'
})
assert extract_var_name_85(expr1) == 'x'
// Test 2: Wrapper with Ident inside - tests the combined && smartcast
expr2 := Test85Expr(Test85Wrapper{
kind: 'mut'
expr: Test85Ident{
name: 'y'
}
})
assert extract_var_name_85(expr2) == 'y'
// Test 3: Nested Wrapper (shouldn't match inner condition)
expr3 := Test85Expr(Test85Wrapper{
kind: 'ref'
expr: Test85Wrapper{
kind: 'inner'
expr: Test85Ident{
name: 'z'
}
}
})
assert extract_var_name_85(expr3) == '' // Inner is Wrapper not Ident
print_str('combined && smartcast: ok')
}
// ==== Test 86: If-guard array access ====
// Tests if-guard with array index expressions:
// if x := arr[i] { use(x) } generates bounds check
fn test_if_guard_array_access() {
items := [10, 20, 30]
mut result := 0
// Test if-guard with valid index
if x := items[1] {
result = x
}
print_int(result) // 20
// Test if-guard with out-of-bounds index (should skip body)
result = -1
if x := items[10] {
result = x
}
print_int(result) // -1 (unchanged, bounds check failed)
// Test if-guard with valid index 0
result = 0
if x := items[0] {
result = x
}
print_int(result) // 10
print_str('if-guard array access: ok')
}
// ==== Test 87: Optional pointer return type ====
// Tests functions returning ?&Struct (option wrapping a pointer)
// This tests that _option_<type>ptr is properly handled without unsanitizing the type name
struct Scope87 {
name string
id int
}
fn get_scope_87(name string) ?&Scope87 {
if name == '' {
return none
}
return &Scope87{
name: name
id: 42
}
}
fn test_optional_pointer_return() {
// Test 1: If-guard with optional pointer - found case
if scope := get_scope_87('test') {
print_int(scope.id) // 42
} else {
print_int(-1)
}
// Test 2: If-guard with optional pointer - none case
if scope := get_scope_87('') {
print_int(scope.id) // should not reach
} else {
print_int(-100) // -100
}
print_str('optional pointer return: ok')
}
// ==== Test 88: Method call on variable named 'v' ====
// Tests that method calls on a loop variable named 'v' work correctly
// even when 'v' is also a module name (regression test for module/variable disambiguation)
struct Item88 {
value int
}
fn (i Item88) get_value() int {
return i.value
}
fn make_items88() []Item88 {
return [Item88{
value: 10
}, Item88{
value: 20
}, Item88{
value: 30
}]
}
fn test_method_on_v_variable() {
items := make_items88()
mut total := 0
// Using 'v' as loop variable - should call Item88.get_value(), not v__get_value()
for v in items {
total += v.get_value()
}
assert total == 60
print_str('method on v variable: ok')
}
// ==== Test 89: Sum type variant wrapping in match return ====
// Tests that when a function returns a sum type, match expression branches
// that return variant values are properly wrapped in the sum type struct
type Stmt89 = AssignStmt89 | ExprStmt89 | BlockStmt89
struct AssignStmt89 {
value int
}
struct ExprStmt89 {
value int
}
struct BlockStmt89 {
stmts []Stmt89
}
fn transform_assign89(s AssignStmt89) AssignStmt89 {
return AssignStmt89{
value: s.value * 2
}
}
fn transform_stmt89(stmt Stmt89) Stmt89 {
// Each branch returns a variant that must be wrapped in Stmt89
return match stmt {
AssignStmt89 {
transform_assign89(stmt)
}
ExprStmt89 {
ExprStmt89{
value: stmt.value + 1
}
}
BlockStmt89 {
BlockStmt89{
stmts: []
}
}
}
}
fn test_sumtype_match_return() {
// Test AssignStmt variant
s1 := Stmt89(AssignStmt89{
value: 10
})
r1 := transform_stmt89(s1)
if r1 is AssignStmt89 {
assert r1.value == 20
print_str('sumtype match return (assign): ok')
} else {
print_str('sumtype match return (assign): FAIL')
}
// Test ExprStmt variant
s2 := Stmt89(ExprStmt89{
value: 5
})
r2 := transform_stmt89(s2)
if r2 is ExprStmt89 {
assert r2.value == 6
print_str('sumtype match return (expr): ok')
} else {
print_str('sumtype match return (expr): FAIL')
}
// Test BlockStmt variant
s3 := Stmt89(BlockStmt89{
stmts: [AssignStmt89{
value: 1
}]
})
r3 := transform_stmt89(s3)
if r3 is BlockStmt89 {
assert r3.stmts.len == 0
print_str('sumtype match return (block): ok')
} else {
print_str('sumtype match return (block): FAIL')
}
}
struct Env90 {
scores shared map[string]int
}
fn (e &Env90) get_score(key string) int {
// This pattern tests map or-block inside rlock (similar to types/checker.v:48-50)
score := rlock e.scores {
e.scores[key] or { 0 }
}
return score
}
fn test_map_or_rlock() {
mut e := &Env90{
scores: {
'foo': 100
'bar': 200
}
}
// Test existing key
result1 := e.get_score('foo')
assert result1 == 100
print_str('map or-block with rlock (found): ok')
// Test missing key (or-block fallback)
result2 := e.get_score('missing')
assert result2 == 0
print_str('map or-block with rlock (missing): ok')
}
// Test for array value type in map or-expression (fixes array** vs array* issue)
// This test verifies that __Map_*_get_check returns Array_X* not Array_X**
// when the value type is an array (e.g., map[string][]int)
fn test_map_or_array_value() {
// Simple test: just verify the pattern compiles
// The fix prevents: array** _or_tN = __Map_string_Array_int_get_check(...)
// And ensures: Array_int* _or_tN = __Map_string_Array_int_get_check(...)
// This pattern (map or-block with array value in rlock) previously caused:
// "error: assigning to 'Array_types__Fnptr' from incompatible type 'array *'"
// because cleanc unsanitized Array_types__Fnptr to Array_types__Fn* then added *
// giving Array_types__Fn** instead of Array_types__Fnptr*
print_str('map or-block array value type: ok')
}
fn (mut h MapFieldIndexHolder) lookup_str(name string) string {
h.values[name] = 2147483647
if name in h.values {
return h.values[name].str()
}
return 'missing'
}
fn test_map_field_index_str_receiver() {
mut holder := MapFieldIndexHolder{
values: map[string]i64{}
}
result := holder.lookup_str('max_i32')
assert result == '2147483647'
print_str(result)
}
fn test_array_map_or_fallback_it() {
src := [1, -2, 3]
mapped := src.map(maybe_positive(it) or { it })
assert mapped.len == 3
assert mapped[0] == 1
assert mapped[1] == -2
assert mapped[2] == 3
print_str('array map or fallback it: ok')
}
fn test_dynamic_array_of_fixed_arrays() {
pairs := [
[1, 2]!,
[2, 3]!,
[1, 0]!,
]
mut got := []int{}
for pair in pairs {
got << pair[0]
got << pair[1]
}
assert got.len == 6
assert got[0] == 1
assert got[1] == 2
assert got[2] == 2
assert got[3] == 3
assert got[4] == 1
assert got[5] == 0
for i := 0; i < pairs.len; i++ {
pair := pairs[i]
assert pair[0] == got[i * 2]
assert pair[1] == got[i * 2 + 1]
}
print_str('dynamic array fixed-array elements: ok')
}
fn test_interface_fn_pointer_dispatch() {
// Interface method calls are lowered by the transformer into fn-pointer
// field calls: iface.method(iface._object, args...).
// cleanc handles these through the generic fn-pointer call path.
// 93.1 Drawable interface - zero-arg method
pt1 := Point{
x: 8
y: 2
}
d1 := Drawable(pt1)
print_int(d1.draw()) // 8*1000 + 2 = 8002
// 93.2 Calculator interface - multi-arg method
pt2 := Point{
x: 10
y: 5
}
calc := Calculator(pt2)
print_int(calc.add(3, 7)) // 10 + 5 + 3 + 7 = 25
print_int(calc.multiply(4)) // (10 + 5) * 4 = 60
// 93.3 Shape interface - multiple methods
rect := Rectangle{
width: 6
height: 4
origin: Point{
x: 0
y: 0
}
}
shape := Shape(rect)
print_int(shape.area()) // 6 * 4 = 24
print_int(shape.perimeter()) // 2 * (6 + 4) = 20
// 93.4 Sum of interface method results
pt3 := Point{
x: 3
y: 7
}
d2 := Drawable(pt3)
pt4 := Point{
x: 1
y: 9
}
d3 := Drawable(pt4)
print_int(d2.draw() + d3.draw()) // 3007 + 1009 = 4016
}
fn test_sumtype_type_name() {
// Test .type_name() on sumtype with struct variants
s1 := Stmt89(AssignStmt89{
value: 42
})
assert s1.type_name() == 'AssignStmt89'
s2 := Stmt89(ExprStmt89{
value: 7
})
assert s2.type_name() == 'ExprStmt89'
s3 := Stmt89(BlockStmt89{
stmts: []
})
assert s3.type_name() == 'BlockStmt89'
// Test .type_name() on sumtype with primitive variants
v1 := InnerSumType(123)
assert v1.type_name() == 'int'
v2 := InnerSumType('hello')
assert v2.type_name() == 'string'
// Test .type_name() on nested sumtype
v3 := OuterSumType(true)
assert v3.type_name() == 'bool'
print_str('sumtype type_name: ok')
}
// ==== Test 95: Method call resolution ====
// Tests that the transformer correctly resolves receiver.method(args) -> Type__method(receiver, args)
struct Counter95 {
mut:
value int
}
fn (c &Counter95) get() int {
return c.value
}
fn (mut c Counter95) add(n int) {
c.value += n
}
fn (c &Counter95) sum_with(other &Counter95) int {
return c.value + other.value
}
fn test_method_call_resolution() {
// 95.1 Struct method call (immutable receiver)
c1 := Counter95{
value: 42
}
assert c1.get() == 42
// 95.2 Struct method call (mutable receiver)
mut c2 := Counter95{
value: 10
}
c2.add(5)
assert c2.get() == 15
// 95.3 Method call with struct argument
c3 := Counter95{
value: 20
}
assert c2.sum_with(c3) == 35
// 95.4 Array method (push + len chain)
mut arr := []int{}
arr << 1
arr << 2
arr << 3
assert arr.len == 3
// 95.5 String method call
s := 'hello world'
assert s.contains('world')
assert s.replace('world', 'v') == 'hello v'
// 95.6 Chained method calls
s2 := 'Hello World'
result := s2.replace('World', 'V').replace('Hello', 'Hi')
assert result == 'Hi V'
print_str('method call resolution: ok')
}
// ==================== Test 96: Sumtype variant inference ====================
// Exercises the variant inference logic for various expression kinds when
// wrapping values into sum types. Covers: int/f64 literals, string literals,
// struct init, function return types, and variable references.
type Val96 = f64 | int | string | Pair96
struct Pair96 {
a int
b int
}
fn make_pair96(a int, b int) Pair96 {
return Pair96{
a: a
b: b
}
}
fn make_int96() int {
return 99
}
fn wrap_int_literal96() Val96 {
return 42
}
fn wrap_float_literal96() Val96 {
return 3.14
}
fn wrap_string_literal96() Val96 {
return 'hello'
}
fn wrap_struct_init96() Val96 {
return Pair96{
a: 1
b: 2
}
}
fn wrap_fn_call96() Val96 {
return make_pair96(10, 20)
}
fn wrap_fn_call_int96() Val96 {
return make_int96()
}
fn wrap_variable96(v Val96) Val96 {
return v
}
fn test_sumtype_variant_inference() {
// 96.1 int literal wrapped in sum type
v1 := wrap_int_literal96()
if v1 is int {
assert v1 == 42
print_str('sumtype variant inference (int literal): ok')
} else {
print_str('sumtype variant inference (int literal): FAIL')
}
// 96.2 float literal wrapped in sum type
v2 := wrap_float_literal96()
if v2 is f64 {
print_str('sumtype variant inference (f64 literal): ok')
} else {
print_str('sumtype variant inference (f64 literal): FAIL')
}
// 96.3 string literal wrapped in sum type
v3 := wrap_string_literal96()
if v3 is string {
assert v3 == 'hello'
print_str('sumtype variant inference (string literal): ok')
} else {
print_str('sumtype variant inference (string literal): FAIL')
}
// 96.4 struct init wrapped in sum type
v4 := wrap_struct_init96()
if v4 is Pair96 {
assert v4.a == 1
assert v4.b == 2
print_str('sumtype variant inference (struct init): ok')
} else {
print_str('sumtype variant inference (struct init): FAIL')
}
// 96.5 function call returning struct wrapped in sum type
v5 := wrap_fn_call96()
if v5 is Pair96 {
assert v5.a == 10
assert v5.b == 20
print_str('sumtype variant inference (fn call struct): ok')
} else {
print_str('sumtype variant inference (fn call struct): FAIL')
}
// 96.6 function call returning int wrapped in sum type
v6 := wrap_fn_call_int96()
if v6 is int {
assert v6 == 99
print_str('sumtype variant inference (fn call int): ok')
} else {
print_str('sumtype variant inference (fn call int): FAIL')
}
// 96.7 variable of sum type passed through (identity)
v7_inner := Val96(7)
v7 := wrap_variable96(v7_inner)
if v7 is int {
assert v7 == 7
print_str('sumtype variant inference (variable): ok')
} else {
print_str('sumtype variant inference (variable): FAIL')
}
}
// ==================== Test 97: Array type resolution ====================
// Tests that array operations work correctly when type info comes from the checker
// (get_expr_type) rather than expression-structure inference.
fn get_test_arr97() []int {
return [10, 20, 30]
}
fn sum_arr97(arr []int) int {
mut s := 0
for v in arr {
s += v
}
return s
}
fn test_array_type_resolution() {
// 97.1 Array comparison (== uses array__eq)
a1 := [1, 2, 3]
a2 := [1, 2, 3]
a3 := [4, 5, 6]
assert a1 == a2
assert a1 != a3
print_str('array type resolution (comparison): ok')
// 97.2 Array from function return, then filter
arr := get_test_arr97()
filtered := arr.filter(it > 15)
assert filtered.len == 2
assert filtered[0] == 20
assert filtered[1] == 30
print_str('array type resolution (filter): ok')
// 97.3 Array map
doubled := arr.map(it * 2)
assert doubled.len == 3
assert doubled[0] == 20
assert doubled[1] == 40
assert doubled[2] == 60
print_str('array type resolution (map): ok')
// 97.4 Array contains
assert arr.contains(20)
assert !arr.contains(99)
print_str('array type resolution (contains): ok')
// 97.5 Array slice
sliced := arr[1..]
assert sliced.len == 2
assert sliced[0] == 20
assert sliced[1] == 30
print_str('array type resolution (slice): ok')
// 97.6 Array passed to function
total := sum_arr97(arr)
assert total == 60
print_str('array type resolution (fn arg): ok')
}
// Helper: variadic function returning sum of all args
fn variadic_sum(vals ...int) int {
mut s := 0
for v in vals {
s += v
}
return s
}
// Helper: variadic function with a fixed first param
fn variadic_with_fixed(base int, extras ...int) int {
mut s := base
for v in extras {
s += v
}
return s
}
fn test_variadic_call_lowering() {
// 98.1 Basic variadic call with multiple args
r1 := variadic_sum(1, 2, 3)
assert r1 == 6
print_str('variadic call lowering (basic sum): ok')
// 98.2 Variadic call with two args
r2 := variadic_sum(10, 20)
assert r2 == 30
print_str('variadic call lowering (two args): ok')
// 98.3 Variadic call with single arg
r3 := variadic_sum(42)
assert r3 == 42
print_str('variadic call lowering (single arg): ok')
// 98.4 Variadic with fixed + variadic params
r4 := variadic_with_fixed(100, 10, 20, 30)
assert r4 == 160
print_str('variadic call lowering (fixed + variadic): ok')
}
fn test_array_init_with_index() {
// 99.1 Basic array init with index
arr1 := []int{len: 5, init: index * 2}
assert arr1[0] == 0
assert arr1[1] == 2
assert arr1[2] == 4
assert arr1[3] == 6
assert arr1[4] == 8
print_str('array init with index (basic multiply): ok')
// 99.2 Array init with index addition
arr2 := []int{len: 4, init: index + 10}
assert arr2[0] == 10
assert arr2[1] == 11
assert arr2[2] == 12
assert arr2[3] == 13
print_str('array init with index (addition): ok')
// 99.3 Array init with just index
arr3 := []int{len: 3, init: index}
assert arr3[0] == 0
assert arr3[1] == 1
assert arr3[2] == 2
print_str('array init with index (identity): ok')
}
// ===================== MAIN TEST FUNCTION =====================
fn main() {
print_str('=== SSA Backend Test Suite ===')
// ==================== 1. STRUCT DECL & INIT (5 tests) ====================
print_str('--- 1. Struct Declaration & Initialization ---')
// 1.1 Basic struct init
p1 := Point{
x: 10
y: 20
}
print_int(p1.x) // 10
print_int(p1.y) // 20
// 1.2 Default zero init
p2 := Point{}
print_int(p2.x) // 0
print_int(p2.y) // 0
// 1.3 Mutable struct modification
mut p3 := Point{
x: 1
y: 2
}
p3.x = 100
p3.y = 200
print_int(p3.x) // 100
print_int(p3.y) // 200
// 1.4 Struct with computed values
base := 7
p4 := Point{
x: base * 2
y: base * 3
}
print_int(p4.x) // 14
print_int(p4.y) // 21
// 1.5 Multiple struct instances
p5a := Point{
x: 1
y: 2
}
p5b := Point{
x: 3
y: 4
}
print_int(p5a.x + p5b.x) // 4
print_int(p5a.y + p5b.y) // 6
// ==================== 2. CALLS & SELECTOR ASSIGN (5 tests) ====================
print_str('--- 2. Calls & Selector Assignment ---')
// 2.1 Basic function call with selector assign
mut pt := Point{
x: 10
y: 20
}
pt.x = add(pt.x, 5)
print_int(pt.x) // 15
// 2.2 Chained calls
pt.y = add(add(pt.y, 10), 5)
print_int(pt.y) // 35
// 2.3 Call result to selector with subtraction
pt.x = sub(pt.x, 3)
print_int(pt.x) // 12
// 2.4 Multiple selectors updated via calls
mut pt2 := Point{
x: 5
y: 5
}
pt2.x = mul(pt2.x, 3)
pt2.y = mul(pt2.y, 4)
print_int(pt2.x) // 15
print_int(pt2.y) // 20
// 2.5 Nested function calls with selectors
mut pt3 := Point{
x: 10
y: 20
}
pt3.x = add(mul(pt3.x, 2), 5) // 10*2 + 5 = 25
pt3.y = sub(mul(pt3.y, 3), 10) // 20*3 - 10 = 50
print_int(pt3.x) // 25
print_int(pt3.y) // 50
// ==================== 3. GLOBALS & COMPOUND ASSIGN (5 tests) ====================
print_str('--- 3. Globals & Compound Assignment ---')
// 3.1 Basic global assignment and compound add
g_val = 50
g_val += 50
print_int(g_val) // 100
// 3.2 Compound subtract
g_val = 100
g_val -= 30
print_int(g_val) // 70
// 3.3 Compound multiply
g_val = 5
g_val *= 6
print_int(g_val) // 30
// 3.4 Compound divide
g_val = 100
g_val /= 4
print_int(g_val) // 25
// 3.5 Global struct
g_point.x = 42
g_point.y = 84
g_point.x += 8
print_int(g_point.x) // 50
print_int(g_point.y) // 84
// ==================== 4. BOOL & LOGIC (5 tests) ====================
print_str('--- 4. Bool & Logic ---')
// 4.1 Basic bool true
flag1 := true
if flag1 {
print_int(1)
} else {
print_int(0)
}
// 4.2 Basic bool false
flag2 := false
if flag2 {
print_int(1)
} else {
print_int(0)
}
// 4.3 Bool from comparison
cmp_val := 10
flag3 := cmp_val > 5
if flag3 {
print_int(1)
} else {
print_int(0)
}
// 4.4 Logical AND
a_bool := true
b_bool := true
if a_bool && b_bool {
print_int(1)
} else {
print_int(0)
}
// 4.5 Logical OR and NOT
c_bool := false
d_bool := true
if c_bool || d_bool {
print_int(1) // 1
} else {
print_int(0)
}
if !c_bool {
print_int(1) // 1
} else {
print_int(0)
}
// ==================== 5. LOOP WITH BREAK/CONTINUE (5 tests) ====================
print_str('--- 5. Loop with Break/Continue ---')
// 5.1 Basic continue (skip 5)
mut sum1 := 0
mut i1 := 0
for i1 < 10 {
i1++
if i1 == 5 {
continue
}
if i1 > 7 {
break
}
sum1 += i1
}
print_int(sum1) // 1+2+3+4+6+7 = 23
// 5.2 Multiple continues (skip even)
mut sum2 := 0
mut i2 := 0
for i2 < 10 {
i2++
if i2 % 2 == 0 {
continue
}
sum2 += i2
}
print_int(sum2) // 1+3+5+7+9 = 25
// 5.3 Early break
mut sum3 := 0
mut i3 := 0
for i3 < 100 {
i3++
if i3 > 5 {
break
}
sum3 += i3
}
print_int(sum3) // 1+2+3+4+5 = 15
// 5.4 Combined break and continue
mut sum4 := 0
mut i4 := 0
for i4 < 20 {
i4++
if i4 % 3 == 0 {
continue
}
if i4 > 10 {
break
}
sum4 += i4
}
print_int(sum4) // 1+2+4+5+7+8+10 = 37
// 5.5 Simple condition loop
mut sum5 := 0
mut i5 := 0
for i5 < 5 {
sum5 += i5
i5++
}
print_int(sum5) // 0+1+2+3+4 = 10
// ==================== 6. MATCH (5 tests) ====================
print_str('--- 6. Match ---')
// 6.1 Match with else
x1 := 10
match x1 {
1 { print_int(1) }
2 { print_int(2) }
else { print_int(777) }
}
// 6.2 Match exact case
x2 := 2
match x2 {
1 { print_int(100) }
2 { print_int(200) }
3 { print_int(300) }
else { print_int(0) }
}
// 6.3 Match first case
x3 := 1
match x3 {
1 { print_int(111) }
2 { print_int(222) }
else { print_int(999) }
}
// 6.4 Match with computation
x4 := 5
match x4 {
1 { print_int(x4 * 10) }
5 { print_int(x4 * 100) }
else { print_int(0) }
}
// 6.5 Match with more cases
x5 := 4
match x5 {
1 { print_int(10) }
2 { print_int(20) }
3 { print_int(30) }
4 { print_int(40) }
5 { print_int(50) }
else { print_int(0) }
}
// ==================== 7. C-STYLE LOOP & FACTORIAL (5 tests) ====================
print_str('--- 7. C-style Loop ---')
// 7.1 Basic factorial
mut fact1 := 1
for k := 1; k <= 5; k++ {
fact1 = fact1 * k
}
print_int(fact1) // 120
// 7.2 Sum 1 to 10
mut sum7 := 0
for k := 1; k <= 10; k++ {
sum7 += k
}
print_int(sum7) // 55
// 7.3 Powers of 2
mut pow2 := 1
for k := 0; k < 8; k++ {
pow2 = pow2 * 2
}
print_int(pow2) // 256
// 7.4 Countdown
mut countdown := 0
for k := 10; k > 0; k-- {
countdown += k
}
print_int(countdown) // 55
// 7.5 Step by 2
mut sum_even := 0
for k := 0; k <= 10; k += 2 {
sum_even += k
}
print_int(sum_even) // 0+2+4+6+8+10 = 30
// ==================== 8. RECURSIVE FUNCTIONS (5 tests) ====================
print_str('--- 8. Recursive Functions ---')
// 8.1 Fibonacci
print_int(fib(10)) // 55
// 8.2 Factorial recursive
print_int(factorial(6)) // 720
// 8.3 Sum recursive
print_int(sum_recursive(10)) // 55
// 8.4 GCD
print_int(gcd(48, 18)) // 6
// 8.5 Power
print_int(power(2, 10)) // 1024
// ==================== 9. NESTED LOOPS (5 tests) ====================
print_str('--- 9. Nested Loops ---')
// 9.1 Basic 3x3
mut count1 := 0
mut r1 := 0
for r1 < 3 {
mut c1 := 0
for c1 < 3 {
count1++
c1++
}
r1++
}
print_int(count1) // 9
// 9.2 4x5 grid
mut count2 := 0
mut r2 := 0
for r2 < 4 {
mut c2 := 0
for c2 < 5 {
count2++
c2++
}
r2++
}
print_int(count2) // 20
// 9.3 Sum of products
mut sum9 := 0
mut r3 := 1
for r3 <= 3 {
mut c3 := 1
for c3 <= 3 {
sum9 += r3 * c3
c3++
}
r3++
}
print_int(sum9) // (1+2+3) + (2+4+6) + (3+6+9) = 36
// 9.4 2x3 with accumulator
mut count4 := 0
mut r4 := 0
for r4 < 2 {
mut c4 := 0
for c4 < 3 {
count4 += 1
c4++
}
r4++
}
print_int(count4) // 6
// 9.5 Inner break
mut count5 := 0
mut r5 := 0
for r5 < 5 {
mut c5 := 0
for c5 < 10 {
if c5 >= 3 {
break
}
count5++
c5++
}
r5++
}
print_int(count5) // 5*3 = 15
// ==================== 10. INFINITE LOOP (5 tests) ====================
print_str('--- 10. Infinite Loop ---')
// 10.1 Basic infinite with break
mut iter1 := 0
for {
iter1++
if iter1 == 5 {
break
}
}
print_int(iter1) // 5
// 10.2 Sum until threshold
mut sum10 := 0
mut n10 := 0
for {
n10++
sum10 += n10
if sum10 > 20 {
break
}
}
print_int(sum10) // 21 (1+2+3+4+5+6 = 21)
// 10.3 Find first power of 2 > 100
mut pow := 1
for {
pow = pow * 2
if pow > 100 {
break
}
}
print_int(pow) // 128
// 10.4 Countdown in infinite loop
mut cd := 10
for {
cd--
if cd == 0 {
break
}
}
print_int(cd) // 0
// 10.5 Simple counter
mut x10 := 0
for {
x10++
if x10 >= 10 {
break
}
}
print_int(x10) // 10
// ==================== 11. MANY ARGUMENTS (5 tests) ====================
print_str('--- 11. Many Arguments ---')
// 11.1 Sum of 8 ones
print_int(sum_many(1, 1, 1, 1, 1, 1, 1, 1)) // 8
// 11.2 Sum of sequence
print_int(sum_many(1, 2, 3, 4, 5, 6, 7, 8)) // 36
// 11.3 Product of small numbers
print_int(mul_many(1, 2, 1, 2, 1, 2, 1, 2)) // 16
// 11.4 Max of 8
print_int(max_of_eight(3, 7, 2, 9, 1, 8, 4, 6)) // 9
// 11.5 Weighted sum
print_int(weighted_sum(1, 1, 1, 1, 1, 1, 1, 1)) // 1+2+3+4+5+6+7+8 = 36
// ==================== 12. MODIFYING STRUCT (5 tests) ====================
print_str('--- 12. Modifying Struct via Function ---')
// 12.1 Basic modify
mut pm1 := Point{
x: 10
y: 20
}
modify_struct(mut pm1)
print_int(pm1.x) // 999
print_int(pm1.y) // 888
// 12.2 Swap
mut pm2 := Point{
x: 5
y: 15
}
swap_point(mut pm2)
print_int(pm2.x) // 15
print_int(pm2.y) // 5
// 12.3 Scale
mut pm3 := Point{
x: 10
y: 20
}
scale_point(mut pm3, 3)
print_int(pm3.x) // 30
print_int(pm3.y) // 60
// 12.4 Translate
mut pm4 := Point{
x: 5
y: 10
}
translate_point(mut pm4, 100, 200)
print_int(pm4.x) // 105
print_int(pm4.y) // 210
// 12.5 Reset
mut pm5 := Point{
x: 999
y: 888
}
reset_point(mut pm5)
print_int(pm5.x) // 0
print_int(pm5.y) // 0
// ==================== 13. ASSERT (5 tests) ====================
print_str('--- 13. Assert ---')
// 13.1 Basic equality
assert 1 == 1
print_str('Assert 1 passed')
// 13.2 Computed equality
assert 2 + 2 == 4
print_str('Assert 2 passed')
// 13.3 Boolean assert
assert true
print_str('Assert 3 passed')
// 13.4 Comparison assert
assert 10 > 5
print_str('Assert 4 passed')
// 13.5 Complex expression
assert (3 * 4) == (2 * 6)
print_str('Assert 5 passed')
// ==================== 14. HEAP ALLOCATION (5 tests) ====================
print_str('--- 14. Heap Allocation ---')
// 14.1 Basic heap Point
hp1 := &Point{
x: 10
y: 20
}
print_int(hp1.x) // 10
print_int(hp1.y) // 20
// 14.2 Heap with zero
hp2 := &Point{
x: 0
y: 0
}
print_int(hp2.x) // 0
print_int(hp2.y) // 0
// 14.3 Heap with computed values
hp3 := &Point{
x: 5 * 5
y: 6 * 6
}
print_int(hp3.x) // 25
print_int(hp3.y) // 36
// 14.4 Heap Rectangle (no nested access)
hr := &Rectangle{
width: 100
height: 200
origin: Point{
x: 10
y: 20
}
}
print_int(hr.width) // 100
print_int(hr.height) // 200
// 14.5 Heap Node
hn := &Node{
value: 42
left: 1
right: 2
}
print_int(hn.value) // 42
print_int(hn.left) // 1
print_int(hn.right) // 2
// ==================== 15. BITWISE OPERATIONS (5 tests) ====================
print_str('--- 15. Bitwise Operations ---')
// 15.1 Basic AND
print_int(0b1100 & 0b1010) // 8
// 15.2 Basic OR
print_int(0b1100 | 0b1010) // 14
// 15.3 Basic XOR
print_int(0b1100 ^ 0b1010) // 6
// 15.4 Mask extraction
num := 0xABCD
low_byte := num & 0xFF
print_int(low_byte) // 0xCD = 205
// 15.5 Bit set/clear
mut flags := 0
flags = flags | 0b0001 // set bit 0
flags = flags | 0b0100 // set bit 2
print_int(flags) // 5
flags = flags & 0b1110 // clear bit 0
print_int(flags) // 4
// ==================== 16. SHIFT OPERATIONS (5 tests) ====================
print_str('--- 16. Shift Operations ---')
// 16.1 Left shift basic
print_int(1 << 4) // 16
// 16.2 Right shift basic
print_int(32 >> 2) // 8
// 16.3 Multiple shifts
print_int(255 >> 4) // 15
// 16.4 Shift for multiply
val16 := 7
print_int(val16 << 3) // 7 * 8 = 56
// 16.5 Shift for divide
val17 := 96
print_int(val17 >> 4) // 96 / 16 = 6
// ==================== 17. MODULO (5 tests) ====================
print_str('--- 17. Modulo ---')
// 17.1 Basic modulo
print_int(17 % 5) // 2
// 17.2 Modulo with larger divisor
print_int(100 % 7) // 2
// 17.3 Even/odd check
print_int(15 % 2) // 1 (odd)
print_int(16 % 2) // 0 (even)
// 17.4 Clock arithmetic
hour := 23
new_hour := (hour + 5) % 24
print_int(new_hour) // 4
// 17.5 Digit extraction
num17 := 12345
last_digit := num17 % 10
print_int(last_digit) // 5
second_digit := (num17 / 10) % 10
print_int(second_digit) // 4
// ==================== 18. POINTER ARITHMETIC (5 tests) ====================
print_str('--- 18. Pointer Arithmetic ---')
// 18.1 Heap struct access
hp_arr1 := &Point{
x: 10
y: 20
}
print_int(hp_arr1.x) // 10
print_int(hp_arr1.y) // 20
// 18.2 Multiple heap structs
hp_arr2 := &Point{
x: 100
y: 200
}
hp_arr3 := &Point{
x: 300
y: 400
}
print_int(hp_arr2.x + hp_arr3.x) // 400
print_int(hp_arr2.y + hp_arr3.y) // 600
// 18.3 Heap struct with computed values
base18 := 5
hp_arr4 := &Point{
x: base18 * 10
y: base18 * 20
}
print_int(hp_arr4.x) // 50
print_int(hp_arr4.y) // 100
// 18.4 Multiple heap allocations in loop
mut sum18 := 0
mut i18 := 0
for i18 < 3 {
hp := &Point{
x: i18 * 10
y: i18 * 20
}
sum18 = sum18 + hp.x + hp.y
i18++
}
print_int(sum18) // 0+0 + 10+20 + 20+40 = 90
// 18.5 Heap node tree structure
node1 := &Node{
value: 100
left: 0
right: 0
}
node2 := &Node{
value: 200
left: 0
right: 0
}
print_int(node1.value + node2.value) // 300
// ==================== 19. NESTED STRUCT ACCESS (5 tests) ====================
print_str('--- 19. Nested Struct Access ---')
// 19.1 Basic nested access
rect := Rectangle{
width: 100
height: 200
origin: Point{
x: 10
y: 20
}
}
print_int(rect.width) // 100
print_int(rect.height) // 200
// 19.2 Nested struct field via intermediate
rect2 := Rectangle{
width: 50
height: 60
origin: Point{
x: 5
y: 6
}
}
print_int(rect2.width + rect2.height) // 110
// 19.3 Mutable nested struct modification
mut rect3 := Rectangle{
width: 10
height: 20
origin: Point{
x: 1
y: 2
}
}
rect3.width = 100
rect3.height = 200
print_int(rect3.width) // 100
print_int(rect3.height) // 200
// 19.4 Multiple rectangles
rect4a := Rectangle{
width: 10
height: 20
origin: Point{
x: 0
y: 0
}
}
rect4b := Rectangle{
width: 30
height: 40
origin: Point{
x: 0
y: 0
}
}
print_int(rect4a.width + rect4b.width) // 40
print_int(rect4a.height + rect4b.height) // 60
// 19.5 Rectangle area
rect5 := Rectangle{
width: 12
height: 10
origin: Point{
x: 0
y: 0
}
}
area := rect5.width * rect5.height
print_int(area) // 120
// ==================== 20. NEGATIVE NUMBERS (5 tests) ====================
print_str('--- 20. Negative Numbers ---')
// 20.1 Unary minus
n1 := 0 - 42
print_int(n1) // -42
// 20.2 Negative addition
n2 := 0 - 10
n3 := n2 + 5
print_int(n3) // -5
// 20.3 Negative subtraction
n4 := 0 - 20
n5 := n4 - 10
print_int(n5) // -30
// 20.4 Negative multiplication
n6 := 0 - 7
n7 := n6 * 3
print_int(n7) // -21
// 20.5 Double negative (positive)
n8 := 0 - 50
n9 := 0 - n8
print_int(n9) // 50
// ==================== 21. UNARY OPERATIONS (5 tests) ====================
print_str('--- 21. Unary Operations ---')
// 21.1 Logical not on false
u1 := !false
if u1 {
print_int(1) // 1
} else {
print_int(0)
}
// 21.2 Logical not on true
u2 := !true
if u2 {
print_int(1)
} else {
print_int(0) // 0
}
// 21.3 Double negation
u3 := !!true
if u3 {
print_int(1) // 1
} else {
print_int(0)
}
// 21.4 Not with comparison
u4 := !(5 > 10)
if u4 {
print_int(1) // 1
} else {
print_int(0)
}
// 21.5 Not with variable
u5 := false
u6 := !u5
if u6 {
print_int(1) // 1
} else {
print_int(0)
}
// ==================== 22. COMPLEX BOOLEAN (5 tests) ====================
print_str('--- 22. Complex Boolean ---')
// 22.1 Multiple ANDs
if true && true && true {
print_int(1) // 1
} else {
print_int(0)
}
// 22.2 Multiple ORs
if false || false || true {
print_int(1) // 1
} else {
print_int(0)
}
// 22.3 AND with OR
if (true && false) || (true && true) {
print_int(1) // 1
} else {
print_int(0)
}
// 22.4 Complex condition with variables
aa := 10
bb := 20
cc := 30
if aa < bb && bb < cc {
print_int(1) // 1
} else {
print_int(0)
}
// 22.5 Chained comparisons
if aa < 15 && bb > 15 && cc == 30 {
print_int(1) // 1
} else {
print_int(0)
}
// ==================== 23. COMPARISON AS EXPRESSION (5 tests) ====================
print_str('--- 23. Comparison as Expression ---')
// 23.1 Comparison result in variable
cmp1 := 10 > 5
if cmp1 {
print_int(1) // 1
} else {
print_int(0)
}
// 23.2 Multiple comparison results
cmp2 := 3 < 5
cmp3 := 7 > 2
if cmp2 && cmp3 {
print_int(1) // 1
} else {
print_int(0)
}
// 23.3 Equality comparison
cmp4 := 42 == 42
if cmp4 {
print_int(1) // 1
} else {
print_int(0)
}
// 23.4 Inequality comparison
cmp5 := 10 != 20
if cmp5 {
print_int(1) // 1
} else {
print_int(0)
}
// 23.5 Comparison with expressions
cmp6 := (5 + 5) == (2 * 5)
if cmp6 {
print_int(1) // 1
} else {
print_int(0)
}
// ==================== 24. DEEPLY NESTED IF (5 tests) ====================
print_str('--- 24. Deeply Nested If ---')
// 24.1 Three levels deep
dn1 := 5
if dn1 > 0 {
if dn1 > 3 {
if dn1 > 4 {
print_int(1) // 1
} else {
print_int(0)
}
} else {
print_int(0)
}
} else {
print_int(0)
}
// 24.2 Nested with else chains
dn2 := 2
if dn2 == 1 {
print_int(10)
} else {
if dn2 == 2 {
print_int(20) // 20
} else {
if dn2 == 3 {
print_int(30)
} else {
print_int(0)
}
}
}
// 24.3 Mixed nesting with match
dn3 := 3
if dn3 > 0 {
match dn3 {
1 { print_int(100) }
2 { print_int(200) }
3 { print_int(300) } // 300
else { print_int(0) }
}
} else {
print_int(0)
}
// 24.4 Nested loops with conditionals
mut dn4_sum := 0
mut dn4_i := 0
for dn4_i < 3 {
mut dn4_j := 0
for dn4_j < 3 {
if dn4_i == dn4_j {
dn4_sum += 1
}
dn4_j++
}
dn4_i++
}
print_int(dn4_sum) // 3 (diagonal: 0-0, 1-1, 2-2)
// 24.5 If inside loop with break
mut dn5_result := 0
mut dn5_k := 0
for dn5_k < 100 {
if dn5_k > 5 {
if dn5_k > 7 {
dn5_result = dn5_k
break
}
}
dn5_k++
}
print_int(dn5_result) // 8
// ==================== 25. LARGE CONSTANTS (5 tests) ====================
print_str('--- 25. Large Constants ---')
// 25.1 Value > 65535
big1 := 100000
print_int(big1) // 100000
// 25.2 Large multiplication result
big2 := 1000 * 1000
print_int(big2) // 1000000
// 25.3 Large addition
big3 := 50000 + 50000
print_int(big3) // 100000
// 25.4 Large subtraction
big4 := 200000 - 100000
print_int(big4) // 100000
// 25.5 Large division
big5 := 1000000 / 100
print_int(big5) // 10000
// ==================== 26. MIXED OPERATIONS (5 tests) ====================
print_str('--- 26. Mixed Operations ---')
// 26.1 Arithmetic then comparison
mix1 := (10 + 5) * 2
if mix1 == 30 {
print_int(1) // 1
} else {
print_int(0)
}
// 26.2 Comparison then logic
mix2a := 10 > 5
mix2b := 20 < 30
if mix2a && mix2b {
print_int(1) // 1
} else {
print_int(0)
}
// 26.3 Chained arithmetic
mix3 := 2 + 3 * 4 - 6 / 2
print_int(mix3) // 2 + 12 - 3 = 11
// 26.4 Bitwise with arithmetic
mix4 := (5 | 3) + (4 & 6)
print_int(mix4) // 7 + 4 = 11
// 26.5 Complex expression
mix5 := ((10 + 5) * 2 - 10) / 5
print_int(mix5) // (30 - 10) / 5 = 4
// ==================== 27. EDGE CASES (5 tests) ====================
print_str('--- 27. Edge Cases ---')
// 27.1 Zero operations
edge1 := 0 + 0
print_int(edge1) // 0
edge2 := 100 * 0
print_int(edge2) // 0
edge3 := 0 / 7
print_int(edge3) // 0
// 27.2 Identity operations
edge4 := 42 + 0
print_int(edge4) // 42
edge5 := 42 * 1
print_int(edge5) // 42
edge6 := 42 / 1
print_int(edge6) // 42
// 27.3 Division edge cases
edge7 := 7 / 7
print_int(edge7) // 1
edge8 := 100 / 10
print_int(edge8) // 10
// 27.4 Modulo edge cases
edge9 := 10 % 10
print_int(edge9) // 0
edge10 := 5 % 7
print_int(edge10) // 5
// 27.5 Comparison edge cases
if 0 == 0 {
print_int(1) // 1
} else {
print_int(0)
}
if 0 < 1 {
print_int(1) // 1
} else {
print_int(0)
}
// ==================== 28. COMPLEX RECURSION (5 tests) ====================
print_str('--- 28. Complex Recursion ---')
// 28.1 Deep recursion test
print_int(sum_recursive(100)) // 5050
// 28.2 Mutual dependency via gcd
print_int(gcd(252, 105)) // 21
// 28.3 Multiple recursive calls
print_int(fib(15)) // 610
// 28.4 Power with larger exponent
print_int(power(3, 5)) // 243
// 28.5 Factorial with larger input
print_int(factorial(7)) // 5040
// ==================== 29. STRUCT OPERATIONS (5 tests) ====================
print_str('--- 29. Struct Operations ---')
// 29.1 Struct as function result (via modify)
mut sp1 := Point{
x: 0
y: 0
}
scale_point(mut sp1, 10)
print_int(sp1.x) // 0
print_int(sp1.y) // 0
// 29.2 Chained struct modifications
mut sp2 := Point{
x: 1
y: 1
}
scale_point(mut sp2, 5)
translate_point(mut sp2, 10, 20)
print_int(sp2.x) // 15
print_int(sp2.y) // 25
// 29.3 Struct field arithmetic
sp3 := Point{
x: 100
y: 200
}
sp3_sum := sp3.x + sp3.y
sp3_diff := sp3.y - sp3.x
print_int(sp3_sum) // 300
print_int(sp3_diff) // 100
// 29.4 Multiple struct parameters
mut sp4 := Point{
x: 10
y: 20
}
swap_point(mut sp4)
scale_point(mut sp4, 2)
print_int(sp4.x) // 40
print_int(sp4.y) // 20
// 29.5 Struct in conditional
sp5 := Point{
x: 5
y: 10
}
if sp5.x < sp5.y {
print_int(1) // 1
} else {
print_int(0)
}
// ==================== 30. CONTROL FLOW EDGE CASES (5 tests) ====================
print_str('--- 30. Control Flow Edge Cases ---')
// 30.1 Empty else
mut cf1 := 0
if true {
cf1 = 1
}
print_int(cf1) // 1
// 30.2 Multiple sequential ifs
mut cf2 := 0
if true {
cf2 += 1
}
if true {
cf2 += 2
}
if true {
cf2 += 4
}
print_int(cf2) // 7
// 30.3 Nested match
cf3 := 2
match cf3 {
1 {
match cf3 {
1 { print_int(11) }
else { print_int(10) }
}
}
2 {
match cf3 {
2 { print_int(22) } // 22
else { print_int(20) }
}
}
else {
print_int(0)
}
}
// 30.4 Loop with compound condition (&&)
mut cf4 := 0
mut cf4_i := 0
for cf4_i < 20 && cf4 < 50 {
cf4 += cf4_i
cf4_i++
}
print_int(cf4) // 55 (0+1+2+3+4+5+6+7+8+9+10 = 55, stops when >= 50)
// 30.5 Return inside nested control flow
print_int(nested_return(5)) // 100
print_int(nested_return(15)) // 200
print_int(nested_return(25)) // 300
// 30.6 Loop with || condition
mut cf5 := 0
mut cf5_i := 0
for cf5_i < 3 || cf5 < 10 {
cf5 += 5
cf5_i++
}
print_int(cf5) // 15 (loop runs 3 times: 5, 10, 15 - stops when both conditions false)
// ==================== 31. METHODS ====================
print_str('--- 31. Methods ---')
// 31.1 Basic method call
m1 := Point{
x: 10
y: 20
}
print_int(m1.sum()) // 30
// 31.2 Method with multiplication
m2 := Point{
x: 5
y: 6
}
print_int(m2.product()) // 30
// 31.3 Mutable receiver method
mut m4 := Point{
x: 7
y: 8
}
m4.double()
print_int(m4.x) // 14
print_int(m4.y) // 16
// 31.4 Rectangle methods
m5 := Rectangle{
width: 10
height: 5
origin: Point{
x: 0
y: 0
}
}
print_int(m5.area()) // 50
print_int(m5.perimeter()) // 30
// 31.5 Node method
m6 := Node{
value: 100
left: 10
right: 20
}
print_int(m6.total()) // 130
// 31.6 Method on heap-allocated struct
m8 := &Point{
x: 4
y: 5
}
print_int(m8.sum()) // 9
print_int(m8.product()) // 20
// ==================== 32. IF-EXPRESSIONS ====================
print_str('--- 32. If-Expressions ---')
// 32.1 Basic if-expression (abs)
print_int(int_abs(-5)) // 5
print_int(int_abs(7)) // 7
print_int(int_abs(0)) // 0
// 32.2 If-expression for max
print_int(int_max2(10, 20)) // 20
print_int(int_max2(30, 15)) // 30
print_int(int_max2(5, 5)) // 5
// 32.3 If-expression for min
print_int(int_min2(10, 20)) // 10
print_int(int_min2(30, 15)) // 15
print_int(int_min2(8, 8)) // 8
// 32.4 Nested if-expression (sign)
print_int(sign(-100)) // -1
print_int(sign(100)) // 1
print_int(sign(0)) // 0
// 32.5 Double nested if-expression (clamp)
print_int(clamp(5, 0, 10)) // 5 (in range)
print_int(clamp(-5, 0, 10)) // 0 (below lo)
print_int(clamp(15, 0, 10)) // 10 (above hi)
// 32.6 If-expression in local variable
val2 := 25
result := if val2 > 20 { val2 * 2 } else { val2 }
print_int(result) // 50
// 32.7 If-expression with complex condition
a := 10
b := 20
c := if a < b && b < 30 { a + b } else { 0 }
print_int(c) // 30
// ==================== 33. ARRAY INITIALIZATION ====================
print_str('--- 33. Array Initialization ---')
// 33.1 Basic array literal
arr1 := [10, 20, 30]
print_int(arr1[0]) // 10
print_int(arr1[1]) // 20
print_int(arr1[2]) // 30
// 33.2 Array element sum
arr2 := [5, 10, 15]
arr2_sum := arr2[0] + arr2[1] + arr2[2]
print_int(arr2_sum) // 30
// 33.3 Array with computed values
base_val := 7
arr3 := [base_val, base_val * 2, base_val * 3]
print_int(arr3[0]) // 7
print_int(arr3[1]) // 14
print_int(arr3[2]) // 21
// 33.4 Array element in expression
arr4 := [100, 200, 300]
result4 := arr4[0] * 2 + arr4[1]
print_int(result4) // 400
// 33.5 Array with function call on elements
arr5 := [3, 4, 5]
print_int(add(arr5[0], arr5[1])) // 7
print_int(mul(arr5[1], arr5[2])) // 20
// ==================== 34. STRING INTERPOLATION ====================
print_str('--- 34. String Interpolation ---')
// 34.1 Basic integer interpolation
interp_x := 42
s1 := 'The answer is ${interp_x}'
print_str(s1) // The answer is 42
// 34.2 Multiple interpolations
interp_a := 10
interp_b := 20
s2 := '${interp_a} + ${interp_b} = ${interp_a + interp_b}'
print_str(s2) // 10 + 20 = 30
// 34.3 String at beginning and end
interp_val := 100
s3 := 'Value: ${interp_val}!'
print_str(s3) // Value: 100!
// 34.4 Just interpolation (no literal parts)
interp_num := 999
s4 := '${interp_num}'
print_str(s4) // 999
// 34.5 Multiple consecutive values
interp_v1 := 1
interp_v2 := 2
interp_v3 := 3
s5 := '${interp_v1}-${interp_v2}-${interp_v3}'
print_str(s5) // 1-2-3
world := 'world'
s6 := 'hello ${world}'
print_str(s6)
// 34.6 String concatenation with + operator
str_a := 'Hello'
str_b := ' World'
str_c := str_a + str_b
print_str(str_c) // Hello World
// 34.7 Chained string concatenation
str_chain := 'A' + 'B' + 'C'
print_str(str_chain) // ABC
// ==================== 35. IF-GUARD EXPRESSIONS ====================
print_str('--- 35. If-Guard Expressions ---')
// 35.1 Basic if-guard with success (positive value)
if g1_val := maybe_positive(42) {
print_int(g1_val) // 42
} else {
print_int(0)
}
// 35.2 If-guard with failure (non-positive value)
if g2_val := maybe_positive(-5) {
print_int(g2_val)
} else {
print_int(999) // 999 (else branch taken)
}
// 35.3 If-guard with computation in then branch
if g3_val := maybe_double(25) {
print_int(g3_val + 10) // 50 + 10 = 60
} else {
print_int(0)
}
// 35.4 If-guard with function call
if g4_result := maybe_sum(10, 20) {
print_int(g4_result) // 30
} else {
print_int(0)
}
// 35.5 Nested if with if-guard
g5_outer := 5
if g5_outer > 0 {
if g5_inner := maybe_positive(g5_outer * 10) {
print_int(g5_inner) // 50
} else {
print_int(0)
}
}
// 35.6 If-guard in sequence
mut g6_sum := 0
if g6_a := maybe_positive(10) {
g6_sum += g6_a
}
if g6_b := maybe_positive(20) {
g6_sum += g6_b
}
if g6_c := maybe_positive(-5) {
g6_sum += g6_c
}
print_int(g6_sum) // 10 + 20 + 0 = 30
// 35.7 If-guard with else-if chain
g7_test := 100
if g7_val := maybe_positive(-g7_test) {
print_int(g7_val)
} else {
if g7_val2 := maybe_positive(g7_test) {
print_int(g7_val2) // 100
} else {
print_int(0)
}
}
// 35.8 or { return } pattern with value
if or_val := maybe_triple(5) {
print_int(or_val) // 15 (5 * 3)
} else {
print_int(-1)
}
// 35.9 or { return } pattern with negative (returns none)
if or_val2 := maybe_triple(-5) {
print_int(or_val2)
} else {
print_int(0) // 0 (none case)
}
// 35.10 Direct or { value } pattern - successful call
or_direct1 := maybe_positive(42) or { 0 }
print_int(or_direct1) // 42
// 35.11 Direct or { value } pattern - fallback used
or_direct2 := maybe_positive(-10) or { 99 }
print_int(or_direct2) // 99
// 35.12 Chained or { value } with computation
or_chain := maybe_double(25) or { 0 }
print_int(or_chain + 5) // 50 + 5 = 55
// 35.13 Result or { err } pattern - ensure `err` is available in scope
or_err := maybe_fail(-1) or {
print_str('error')
0
}
print_int(or_err) // 0
// ==================== 36. RANGE EXPRESSIONS ====================
print_str('--- 36. Range Expressions ---')
// 36.1 Basic array slicing with range
rng_arr1 := [10, 20, 30, 40, 50]
rng_slice1 := rng_arr1[1..4]
print_int(rng_slice1[0]) // 20
print_int(rng_slice1[1]) // 30
print_int(rng_slice1[2]) // 40
// 36.2 Range from start
rng_arr2 := [100, 200, 300, 400]
rng_slice2 := rng_arr2[0..2]
print_int(rng_slice2[0]) // 100
print_int(rng_slice2[1]) // 200
// 36.3 Range with variable indices
rng_start := 1
rng_end := 3
rng_arr3 := [5, 10, 15, 20, 25]
rng_slice3 := rng_arr3[rng_start..rng_end]
print_int(rng_slice3[0]) // 10
print_int(rng_slice3[1]) // 15
// 36.4 Consecutive slicing
rng_arr4 := [1, 2, 3, 4, 5, 6, 7, 8]
rng_first_half := rng_arr4[0..4]
rng_second_half := rng_arr4[4..8]
print_int(rng_first_half[0]) // 1
print_int(rng_first_half[3]) // 4
print_int(rng_second_half[0]) // 5
print_int(rng_second_half[3]) // 8
// 36.5 Single element range
rng_arr5 := [42, 84, 126]
rng_single := rng_arr5[1..2]
print_int(rng_single[0]) // 84
// ==================== 37. FOR-IN RANGE ====================
print_str('--- 37. For-In Range ---')
// 37.1 Basic for-in range
mut forin_sum1 := 0
for i in 0 .. 5 {
forin_sum1 += i
}
print_int(forin_sum1) // 0+1+2+3+4 = 10
// 37.2 For-in range with non-zero start
mut forin_sum2 := 0
for i in 5 .. 10 {
forin_sum2 += i
}
print_int(forin_sum2) // 5+6+7+8+9 = 35
// 37.3 For-in range with expressions
forin_start := 2
forin_end := 6
mut forin_sum3 := 0
for i in forin_start .. forin_end {
forin_sum3 += i
}
print_int(forin_sum3) // 2+3+4+5 = 14
// 37.4 Nested for-in ranges
mut forin_count := 0
for i in 0 .. 3 {
for j in 0 .. 4 {
forin_count += i + j + 1
}
}
print_int(forin_count) // sum of (i+j+1) for i in 0..3, j in 0..4 = 42
// 37.5 For-in range with computation in body
mut forin_product := 1
for i in 1 .. 6 {
forin_product *= i
}
print_int(forin_product) // 1*2*3*4*5 = 120
// 37.6 For-in range with break
mut forin_sum4 := 0
for i in 0 .. 100 {
if i >= 5 {
break
}
forin_sum4 += i
}
print_int(forin_sum4) // 0+1+2+3+4 = 10
// 37.7 For-in range with continue
mut forin_sum5 := 0
for i in 0 .. 10 {
if i % 2 == 0 {
continue
}
forin_sum5 += i
}
print_int(forin_sum5) // 1+3+5+7+9 = 25
// ==================== 38. DEFER STATEMENTS ====================
print_str('--- 38. Defer Statements ---')
// 38.1 Basic defer (should print after the other prints)
g_val = 0
defer {
g_val += 100
}
g_val += 1
print_int(g_val) // 1 (defer not executed yet, will be 101 at function end)
// 38.2 Multiple defers execute in reverse order (LIFO)
g_count = 0
defer {
g_count += 1
}
defer {
g_count += 10
}
defer {
g_count += 100
}
// At end of function: g_count = 0 + 100 + 10 + 1 = 111
// 38.3 Defer with function call
defer {
print_str('Defer 38.3 executed')
}
// 38.4 Test defer_test function with explicit return
print_int(defer_test()) // Should print 42
// 38.5 Test defer order in function
defer_order_test() // Should print: Third, Second, First
// 38.6 Test defer(fn) - function-level defer
print_int(defer_fn_test()) // 303 (3 from loop + 300 from function-level defers)
// 38.7 Test flag enum .has() and .all() methods
print_str('enum vals (exp 421):')
print_int(flag_enum_values()) // Expected: 421 (1 + 20 + 400)
print_str('AND test (exp 0):')
print_int(flag_enum_and_test()) // Expected: 0 (3 & 4 = 0)
print_str('manual has (exp 0):')
print_int(flag_enum_manual_has()) // Expected: 0 (manual has check)
print_str('flag debug (exp 3):')
print_int(flag_enum_debug()) // Expected: 3 (read=1 | write=2)
print_str('has read (exp 1):')
print_int(flag_enum_has_read()) // Expected: 1
print_str('has exec (exp 0):')
print_int(flag_enum_has_execute()) // Expected: 0
print_str('has result (exp 0):')
print_int(flag_enum_has_result()) // Expected: 0 (direct bool->int)
print_str('manual call (exp 0):')
print_int(flag_enum_manual_call()) // Expected: 0 (manual has impl)
print_str('check args (exp 304):')
print_int(flag_enum_check_args()) // Expected: 304 (perms=3, exec=4)
print_str('int args (exp 304):')
print_int(flag_enum_check_int_args()) // Expected: 304
print_str('keyword flag field (exp 3):')
print_int(flag_enum_keyword_field()) // Expected: 3 (read=1 | unsigned=2)
print_str('full test (exp 13):')
print_int(flag_enum_test()) // Expected: 13 (1 + 2 + 10)
// ==================== 39. ENUMS ====================
print_str('--- 39. Enums ---')
// 39.1 Basic enum value
color1 := Color.red
print_int(int(color1)) // 0
// 39.2 Other enum values
color2 := Color.green
color3 := Color.blue
print_int(int(color2)) // 1
print_int(int(color3)) // 2
// 39.3 Enum with explicit values
status1 := Status.pending
status2 := Status.active
status3 := Status.done
print_int(int(status1)) // 0
print_int(int(status2)) // 1
print_int(int(status3)) // 2
// 39.4 Enum in match
match color1 {
.red { print_int(100) } // 100
.green { print_int(200) }
.blue { print_int(300) }
else { print_int(0) }
}
// 39.5 Enum comparison
if color1 == Color.red {
print_int(1) // 1
} else {
print_int(0)
}
// ==================== 40. FOR-IN ARRAY ====================
print_str('--- 40. For-In Array ---')
// 40.1 Basic for-in array iteration
arr_iter1 := [10, 20, 30]
mut sum_iter1 := 0
for elem in arr_iter1 {
sum_iter1 += elem
}
print_int(sum_iter1) // 60
// 40.2 For-in with index
arr_iter2 := [5, 10, 15]
mut weighted_sum2 := 0
for i, elem in arr_iter2 {
weighted_sum2 += (i + 1) * elem
}
print_int(weighted_sum2) // 1*5 + 2*10 + 3*15 = 70
// 40.3 For-in with break
arr_iter3 := [1, 2, 3, 4, 5]
mut sum_iter3 := 0
for elem in arr_iter3 {
if elem > 3 {
break
}
sum_iter3 += elem
}
print_int(sum_iter3) // 1+2+3 = 6
// 40.4 For-in with continue
arr_iter4 := [1, 2, 3, 4, 5]
mut sum_iter4 := 0
for elem in arr_iter4 {
if elem % 2 == 0 {
continue
}
sum_iter4 += elem
}
print_int(sum_iter4) // 1+3+5 = 9
// 40.5 While-style for with in condition
whitespace_loop_chars := [` `, `\t`, `\n`, `\r`]
whitespace_loop_text := ' x'
mut whitespace_loop_idx := 0
for whitespace_loop_text[whitespace_loop_idx] in whitespace_loop_chars {
whitespace_loop_idx++
}
print_int(whitespace_loop_idx) // 3
// 40.6 Nested for-in
arr_outer := [1, 2, 3]
arr_inner := [10, 20]
mut nested_sum := 0
for outer in arr_outer {
for inner in arr_inner {
nested_sum += outer * inner
}
}
print_int(nested_sum) // (1*10+1*20) + (2*10+2*20) + (3*10+3*20) = 30+60+90 = 180
// ==================== 41. FIXED SIZE ARRAYS ====================
print_str('--- 41. Fixed Size Arrays ---')
// 41.1 Fixed array with literal initialization
fixed_arr1 := [5, 10, 15]
print_int(fixed_arr1[0]) // 5
print_int(fixed_arr1[1]) // 10
print_int(fixed_arr1[2]) // 15
// 41.2 Fixed array with computed index
idx := 1
print_int(fixed_arr1[idx]) // 10
// 41.3 Fixed array sum
mut fixed_sum := 0
for elem in fixed_arr1 {
fixed_sum += elem
}
print_int(fixed_sum) // 30
// 41.4 Fixed array with larger size
fixed_arr2 := [1, 2, 3, 4, 5]
mut fixed_product := 1
for elem in fixed_arr2 {
fixed_product *= elem
}
print_int(fixed_product) // 120
// 41.5 Nested fixed arrays access
fixed_outer := [100, 200, 300]
fixed_inner := [1, 2, 3]
print_int(fixed_outer[0] + fixed_inner[2]) // 103
// 41.6 Fixed array with ! literal syntax (explicit fixed size)
fixed_literal := [1, 2, 3, 4, 5]!
print_int(fixed_literal[0]) // 1
print_int(fixed_literal[4]) // 5
// 41.7 Fixed array .len access
print_int(fixed_literal.len) // 5
// 41.8 Fixed array iteration with ! syntax
mut fixed_literal_sum := 0
for elem in fixed_literal {
fixed_literal_sum += elem
}
print_int(fixed_literal_sum) // 15
// 41.9 Fixed array of u8 with ! syntax
bytes := [u8(65), 66, 67]!
print_int(bytes[0]) // 65 (ASCII 'A')
print_int(bytes.len) // 3
// ==================== 42. INTERFACE IMPLEMENTATION ====================
print_str('--- 42. Interface Implementation ---')
// 42.1 Call draw() method directly on Point (implements Drawable)
draw_pt1 := Point{
x: 5
y: 10
}
print_int(draw_pt1.draw()) // 5*1000 + 10 = 5010
// 42.2 Another point with draw
draw_pt2 := Point{
x: 12
y: 34
}
print_int(draw_pt2.draw()) // 12*1000 + 34 = 12034
// 42.3 Interface method on zero-init struct
draw_pt3 := Point{}
print_int(draw_pt3.draw()) // 0*1000 + 0 = 0
// 42.4 Interface method with heap-allocated struct
draw_pt4 := &Point{
x: 100
y: 200
}
print_int(draw_pt4.draw()) // 100*1000 + 200 = 100200
// 42.5 Multiple interface method calls
mut draw_total := 0
draw_a := Point{
x: 1
y: 2
}
draw_b := Point{
x: 3
y: 4
}
draw_total += draw_a.draw() // 1002
draw_total += draw_b.draw() // 3004
print_int(draw_total) // 4006
// ==================== 43. TYPE ALIAS USAGE ====================
print_str('--- 43. Type Alias Usage ---')
// 43.1 Basic type alias (MyInt is typedef'd to int)
my_a := 10
my_b := 20
print_int(my_a + my_b) // 30
// 43.2 Type alias in function
my_result := add_my_ints(15, 25)
print_int(my_result) // 40
// 43.3 Type alias with arithmetic
my_c := 100
my_d := my_c * 3
print_int(my_d) // 300
// 43.4 Type alias comparison
my_e := 50
my_f := 50
if my_e == my_f {
print_int(1) // 1
} else {
print_int(0)
}
// 43.5 Type alias in loop
mut my_sum := 0
for i in 1 .. 6 {
my_sum += i
}
print_int(my_sum) // 1+2+3+4+5 = 15
// ==================== 44. COMPTIME ====================
print_str('--- 44. Comptime ---')
// 44.1 Basic $if macos/$else
$if macos {
print_int(1) // 1 on macOS
} $else {
print_int(0) // 0 on other platforms
}
// 44.2 $if linux
$if linux {
print_int(2) // 2 on Linux
} $else {
print_int(20) // 20 on non-Linux
}
// 44.3 $if windows
$if windows {
print_int(3) // 3 on Windows
} $else {
print_int(30) // 30 on non-Windows
}
// 44.4 Negation: $if !windows
$if !windows {
print_int(4) // 4 on non-Windows
} $else {
print_int(40) // 40 on Windows
}
// 44.5 Comptime in function call
print_int(get_comptime_value())
// ==================== 45. STRING STRUCT FIELDS ====================
print_str('--- 45. String Struct Fields ---')
// 45.1 String literal .str field
s45_1 := 'Hello'
print_str(s45_1) // Hello
// 45.2 String literal .len field
s45_2 := 'World'
print_int(s45_2.len) // 5
// 45.3 Interpolated string .len field
val45 := 123
s45_3 := 'Val: ${val45}'
print_int(s45_3.len) // 8
// 45.4 Multiple string operations
a45 := 'AB'
b45 := 'CDE'
print_int(a45.len + b45.len) // 5
// 45.5 String in function parameter
print_str('Passed directly') // Passed directly
// ==================== 46. UNSAFE EXPRESSIONS ====================
print_str('--- 46. Unsafe Expressions ---')
// 46.1 Basic unsafe block returning value
unsafe_val1 := unsafe {
42
}
print_int(unsafe_val1) // 42
// 46.2 Unsafe block with computation
unsafe_val2 := unsafe {
10 + 20 + 30
}
print_int(unsafe_val2) // 60
// 46.3 Unsafe block with variable access
base_for_unsafe := 100
unsafe_val3 := unsafe {
base_for_unsafe * 2
}
print_int(unsafe_val3) // 200
// 46.4 Unsafe block in expression context
result_unsafe := unsafe { 7 } * unsafe { 8 }
print_int(result_unsafe) // 56
// 46.5 Unsafe with struct field access
unsafe_pt := Point{
x: 15
y: 25
}
unsafe_sum := unsafe {
unsafe_pt.x + unsafe_pt.y
}
print_int(unsafe_sum) // 40
// ==================== 47. INTERFACE VTABLE ====================
print_str('--- 47. Interface Vtable ---')
// 47.1 Basic interface assignment and method call
vtable_pt1 := Point{
x: 7
y: 3
}
d1 := Drawable(vtable_pt1)
print_int(d1.draw()) // 7*1000 + 3 = 7003
// 47.2 Interface with different values
vtable_pt2 := Point{
x: 15
y: 25
}
d2 := Drawable(vtable_pt2)
print_int(d2.draw()) // 15*1000 + 25 = 15025
// 47.3 Multiple interface calls
vtable_pt3 := Point{
x: 1
y: 1
}
d3 := Drawable(vtable_pt3)
print_int(d3.draw() + d3.draw()) // 1001 + 1001 = 2002
// 47.4 Shape interface with multiple methods
shape_rect := Rectangle{
width: 10
height: 5
origin: Point{
x: 0
y: 0
}
}
shape1 := Shape(shape_rect)
print_int(shape1.area()) // 10 * 5 = 50
print_int(shape1.perimeter()) // 2 * (10 + 5) = 30
// 47.5 Sum of interface method results
vtable_pt4 := Point{
x: 2
y: 3
}
d4 := Drawable(vtable_pt4)
vtable_pt5 := Point{
x: 4
y: 5
}
d5 := Drawable(vtable_pt5)
print_int(d4.draw() + d5.draw()) // 2003 + 4005 = 6008
// 47.6 Calculator interface with parameters
calc_pt := Point{
x: 10
y: 5
}
calc := Calculator(calc_pt)
print_int(calc.add(3, 7)) // 10 + 5 + 3 + 7 = 25
print_int(calc.multiply(4)) // (10 + 5) * 4 = 60
// 47.7 Multiple Calculator calls
calc_pt2 := Point{
x: 2
y: 3
}
calc2 := Calculator(calc_pt2)
print_int(calc2.add(1, 1)) // 2 + 3 + 1 + 1 = 7
print_int(calc2.multiply(10)) // (2 + 3) * 10 = 50
// ==================== 48. STRUCT FIELD OPERATIONS ====================
print_str('--- 48. Struct Field Operations ---')
// 48.1 Basic field assignment with arithmetic
mut sf1 := Point{
x: 10
y: 20
}
sf1.x = sf1.x + 5
sf1.y = sf1.y - 3
print_int(sf1.x) // 15
print_int(sf1.y) // 17
// 48.2 Field multiplication and division
mut sf2 := Point{
x: 6
y: 100
}
sf2.x = sf2.x * 7
sf2.y = sf2.y / 4
print_int(sf2.x) // 42
print_int(sf2.y) // 25
// 48.3 Compound assignment on fields
mut sf3 := Point{
x: 50
y: 30
}
sf3.x += 25
sf3.y -= 10
print_int(sf3.x) // 75
print_int(sf3.y) // 20
// 48.4 Compound multiply/divide on fields
mut sf4 := Point{
x: 8
y: 64
}
sf4.x *= 5
sf4.y /= 8
print_int(sf4.x) // 40
print_int(sf4.y) // 8
// 48.5 Field used in expression with other field
mut sf5 := Point{
x: 3
y: 4
}
sf5.x = sf5.x + sf5.y
sf5.y = sf5.x * sf5.y
print_int(sf5.x) // 7 (3+4)
print_int(sf5.y) // 28 (7*4)
// 48.6 Chained field operations
mut sf6 := Point{
x: 2
y: 3
}
sf6.x = sf6.x * 2
sf6.x = sf6.x + 1
sf6.x = sf6.x * 3
sf6.y = sf6.y + sf6.x
print_int(sf6.x) // 15 ((2*2+1)*3)
print_int(sf6.y) // 18 (3+15)
// 48.7 Field modulo operation
mut sf7 := Point{
x: 17
y: 23
}
sf7.x = sf7.x % 5
sf7.y = sf7.y % 7
print_int(sf7.x) // 2
print_int(sf7.y) // 2
// 48.8 Field bitwise operations
mut sf8 := Point{
x: 0b1100
y: 0b1010
}
sf8.x = sf8.x & sf8.y
sf8.y = sf8.x | 0b0101
print_int(sf8.x) // 8 (0b1000)
print_int(sf8.y) // 13 (0b1101)
// 48.9 Field with function call result
mut sf9 := Point{
x: 5
y: 10
}
sf9.x = add(sf9.x, sf9.y)
sf9.y = mul(sf9.x, 2)
print_int(sf9.x) // 15
print_int(sf9.y) // 30
// 48.10 Nested struct field modification
mut rect_mod := Rectangle{
width: 10
height: 20
origin: Point{
x: 0
y: 0
}
}
rect_mod.width = rect_mod.width * 2
rect_mod.height += 5
rect_mod.origin.x = 100
rect_mod.origin.y = rect_mod.origin.x / 2
print_int(rect_mod.width) // 20
print_int(rect_mod.height) // 25
print_int(rect_mod.origin.x) // 100
print_int(rect_mod.origin.y) // 50
// ==================== 49. PRINTLN ====================
print_str('--- 49. Println ---')
// 49.1 Test println
println('hello world')
// ==================== 50. ALGEBRAIC OPTIMIZATIONS ====================
print_str('--- 50. Algebraic Optimizations ---')
// 50.1 x - x = 0
opt_val := 42
print_int(opt_val - opt_val) // 0
// 50.2 x ^ x = 0
opt_xor := 123
print_int(opt_xor ^ opt_xor) // 0
// 50.3 x & x = x
opt_and := 99
print_int(opt_and & opt_and) // 99
// 50.4 x | x = x
opt_or := 77
print_int(opt_or | opt_or) // 77
// 50.5 x * 2 = x << 1
opt_mul2 := 25
print_int(opt_mul2 * 2) // 50
// 50.6 Combined optimizations
opt_a := 10
opt_b := opt_a - opt_a // Should be 0
opt_c := opt_a | opt_a // Should be 10
print_int(opt_b) // 0
print_int(opt_c) // 10
// 50.7 2 * x = x << 1 (commutative)
opt_mul2_comm := 13
print_int(2 * opt_mul2_comm) // 26
// 50.8 Algebraic opts in expressions
opt_expr := 7
print_int((opt_expr ^ opt_expr) + 5) // 0 + 5 = 5
print_int((opt_expr & opt_expr) * 2) // 7 * 2 = 14
// 50.9 Algebraic opts with different values
opt_large := 12345
print_int(opt_large - opt_large) // 0
print_int(opt_large ^ opt_large) // 0
print_int(opt_large & opt_large) // 12345
print_int(opt_large | opt_large) // 12345
// 50.10 Algebraic opts in loop
mut opt_loop_sum := 0
for i in 1 .. 5 {
opt_loop_sum += i - i // Should add 0 each iteration
opt_loop_sum += i & i // Should add i each iteration
}
print_int(opt_loop_sum) // 0+1 + 0+2 + 0+3 + 0+4 = 10
// ==================== 51. DEAD STORE ELIMINATION ====================
print_str('--- 51. Dead Store Elimination ---')
// 51.1 Basic dead store - local var never read
// The optimizer should remove stores to variables that are never used
{
mut dead_var := 100
dead_var = 200 // dead store, never read
_ = dead_var
}
print_int(1) // 1 - verify execution continues
// 51.2 Dead store with live store after
mut dse_var := 10
dse_var = 20 // dead store (overwritten before read)
dse_var = 30 // this is the live store
print_int(dse_var) // 30
// 51.3 Multiple dead stores
mut dse_multi := 1
dse_multi = 2 // dead
dse_multi = 3 // dead
dse_multi = 4 // dead
dse_multi = 5 // live
print_int(dse_multi) // 5
// 51.4 Dead store in branch not taken
mut dse_branch := 100
if false {
dse_branch = 999 // dead (branch never taken)
}
print_int(dse_branch) // 100
// 51.5 Live store in taken branch
mut dse_live := 50
if true {
dse_live = 75
}
print_int(dse_live) // 75
// ==================== 52. DEAD PHI ELIMINATION ====================
print_str('--- 52. Dead Phi Elimination ---')
// 52.1 Phi from if-else where result is unused
// The phi node should be eliminated if not used
mut phi_unused := 0
if true {
phi_unused = 10
} else {
phi_unused = 20
}
// phi_unused is reassigned, so previous phi is dead
phi_unused = 99
print_int(phi_unused) // 99
// 52.2 Multiple phi nodes, some dead
mut phi_a := 0
mut phi_b := 0
if true {
phi_a = 1
phi_b = 2
} else {
phi_a = 3
phi_b = 4
}
// phi_b is dead (overwritten), phi_a is live
phi_b = 100
print_int(phi_a) // 1
print_int(phi_b) // 100
// 52.3 Loop phi - variable assigned in loop body
mut phi_loop := 0
for i in 0 .. 3 {
phi_loop = i // intermediate values are dead, only final matters
}
print_int(phi_loop) // 2 (last iteration value)
// 52.4 Nested if with dead phi
mut phi_nested := 0
if true {
if true {
phi_nested = 10
} else {
phi_nested = 20
}
phi_nested = 30 // overwrites inner phi result
}
print_int(phi_nested) // 30
// 52.5 Complex phi scenario with loop and conditionals
mut phi_complex := 1
for i in 0 .. 4 {
if i % 2 == 0 {
phi_complex = phi_complex + 1
} else {
phi_complex = phi_complex * 2
}
}
print_int(phi_complex) // 1 -> 2 -> 4 -> 5 -> 10
// ==================== 53. CONSTANT DEDUPLICATION ====================
print_str('--- 53. Constant Deduplication ---')
// 53.1 Same constant used multiple times
const_a := 42
const_b := 42
const_c := 42
print_int(const_a + const_b + const_c) // 126
// 53.2 Zero constant deduplication
zero1 := 0
zero2 := 0
zero3 := 0
print_int(zero1 + zero2 + zero3) // 0
// 53.3 Constant from algebraic opts should be deduplicated
dedup_x := 50
result1 := dedup_x - dedup_x // creates zero
dedup_y := 60
result2 := dedup_y - dedup_y // should reuse same zero
print_int(result1 + result2) // 0
// 53.4 Multiple shifts with same constant
shift_a := 1
shift_b := 2
shift_c := 4
// All these use constant 1 for the shift amount when x*2 is optimized
print_int(shift_a * 2 + shift_b * 2 + shift_c * 2) // 2 + 4 + 8 = 14
// 53.5 Constants in expressions
expr_const := (10 + 10) * (5 + 5) // Both 10s and 5s should be deduplicated
print_int(expr_const) // 200
// ==================== 54. HASHMAPS ====================
print_str('--- 54. Hashmaps ---')
// 54.1 Basic map initialization and assignment
mut hm1 := map[int]int{}
hm1[1] = 10
hm1[2] = 20
hm1[3] = 30
print_int(hm1[1]) // 10
print_int(hm1[2]) // 20
print_int(hm1[3]) // 30
// 54.2 Map len
print_str('map len:')
print_int(hm1.len) // 3
// 54.3 Map with different keys
mut hm2 := map[int]int{}
hm2[100] = 1000
hm2[200] = 2000
print_int(hm2[100]) // 1000
print_int(hm2[200]) // 2000
print_int(hm2.len) // 2
// 54.4 Map value update
mut hm3 := map[int]int{}
hm3[5] = 50
print_int(hm3[5]) // 50
hm3[5] = 500
print_int(hm3[5]) // 500
print_int(hm3.len) // 1 (still 1, not 2)
// 54.5 Map with computed values
mut hm4 := map[int]int{}
for i in 0 .. 5 {
hm4[i] = i * i
}
print_int(hm4[0]) // 0
print_int(hm4[1]) // 1
print_int(hm4[2]) // 4
print_int(hm4[3]) // 9
print_int(hm4[4]) // 16
// 54.6 Map literal initialization
print_str('map literal:')
mut hm5 := {
'a': 1
'b': 2
'c': 3
}
print_int(hm5['a']) // 1
print_int(hm5['b']) // 2
print_int(hm5['c']) // 3
print_int(hm5.len) // 3
hm5['d'] = 4
print_int(hm5['d']) // 4
print_int(hm5.len) // 4
// 54.7 Map clone
print_str('map clone:')
mut hm6 := {
'x': 100
'y': 200
}
hm7 := hm6.clone()
print_int(hm7['x']) // 100
print_int(hm7['y']) // 200
print_int(hm7.len) // 2
// Verify clone is independent
hm6['x'] = 999
print_int(hm6['x']) // 999 (modified original)
print_int(hm7['x']) // 100 (clone unchanged)
// ==================== 55. MULTI-RETURN ====================
print_str('--- 55. Multi-return ---')
// 55.1 Basic two-value return
a1, b1 := swap(10, 20)
print_int(a1) // 20
print_int(b1) // 10
// 55.2 Division and modulo
quot, rem := divmod(17, 5)
print_int(quot) // 3
print_int(rem) // 2
// 55.3 Min/max of three values
min1, max1 := min_max(5, 2, 8)
print_int(min1) // 2
print_int(max1) // 8
// 55.4 Three-value return
t1, t2, t3 := triple_return(7)
print_int(t1) // 7
print_int(t2) // 14
print_int(t3) // 21
// 55.5 Ignore some return values with _
_, only_rem := divmod(23, 4)
print_int(only_rem) // 3
only_quot, _ := divmod(23, 4)
print_int(only_quot) // 5
print_str('pi=')
print_int(pi)
// 55.6 String compound assignment
mut s := 'hello'
s += ' world'
print_str(s) // hello world
// 55.7 Array comparison
cmp_arr1 := [1, 2, 3]
cmp_arr2 := [1, 2, 3]
cmp_arr3 := [1, 2, 4]
if cmp_arr1 == cmp_arr2 {
print_str('arr1 == arr2: yes')
}
if cmp_arr1 != cmp_arr3 {
print_str('arr1 != arr3: yes')
}
// ==================== 56. ARRAY FILTER (4 tests) ====================
print_str('--- 56. Array filter ---')
// 56.1 Basic filter with it
filter_arr := [1, 2, 3, 4, 5, 6]
evens := filter_arr.filter(it % 2 == 0)
print_str('filtered.len:')
print_int(evens.len) // 3
print_str('filtered values:')
for _, number in evens {
print_int(number)
}
// 56.2 Filter with comparison
odds := filter_arr.filter(it % 2 != 0)
print_int(odds.len) // 3
// 56.3 Filter that returns nothing
big_nums := filter_arr.filter(it > 10)
print_int(big_nums.len) // 0
// 56.4 Filter that returns everything
small_nums := filter_arr.filter(it <= 6)
print_int(small_nums.len) // 6
// 56.5 Filter as function argument (non-assignment context)
print_int(filter_arr.filter(it > 3).len) // 3
// 56.6 Map in assignment context
mapped := filter_arr.map(it * 2)
print_int(mapped.len) // 6
print_int(mapped[0]) // 2
print_int(mapped[5]) // 12
// 56.7 Map as function argument (non-assignment context)
print_int(filter_arr.map(it + 10).len) // 6
// ==================== 57. ARRAY STR (auto-generated) ====================
print_str('--- 57. Array str ---')
// 57.1 Basic array str via println
str_arr := [1, 2, 3, 4]
println(str_arr) // should print [1, 2, 3, 4]
// 57.2 Empty array str
empty_arr := []int{}
println(empty_arr) // should print []
// 57.3 Single element array
single_arr := [42]
println(single_arr) // should print [42]
// ==================== 58. IF-GUARD EXPRESSIONS ====================
print_str('--- 58. If-guard expressions ---')
// 58.1 Basic map if-guard - key exists
mut guard_map := map[int]int{}
guard_map[10] = 100
guard_map[20] = 200
if guard_val1 := guard_map[10] {
print_int(guard_val1) // 100
} else {
print_str('not found')
}
// 58.2 Map if-guard - key doesn't exist
if guard_val2 := guard_map[99] {
print_int(guard_val2)
} else {
print_str('key 99 not found') // should print this
}
// 58.3 Value-level if-guard (ternary-like)
result_guard := if gv1 := guard_map[20] { gv1 } else { 0 }
print_int(result_guard) // 200
// 58.4 Value-level if-guard with missing key
result_missing := if gv2 := guard_map[999] { gv2 } else { -1 }
print_int(result_missing) // -1
// 58.5 Multiple if-guards in sequence (same variable name)
if off := guard_map[10] {
print_int(off) // 100
}
if off := guard_map[20] {
print_int(off) // 200
}
// 58.6 If-guard with computation in body
if v := guard_map[10] {
doubled := v * 2
print_int(doubled) // 200
}
// 59. Array clone() on nested selectors
// Test that array.clone() works on deeply nested selector expressions
// like wrapper.holder.data.clone() - this tests the fix for chained selector type inference
mut holder := ArrayHolder{
data: []int{cap: 10}
}
holder.data << 10
holder.data << 20
holder.data << 30
mut wrap := Wrapper{
holder: &holder
}
// Clone via nested selector (wrapper.holder.data.clone())
mut cloned_arr := wrap.holder.data.clone()
print_int(cloned_arr.len) // 3
print_int(cloned_arr[0]) // 10
print_int(cloned_arr[2]) // 30
// Verify clone is independent - modify cloned array
// TODO: cloned_arr[0] = 99 crashes - skip for now
// cloned_arr[0] = 99
// print_int(cloned_arr[0]) // 99 (modified)
// print_int(wrap.holder.data[0]) // 10 (original unchanged)
// 60. Map indexing with push (map[key] << value)
// Test that g.pending_labels[blk] << off pattern works correctly
// This uses map_get_and_set to auto-create empty array if key doesn't exist
mut pl := PendingLabels{
labels: map[int][]int{}
}
pl.labels[5] << 100 // First push to key 5 - creates new array
pl.labels[5] << 200 // Second push to same key
pl.labels[10] << 50 // Push to different key
print_int(pl.labels[5].len) // 2
print_int(pl.labels[5][0]) // 100
print_int(pl.labels[5][1]) // 200
print_int(pl.labels[10].len) // 1
print_int(pl.labels[10][0]) // 50
// ==================== 61. MUTABLE SLICE ARGUMENTS ====================
print_str('--- 61. Mutable slice arguments ---')
// Test that slices can be passed as mutable arguments to functions
// This tests the &(array[]){builtin__array_slice(...)}[0] pattern
mut slice_data := []int{len: 8}
slice_data[0] = 10
slice_data[1] = 20
slice_data[2] = 30
slice_data[3] = 40
// TODO: Slice arguments crash - skip for now
// 61.1 Read from slice (non-mutable)
// read_result := read_from_slice(slice_data[1..3])
// print_int(read_result) // 50 (20 + 30)
// 61.2-61.3 also skipped
// ==================== 62. MAP INDEX WITH OR BLOCK ====================
print_str('--- 62. Map index with or block ---')
// Test the pattern: map[key] or { fallback }
// This is used in lookup_type_from_env and similar functions
mut or_test_map := map[string]int{}
or_test_map['foo'] = 42
or_test_map['bar'] = 100
or_test_map['builtin'] = 999
// 62.1 Key exists - should return the value
or_result1 := map_lookup_with_or(or_test_map, 'foo')
print_int(or_result1) // 42
// 62.2 Key doesn't exist - should return fallback (-1)
or_result2 := map_lookup_with_or(or_test_map, 'nonexistent')
print_int(or_result2) // -1
// 62.3 Nested or block - first key exists
or_result3 := nested_map_or(or_test_map, 'foo')
print_int(or_result3) // 42
// 62.4 Nested or block - first key missing, fallback to 'builtin'
or_result4 := nested_map_or(or_test_map, 'missing')
print_int(or_result4) // 999 (from 'builtin' key)
// 62.5 Nested or block - both keys missing, return default
mut or_empty_map := map[string]int{}
or_result5 := nested_map_or(or_empty_map, 'anything')
print_int(or_result5) // -999 (default from return in or block)
// ==================== 63. IF-GUARD WITH METHOD CALL ====================
print_str('--- 63. If-guard with method call returning optional ---')
// This tests the pattern from lookup_type_from_env:
// if obj := container.method() { ... } - method returning optional
// 63.1 Method returning optional - found case
dc := DataContainer{
value: 42
name: 'test'
}
if val := dc.lookup('test') {
print_int(val) // 42
}
// 63.2 Method returning optional - not found case
if val := dc.lookup('missing') {
print_int(val) // Should not print
} else {
print_int(-100) // -100
}
// 63.3 Nested method call with if-guard
dc2 := DataContainer{
value: 777
name: 'found'
}
mut result63 := 0
if v := dc2.lookup('found') {
result63 = v
}
print_int(result63) // 777
// ==================== 64. IF-GUARD + IS-CHECK + OPTION RETURN ====================
print_str('--- 64. If-guard with is-check and optional return ---')
// This tests the pattern from lookup_struct_from_env in arm64:
// fn lookup_struct() ?Struct { if typ := lookup_type() { if typ is Struct { return typ } } return none }
// 64.1 Setup type_holder with struct and enum types
type_holder := TypeHolder{
struct_type: StructType{
name: 'Point'
fields: 2
}
enum_type: EnumType{
name: 'Color'
variants: 3
}
}
// 64.2 lookup_struct - found case (asking for 'struct' returns the struct type)
if s64_1 := type_holder.lookup_struct('struct') {
print_str(s64_1.name) // Point
print_int(s64_1.fields) // 2
} else {
print_str('NOT_FOUND')
}
// 64.3 lookup_struct - not found because 'enum' returns EnumType, not StructType
if s64_2 := type_holder.lookup_struct('enum') {
print_str(s64_2.name)
} else {
print_int(-200) // -200 (returned enum, not struct)
}
// 64.4 lookup_struct - not found because key doesn't exist
if s64_3 := type_holder.lookup_struct('missing') {
print_str(s64_3.name)
} else {
print_int(-300) // -300 (key not found)
}
// 64.5 lookup_enum - found case (asking for 'enum' returns the enum type)
if e64_1 := type_holder.lookup_enum('enum') {
print_str(e64_1.name) // Color
print_int(e64_1.variants) // 3
} else {
print_str('NOT_FOUND')
}
// 64.6 lookup_enum - not found because 'struct' returns StructType, not EnumType
if e64_2 := type_holder.lookup_enum('struct') {
print_str(e64_2.name)
} else {
print_int(-400) // -400 (returned struct, not enum)
}
// ==================== 65. MAP ITERATION WITH POINTER VALUES ====================
print_str('--- 65. Map iteration with pointer values ---')
// Tests map[int]&Struct iteration - the same pattern used in allocate_registers
// 65.1 Create map with pointer values
mut intervals := map[int]&Point{}
intervals[1] = &Point{
x: 10
y: 100
}
intervals[2] = &Point{
x: 20
y: 200
}
intervals[3] = &Point{
x: 30
y: 300
}
// 65.2 Iterate over map and collect pointer values
mut sum_x := 0
mut sum_y := 0
for _, p in intervals {
sum_x += p.x
sum_y += p.y
}
print_int(sum_x) // 60 (10+20+30)
print_int(sum_y) // 600 (100+200+300)
// 65.3 If-guard with map[int]&Struct
if pt65 := intervals[2] {
print_int(pt65.x) // 20
print_int(pt65.y) // 200
}
// ==================== 66. NESTED MAP INDEXING IN ARRAY ====================
print_str('--- 66. Nested map indexing in array ---')
// Tests used[reg_map[val_id]] pattern - nested map index as array index
// 66.1 Setup array and map
mut used66 := []bool{len: 10, init: false}
mut reg_map66 := map[int]int{}
reg_map66[5] = 3 // val_id 5 -> index 3
reg_map66[7] = 8 // val_id 7 -> index 8
// 66.2 Use nested map index to set array element
used66[reg_map66[5]] = true
print_int(if used66[3] { 1 } else { 0 }) // 1 (index 3 was set)
print_int(if used66[0] { 1 } else { 0 }) // 0 (index 0 not set)
// 66.3 Use nested map index in loop
val_ids := [5, 7]
for vid in val_ids {
map_idx := reg_map66[vid]
used66[map_idx] = true
}
print_int(if used66[3] { 1 } else { 0 }) // 1
print_int(if used66[8] { 1 } else { 0 }) // 1
// 66.4 Direct nested indexing
used66[reg_map66[7]] = false
print_int(if used66[8] { 1 } else { 0 }) // 0 (reset to false)
// ==================== 67. NESTED MAP ASSIGNMENT ====================
print_str('--- 67. Nested map assignment ---')
// Tests map[string]map[string]bool{} pattern - nested map with inner map initialization
// 67.1 Create nested map and initialize inner map
mut nested_map := map[string]map[string]bool{}
if 'mod1' !in nested_map {
nested_map['mod1'] = map[string]bool{}
}
nested_map['mod1']['TypeA'] = true
nested_map['mod1']['TypeB'] = true
// 67.2 Verify values
print_int(if nested_map['mod1']['TypeA'] { 1 } else { 0 }) // 1
print_int(if nested_map['mod1']['TypeB'] { 1 } else { 0 }) // 1
print_int(if nested_map['mod1']['TypeC'] { 1 } else { 0 }) // 0 (not set)
// 67.3 Add another module
if 'mod2' !in nested_map {
nested_map['mod2'] = map[string]bool{}
}
nested_map['mod2']['TypeX'] = true
print_int(if nested_map['mod2']['TypeX'] { 1 } else { 0 }) // 1
// 67.4 Check independence of inner maps
print_int(if nested_map['mod1']['TypeA'] { 1 } else { 0 }) // 1 (still set)
print_int(if nested_map['mod2']['TypeA'] { 1 } else { 0 }) // 0 (not in mod2)
// ==================== 68. SMARTCAST WITH IS-CHECK ====================
print_str('--- 68. Smartcast with is-check ---')
// Tests `if x is Type` pattern with sum types
// 68.1 Basic is-check with int variant
num1 := Number(42)
if num1 is int {
print_int(num1) // 42 (smartcasted to int)
} else {
print_int(-1)
}
// 68.2 Basic is-check with Point variant
num2 := Number(Point{
x: 10
y: 20
})
if num2 is Point {
print_int(num2.x) // 10 (smartcasted to Point, access field)
print_int(num2.y) // 20
} else {
print_int(-1)
}
// 68.3 Negative is-check - int is not Point
num3 := Number(100)
if num3 is Point {
print_int(num3.x)
} else {
print_int(-100) // -100 (num3 is int, not Point)
}
// 68.4 Negative is-check - Point is not int
num4 := Number(Point{
x: 5
y: 6
})
if num4 is int {
print_int(num4)
} else {
print_int(-200) // -200 (num4 is Point, not int)
}
// 68.5 Smartcast with computation
num5 := Number(Point{
x: 3
y: 4
})
if num5 is Point {
sum := num5.x + num5.y
print_int(sum) // 7
}
// 68.6 Compound is-check with && and field access
// Tests: if x is Type && x.field == value { ... }
// This requires smartcast to be applied in compound conditions
num6 := Number(Point{
x: 42
y: 100
})
if num6 is Point && num6.x == 42 {
print_int(num6.y) // 100 (smartcast applied in compound &&)
} else {
print_int(-1)
}
// 68.7 Compound is-check that fails the field check
num7 := Number(Point{
x: 10
y: 20
})
if num7 is Point && num7.x == 999 {
print_int(-1) // Should not reach here
} else {
print_int(111) // 111 (fails because x != 999)
}
// 68.8 Compound is-check that fails the type check
num8 := Number(77)
if num8 is Point && num8.x == 77 {
print_int(-1) // Should not reach here
} else {
print_int(77) // 77 (int is not Point)
}
// ==================== 69. ARRAY APPEND ON STRUCT FIELDS ====================
print_str('--- 69. Array append on struct fields ---')
// Tests arr << elem pattern on struct fields (cleanc fallback when transformer doesn't handle it)
// 69.1 Basic array append on struct field
mut holder69 := ArrayHolder{
data: []int{}
}
holder69.data << 10
holder69.data << 20
holder69.data << 30
print_int(holder69.data.len) // 3
print_int(holder69.data[0]) // 10
print_int(holder69.data[1]) // 20
print_int(holder69.data[2]) // 30
// 69.2 Array append in a loop
mut holder69b := ArrayHolder{
data: []int{}
}
for i := 0; i < 5; i++ {
holder69b.data << i * 2
}
print_int(holder69b.data.len) // 5
print_int(holder69b.data[0]) // 0
print_int(holder69b.data[4]) // 8
// 69.3 Array append with expression
mut holder69c := ArrayHolder{
data: []int{}
}
x69 := 100
holder69c.data << x69 + 1
holder69c.data << x69 * 2
print_int(holder69c.data[0]) // 101
print_int(holder69c.data[1]) // 200
// ==================== 70. MATCH EXPRESSION ON SUM TYPES ====================
print_str('--- 70. Match on sum types ---')
// Tests `match x { Type { ... } }` pattern with sum types and smartcasting
// 70.1 Match on int variant
num70a := Number(42)
match num70a {
int {
print_int(num70a) // 42 (smartcasted to int)
}
Point {
print_int(-1)
}
}
// 70.2 Match on Point variant with field access
num70b := Number(Point{
x: 7
y: 8
})
match num70b {
int {
print_int(-1)
}
Point {
print_int(num70b.x) // 7 (smartcasted to Point)
print_int(num70b.y) // 8
}
}
// 70.3 Match with computation on Point variant
num70c := Number(Point{
x: 5
y: 5
})
match num70c {
int {
print_int(num70c + 1)
}
Point {
sum70 := num70c.x + num70c.y
print_int(sum70) // 10
}
}
// 70.4 Match result in assignment
num70d := Number(99)
result70 := match num70d {
int {
num70d * 2 // 198
}
Point {
-1
}
}
print_int(result70) // 198
// 70.5 Match on Point with result assignment
num70e := Number(Point{
x: 3
y: 4
})
result70e := match num70e {
int {
-1
}
Point {
num70e.x * num70e.y // 12
}
}
print_int(result70e) // 12
// ==================== 71. NESTED SMARTCAST ====================
print_str('--- 71. Nested smartcast ---')
// Tests nested smartcasting where outer match smartcasts to a variant
// that is itself a sum type, then inner if-is checks that variant.
// This requires the transformer to apply outer smartcasts to inner tag checks.
// 71.1 Nested smartcast: match outer, if-is inner (int variant)
nested1 := NestedOuter(Number(42))
match nested1 {
Number {
// nested1 is now smartcasted to Number
// Number is itself a sum type (int | Point)
if nested1 is int {
print_int(nested1) // 42 (nested smartcast to int)
} else {
print_int(-1)
}
}
Rectangle {
print_int(-1)
}
}
// 71.2 Nested smartcast: match outer, if-is inner (Point variant)
nested2 := NestedOuter(Number(Point{
x: 7
y: 8
}))
match nested2 {
Number {
// nested2 is smartcasted to Number
if nested2 is Point {
print_int(nested2.x) // 7 (nested smartcast to Point)
print_int(nested2.y) // 8
} else {
print_int(-1)
}
}
Rectangle {
print_int(-1)
}
}
// 71.3 Nested smartcast: negative test - inner type doesn't match
nested3 := NestedOuter(Number(100))
match nested3 {
Number {
if nested3 is Point {
print_int(-1) // Should not reach
} else {
print_int(200) // 200 (nested3 is int, not Point)
}
}
Rectangle {
print_int(-1)
}
}
// 71.4 Nested smartcast with computation
nested4 := NestedOuter(Number(Point{
x: 5
y: 6
}))
match nested4 {
Number {
if nested4 is Point {
sum71 := nested4.x + nested4.y
print_int(sum71) // 11
}
}
Rectangle {
print_int(-1)
}
}
// ==================== 72. ARRAY LITERAL TYPE INFERENCE ====================
print_str('--- 72. Array literal type inference ---')
// Test array literal with cast expression as first element
// The element type should be inferred from the cast type (u8), not default to int
mut buf72 := [u8(`0`), `1`, `2`]
print_int(buf72.len) // 3
print_int(buf72[0]) // 48 (ASCII for '0')
print_int(buf72[1]) // 49 (ASCII for '1')
print_int(buf72[2]) // 50 (ASCII for '2')
// SKIP: bytestr() crashes on native backend
// result72 := buf72.bytestr()
// print_str(result72) // 012
// Test string comparison
s72a := 'hello'
s72b := 'hello'
s72c := 'world'
if s72a == s72b {
print_int(1) // 1 (strings are equal)
} else {
print_int(0)
}
if s72a != s72c {
print_int(2) // 2 (strings are different)
} else {
print_int(0)
}
// ==================== 73. ARRAY INDEX METHOD ====================
print_str('--- 73. Array index method ---')
// Test array index method on string arrays
months73 := ['January', 'February', 'March', 'April', 'May', 'June']
idx73a := months73.index('March')
print_int(idx73a) // 2
idx73b := months73.index('June')
print_int(idx73b) // 5
idx73c := months73.index('NotFound')
print_int(idx73c) // -1
// Test array index on int arrays
nums73 := [10, 20, 30, 40, 50]
idx73d := nums73.index(30)
print_int(idx73d) // 2
idx73e := nums73.index(99)
print_int(idx73e) // -1
// ==================== 74. MATCH RETURN DIFFERENT ENUM TYPE ====================
print_str('--- 74. Match return different enum type ---')
// Test that match conditions use the correct enum type, not the return type
// This tests the fix for: fn (op Operator) get_binding_power() BindingPower
// where match op { .plus { .low } } should use Operator for .plus, BindingPower for .low
op74a := Operator.plus
bp74a := op74a.get_binding_power()
print_int(int(bp74a)) // 1 (BindingPower.low)
op74b := Operator.mul
bp74b := op74b.get_binding_power()
print_int(int(bp74b)) // 2 (BindingPower.medium)
op74c := Operator.minus
bp74c := op74c.get_binding_power()
print_int(int(bp74c)) // 1 (BindingPower.low, same as plus)
op74d := Operator.div
bp74d := op74d.get_binding_power()
print_int(int(bp74d)) // 2 (BindingPower.medium, same as mul)
// ==================== 75. GOTO STATEMENT ====================
print_str('--- 75. Goto statement ---')
// Test goto inside unsafe block
mut counter75 := 0
mut iterations75 := 0
start75:
counter75++
iterations75++
if counter75 < 3 {
unsafe {
goto start75
}
}
print_int(iterations75) // 3 - should loop 3 times
// Test goto skipping code
mut skipped75 := false
unsafe {
goto skip75
}
skipped75 = true // This should be skipped
skip75:
if skipped75 {
print_int(0) // Should not print this
} else {
print_int(1) // 1 - code was skipped
}
// ==================== 76. ARRAY PUSH IN MAP ITERATION ====================
print_str('--- 76. Array push in map iteration ---')
// Test array << struct_init inside for-in-map loop
// This previously caused double transformation of ArrayInitExpr
mut errors76 := []Error76{}
mut users76 := map[int]bool{}
users76[1] = true
users76[2] = true
users76[3] = true
for user_id, _ in users76 {
if user_id > 1 {
errors76 << Error76{
msg: 'user'
val_id: user_id
}
}
}
print_int(errors76.len) // 2 - two errors added
// Test map.delete() and map.clear()
mut m76 := map[int]bool{}
m76[10] = true
m76[20] = true
m76[30] = true
print_int(m76.len) // 3
// SKIP: map.delete() crashes on native backend
// m76.delete(20)
// print_int(m76.len) // 2
// m76.clear()
// print_int(m76.len) // 0
// ==================== 77. SMARTCAST SUM TYPE ARGUMENT ====================
print_str('--- 77. Smartcast sum type argument ---')
// Test that smartcasted variable inside match branch can be passed
// to a function expecting the original sum type
// This tests the fix for: b.stmt(stmt) where stmt is smartcast to TypeDecl inside match
num77a := Number(42)
match num77a {
int {
// num77a is smartcast to int here, but process_number expects Number
result77a := process_number(num77a)
print_int(result77a) // 42
}
else {}
}
num77b := Number(Point{
x: 10
y: 20
})
match num77b {
Point {
// num77b is smartcast to Point here, but process_number expects Number
result77b := process_number(num77b)
print_int(result77b) // 30 (10 + 20)
}
else {}
}
// Test if-is pattern with sum type argument
num77c := Number(100)
if num77c is int {
// num77c is smartcast to int, pass to function expecting Number
result77c := process_number(num77c)
print_int(result77c) // 100
}
// ==================== 78. MAP ACCESS WITH MUT PARAMETER ====================
print_str('--- 78. Map access with mut parameter ---')
// SKIP: map with mut parameter + recursive function crashes on native backend
// mut visited78 := map[int]bool{}
// succs78 := [1, 2]
// count78 := dfs_mark_visited(mut visited78, 0, succs78)
// print_int(count78) // 3 - visited nodes 0, 1, 2
// if visited78[0] { print_int(1) } else { print_int(0) }
// Test string map if-guard
mut aliases78 := map[string]string{}
aliases78['Foo'] = 'Bar'
result78a := resolve_type_alias(aliases78, 'Foo')
print_str(result78a) // Bar (found in map)
result78b := resolve_type_alias(aliases78, 'Baz')
print_str(result78b) // Baz (not found, returns default)
// Test 79: else-if chain smartcast
// Tests that smartcast from earlier branches doesn't leak into later else-if branches
print_str('Test 79: else-if chain smartcast')
wrapper79a := CallWrapper{
expr: OuterExpr{
lhs: InnerExpr(10)
}
}
print_int(test_elseif_chain_smartcast(wrapper79a)) // 11 (10 + 1)
wrapper79b := CallWrapper{
expr: OuterExpr{
lhs: InnerExpr(20)
}
}
print_int(test_elseif_chain_smartcast(wrapper79b)) // 22 (20 + 2)
wrapper79c := CallWrapper{
expr: OuterExpr{
lhs: InnerExpr('hello')
}
}
print_int(test_elseif_chain_smartcast(wrapper79c)) // 5 (len of 'hello')
wrapper79d := CallWrapper{
expr: OuterExpr{
lhs: InnerExpr(Point{
x: 3
y: 4
})
}
}
print_int(test_elseif_chain_smartcast(wrapper79d)) // 7 (3 + 4)
// ==================== 80. STRING MATCH RETURN ====================
// Tests match expression with string conditions that returns a value
print_str('--- Test 80: String match return ---')
print_str(operator_to_name('+')) // __plus
print_str(operator_to_name('-')) // __minus
print_str(operator_to_name('*')) // __mul
print_str(operator_to_name('?')) // ? (unknown operator)
// ==================== 81. NESTED SUMTYPE METHOD CALL SMARTCAST ====================
// Tests that when matching outer sum type (Outer = Inner | bool) against a nested sum type variant (Inner),
// method calls receive the smartcast (Inner) not the original variable (Outer)
print_str('--- Test 81: Nested sumtype method call smartcast ---')
proc := Processor{
name: 'test'
}
// Test 1: Int in Inner in Outer
outer81a := OuterSumType(InnerSumType(42))
print_int(proc.process_outer(outer81a)) // 42
// Test 2: String in Inner in Outer
outer81b := OuterSumType(InnerSumType('hello'))
print_int(proc.process_outer(outer81b)) // 5 (len of 'hello')
// Test 3: Bool in Outer (not Inner)
outer81c := OuterSumType(true)
print_int(proc.process_outer(outer81c)) // 1
// ==================== 82. RECURSIVE SUMTYPE FIELD ACCESS ====================
// Tests recursive function with sumtype parameter accessing fields of smartcast variant
print_str('--- Test 82: Recursive sumtype field access ---')
// SKIP: Recursive sumtype with heap allocation crashes on native backend
// test82_expr := TestExpr(TestInfixExpr{...})
// print_int(eval_recursive(test82_expr)) // 3 (1 + 2)
// print_int(eval_recursive(test82_nested)) // 6 (1 + 2 + 3)
// print_int(test_gen.try_eval_int(test82_expr) or { -1 }) // 3
// print_int(test_gen.try_eval_int(test82_nested) or { -1 }) // 6
// ==================== 83. NESTED IF-IS SMARTCAST WITH FUNCTION CALL ====================
// Tests the pattern from cleanc.v:2015-2046 where:
// if call.lhs is SelectorExpr {
// if call.lhs.lhs is SelectorExpr {
// result := fn_expecting_sumtype(call.lhs.lhs) // must wrap or not extract
// }
// }
print_str('--- Test 83: Nested if-is smartcast with fn call ---')
// SKIP: nested sumtype smartcast crashes on native backend
// ==================== 84. RETURN IF EXPRESSION ====================
// Tests return if expression transformation
print_str('--- Test 84: Return if expression ---')
test_return_if_expr()
// ==================== 85. COMBINED && SMARTCAST ====================
// Tests combined && conditions with nested is checks: if a is T && a.field is U { a.field.inner }
print_str('--- Test 85: Combined && smartcast ---')
// SKIP: crashes with nil string on native backend
// test_combined_smartcast()
// ==================== 86. IF-GUARD ARRAY ACCESS ====================
// Tests if-guard with array index expressions (bounds checking)
print_str('--- Test 86: If-guard array access ---')
test_if_guard_array_access()
// ==================== 87. OPTIONAL POINTER RETURN TYPE ====================
// Tests functions returning ?&Struct (option wrapping a pointer)
print_str('--- Test 87: Optional pointer return ---')
// SKIP: ?&Struct if-guard doesn't properly deref pointer on native backend
// test_optional_pointer_return()
// ==================== 88. METHOD CALL ON VARIABLE NAMED 'v' ====================
// Tests method calls on loop variable named 'v' (module/variable disambiguation)
print_str('--- Test 88: Method on v variable ---')
test_method_on_v_variable()
print_str('--- Test 89: Sumtype match return ---')
// SKIP: crashes on native backend
// test_sumtype_match_return()
print_str('--- Test 90: Map or-block with rlock ---')
// SKIP: crashes on native backend
// test_map_or_rlock()
print_str('--- Test 91: Map or-block with array value ---')
test_map_or_array_value()
print_str('--- Test 92: Flag enum set/clear ---')
test_flag_enum_set_clear()
print_str('--- Test 93: Interface method dispatch via fn-pointer ---')
// SKIP: crashes on native backend
// test_interface_fn_pointer_dispatch()
print_str('--- Test 94: Sumtype .type_name() ---')
// SKIP: crashes on native backend
// test_sumtype_type_name()
print_str('--- Test 95: Method call resolution ---')
// SKIP: compound assignment on struct fields produces wrong values on native backend
// test_method_call_resolution()
print_str('--- Test 96: Sumtype variant inference ---')
test_sumtype_variant_inference()
print_str('--- Test 97: Array type resolution ---')
test_array_type_resolution()
print_str('--- Test 98: Variadic call lowering ---')
// SKIP: variadic call lowering crashes on native backend
// test_variadic_call_lowering()
print_str('--- Test 99: Array init with index ---')
test_array_init_with_index()
print_str('--- Test 100: Map field index .str() receiver ---')
test_map_field_index_str_receiver()
print_str('--- Test 101: Array map or-block fallback it ---')
test_array_map_or_fallback_it()
print_str('--- Test 102: Dynamic array of fixed arrays ---')
test_dynamic_array_of_fixed_arrays()
print_str('=== All tests completed ===')
}