// Tests for inst.zig

const std = @import("std");
const types = @import("types.zig");
const inst_mod = @import("inst.zig");

const Ref = inst_mod.Ref;
const BlockId = inst_mod.BlockId;
const FuncId = inst_mod.FuncId;
const Inst = inst_mod.Inst;
const Block = inst_mod.Block;
const Function = inst_mod.Function;

test "Ref none sentinel" {
    try std.testing.expect(Ref.none.isNone());
    try std.testing.expect(!Ref.fromIndex(0).isNone());
}

test "basic instruction creation" {
    const inst = Inst{
        .op = .{ .add = .{ .lhs = Ref.fromIndex(0), .rhs = Ref.fromIndex(1) } },
        .ty = .s32,
    };
    try std.testing.expectEqual(types.TypeId.s32, inst.ty);
    switch (inst.op) {
        .add => |bin| {
            try std.testing.expectEqual(Ref.fromIndex(0), bin.lhs);
            try std.testing.expectEqual(Ref.fromIndex(1), bin.rhs);
        },
        else => unreachable,
    }
}

test "block creation" {
    const alloc = std.testing.allocator;
    var block = Block.init(@enumFromInt(1), &.{});
    defer block.deinit(alloc);

    block.insts.append(alloc, .{
        .op = .{ .const_int = 42 },
        .ty = .s64,
    }) catch unreachable;
    block.insts.append(alloc, .{
        .op = .{ .ret = .{ .operand = Ref.fromIndex(0) } },
        .ty = .s64,
    }) catch unreachable;

    try std.testing.expectEqual(@as(usize, 2), block.insts.items.len);
}

test "function creation" {
    const alloc = std.testing.allocator;
    const params = &[_]Function.Param{
        .{ .name = @enumFromInt(1), .ty = .s32 },
        .{ .name = @enumFromInt(2), .ty = .s32 },
    };
    var func = Function.init(@enumFromInt(3), params, .s64);
    defer func.deinit(alloc);

    try std.testing.expectEqual(types.TypeId.s64, func.ret);
    try std.testing.expectEqual(@as(usize, 2), func.params.len);
}
