@@ -494,6 +494,201 @@ pub fn (mut g Gen) ensure_cap(arr_var Var, required int) {
494494 g.store (ast.int_type, 12 )
495495}
496496
497+ // array_push implements the array << operator (append single element)
498+ // arr_var: Var pointing to the array struct
499+ // elem_expr: Expression for the element to append
500+ pub fn (mut g Gen) array_push (arr_var Var, elem_expr ast.Expr) {
501+ // Get array element type
502+ elem_type := g.table.value_type (arr_var.typ)
503+
504+ // Load current len and check if len >= max_int
505+ g.get (arr_var)
506+ g.load (ast.int_type, 8 ) // array.len
507+ current_len := g.func.new_local_named (.i32_ t, '__tmp<len>' )
508+ g.func.local_tee (current_len)
509+
510+ g.literalint (2147483647 , ast.int_type) // max_int
511+ g.func.ge (.i32_ t, true ) // len >= max_int
512+
513+ blk_len_check := g.func.c_if ([], [])
514+ {
515+ // len >= max_int, panic
516+ g.expr (ast.StringLiteral{ val: 'array.push: len exceeds max_int' }, ast.string_type)
517+ g.func.call ('panic' )
518+ }
519+ g.func.c_end (blk_len_check)
520+
521+ // Load current cap
522+ g.get (arr_var)
523+ g.load (ast.int_type, 12 ) // array.cap
524+ current_cap := g.func.new_local_named (.i32_ t, '__tmp<cap>' )
525+ g.func.local_set (current_cap)
526+
527+ // Check if we need to grow: len >= cap
528+ g.func.local_get (current_len)
529+ g.func.local_get (current_cap)
530+ g.func.ge (.i32_ t, true ) // len >= cap
531+
532+ blk_grow := g.func.c_if ([], [])
533+ {
534+ // Need to grow, call ensure_cap(len + 1)
535+ // Calculate required capacity
536+ g.func.local_get (current_len)
537+ g.literalint (1 , ast.int_type)
538+ g.func.add (.i32_ t)
539+ required := g.func.new_local_named (.i32_ t, '__tmp<required>' )
540+ g.func.local_tee (required)
541+
542+ // Call ensure_cap with the required capacity as int
543+ // We need to pass it as a literal to ensure_cap
544+ // Since ensure_cap expects a compile-time int, we'll inline the logic here
545+
546+ // Get element_size first
547+ g.get (arr_var)
548+ elem_size := g.func.new_local_named (.i32_ t, '__tmp<elem_size>' )
549+ g.load (ast.int_type, 20 ) // array.element_size
550+ g.func.local_set (elem_size)
551+
552+ // Check nogrow flag
553+ g.get (arr_var)
554+ g.load (ast.int_type, 16 ) // array.flags
555+ flags := g.func.new_local_named (.i32_ t, '__tmp<flags>' )
556+ g.func.local_tee (flags)
557+
558+ g.literalint (4 , ast.int_type) // nogrow = bit 2 = 4
559+ g.func.b_and (.i32_ t)
560+
561+ blk_nogrow := g.func.c_if ([], [])
562+ {
563+ g.expr (ast.StringLiteral{ val: 'array.push: array with nogrow flag cannot grow' }, ast.string_type)
564+ g.func.call ('panic' )
565+ }
566+ g.func.c_end (blk_nogrow)
567+
568+ // Calculate new capacity (doubling from current)
569+ g.func.local_get (current_cap)
570+ new_cap := g.func.new_local_named (.i32_ t, '__tmp<new_cap>' )
571+
572+ // If cap <= 0, use 2, else double
573+ g.func.eqz (.i32_ t)
574+ blk_cap_init := g.func.c_if ([], [.i32_ t])
575+ {
576+ g.literalint (2 , ast.int_type)
577+ }
578+ g.func.c_else (blk_cap_init)
579+ {
580+ g.func.local_get (current_cap)
581+ g.literalint (2 , ast.int_type)
582+ g.func.mul (.i32_ t)
583+ }
584+ g.func.c_end (blk_cap_init)
585+ g.func.local_set (new_cap)
586+
587+ // Ensure new_cap >= required
588+ loop_lbl := g.func.c_loop ([], [])
589+ {
590+ g.func.local_get (new_cap)
591+ g.func.local_get (required)
592+ g.func.lt (.i32_ t, true )
593+
594+ blk_double := g.func.c_if ([], [])
595+ {
596+ g.func.local_get (new_cap)
597+ g.literalint (2 , ast.int_type)
598+ g.func.mul (.i32_ t)
599+ g.func.local_set (new_cap)
600+ g.func.c_br (loop_lbl)
601+ }
602+ g.func.c_end (blk_double)
603+ }
604+ g.func.c_end (loop_lbl)
605+
606+ // Allocate new memory
607+ g.func.local_get (new_cap)
608+ g.func.local_get (elem_size)
609+ g.func.mul (.i32_ t)
610+ g.func.call ('malloc' )
611+ new_data := g.func.new_local_named (.i32_ t, '__tmp<new_data>' )
612+ g.func.local_set (new_data)
613+
614+ // Copy existing data
615+ g.get (arr_var)
616+ old_data := g.func.new_local_named (.i32_ t, '__tmp<old_data>' )
617+ g.load (ast.voidptr_type, 0 )
618+ g.func.local_tee (old_data)
619+
620+ g.func.eqz (.i32_ t)
621+ blk_copy := g.func.c_if ([], [])
622+ {
623+ // old_data is nil
624+ }
625+ g.func.c_else (blk_copy)
626+ {
627+ // vmemcpy(new_data, old_data, len * element_size)
628+ g.func.local_get (new_data)
629+ g.func.local_get (old_data)
630+ g.func.local_get (current_len)
631+ g.func.local_get (elem_size)
632+ g.func.mul (.i32_ t)
633+ g.func.call ('vmemcpy' )
634+ g.func.drop ()
635+
636+ // Free old data if noslices
637+ g.func.local_get (flags)
638+ g.literalint (1 , ast.int_type)
639+ g.func.b_and (.i32_ t)
640+
641+ blk_free := g.func.c_if ([], [])
642+ {
643+ g.func.local_get (old_data)
644+ g.func.call ('free' )
645+ }
646+ g.func.c_end (blk_free)
647+ }
648+ g.func.c_end (blk_copy)
649+
650+ // Update array struct
651+ g.get (arr_var)
652+ g.func.local_get (new_data)
653+ g.store (ast.voidptr_type, 0 )
654+
655+ g.get (arr_var)
656+ g.literalint (0 , ast.int_type)
657+ g.store (ast.int_type, 4 ) // offset = 0
658+
659+ g.get (arr_var)
660+ g.func.local_get (new_cap)
661+ g.store (ast.int_type, 12 ) // cap = new_cap
662+ }
663+ g.func.c_end (blk_grow)
664+
665+ // Get element_size (offset 20)
666+ g.get (arr_var)
667+ final_elem_size := g.func.new_local_named (.i32_ t, '__tmp<final_elem_size>' )
668+ g.load (ast.int_type, 20 )
669+ g.func.local_set (final_elem_size)
670+
671+ // Calculate address for new element: data + (len * element_size)
672+ g.get (arr_var)
673+ g.load (ast.voidptr_type, 0 ) // array.data
674+
675+ g.func.local_get (current_len)
676+ g.func.local_get (final_elem_size)
677+ g.func.mul (.i32_ t)
678+ g.func.add (.i32_ t)
679+
680+ // Evaluate and store the new element
681+ g.expr (elem_expr, elem_type)
682+ g.store (elem_type, 0 )
683+
684+ // Increment len (offset 8)
685+ g.get (arr_var)
686+ g.func.local_get (current_len)
687+ g.literalint (1 , ast.int_type)
688+ g.func.add (.i32_ t)
689+ g.store (ast.int_type, 8 )
690+ }
691+
497692pub fn log2 (size int ) int {
498693 return match size {
499694 1 { 0 }
0 commit comments