1 const std = @import("std");
2 const Allocator = std.mem.Allocator;
3 const Scanner = @import("Scanner.zig");
4 const Token = @import("Token.zig");
5 const Parser = @import("Parser.zig");
6 const Interpreter = @import("Interpreter.zig");
7 const ErrorPayload = Interpreter.ErrorPayload;
9 var interpreter: Interpreter = undefined;
11 var hadRuntimeError = false;
14 var gpa: std.heap.DebugAllocator(.{}) = .init;
15 defer _ = gpa.deinit();
16 const allocator = gpa.allocator();
18 const args = try std.process.argsAlloc(allocator);
19 defer std.process.argsFree(allocator, args);
21 var stdout_buffer: [1024]u8 = undefined;
22 var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer);
23 const stdout = &stdout_writer.interface;
24 interpreter = Interpreter.init(allocator, stdout);
25 defer interpreter.deinit();
28 try stdout.writeAll("Usage: zlox [script]\n");
31 } else if (args.len == 2) {
32 return runFile(allocator, args[1]);
34 try runPrompt(allocator, stdout);
40 fn runFile(allocator: Allocator, path: []const u8) !u8 {
41 const bytes = try std.fs.cwd().readFileAlloc(allocator, path, std.math.maxInt(usize));
42 defer allocator.free(bytes);
43 try run(allocator, bytes);
45 // Indicate an error in the exit code.
46 if (hadError) return 65;
47 if (hadRuntimeError) return 70;
52 fn runPrompt(allocator: Allocator, stdout: *std.Io.Writer) !void {
53 var stdin_buffer: [1024]u8 = undefined;
54 var stdin_reader = std.fs.File.stdin().reader(&stdin_buffer);
55 const stdin = &stdin_reader.interface;
58 try stdout.writeAll("> ");
60 const line = try stdin.takeDelimiter('\n');
61 if (line == null) break;
62 try run(allocator, line.?);
67 fn run(allocator: Allocator, source: []const u8) !void {
68 var scanner = Scanner.init(allocator, source);
69 const tokens = try scanner.scanTokens();
70 defer allocator.free(tokens);
71 var parser = try Parser.init(allocator, tokens);
72 defer parser.deinit();
73 const expression = try parser.parse();
75 // Stop if there was a syntax error.
78 try interpreter.interpret(expression.?);
79 try interpreter.stdout.flush();
82 pub fn scanError(line: u32, message: []const u8) !void {
83 try report(line, "", message);
86 var stderr_buffer: [1024]u8 = undefined;
87 var stderr_writer = std.fs.File.stderr().writer(&stderr_buffer);
88 const stderr = &stderr_writer.interface;
90 fn report(line: u32, where: []const u8, message: []const u8) !void {
91 try stderr.print("[line {}] Error{s}: {s}\n", .{ line, where, message });
96 pub fn parseError(allocator: Allocator, token: Token, message: []const u8) !void {
97 if (token.type == .eof) {
98 try report(token.line, " at end", message);
100 try report(token.line, try std.fmt.allocPrint(allocator, " at '{s}'", .{token.lexeme}), message);
104 pub fn runtimeError(err: ErrorPayload) !void {
105 try stderr.print("{s}\n[line {}]\n", .{ err.message, err.token.line });
107 hadRuntimeError = true;