Skip to content

Commit

Permalink
Move standard library to own file
Browse files Browse the repository at this point in the history
  • Loading branch information
yukiisbored committed Jul 8, 2023
1 parent 912dd36 commit a7224cd
Show file tree
Hide file tree
Showing 2 changed files with 179 additions and 168 deletions.
178 changes: 10 additions & 168 deletions src/Vm.zig
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ const debug = @import("./constants.zig").debug;
const FrameStack = Stack(Frame, 64);
const ValueStack = Stack(Value, FrameStack.capacity * 256);

const stdlib_routines = @import("./stdlib.zig").routines;

pub const RuntimeError = error{
InvalidType,
UnknownRoutine,
Expand Down Expand Up @@ -83,6 +85,11 @@ pub const Instruction = union(enum) {
}
};

pub const NativeRoutine = struct {
name: []const u8,
func: *const fn (self: *Self) anyerror!void,
};

const Routine = union(enum) {
user: []const Instruction,
native: *const fn (self: *Self) anyerror!void,
Expand All @@ -100,7 +107,9 @@ pub fn init(allocator: std.mem.Allocator) !Self {
.routines = std.StringHashMap(Routine).init(allocator),
};

try res.injectNativeRoutines();
inline for (stdlib_routines) |r| {
try res.routines.put(r.name, Routine{ .native = r.func });
}

return res;
}
Expand All @@ -113,173 +122,6 @@ pub fn addRoutine(self: *Self, name: []const u8, instructions: []const Instructi
try self.routines.put(name, Routine{ .user = instructions });
}

fn nativePrint(self: *Self) !void {
const stdout = std.io.getStdOut().writer();
try (try self.stack.pop()).print(stdout);
try stdout.writeAll("\n");
}

fn nativeDrop(self: *Self) !void {
try self.stack.drop();
}

fn nativeDup(self: *Self) !void {
try self.stack.push((try self.stack.peek()).*);
}

fn nativeSwap(self: *Self) !void {
const top = try self.stack.pop();
const below = try self.stack.pop();
try self.stack.push(top);
try self.stack.push(below);
}

fn nativeRot(self: *Self) !void {
const a = try self.stack.pop();
const b = try self.stack.pop();
const c = try self.stack.pop();
try self.stack.push(b);
try self.stack.push(a);
try self.stack.push(c);
}

fn nativeOver(self: *Self) !void {
const a = try self.stack.pop();
const b = try self.stack.pop();
try self.stack.push(b);
try self.stack.push(a);
try self.stack.push(b);
}

fn nativeEquals(self: *Self) !void {
const a = try self.stack.pop();
const b = try self.stack.pop();
try self.stack.push(.{ .b = try a.equals(b) });
}

fn nativeAssert(self: *Self) !void {
switch (try self.stack.pop()) {
.b => |b| if (!b) return error.AssertFailed,
else => return error.InvalidType,
}
}

fn nativeNot(self: *Self) !void {
try self.stack.push(switch (try self.stack.pop()) {
.b => |b| .{ .b = !b },
else => return error.InvalidType,
});
}

const BooleanBinaryOp = enum {
@"or",
@"and",
};

inline fn nativeBooleanBinaryOp(self: *Self, comptime op: BooleanBinaryOp) !void {
const a = switch (try self.stack.pop()) {
.b => |b| b,
else => return error.InvalidType,
};
const t = try self.stack.peek();
const b = switch (t.*) {
.b => |b| b,
else => return error.InvalidType,
};
const res = switch (op) {
.@"or" => a or b,
.@"and" => a and b,
};
t.b = res;
}

const NumberComparisonOp = enum {
gt,
ge,
lt,
le,
};

inline fn nativeNumberComparisonOp(self: *Self, comptime op: NumberComparisonOp) !void {
const b = switch (try self.stack.pop()) {
.n => |n| n,
else => return error.InvalidType,
};
const a = switch (try self.stack.pop()) {
.n => |n| n,
else => return error.InvalidType,
};
const res = switch (op) {
.gt => a > b,
.ge => a >= b,
.lt => a < b,
.le => a <= b,
};
try self.stack.push(Value{ .b = res });
}

// FIXME: Use function definition expressions once it's implemented.
// https://github.com/ziglang/zig/issues/1717
fn nativeOr(self: *Self) !void {
return self.nativeBooleanBinaryOp(.@"or");
}

fn nativeAnd(self: *Self) !void {
return self.nativeBooleanBinaryOp(.@"and");
}

fn nativeGreaterThan(self: *Self) !void {
return self.nativeNumberComparisonOp(.gt);
}

fn nativeGreaterEqual(self: *Self) !void {
return self.nativeNumberComparisonOp(.ge);
}

fn nativeLessThan(self: *Self) !void {
return self.nativeNumberComparisonOp(.lt);
}

fn nativeLessEqual(self: *Self) !void {
return self.nativeNumberComparisonOp(.le);
}

const NativeRoutine = struct {
name: []const u8,
func: *const fn (self: *Self) anyerror!void,
};

fn injectNativeRoutines(self: *Self) !void {
const xs = comptime [_]NativeRoutine{
// General purpose
.{ .name = "PRINT", .func = nativePrint },
.{ .name = "ASSERT", .func = nativeAssert },
.{ .name = "EQUALS", .func = nativeEquals },

// Stack manipulation
.{ .name = "DROP", .func = nativeDrop },
.{ .name = "DUP", .func = nativeDup },
.{ .name = "SWAP", .func = nativeSwap },
.{ .name = "ROT", .func = nativeRot },
.{ .name = "OVER", .func = nativeOver },

// Boolean operations
.{ .name = "OR", .func = nativeOr },
.{ .name = "AND", .func = nativeAnd },
.{ .name = "NOT", .func = nativeNot },

// Number comparators
.{ .name = "GREATER-THAN", .func = nativeGreaterThan },
.{ .name = "GREATER-EQUAL", .func = nativeGreaterEqual },
.{ .name = "LESS-THAN", .func = nativeLessThan },
.{ .name = "LESS-EQUAL", .func = nativeLessEqual },
};

inline for (xs) |x| {
try self.routines.put(x.name, .{ .native = x.func });
}
}

