diff --git a/src/lang.zig b/src/lang.zig index 9724dfb..a75193b 100644 --- a/src/lang.zig +++ b/src/lang.zig @@ -140,6 +140,7 @@ pub const ArgList = std.ArrayList([]const u8); pub const KeywordMap = std.StringHashMap(CommandType); +/// A parser. pub const Lang = struct { allocator: *std.mem.Allocator, keywords: KeywordMap, diff --git a/src/main.zig b/src/main.zig index a54a7c5..7a05be3 100644 --- a/src/main.zig +++ b/src/main.zig @@ -25,29 +25,59 @@ fn wrapInCmdList(allocator: *std.mem.Allocator, cmd: langs.Command) !langs.Comma pub fn doRepl(allocator: *std.mem.Allocator, args_it: var) !void { var stdout_file = try std.io.getStdOut(); const stdout = &stdout_file.outStream().stream; - const scri_path = try (args_it.next(allocator) orelse @panic("expected scri path")); + var file_read = try std.fs.File.openRead(scri_path); + const total_bytes = try file_read.getEndPos(); + + var cmds = langs.CommandList.init(allocator); + defer cmds.deinit(); + + var lang = langs.Lang.init(allocator); + defer lang.deinit(); + + if (total_bytes > 0) { + // this MUST BE long lived (a reference to it is kept inside + // existing_cmds, and then passed along to cmds), + // we can't defer them here + var scri_existing = try allocator.alloc(u8, total_bytes); + _ = try file_read.read(scri_existing); + + // we can defer this because we copy the Command structs back to cmds + var existing_cmds = try lang.parse(scri_existing); + defer existing_cmds.deinit(); + + // copy the existing command list into the repl's command list + var it = existing_cmds.iterator(); + while (it.next()) |existing_cmd| { + try cmds.append(existing_cmd); + } + } else { + // if there isn't any commands on the file, we load our default + // 'load :1' command + + // TODO load should +1 the index if its on repl + var loadargs = langs.ArgList.init(allocator); + try loadargs.append(":1"); + + try cmds.append(langs.Command{ + .command = .Load, + .args = loadargs, + }); + } + + file_read.close(); + var file = try std.fs.File.openWrite(scri_path); defer file.close(); var out = file.outStream(); var stream = &out.stream; - // 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 loadargs = langs.ArgList.init(allocator); - defer loadargs.deinit(); - try loadargs.append(":1"); - - var cmds = try wrapInCmdList(allocator, langs.Command{ - .command = .Load, - .args = loadargs, - }); - - defer cmds.deinit(); + // since we opened the file for writing, it becomes empty, so, to ensure + // we don't fuck up later on, we print cmds before starting the repl + try printer.printList(cmds, stdout); + try printer.printList(cmds, stream); // we keep // - a CommandList with the full commands we have right now @@ -58,9 +88,6 @@ pub fn doRepl(allocator: *std.mem.Allocator, args_it: var) !void { // - one runner that gets copied from the original on every new // command the user issues - var lang = langs.Lang.init(allocator); - defer lang.deinit(); - var current: langs.Command = undefined; var runner = runners.Runner.init(allocator); @@ -99,6 +126,8 @@ pub fn doRepl(allocator: *std.mem.Allocator, args_it: var) !void { try printer.printList(cmds, stdout); continue; } else if (std.mem.eql(u8, line, "save")) { + // seek to 0 instead of appending the new command + // NOTE appending single command might be faster try file.seekTo(0); try printer.printList(cmds, stream); continue;