aboutsummaryrefslogtreecommitdiff
path: root/src/argument.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/argument.zig')
-rw-r--r--src/argument.zig341
1 files changed, 174 insertions, 167 deletions
diff --git a/src/argument.zig b/src/argument.zig
index 7912397..81172fb 100644
--- a/src/argument.zig
+++ b/src/argument.zig
@@ -2,223 +2,230 @@ const std = @import("std");
pub const Grammar = @import("grammar.zig");
fn help(err: ?anyerror) noreturn {
- const stderr = std.io.getStdErr().writer();
+ const stderr = std.io.getStdErr().writer();
- if (err) |e| {
- stderr.print("error: {s}\n", .{@errorName(e)}) catch unreachable;
- }
+ if (err) |e| {
+ stderr.print("error: {s}\n", .{@errorName(e)}) catch unreachable;
+ }
- stderr.writeAll(
- \\mry [command] [options]
- \\
- \\Commands:
- \\
- \\ generate [grammar] [options]
- \\ Options:
- \\ -e, --entry label Name of the entry point. (default: main)
- \\
- \\ -o, --output entry Output string to file
- \\ By default stdout will be used.
- \\
- \\ -c, --count n Number of texts to generate. (default: 1)
- \\
- \\ -n, --non-empty Only output texts which are non-empty.
- \\
- \\ -m, --min-length n Minimum length of sentential string.
- \\
- \\ benchmark [grammar] [options]
- \\ Options:
- \\ -e, --entry label Name of the entry point. (default: main)
- \\
- \\ -i, --input entry Specify input source, if the path
- \\ points to a directory it will scan
- \\ all files in it. By default stdin will
- \\ be used as input.
- \\
- \\General Options
- \\ -h, --help Print usage
- \\
- ) catch unreachable;
- std.process.exit(@intFromBool(err != null));
+ stderr.writeAll(
+ \\mry [command] [options]
+ \\
+ \\Commands:
+ \\
+ \\ generate [grammar] [options]
+ \\ Options:
+ \\ -e, --entry label Name of the entry point. (default: main)
+ \\
+ \\ -o, --output entry Output string to file
+ \\ By default stdout will be used.
+ \\
+ \\ -c, --count n Number of texts to generate. (default: 1)
+ \\
+ \\ -n, --non-empty Only output texts which are non-empty.
+ \\
+ \\ -m, --min-length n Minimum length of sentential string.
+ \\
+ \\ benchmark [grammar] [options]
+ \\ Options:
+ \\ -e, --entry label Name of the entry point. (default: main)
+ \\
+ \\ -i, --input entry Specify input source, if the path
+ \\ points to a directory it will scan
+ \\ all files in it. By default stdin will
+ \\ be used as input.
+ \\
+ \\ --csv output in CSV format.
+ \\
+ \\General Options
+ \\ -h, --help Print usage
+ \\
+ ) catch unreachable;
+ std.process.exit(@intFromBool(err != null));
}
fn check(arg_or_null: ?[]const u8) []const u8 {
- const arg = arg_or_null orelse help(error.MissingArgument);
+ const arg = arg_or_null orelse help(error.MissingArgument);
- if (std.mem.eql(u8, arg, "-h") or std.mem.eql(u8, arg, "--help")) {
- help(null);
- }
- return arg;
+ if (std.mem.eql(u8, arg, "-h") or std.mem.eql(u8, arg, "--help")) {
+ help(null);
+ }
+ return arg;
}
fn parse_enum(T: type, arg: []const u8) T {
- return std.meta.stringToEnum(T, arg) orelse help(error.InvalidArgument);
+ return std.meta.stringToEnum(T, arg) orelse help(error.InvalidArgument);
}
fn parse_int(n: []const u8) usize {
- return std.fmt.parseInt(usize, n, 10) catch |e| help(e);
+ return std.fmt.parseInt(usize, n, 10) catch |e| help(e);
}
fn check_flags(arg: []const u8, comptime flags: []const []const u8) bool {
- inline for (flags) |flag| {
- if (std.mem.eql(u8, arg, flag)) {
- return true;
- }
- }
+ inline for (flags) |flag| {
+ if (std.mem.eql(u8, arg, flag)) {
+ return true;
+ }
+ }
- return false;
+ return false;
}
pub const Mode = enum {
- benchmark,
- generate,
+ benchmark,
+ generate,
};
pub const Entry = struct {
- const Self = @This();
+ const Self = @This();
- name: []const u8,
- file: std.fs.File,
+ name: []const u8,
+ file: std.fs.File,
- pub fn open(path: []const u8, writer: bool) Self {
- var cwd = std.fs.cwd();
+ pub fn open(path: []const u8, writer: bool) Self {
+ var cwd = std.fs.cwd();
- return Self {
- .name = path,
- .file = (if (writer) cwd.createFile(path, .{})
- else cwd.openFile(path, .{})) catch |e| help(e)
- };
- }
+ return Self {
+ .name = path,
+ .file = (if (writer) cwd.createFile(path, .{})
+ else cwd.openFile(path, .{})) catch |e| help(e)
+ };
+ }
- pub fn read_file(path: []const u8, allocator: std.mem.Allocator) []const u8 {
- var cwd = std.fs.cwd();
+ pub fn read_file(path: []const u8, allocator: std.mem.Allocator) []const u8 {
+ var cwd = std.fs.cwd();
- var file = cwd.openFile(path, .{}) catch |e| help(e);
- defer file.close();
- const stat = file.stat() catch |e| help(e);
+ var file = cwd.openFile(path, .{}) catch |e| help(e);
+ defer file.close();
+ const stat = file.stat() catch |e| help(e);
- return file.readToEndAlloc(allocator, stat.size) catch |e| help(e);
- }
+ return file.readToEndAlloc(allocator, stat.size) catch |e| help(e);
+ }
- pub fn stdin() Self {
- return Self {
- .name = "[stdin]",
- .file = std.io.getStdIn(),
- };
- }
+ pub fn stdin() Self {
+ return Self {
+ .name = "[stdin]",
+ .file = std.io.getStdIn(),
+ };
+ }
- pub fn stdout() Self {
- return Self {
- .name = "[stdout]",
- .file = std.io.getStdOut(),
- };
- }
+ pub fn stdout() Self {
+ return Self {
+ .name = "[stdout]",
+ .file = std.io.getStdOut(),
+ };
+ }
};
pub const BenchmarkArgs = struct {
- input: Entry,
- grammar: Grammar,
- entry: []const u8,
+ input: Entry,
+ grammar: Grammar,
+ entry: []const u8,
+ csv: bool,
};
pub const GenerateArgs = struct {
- count: usize,
- min_length: usize,
- output: Entry,
- grammar: Grammar,
- entry: []const u8,
+ count: usize,
+ min_length: usize,
+ output: Entry,
+ grammar: Grammar,
+ entry: []const u8,
};
pub const Args = union(Mode) {
- const Self = @This();
+ const Self = @This();
- benchmark: BenchmarkArgs,
- generate: GenerateArgs,
+ benchmark: BenchmarkArgs,
+ generate: GenerateArgs,
- pub fn parse(allocator: std.mem.Allocator) Self {
- var args = std.process.args();
- _ = args.next();
+ pub fn parse(allocator: std.mem.Allocator) Self {
+ var args = std.process.args();
+ _ = args.next();
- const mode = parse_enum(Mode, check(args.next()));
+ const mode = parse_enum(Mode, check(args.next()));
- const text = Entry.read_file(check(args.next()), allocator);
- defer allocator.free(text);
+ const text = Entry.read_file(check(args.next()), allocator);
+ defer allocator.free(text);
- switch (mode) {
- .benchmark => {
- var input: ?Entry = null;
- var entry: []const u8 = "main";
+ switch (mode) {
+ .benchmark => {
+ var input: ?Entry = null;
+ var entry: []const u8 = "main";
+ var csv = false;
- while (args.next()) |arg| {
- if (check_flags(arg, &[_][]const u8 { "-i", "--input" })) {
- input = Entry.open(check(args.next()), false);
- } else if (check_flags(arg, &[_][]const u8 { "-e", "--entry" })) {
- entry = check(args.next());
- } else help(error.InvalidArgument);
- }
+ while (args.next()) |arg| {
+ if (check_flags(arg, &[_][]const u8 { "-i", "--input" })) {
+ input = Entry.open(check(args.next()), false);
+ } else if (check_flags(arg, &[_][]const u8 { "-e", "--entry" })) {
+ entry = check(args.next());
+ } else if (check_flags(arg, &[_][]const u8 { "--csv" })) {
+ csv = true;
+ } else help(error.InvalidArgument);
+ }
- const grammar = Grammar.parse(
- entry,
- text,
- allocator
- ) catch |e| help(e);
+ const grammar = Grammar.parse(
+ entry,
+ text,
+ allocator
+ ) catch |e| help(e);
- return Self {
- .benchmark = .{
- .input = input orelse Entry.stdin(),
- .grammar = grammar,
- .entry = entry,
- },
- };
- },
+ return Self {
+ .benchmark = .{
+ .input = input orelse Entry.stdin(),
+ .grammar = grammar,
+ .entry = entry,
+ .csv = csv,
+ },
+ };
+ },
- .generate => {
- var count: usize = 1;
- var output: ?Entry = null;
- var min_length: usize = 0;
- var entry: []const u8 = "main";
+ .generate => {
+ var count: usize = 1;
+ var output: ?Entry = null;
+ var min_length: usize = 0;
+ var entry: []const u8 = "main";
- while (args.next()) |arg| {
- if (check_flags(arg, &[_][]const u8 { "-o", "--output" })) {
- output = Entry.open(check(args.next()), true);
- } else if (check_flags(arg, &[_][]const u8 { "-c", "--count" })) {
- count = parse_int(check(args.next()));
- } else if (check_flags(arg, &[_][]const u8 { "-n", "--non-empty" })) {
- min_length = 1;
- } else if (check_flags(arg, &[_][]const u8 { "-m", "--min-length" })) {
- min_length = parse_int(check(args.next()));
- } else if (check_flags(arg, &[_][]const u8 { "-e", "--entry" })) {
- entry = check(args.next());
- } else help(error.InvalidArgument);
- }
+ while (args.next()) |arg| {
+ if (check_flags(arg, &[_][]const u8 { "-o", "--output" })) {
+ output = Entry.open(check(args.next()), true);
+ } else if (check_flags(arg, &[_][]const u8 { "-c", "--count" })) {
+ count = parse_int(check(args.next()));
+ } else if (check_flags(arg, &[_][]const u8 { "-n", "--non-empty" })) {
+ min_length = 1;
+ } else if (check_flags(arg, &[_][]const u8 { "-m", "--min-length" })) {
+ min_length = parse_int(check(args.next()));
+ } else if (check_flags(arg, &[_][]const u8 { "-e", "--entry" })) {
+ entry = check(args.next());
+ } else help(error.InvalidArgument);
+ }
- const grammar = Grammar.parse(
- entry,
- text,
- allocator
- ) catch |e| help(e);
+ const grammar = Grammar.parse(
+ entry,
+ text,
+ allocator
+ ) catch |e| help(e);
- return Self {
- .generate = .{
- .count = count,
- .min_length = min_length,
- .output = output orelse Entry.stdout(),
- .grammar = grammar,
- .entry = entry,
- },
- };
- },
- }
- }
+ return Self {
+ .generate = .{
+ .count = count,
+ .min_length = min_length,
+ .output = output orelse Entry.stdout(),
+ .grammar = grammar,
+ .entry = entry,
+ },
+ };
+ },
+ }
+ }
- pub fn deinit(self: *Self) void {
- switch (self.*) {
- .benchmark => |*rec| {
- rec.grammar.deinit();
- },
- .generate => |*gen| {
- gen.grammar.deinit();
- }
- }
- }
+ pub fn deinit(self: *Self) void {
+ switch (self.*) {
+ .benchmark => |*rec| {
+ rec.grammar.deinit();
+ },
+ .generate => |*gen| {
+ gen.grammar.deinit();
+ }
+ }
+ }
};