const std = @import("std"); const common = @import("common.zig"); const Str = common.Str; // Ideally should be in main, but I'm using parsed options from this to modify output. filename: Str, printTokens: bool = false, printRootTokens: bool = false, printAST: bool = false, printRootAST: bool = false, printExports: bool = false, noImplicitPrelude: bool = false, dontRun: bool = false, dontCompile: bool = false, noDefaultImports: bool = false, hideErrors: bool = false, programArgs: []Arg = &.{}, backend: ?Backend = null, exeName: ?Str = null, pub const Arg = [*:0]const u8; pub fn parse(args: std.process.ArgIterator, al: std.mem.Allocator) !@This() { var opts = @This(){ .filename = undefined }; var filename: ?[:0]const u8 = null; var progArgs = std.ArrayList(Arg).init(al); var argIt = args; _ = argIt.skip(); // skip filename while (argIt.next()) |arg| { if (std.mem.eql(u8, arg[0..2], "--")) { // NOTE: the commented out part would be the correct thing to do // But I don't feel like writing '--' // // // check if this is an arg break. // if (arg.len == 2) { // // if filename was not defined, I assume the first arg is the filename (for shebang stuff) // if (filename == null) { // const fname = argIt.next() orelse return error.DidNotDefineFilename; // filename = fname; // try progArgs.append(fname); // also make sure that the first arg is the filename. // } // while (argIt.next()) |a| { // try progArgs.append(a); // } // } const option = std.meta.stringToEnum(ProgramOption, arg[2..]) orelse { // if option does not exist, pass it to the proogram // TODO: add trailing '/' if not present try progArgs.append(try al.dupeZ(u8, arg)); // NOTE: copy just in case, I'm not sure if its needed tho. continue; }; switch (option) { .@"no-prelude" => opts.noImplicitPrelude = true, .noimplicit => opts.noImplicitPrelude = true, .tokens => opts.printTokens = true, .ast => opts.printAST = true, .exports => opts.printExports = true, .@"!tokens" => opts.printRootTokens = true, .@"!ast" => opts.printRootAST = true, .@"no-default-imports" => opts.noDefaultImports = true, .dontRun => opts.dontRun = true, .@"dont-compile" => opts.dontCompile = true, .@"hide-errors" => opts.hideErrors = true, .backend => { if (argIt.next()) |barg| { const bopt = std.meta.stringToEnum(Backend, barg) orelse { unreachable; // report error }; opts.backend = bopt; } else { unreachable; // report error } }, } } else if (std.mem.eql(u8, arg[0..1], "-")) { const option = std.meta.stringToEnum(ShortOption, arg[1..]) orelse { // if option does not exist, pass it to the proogram // TODO: add trailing '/' if not present try progArgs.append(try al.dupeZ(u8, arg)); // NOTE: copy just in case, I'm not sure if its needed tho. continue; }; switch (option) { .o => { opts.exeName = argIt.next().?; }, } } else { // we also include the program name for argc/argv C compat. try progArgs.append(arg); if (filename == null) { filename = arg; } } } if (filename) |realAssFilename| { opts.filename = realAssFilename; opts.programArgs = progArgs.items; return opts; } else { return error.DidNotDefineFilename; } } // define enum for quick qt parsing const ProgramOption = enum { tokens, ast, exports, @"!tokens", @"!ast", noimplicit, @"no-default-imports", dontRun, @"dont-compile", @"hide-errors", backend, @"no-prelude", }; const ShortOption = enum { o, }; pub const Backend = enum { c, };