1.1 adding a scanner

last updated: Oct 20, 2023

Let's next add a fake Scanner, before we fill it out a bit:

const std = @import("std");

const TokenType = enum {
    space,
    char,
};

const Token = struct {
    typ: TokenType,
    start: u8,
    end: u8,
};

const TokenList = std.ArrayList(*Token);

const Scanner = struct {
    allocator: std.mem.Allocator,
    buf: []const u8,

    pub fn init(allocator: std.mem.Allocator, buf: []const u8) Scanner {
        return Scanner{
            .allocator = allocator,
            .buf = buf,
        };
    }

    pub fn scan(self: Scanner) !TokenList {
        var tl = TokenList.init(self.allocator);
        var tok = Token{ .typ = .space, .start = 0, .end = 0 };
        try tl.append(&tok);
        return tl;
    }
};

fn run(allocator: std.mem.Allocator, buf: []const u8) void {
    std.debug.print("file contents: {s}", .{buf});
    var scanner = Scanner.init(allocator, buf);
    var tokens = scanner.scan();
    std.debug.print("tokens: {s}\n", .{tokens});
}

fn runFile(allocator: std.mem.Allocator, path: []const u8) !void {
    std.debug.print("reading file {s}\n", .{path});

    var input = try std.fs.cwd().readFileAlloc(allocator, path, std.math.maxInt(usize));
    defer allocator.free(input);

    run(allocator, input);
}

fn runPrompt(allocator: std.mem.Allocator) !void {
    std.debug.print("run the interpreter\n", .{});
    const stdin = std.io.getStdIn().reader();
    const stderr = std.io.getStdErr().writer();
    var repl_buf: [1024]u8 = undefined;

    if (stdin.readUntilDelimiterOrEof(&repl_buf, '\n') catch |err| {
        try stderr.print("\nUnable to parse command: {s}\n", .{@errorName(err)});
        return;
    }) |line| {
        run(allocator, line);
    }
}

pub fn main() anyerror!void {
    var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){};
    const gpa = general_purpose_allocator.allocator();
    const args = try std.process.argsAlloc(gpa);
    defer std.process.argsFree(gpa, args);

    // args[0] is our executable
    if (args.len > 2) {
        std.debug.print("Usage: lexzical [script]\n", .{});
    } else if (args.len == 2) {
        try runFile(gpa, args[1]);
    } else {
        try runPrompt(gpa);
    }
}
↑ up