diff --git a/compiler/arch.ts b/compiler/arch.ts
index 7ada7dd..e1c51e6 100644
--- a/compiler/arch.ts
+++ b/compiler/arch.ts
@@ -50,85 +50,16 @@ export const Builtins = {
     ArrayLength: 0x24,
     StructSet: 0x30,
     Print: 0x40,
-
 } as const;
 
 export function opToString(op: number): string {
-    switch (op) {
-        case Ops.Nop:
-            return "Nop";
-        case Ops.PushNull:
-            return "PushNull";
-        case Ops.PushInt:
-            return "PushInt";
-        case Ops.PushBool:
-            return "PushBool";
-        case Ops.PushString:
-            return "PushString";
-        case Ops.PushPtr:
-            return "PushPtr";
-        case Ops.Pop:
-            return "Pop";
-        case Ops.ReserveStatic:
-            return "ReserveStatic";
-        case Ops.LoadStatic:
-            return "LoadStatic";
-        case Ops.StoreStatic:
-            return "StoreStatic";
-        case Ops.LoadLocal:
-            return "LoadLocal";
-        case Ops.StoreLocal:
-            return "StoreLocal";
-        case Ops.Call:
-            return "Call";
-        case Ops.Return:
-            return "Return";
-        case Ops.Jump:
-            return "Jump";
-        case Ops.JumpIfTrue:
-            return "JumpIfTrue";
-        case Ops.Builtin:
-            return "Builtin";
-        case Ops.Add:
-            return "Add";
-        case Ops.Subtract:
-            return "Subtract";
-        case Ops.Multiply:
-            return "Multiply";
-        case Ops.Divide:
-            return "Divide";
-        case Ops.Remainder:
-            return "Remainder";
-        case Ops.Equal:
-            return "Equal";
-        case Ops.LessThan:
-            return "LessThan";
-        case Ops.And:
-            return "And";
-        case Ops.Or:
-            return "Or";
-        case Ops.Xor:
-            return "Xor";
-        case Ops.Not:
-            return "Not";
-        case Ops.SourceMap:
-            return "SourceMap";
-        default:
-            return `<unknown Op ${op}>`;
-    }
+    return Object.entries(Ops)
+        .find(([_key, value]) => value === op)
+        ?.[0] ?? `<unknown Op ${op}>`;
 }
 
 export function builtinToString(builtin: number): string {
-    switch (builtin) {
-        case Builtins.StringConcat: return "StringConcat";
-        case Builtins.StringEqual: return "StringEqual";
-        case Builtins.StringCharAt: return "StringCharAt";
-        case Builtins.StringLength: return "StringLength";
-        case Builtins.StringPushChar: return "StringPushChar";
-        case Builtins.ArraySet: return "ArraySet";
-        case Builtins.StructSet: return "StructSet";
-        case Builtins.Print: return "Print";
-        default:
-            return `<unknown Builtin ${builtin}>`;
-    }
+    return Object.entries(Builtins)
+        .find(([_key, value]) => value === builtin)
+        ?.[0] ?? `<unknown Builtin ${builtin}>`;
 }
