const std = @import("std"); const Allocator = std.mem.Allocator; const Scanner = @import("Scanner.zig"); var hadError = false; pub fn main() !u8 { var gpa: std.heap.DebugAllocator(.{}) = .init; defer _ = gpa.deinit(); const allocator = gpa.allocator(); const args = try std.process.argsAlloc(allocator); defer std.process.argsFree(allocator, args); if (args.len > 2) { var stdout_writer = std.fs.File.stdout().writer(&.{}); const stdout = &stdout_writer.interface; try stdout.writeAll("Usage: zlox [script]\n"); return 64; } else if (args.len == 2) { return runFile(allocator, args[1]); } else { try runPrompt(allocator); } return 0; } fn runFile(allocator: Allocator, path: []const u8) !u8 { const bytes = try std.fs.cwd().readFileAlloc(allocator, path, std.math.maxInt(usize)); defer allocator.free(bytes); try run(allocator, bytes); // Indicate an error in the exit code. if (hadError) return 65; return 0; } fn runPrompt(allocator: Allocator) !void { var stdin_buffer: [1024]u8 = undefined; var stdin_reader = std.fs.File.stdin().reader(&stdin_buffer); const stdin = &stdin_reader.interface; var stdout_writer = std.fs.File.stdout().writer(&.{}); const stdout = &stdout_writer.interface; while (true) { try stdout.writeAll("> "); const line = try stdin.takeDelimiter('\n'); if (line == null) break; try run(allocator, line.?); hadError = false; } } fn run(allocator: Allocator, source: []const u8) !void { var scanner = Scanner.init(source); const tokens = try scanner.scanTokens(allocator); defer allocator.free(tokens); // For now, just print the tokens. for (tokens) |token| { std.debug.print("{f}\n", .{token}); } } pub fn @"error"(line: u32, message: []const u8) !void { try report(line, "", message); } var stderr_buffer: [1024]u8 = undefined; var stderr_writer = std.fs.File.stderr().writer(&stderr_buffer); const stderr = &stderr_writer.interface; fn report(line: u32, where: []const u8, message: []const u8) !void { try stderr.print("[line {}] Error{s}: {s}\n", .{ line, where, message }); try stderr.flush(); hadError = true; }