Skip to content

Commit

Permalink
feat(opcodes): add OP_2OVER and OP_2SWAP (#117)
Browse files Browse the repository at this point in the history
  • Loading branch information
KhairallahA authored Sep 24, 2024
1 parent f9f22bd commit e4de9fe
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 0 deletions.
80 changes: 80 additions & 0 deletions src/script/engine.zig
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ pub const Engine = struct {
Opcode.OP_2DROP => try self.op2Drop(),
Opcode.OP_2DUP => try self.op2Dup(),
Opcode.OP_3DUP => try self.op3Dup(),
Opcode.OP_2OVER => try self.op2Over(),
Opcode.OP_2SWAP => try self.op2Swap(),
Opcode.OP_IFDUP => self.opIfDup(),
Opcode.OP_DEPTH => self.opDepth(),
Opcode.OP_DROP => try self.opDrop(),
Expand Down Expand Up @@ -309,6 +311,20 @@ pub const Engine = struct {
try self.stack.pushByteArray(first);
}

// OP_2OVER: Copies the pair of items two spaces back in the stack to the front
fn op2Over(self: *Engine) !void {
const fourth = try self.stack.peek(3);
const third = try self.stack.peek(2);
try self.stack.pushByteArray(fourth);
try self.stack.pushByteArray(third);
}

// OP_2SWAP: Swaps the top two pairs of items
fn op2Swap(self: *Engine) !void {
try self.stack.swap(0, 2);
try self.stack.swap(1, 3);
}

/// OP_DEPTH: Puts the number of stack items onto the stack.
fn opDepth(self: *Engine) !void {
const stack_length = self.stack.len();
Expand Down Expand Up @@ -633,6 +649,70 @@ test "Script execution - OP_1 OP_2 OP_3 OP_4 OP_3Dup" {
try std.testing.expectEqual(1, element6);
}

test "Script execution - OP_1 OP_2 OP_3 OP_4 OP_2OVER" {
const allocator = std.testing.allocator;

// Simple script: OP_1 OP_2 OP_3 OP_4 OP_2OVER
const script_bytes = [_]u8{
Opcode.OP_1.toBytes(),
Opcode.OP_2.toBytes(),
Opcode.OP_3.toBytes(),
Opcode.OP_4.toBytes(),
Opcode.OP_2OVER.toBytes(),
};
const script = Script.init(&script_bytes);

var engine = Engine.init(allocator, script, .{});
defer engine.deinit();

try engine.execute();
try std.testing.expectEqual(6, engine.stack.len());

const element0 = try engine.stack.peekInt(0);
const element1 = try engine.stack.peekInt(1);
const element2 = try engine.stack.peekInt(2);
const element3 = try engine.stack.peekInt(3);
const element4 = try engine.stack.peekInt(4);
const element5 = try engine.stack.peekInt(5);

try std.testing.expectEqual(2, element0);
try std.testing.expectEqual(1, element1);
try std.testing.expectEqual(4, element2);
try std.testing.expectEqual(3, element3);
try std.testing.expectEqual(2, element4);
try std.testing.expectEqual(1, element5);
}

test "Script execution - OP_1 OP_2 OP_3 OP_4 OP_2SWAP" {
const allocator = std.testing.allocator;

// Simple script: OP_1 OP_2 OP_3 OP_4 OP_2SWAP
const script_bytes = [_]u8{
Opcode.OP_1.toBytes(),
Opcode.OP_2.toBytes(),
Opcode.OP_3.toBytes(),
Opcode.OP_4.toBytes(),
Opcode.OP_2SWAP.toBytes(),
};
const script = Script.init(&script_bytes);

var engine = Engine.init(allocator, script, .{});
defer engine.deinit();

try engine.execute();
try std.testing.expectEqual(4, engine.stack.len());

const element0 = try engine.stack.peekInt(0);
const element1 = try engine.stack.peekInt(1);
const element2 = try engine.stack.peekInt(2);
const element3 = try engine.stack.peekInt(3);

try std.testing.expectEqual(2, element0);
try std.testing.expectEqual(1, element1);
try std.testing.expectEqual(4, element2);
try std.testing.expectEqual(3, element3);
}

test "Script execution - OP_1 OP_2 OP_IFDUP" {
const allocator = std.testing.allocator;

Expand Down
5 changes: 5 additions & 0 deletions src/script/stack.zig
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,11 @@ pub const Stack = struct {
return asBool(bytes);
}

pub fn swap(self: *Stack, idx1: usize, idx2: usize) StackError!void {
if (self.len() <= @max(idx1, idx2)) { return StackError.StackUnderflow; }
std.mem.swap([]u8, &self.items.items[idx1], &self.items.items[idx2]);
}

/// Get the number of items in the stack
///
/// # Returns
Expand Down

0 comments on commit e4de9fe

Please sign in to comment.