const std = @import("std"); const langs = @import("lang.zig"); const runners = @import("runner.zig"); test "scritcher" { _ = @import("lang.zig"); _ = @import("runner.zig"); } pub fn doRepl(allocator: *std.mem.Allocator, args_it: var) !void { const scri_path = try (args_it.next(allocator) orelse @panic("expected scri path")); // the thing here is that 'load :0' would load the scri_path, since we // now have a 'repl' argument right before it. to counteract that, the // initial repl buffer contains 'load :1' instead. var cmds = langs.CommandList.init(allocator); defer cmds.deinit(); var loadargs = langs.ArgList.init(allocator); defer loadargs.deinit(); try loadargs.append(":1"); try cmds.append(langs.Command{ .command = .Load, .args = loadargs, }); // TODO start a runner and keep it hot while (true) { try stdout.print("> "); var buffer = try std.Buffer.init(allocator, ""[0..]); var line = std.io.readLine(&buffer) catch |err| { if (err == error.EndOfStream) return; return err; }; // TODO parse the line through langs.parse, then add the command to cmds // TODO save the line to scri_file? or should we have a special `push` // to do so? } } pub fn main() !void { const allocator = std.heap.direct_allocator; var lang = langs.Lang.init(allocator); defer lang.deinit(); var runner = runners.Runner.init(allocator); defer runner.deinit(); var args_it = std.process.args(); // TODO print help _ = try (args_it.next(allocator) orelse @panic("expected exe name")); const scri_path = try (args_it.next(allocator) orelse @panic("expected scri path")); if (std.mem.eql(u8, scri_path, "repl")) { return try doRepl(allocator, &args_it); } var file = try std.fs.File.openRead(scri_path); defer file.close(); // sadly, we read it all into memory. such is life const total_bytes = try file.getEndPos(); var data = try allocator.alloc(u8, total_bytes); defer allocator.free(data); _ = try file.read(data); var cmds = try lang.parse(data); defer cmds.deinit(); try runner.runCommands(cmds, true); }