~ntgg/PGLang

97fab4ca046e0180ccfa8653858c19fa6dc6cdd3 — Noah Graff 2 months ago 5b64a42
moved to stream based io, removed wasm temporarily

allows for easier IO accros multiple platforms, have to write in and
out streams for wasm, so the support is temporarily removed
3 files changed, 112 insertions(+), 87 deletions(-)

M build.zig
M src/main.zig
M src/vm.zig
M build.zig => build.zig +11 -4
@@ 2,8 2,15 @@ const Builder = @import("std").build.Builder;

pub fn build(b: *Builder) void {
    const mode = b.standardReleaseOptions();
    const lib = b.addStaticLibrary("bfzk", "src/main.zig");
    lib.setBuildMode(mode);
    lib.setTarget(.wasm32, .freestanding, .none);
    lib.install();
    const exe = b.addExecutable("bfzk", "src/main.zig");
    exe.setBuildMode(mode);
    exe.install();

    const run_cmd = exe.run();
    run_cmd.step.dependOn(b.getInstallStep());

    const run_step = b.step("run", "Run the app");
    run_step.dependOn(&run_cmd.step);
}



M src/main.zig => src/main.zig +32 -21
@@ 2,31 2,42 @@ const std = @import("std");
const Allocator = std.mem.Allocator;
const VM = @import("vm.zig").VM;

pub export fn runBrainFuckSource(source: [*c]const u8, length: usize) void {
fn runBrainFuckSourceSlice(allocator: *Allocator, source: []const u8) !void {
    const stdin = std.io.getStdIn();
    const stdout = std.io.getStdOut();

    var vm = try VM(
        std.fs.File.InStream.Error,
        std.fs.File.OutStream.Error,
    ).init(
        allocator,
        source,
        &stdin.inStream().stream,
        &stdout.outStream().stream,
    );
    defer vm.deinit();
    try vm.run();
}

pub fn main() !void {
    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 = @as(usize, 0);
    while (i < length) : (i += 1) {
        list.append(source[i]) catch return;
    }

    // const source_slice = source[0..length];
    const source_slice = list.toOwnedSlice();
    runBrainFuckSourceSlice(allocator, source_slice) catch {
        return;
    var args = std.process.args();
    var exe_path = try args.next(allocator) orelse unreachable;
    defer allocator.free(exe_path);
    var brainfuck_source_file_path = try args.next(allocator) orelse {
        std.debug.warn("Usage: {} FILE\n", .{exe_path});
        std.process.exit(1);
    };
}
// from https://github.com/fengb/fundude/blob/master/src/wasm.zig
pub export fn malloc(size: usize) ?*c_void {
    const result = std.heap.page_allocator.alloc(u8, size) catch return null;
    return result.ptr;
}
    defer allocator.free(brainfuck_source_file_path);

fn runBrainFuckSourceSlice(allocator: *Allocator, source: []const u8) !void {
    var vm = try VM.init(allocator, source);
    defer vm.deinit();
    try vm.run();
    var brainfuck_source_file = try std.fs.cwd().openFile(brainfuck_source_file_path, .{});
    defer brainfuck_source_file.close();

    var brainfuck_source = try brainfuck_source_file.inStream().stream.readAllAlloc(allocator, 1024 * 1024 * 1024);
    defer allocator.free(brainfuck_source);

    try runBrainFuckSourceSlice(allocator, brainfuck_source);
}

M src/vm.zig => src/vm.zig +69 -62
@@ 3,75 3,82 @@ 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 fn VM(comptime ReadError: type, comptime WriteError: type) type {
    return struct {
        const Self = @This();

pub const VM = struct {
    const Self = @This();
        const InStream = std.io.InStream(ReadError);
        const OutStream = std.io.OutStream(WriteError);

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

    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 init(allocator: *Allocator, source: []const u8, in_stream: *InStream, out_stream: *OutStream) !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,
                .in_stream = in_stream,
                .out_stream = out_stream,
            };
        }

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

    pub fn run(vm: *Self) !void {
        while (try vm.step()) {}
    }
        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;
        // 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));
        }
            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 => {
                    try vm.out_stream.print("{}", .{&[_]u8{cell.*}});
                },
                .Input => {
                    cell.* = try vm.in_stream.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;
                },
            }

        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;
        }
    };
}

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