diff --git a/compiler/info.ts b/compiler/info.ts
index 07b2ca8..55a3dad 100644
--- a/compiler/info.ts
+++ b/compiler/info.ts
@@ -19,7 +19,7 @@ export class Reporter {
 
     private printReport({ reporter, type, pos, msg }: Report) {
         console.error(
-            `${reporter}: ${type}: ${msg}${
+            `${reporter} ${type}: ${msg}${
                 pos ? ` at ${pos.line}:${pos.col}` : ""
             }`,
         );
diff --git a/compiler/lowerer.ts b/compiler/lowerer.ts
index 80beeb5..6f78e42 100644
--- a/compiler/lowerer.ts
+++ b/compiler/lowerer.ts
@@ -113,7 +113,8 @@ export class Lowerer {
         if (stmt.kind.expr) {
             this.lowerExpr(stmt.kind.expr);
         }
-        this.program.add(Ops.Jump, this.breakStack.at(-1)!);
+        this.program.add(Ops.PushPtr, this.breakStack.at(-1)!);
+        this.program.add(Ops.Jump);
     }
 
     private lowerBuiltinAnno(annoArgs: Expr[]) {
@@ -127,49 +128,15 @@ export class Lowerer {
             );
         }
         const value = anno.kind.value;
-        switch (value) {
-            case "Print": {
-                this.program.add(Ops.Builtin, Builtins.Print);
-                break;
-            }
-            case "StringLength": {
-                this.program.add(Ops.Builtin, Builtins.StringLength);
-                break;
-            }
-            case "StringCharAt": {
-                this.program.add(Ops.Builtin, Builtins.StringCharAt);
-                break;
-            }
-            case "StringPushChar": {
-                this.program.add(Ops.Builtin, Builtins.StringPushChar);
-                break;
-            }
-            case "ArrayNew": {
-                this.program.add(Ops.Builtin, Builtins.ArrayNew);
-                break;
-            }
-            case "ArraySet": {
-                this.program.add(Ops.Builtin, Builtins.ArraySet);
-                break;
-            }
-            case "ArrayPush": {
-                this.program.add(Ops.Builtin, Builtins.ArrayPush);
-                break;
-            }
-            case "ArrayLength": {
-                this.program.add(Ops.Builtin, Builtins.ArrayLength);
-                break;
-            }
-            case "ArrayAt": {
-                this.program.add(Ops.Builtin, Builtins.ArrayAt);
-                break;
-            }
-            default: {
-                throw new Error(
-                    `unrecognized builtin '${value}'`,
-                );
-            }
+        const builtin = Object.entries(Builtins).find((entry) =>
+            entry[0] === value
+        )?.[1];
+        if (builtin === undefined) {
+            throw new Error(
+                `unrecognized builtin '${value}'`,
+            );
         }
+        this.program.add(Ops.Builtin, builtin);
     }
 
     private lowerFnStmt(stmt: Stmt) {
@@ -238,7 +205,7 @@ export class Lowerer {
             case "ident":
                 break;
             case "group":
-                break;
+                return void this.lowerExpr(expr.kind.expr);
             case "field":
                 break;
             case "index":
@@ -246,7 +213,7 @@ export class Lowerer {
             case "call":
                 return this.lowerCallExpr(expr);
             case "unary":
-                break;
+                return this.lowerUnaryExpr(expr);
             case "binary":
                 return this.lowerBinaryExpr(expr);
             case "if":
@@ -299,6 +266,28 @@ export class Lowerer {
         this.program.add(Ops.PushString, expr.kind.value);
     }
 
+    private lowerUnaryExpr(expr: Expr) {
+        if (expr.kind.type !== "unary") {
+            throw new Error();
+        }
+        this.lowerExpr(expr.kind.subject);
+        const vtype = expr.kind.subject.vtype!;
+        if (vtype.type === "bool") {
+            switch (expr.kind.unaryType) {
+                case "not":
+                    this.program.add(Ops.Not);
+                    return;
+                default:
+            }
+        }
+        throw new Error(
+            `unhandled unary` +
+                ` '${vtypeToString(expr.vtype!)}' aka. ` +
+                ` ${expr.kind.unaryType}` +
+                ` '${vtypeToString(expr.kind.subject.vtype!)}'`,
+        );
+    }
+
     private lowerBinaryExpr(expr: Expr) {
         if (expr.kind.type !== "binary") {
             throw new Error();
@@ -320,6 +309,9 @@ export class Lowerer {
                 case "==":
                     this.program.add(Ops.Equal);
                     return;
+                case "<":
+                    this.program.add(Ops.LessThan);
+                    return;
                 case ">=":
                     this.program.add(Ops.LessThan);
                     this.program.add(Ops.Not);
@@ -403,7 +395,8 @@ export class Lowerer {
 
         this.program.setLabel(contineLabel);
         this.lowerExpr(expr.kind.body);
-        this.program.add(Ops.PushPtr, breakLabel);
+        this.program.add(Ops.Pop);
+        this.program.add(Ops.PushPtr, contineLabel);
         this.program.add(Ops.Jump);
         this.program.setLabel(breakLabel);
         if (expr.vtype!.type === "null") {
diff --git a/examples/std.slg b/examples/std.slg
index 549699f..9c82740 100644
--- a/examples/std.slg
+++ b/examples/std.slg
@@ -1,19 +1,16 @@
 
-fn array_new_string() -> [string] #[builtin(ArrayNew)] {}
 
 fn print(msg: string) #[builtin(Print)] {}
+fn println(msg: string) { print(msg + "\n") }
 
-fn array_push_string(array: [string], str: string) #[builtin(ArrayPush)] {}
-
-fn string_push_char(str: string, value: int) #[builtin(StringPushChar)] {}
-
+fn string_push_char(str: string, value: int) -> string #[builtin(StringPushChar)] {}
 fn string_char_at(str: string, index: int) -> int #[builtin(StringCharAt)] {}
-
 fn string_length(str: string) -> int #[builtin(StringLength)] {}
 
-fn array_string_length(array: [string]) -> int #[builtin(StringLength)] {}
-
-fn array_string_at(array: [string], index: int) -> string #[builtin(ArrayAt)] {}
+fn array_new_string() -> [string] #[builtin(ArrayNew)] {}
+fn array_push_string(array: [string], value: string) #[builtin(ArrayPush)] {}
+fn array_length_string(array: [string]) -> int #[builtin(ArrayLength)] {}
+fn array_at_string(array: [string], index: int) -> string #[builtin(ArrayAt)] {}
 
 fn char(ch: string) -> int {
     string_char_at(ch, 0)
@@ -25,6 +22,9 @@ fn split(str: string, seperator: int) -> [string] {
     let i = 0;
     let current_str = "";
     loop {
+        if i >= string_length(str) {
+            break;
+        }
         let char = string_char_at(str, i);
         if char == seperator {
             array_push_string(result, current_str);
@@ -32,9 +32,6 @@ fn split(str: string, seperator: int) -> [string] {
         } else {
             string_push_char(current_str, char);
         }
-        if string_length(str) - 1 == i {
-            break;
-        }
         i = i + 1;
     }
     result
@@ -43,11 +40,13 @@ fn split(str: string, seperator: int) -> [string] {
 fn main() {
     let array = split("aoisfjasoifjsaiofjsa", char("a"));
     let i = 0;
+    let array_length = array_length_string(array);
     loop {
-        print(array_string_at(array, i) + "\n");
-        i = i + 1;
-        if array_string_length(array) - 1 == i {
+        if i >= array_length {
             break;
         }
+        let v = array_at_string(array, 0);
+        println(v);
+        i = i + 1;
     }
 }
diff --git a/examples/string_int_args.slg b/examples/string_int_args.slg
new file mode 100644
index 0000000..310fef2
--- /dev/null
+++ b/examples/string_int_args.slg
@@ -0,0 +1,25 @@
+
+fn print(msg: string) #[builtin(Print)] {}
+
+fn repeat(value: string, amount: int) -> string {
+    let result = "";
+
+    let i = 0;
+    loop {
+        if not (i < amount) {
+            break;
+        }
+
+        result = result + value;
+
+        i = i + 1;
+    }
+
+    result
+}
+
+fn main() {
+    let value = repeat("hello world\n", 3);
+    print(value);
+}
+
diff --git a/runtime/vm.cpp b/runtime/vm.cpp
index 503e77d..9812503 100644
--- a/runtime/vm.cpp
+++ b/runtime/vm.cpp
@@ -30,8 +30,13 @@ void VM::run_n_instructions(size_t amount)
 void VM::run_instruction()
 {
     if (this->opts.print_stack_debug) {
+        // std::cout << std::format("    {:>4}: {:<12}{}\n", this->pc,
+        //     maybe_op_to_string(this->program[this->pc]),
+        //     stack_repr_string(8));
+        auto stack_frame_size = this->stack.size() - this->bp;
         std::cout << std::format("    {:>4}: {:<12}{}\n", this->pc,
-            maybe_op_to_string(this->program[this->pc]), stack_repr_string(8));
+            maybe_op_to_string(this->program[this->pc]),
+            stack_repr_string(stack_frame_size));
     }
     auto op = eat_op();
     switch (op) {
@@ -125,11 +130,9 @@ void VM::run_instruction()
             stack_push(Ptr { .value = this->bp });
             this->pc = fn_ptr.as_ptr().value;
             this->bp = static_cast<uint32_t>(this->stack.size());
-            // for (size_t i = arguments.size(); i > 0; --i) {
-            //     stack_push(std::move(arguments.at(i - 1)));
-            // }
-            for (size_t i = 0; i < arguments.size(); ++i) {
-                stack_push(std::move(arguments.at(i)));
+            for (auto&& arg = arguments.rbegin(); arg != arguments.rend();
+                 ++arg) {
+                stack_push(*arg);
             }
             if (this->opts.flame_graph) {
                 this->flame_graph.report_call(
@@ -277,20 +280,57 @@ void VM::run_instruction()
 
 void VM::run_builtin(Builtin builtin_id)
 {
+    if (this->opts.print_stack_debug) {
+        std::cout << std::format(
+            "Running builtin {}\n", static_cast<uint32_t>(builtin_id));
+    }
     switch (builtin_id) {
         case Builtin::StringConcat: {
             assert_stack_has(2);
-            auto left = stack_pop();
             auto right = stack_pop();
+            auto left = stack_pop();
             stack_push(
-                String(right.as_string().value + left.as_string().value));
+                String(left.as_string().value + right.as_string().value));
             break;
         }
         case Builtin::StringEqual: {
             assert_stack_has(2);
-            auto left = stack_pop();
             auto right = stack_pop();
-            stack_push(Bool(right.as_string().value == left.as_string().value));
+            auto left = stack_pop();
+            stack_push(Bool(left.as_string().value == right.as_string().value));
+            break;
+        }
+        case Builtin::StringCharAt: {
+            assert_stack_has(2);
+            auto index_value = stack_pop();
+            auto str = stack_pop();
+
+            auto index = static_cast<size_t>(index_value.as_int().value);
+            auto ch = static_cast<int32_t>(str.as_string().value.at(index));
+            stack_push(Int(ch));
+            break;
+        }
+        case Builtin::StringLength: {
+            assert_stack_has(1);
+            auto str = stack_pop().as_string().value;
+
+            auto length = static_cast<int32_t>(str.length());
+            stack_push(Int(length));
+            break;
+        }
+        case Builtin::StringPushChar: {
+            assert_stack_has(2);
+            auto ch = stack_pop();
+            auto str = stack_pop();
+
+            auto new_str = std::string(str.as_string().value);
+            new_str.push_back(static_cast<char>(ch.as_int().value));
+            stack_push(String(new_str));
+            break;
+        }
+        case Builtin::ArrayNew: {
+            auto alloc_res = this->heap.alloc<heap::AllocType::Array>();
+            stack_push(Ptr(alloc_res.val()));
             break;
         }
         case Builtin::ArraySet: {
@@ -299,6 +339,32 @@ void VM::run_builtin(Builtin builtin_id)
             std::exit(1);
             break;
         }
+        case Builtin::ArrayPush: {
+            assert_stack_has(2);
+            auto value = stack_pop();
+            auto array_ptr = stack_pop().as_ptr().value;
+
+            this->heap.at(array_ptr).val()->as_array().values.push_back(value);
+            stack_push(Null());
+            break;
+        }
+        case Builtin::ArrayAt: {
+            assert_stack_has(2);
+            auto index = stack_pop().as_int().value;
+            auto array_ptr = stack_pop().as_ptr().value;
+
+            auto array = this->heap.at(array_ptr).val()->as_array();
+            stack_push(array.values.at(static_cast<size_t>(index)));
+            break;
+        }
+        case Builtin::ArrayLength: {
+            assert_stack_has(1);
+            auto array_ptr = stack_pop().as_ptr().value;
+
+            auto array = this->heap.at(array_ptr).val()->as_array();
+            stack_push(Int(static_cast<int32_t>(array.values.size())));
+            break;
+        }
         case Builtin::StructSet: {
             assert_stack_has(2);
             std::cerr << std::format("not implemented\n");
@@ -312,59 +378,5 @@ void VM::run_builtin(Builtin builtin_id)
             stack_push(Null());
             break;
         }
-        case Builtin::StringCharAt: {
-            assert_stack_has(2);
-            auto str = stack_pop();
-            auto index_value = stack_pop();
-            auto index = static_cast<size_t>(index_value.as_int().value);
-            auto ch = static_cast<int32_t>(str.as_string().value.at(index));
-            stack_push(Int(ch));
-            break;
-        }
-        case Builtin::StringLength: {
-            assert_stack_has(1);
-            auto str = stack_pop().as_string().value;
-            auto length = static_cast<int32_t>(str.length());
-            stack_push(Int(length));
-            break;
-        }
-        case Builtin::StringPushChar: {
-            assert_stack_has(2);
-            auto str = stack_pop();
-            auto ch = stack_pop();
-            auto new_str = std::string(str.as_string().value);
-            new_str.push_back(static_cast<char>(ch.as_int().value));
-            stack_push(String(new_str));
-            break;
-        }
-        case Builtin::ArrayNew: {
-            auto alloc_res = this->heap.alloc<heap::AllocType::Array>();
-            stack_push(Ptr(alloc_res.val()));
-            break;
-        }
-        case Builtin::ArrayPush: {
-            assert_stack_has(2);
-            auto array_ptr = stack_pop().as_ptr().value;
-            auto value = stack_pop();
-            auto array = this->heap.at(array_ptr).val()->as_array();
-            array.values.push_back(value);
-            stack_push(Null());
-            break;
-        }
-        case Builtin::ArrayAt: {
-            assert_stack_has(2);
-            auto array_ptr = stack_pop().as_ptr().value;
-            auto index = stack_pop().as_int().value;
-            auto array = this->heap.at(array_ptr).val()->as_array();
-            stack_push(array.values.at(static_cast<size_t>(index)));
-            break;
-        }
-        case Builtin::ArrayLength: {
-            assert_stack_has(1);
-            auto array_ptr = stack_pop().as_ptr().value;
-            auto array = this->heap.at(array_ptr).val()->as_array();
-            stack_push(Int(static_cast<int32_t>(array.values.size())));
-            break;
-        }
     }
 }
diff --git a/runtime/vm.hpp b/runtime/vm.hpp
index 6adbf69..5a1bc45 100644
--- a/runtime/vm.hpp
+++ b/runtime/vm.hpp
@@ -185,8 +185,8 @@ public:
             result += std::format(
                 "{:<11}", stack[stack.size() - i - 1].to_repr_string());
         }
-        if (stack.size() >= max_items) {
-            result += std::format(" ... + {}", stack.size() - max_items + 1);
+        if (stack.size() > max_items) {
+            result += std::format(" ... + {}", stack.size() - max_items);
         }
         return result;
     }