summaryrefslogtreecommitdiffstats
path: root/js/src/devtools/gc-ubench/argparse.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/devtools/gc-ubench/argparse.js')
-rw-r--r--js/src/devtools/gc-ubench/argparse.js127
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);
+ }
+};