]> Repositories - zlox.git/blob - src/main.zig
License project
[zlox.git] / src / main.zig
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 ast_printer = @import("ast_printer.zig");
7
8 var hadError = false;
9
10 pub fn main() !u8 {
11     var gpa: std.heap.DebugAllocator(.{}) = .init;
12     defer _ = gpa.deinit();
13     const allocator = gpa.allocator();
14     const args = try std.process.argsAlloc(allocator);
15     defer std.process.argsFree(allocator, args);
16
17     if (args.len > 2) {
18         var stdout_writer = std.fs.File.stdout().writer(&.{});
19         const stdout = &stdout_writer.interface;
20         try stdout.writeAll("Usage: zlox [script]\n");
21         return 64;
22     } else if (args.len == 2) {
23         return runFile(allocator, args[1]);
24     } else {
25         try runPrompt(allocator);
26     }
27
28     return 0;
29 }
30
31 fn runFile(allocator: Allocator, path: []const u8) !u8 {
32     const bytes = try std.fs.cwd().readFileAlloc(allocator, path, std.math.maxInt(usize));
33     defer allocator.free(bytes);
34     try run(allocator, bytes);
35
36     // Indicate an error in the exit code.
37     if (hadError) return 65;
38
39     return 0;
40 }
41
42 fn runPrompt(allocator: Allocator) !void {
43     var stdin_buffer: [1024]u8 = undefined;
44     var stdin_reader = std.fs.File.stdin().reader(&stdin_buffer);
45     const stdin = &stdin_reader.interface;
46     var stdout_writer = std.fs.File.stdout().writer(&.{});
47     const stdout = &stdout_writer.interface;
48
49     while (true) {
50         try stdout.writeAll("> ");
51         const line = try stdin.takeDelimiter('\n');
52         if (line == null) break;
53         try run(allocator, line.?);
54         hadError = false;
55     }
56 }
57
58 fn run(allocator: Allocator, source: []const u8) !void {
59     var scanner = Scanner.init(allocator, source);
60     const tokens = try scanner.scanTokens();
61     defer allocator.free(tokens);
62     var parser = try Parser.init(allocator, tokens);
63     defer parser.deinit();
64     const expression = try parser.parse();
65
66     // Stop if there was a syntax error.
67     if (hadError) return;
68
69     const printed = try ast_printer.print(allocator, expression.?);
70     defer allocator.free(printed);
71     std.debug.print("{s}\n", .{printed});
72 }
73
74 pub fn scanError(line: u32, message: []const u8) !void {
75     try report(line, "", message);
76 }
77
78 var stderr_buffer: [1024]u8 = undefined;
79 var stderr_writer = std.fs.File.stderr().writer(&stderr_buffer);
80 const stderr = &stderr_writer.interface;
81
82 fn report(line: u32, where: []const u8, message: []const u8) !void {
83     try stderr.print("[line {}] Error{s}: {s}\n", .{ line, where, message });
84     try stderr.flush();
85     hadError = true;
86 }
87
88 pub fn parseError(allocator: Allocator, token: Token, message: []const u8) !void {
89     if (token.type == .eof) {
90         try report(token.line, " at end", message);
91     } else {
92         try report(token.line, try std.fmt.allocPrint(allocator, " at '{s}'", .{token.lexeme}), message);
93     }
94 }