const std = @import("std"); const Allocator = std.mem.Allocator; const Scanner = @import("Scanner.zig"); const Token = @import("Token.zig"); const Parser = @import("Parser.zig"); const ast_printer = @import("ast_printer.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(allocator, source); const tokens = try scanner.scanTokens(); defer allocator.free(tokens); var parser = try Parser.init(allocator, tokens); defer parser.deinit(); const expression = try parser.parse(); // Stop if there was a syntax error. if (hadError) return; const printed = try ast_printer.print(allocator, expression.?); defer allocator.free(printed); std.debug.print("{s}\n", .{printed}); } 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; } pub fn parse_error(allocator: Allocator, token: Token, message: []const u8) !void { if (token.type == .eof) { try report(token.line, " at end", message); } else { try report(token.line, try std.fmt.allocPrint(allocator, " at '{s}'", .{token.lexeme}), message); } }