const BinaryOp = enum {
add,
sub,
Expand Down
169 changes: 169 additions & 0 deletions src/stdlib.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
const std = @import("std");

const Vm = @import("./Vm.zig");

pub const routines = [_]Vm.NativeRoutine{
// General purpose
.{ .name = "PRINT", .func = nativePrint },
.{ .name = "ASSERT", .func = nativeAssert },
.{ .name = "EQUALS", .func = nativeEquals },

// Stack manipulation
.{ .name = "DROP", .func = nativeDrop },
.{ .name = "DUP", .func = nativeDup },
.{ .name = "SWAP", .func = nativeSwap },
.{ .name = "ROT", .func = nativeRot },
.{ .name = "OVER", .func = nativeOver },

// Boolean operations
.{ .name = "OR", .func = nativeOr },
.{ .name = "AND", .func = nativeAnd },
.{ .name = "NOT", .func = nativeNot },

// Number comparators
.{ .name = "GREATER-THAN", .func = nativeGreaterThan },
.{ .name = "GREATER-EQUAL", .func = nativeGreaterEqual },
.{ .name = "LESS-THAN", .func = nativeLessThan },
.{ .name = "LESS-EQUAL", .func = nativeLessEqual },
};

// == GENERAL PURPOSE == //

fn nativePrint(vm: *Vm) !void {
const stdout = std.io.getStdOut().writer();
try (try vm.stack.pop()).print(stdout);
try stdout.writeAll("\n");
}

fn nativeAssert(vm: *Vm) !void {
switch (try vm.stack.pop()) {
.b => |b| if (!b) return error.AssertFailed,
else => return error.InvalidType,
}
}

fn nativeEquals(vm: *Vm) !void {
const a = try vm.stack.pop();
const b = try vm.stack.pop();
try vm.stack.push(.{ .b = try a.equals(b) });
}

// == STACK MANIPULATION == //

fn nativeDrop(vm: *Vm) !void {
try vm.stack.drop();
}

fn nativeDup(vm: *Vm) !void {
try vm.stack.push((try vm.stack.peek()).*);
}

fn nativeSwap(vm: *Vm) !void {
const top = try vm.stack.pop();
const below = try vm.stack.pop();
try vm.stack.push(top);
try vm.stack.push(below);
}

fn nativeRot(vm: *Vm) !void {
const a = try vm.stack.pop();
const b = try vm.stack.pop();
const c = try vm.stack.pop();
try vm.stack.push(b);
try vm.stack.push(a);
try vm.stack.push(c);
}

fn nativeOver(vm: *Vm) !void {
const a = try vm.stack.pop();
const b = try vm.stack.pop();
try vm.stack.push(b);
try vm.stack.push(a);
try vm.stack.push(b);
}

// == BOOLEAN OPERATIONS == //

fn nativeNot(vm: *Vm) !void {
try vm.stack.push(switch (try vm.stack.pop()) {
.b => |b| .{ .b = !b },
else => return error.InvalidType,
});
}

const BooleanBinaryOp = enum {
@"or",
@"and",
};

inline fn nativeBooleanBinaryOp(vm: *Vm, comptime op: BooleanBinaryOp) !void {
const a = switch (try vm.stack.pop()) {
.b => |b| b,
else => return error.InvalidType,
};
const t = try vm.stack.peek();
const b = switch (t.*) {
.b => |b| b,
else => return error.InvalidType,
};
const res = switch (op) {
.@"or" => a or b,
.@"and" => a and b,
};
t.b = res;
}

// FIXME: Use function definition expressions once it's implemented.
// https://github.com/ziglang/zig/issues/1717
fn nativeOr(vm: *Vm) !void {
return nativeBooleanBinaryOp(vm, .@"or");
}

fn nativeAnd(vm: *Vm) !void {
return nativeBooleanBinaryOp(vm, .@"and");
}

// == NUMBER COMPARATORS == //

const NumberComparisonOp = enum {
gt,
ge,
lt,
le,
};

inline fn nativeNumberComparisonOp(vm: *Vm, comptime op: NumberComparisonOp) !void {
const b = switch (try vm.stack.pop()) {
.n => |n| n,
else => return error.InvalidType,
};
const a = switch (try vm.stack.pop()) {
.n => |n| n,
else => return error.InvalidType,
};
const res = switch (op) {
.gt => a > b,
.ge => a >= b,
.lt => a < b,
.le => a <= b,
};
try vm.stack.push(Vm.Value{ .b = res });
}

// FIXME: Use function definition expressions once it's implemented.
// https://github.com/ziglang/zig/issues/1717
fn nativeGreaterThan(vm: *Vm) !void {
return nativeNumberComparisonOp(vm, .gt);
}

fn nativeGreaterEqual(vm: *Vm) !void {
return nativeNumberComparisonOp(vm, .ge);
}

fn nativeLessThan(vm: *Vm) !void {
return nativeNumberComparisonOp(vm, .lt);
}

fn nativeLessEqual(vm: *Vm) !void {
return nativeNumberComparisonOp(vm, .le);
}

0 comments on commit a7224cd

Please sign in to comment.