~ntgg/PGLang

5b64a42f5b965a902bb3d349ffb583b4738b8dac — Noah Graff 7 months ago 633e512
moved VM to seperate file
2 files changed, 81 insertions(+), 78 deletions(-)

M src/main.zig
A src/vm.zig
M src/main.zig => src/main.zig +4 -78
@@ 1,88 1,14 @@
const std = @import("std");
const parse = @import("parse.zig").parse;
const Allocator = std.mem.Allocator;
const Instruction = @import("parse.zig").Instruction;

extern fn readByte() u8;
extern fn writeByte(byte: u8) void;

pub const VM = struct {
    const Self = @This();

    allocator: *Allocator,
    instructions: std.ArrayList(Instruction),
    current_instr: usize,
    memory: []u8,
    current_cell: usize,

    pub fn init(allocator: *Allocator, source: []const u8) !Self {
        var memory = try allocator.alloc(u8, 30000);
        std.mem.secureZero(u8, memory);
        return Self{
            .allocator = allocator,
            .instructions = try parse(allocator, source),
            .current_instr = 0,
            .memory = memory,
            .current_cell = 0,
        };
    }

    pub fn deinit(vm: *Self) void {
        vm.instructions.deinit();
        vm.allocator.free(vm.memory);
    }

    pub fn run(vm: *Self) !void {
        while (try vm.step()) {}
    }

    // false if should finish
    pub fn step(vm: *Self) !bool {
        if (vm.current_instr >= vm.instructions.len) return false;

        if (vm.current_cell > vm.memory.len) {
            vm.memory = try vm.allocator.realloc(vm.memory, std.math.max(vm.memory.len * 2, vm.current_cell));
        }

        const instr = vm.instructions.toSliceConst()[vm.current_instr];
        const cell = &vm.memory[vm.current_cell];
        switch (instr) {
            .Incr => |by| {
                cell.* +%= by;
            },
            .Decr => |by| cell.* -%= by,
            .Next => |cells| vm.current_cell += cells,
            .Prev => |cells| {
                if (vm.current_cell < cells) return error.InvalidPointer;
                vm.current_cell -= cells;
            },
            .Output => {
                writeByte(cell.*);
            },
            .Input => {
                cell.* = readByte();
            },
            .LoopStart => |end| if (cell.* == 0) {
                // parse returns only vaild code, so .? is safe
                vm.current_instr = end.?;
            },
            .LoopEnd => |start| if (cell.* != 0) {
                vm.current_instr = start;
            },
        }

        vm.current_instr += 1;
        return true;
    }
};
const VM = @import("vm.zig").VM;

pub export fn runBrainFuckSource(source: [*c]const u8, length: usize) void {
    var arena = std.heap.ArenaAllocator.init(std.heap.wasm_allocator);
    var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
    defer arena.deinit();
    const allocator = &arena.allocator;

    var list = std.ArrayList(u8).init(allocator);
    var i = usize(0);
    var i = @as(usize, 0);
    while (i < length) : (i += 1) {
        list.append(source[i]) catch return;
    }


@@ 95,7 21,7 @@ pub export fn runBrainFuckSource(source: [*c]const u8, length: usize) void {
}
// from https://github.com/fengb/fundude/blob/master/src/wasm.zig
pub export fn malloc(size: usize) ?*c_void {
    const result = std.heap.wasm_allocator.alloc(u8, size) catch return null;
    const result = std.heap.page_allocator.alloc(u8, size) catch return null;
    return result.ptr;
}


A src/vm.zig => src/vm.zig +77 -0
@@ 0,0 1,77 @@
const std = @import("std");
const Allocator = std.mem.Allocator;
const parse = @import("parse.zig").parse;
const Instruction = @import("parse.zig").Instruction;

extern fn readByte() u8;
extern fn writeByte(byte: u8) void;

pub const VM = struct {
    const Self = @This();

    allocator: *Allocator,
    instructions: std.ArrayList(Instruction),
    current_instr: usize,
    memory: []u8,
    current_cell: usize,

    pub fn init(allocator: *Allocator, source: []const u8) !Self {
        var memory = try allocator.alloc(u8, 30000);
        std.mem.secureZero(u8, memory);
        return Self{
            .allocator = allocator,
            .instructions = try parse(allocator, source),
            .current_instr = 0,
            .memory = memory,
            .current_cell = 0,
        };
    }

    pub fn deinit(vm: *Self) void {
        vm.instructions.deinit();
        vm.allocator.free(vm.memory);
    }

    pub fn run(vm: *Self) !void {
        while (try vm.step()) {}
    }

    // false if should finish
    pub fn step(vm: *Self) !bool {
        if (vm.current_instr >= vm.instructions.len) return false;

        if (vm.current_cell > vm.memory.len) {
            vm.memory = try vm.allocator.realloc(vm.memory, std.math.max(vm.memory.len * 2, vm.current_cell));
        }

        const instr = vm.instructions.toSliceConst()[vm.current_instr];
        const cell = &vm.memory[vm.current_cell];
        switch (instr) {
            .Incr => |by| {
                cell.* +%= by;
            },
            .Decr => |by| cell.* -%= by,
            .Next => |cells| vm.current_cell += cells,
            .Prev => |cells| {
                if (vm.current_cell < cells) return error.InvalidPointer;
                vm.current_cell -= cells;
            },
            .Output => {
                writeByte(cell.*);
            },
            .Input => {
                cell.* = readByte();
            },
            .LoopStart => |end| if (cell.* == 0) {
                // parse returns only vaild code, so .? is safe
                vm.current_instr = end.?;
            },
            .LoopEnd => |start| if (cell.* != 0) {
                vm.current_instr = start;
            },
        }

        vm.current_instr += 1;
        return true;
    }
};