diff options
Diffstat (limited to 'js/src/devtools/gc-ubench/argparse.js')
-rw-r--r-- | js/src/devtools/gc-ubench/argparse.js | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/js/src/devtools/gc-ubench/argparse.js b/js/src/devtools/gc-ubench/argparse.js new file mode 100644 index 0000000000..454b53fb71 --- /dev/null +++ b/js/src/devtools/gc-ubench/argparse.js @@ -0,0 +1,127 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// Command-line argument parser, modeled after but not identical to Python's +// argparse. + +var ArgParser = class { + constructor(desc) { + this._params = []; + this._doc = desc; + + this.add_argument("--help", { + help: "display this help message", + }); + } + + // name is '--foo', '-f', or an array of aliases. + // + // spec is an options object with keys: + // dest: key name to store the result in (optional for long options) + // default: value to use if not passed on command line (optional) + // help: description of the option to show in --help + // options: array of valid choices + // + // Prefixes of long option names are allowed. If a prefix is ambiguous, it + // will match the first parameter added to the ArgParser. + add_argument(name, spec) { + const names = Array.isArray(name) ? name : [name]; + + spec = Object.assign({}, spec); + spec.aliases = names; + for (const name of names) { + if (!name.startsWith("-")) { + throw new Error(`unhandled argument syntax '${name}'`); + } + if (name.startsWith("--")) { + spec.dest = spec.dest || name.substr(2); + } + this._params.push({ name, spec }); + } + } + + parse_args(args) { + const opts = {}; + const rest = []; + + for (const { spec } of this._params) { + if (spec.default !== undefined) { + opts[spec.dest] = spec.default; + } + } + + const seen = new Set(); + for (let i = 0; i < args.length; i++) { + const arg = args[i]; + if (!arg.startsWith("-")) { + rest.push(arg); + continue; + } else if (arg === "--") { + rest.push(args.slice(i+1)); + break; + } + + if (arg == "--help" || arg == "-h") { + this.help(); + } + + let parameter; + let [passed, value] = arg.split("="); + for (const { name, spec } of this._params) { + if (passed.startsWith("--")) { + if (name.startsWith(passed)) { + parameter = spec; + } + } else if (passed.startsWith("-") && passed === name) { + parameter = spec; + } + if (parameter) { + if (value === undefined) { + value = args[++i]; + } + opts[parameter.dest] = value; + break; + } + } + + if (parameter) { + if (seen.has(parameter)) { + throw new Error(`${parameter.aliases[0]} given multiple times`); + } + seen.add(parameter); + } else { + throw new Error(`invalid command-line argument '${arg}'`); + } + } + + for (const { name, spec } of this._params) { + if (spec.options && !spec.options.includes(opts[spec.dest])) { + throw new Error(`invalid ${name} value '${opts[spec.dest]}'`); + opts[spec.dest] = spec.default; + } + } + + return { opts, rest }; + } + + help() { + print(`Usage: ${this._doc}`); + const specs = new Set(this._params.map(p => p.spec)); + const optstrs = [...specs].map(p => p.aliases.join(", ")); + let maxlen = Math.max(...optstrs.map(s => s.length)); + for (const spec of specs) { + const name = spec.aliases[0]; + let helptext = spec.help ?? "undocumented"; + if ("options" in spec) { + helptext += ` (one of ${spec.options.map(x => `'${x}'`).join(", ")})`; + } + if ("default" in spec) { + helptext += ` (default '${spec.default}')`; + } + const optstr = spec.aliases.join(", "); + print(` ${optstr.padEnd(maxlen)} ${helptext}`); + } + quit(0); + } +}; |