X-Git-Url: https://git.ayoreis.com/zlox.git/blobdiff_plain/abb953787c9ce7a2eb0459ecbf7b1b9a7000b0c1..refs/heads/main:/src/main.zig?ds=inline diff --git a/src/main.zig b/src/main.zig index 5905114..19aae30 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,25 +1,37 @@ 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 Interpreter = @import("Interpreter.zig"); +const ErrorPayload = Interpreter.ErrorPayload; +var interpreter: Interpreter = undefined; var hadError = false; +var hadRuntimeError = 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); + var stdout_buffer: [1024]u8 = undefined; + var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer); + const stdout = &stdout_writer.interface; + interpreter = Interpreter.init(allocator, stdout); + defer interpreter.deinit(); + if (args.len > 2) { - var stdout_writer = std.fs.File.stdout().writer(&.{}); - const stdout = &stdout_writer.interface; try stdout.writeAll("Usage: zlox [script]\n"); + try stdout.flush(); return 64; } else if (args.len == 2) { return runFile(allocator, args[1]); } else { - try runPrompt(allocator); + try runPrompt(allocator, stdout); } return 0; @@ -32,19 +44,19 @@ fn runFile(allocator: Allocator, path: []const u8) !u8 { // Indicate an error in the exit code. if (hadError) return 65; + if (hadRuntimeError) return 70; return 0; } -fn runPrompt(allocator: Allocator) !void { +fn runPrompt(allocator: Allocator, stdout: *std.Io.Writer) !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("> "); + try stdout.flush(); const line = try stdin.takeDelimiter('\n'); if (line == null) break; try run(allocator, line.?); @@ -56,14 +68,18 @@ 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 statements = try parser.parse(); - // For now, just print the tokens. - for (tokens) |token| { - std.debug.print("{f}\n", .{token}); - } + // Stop if there was a syntax error. + if (hadError) return; + + try interpreter.interpret(statements); + try interpreter.stdout.flush(); } -pub fn @"error"(line: u32, message: []const u8) !void { +pub fn scanError(line: u32, message: []const u8) !void { try report(line, "", message); } @@ -76,3 +92,17 @@ fn report(line: u32, where: []const u8, message: []const u8) !void { try stderr.flush(); hadError = true; } + +pub fn parseError(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); + } +} + +pub fn runtimeError(err: ErrorPayload) !void { + try stderr.print("{s}\n[line {}]\n", .{ err.message, err.token.line }); + try stderr.flush(); + hadRuntimeError = true; +}