Version 2.19.0-33.0.dev

Merge commit 'c8728d92e3abc5f06e8c4e744f4671611511669c' into 'dev'
diff --git a/pkg/dart2wasm/bin/dart2wasm.dart b/pkg/dart2wasm/bin/dart2wasm.dart
index 4a382a9..8e1f696 100644
--- a/pkg/dart2wasm/bin/dart2wasm.dart
+++ b/pkg/dart2wasm/bin/dart2wasm.dart
@@ -5,102 +5,109 @@
 import 'dart:io';
 import 'dart:typed_data';
 
+import 'package:args/args.dart' as args;
 import 'package:front_end/src/api_unstable/vm.dart'
     show printDiagnosticMessage, resolveInputUri;
 
 import 'package:dart2wasm/compile.dart';
-import 'package:dart2wasm/translator.dart';
+import 'package:dart2wasm/compiler_options.dart';
+import 'package:dart2wasm/option.dart';
 
-final Map<String, void Function(TranslatorOptions, bool)> boolOptionMap = {
-  "export-all": (o, value) => o.exportAll = value,
-  "import-shared-memory": (o, value) => o.importSharedMemory = value,
-  "inlining": (o, value) => o.inlining = value,
-  "lazy-constants": (o, value) => o.lazyConstants = value,
-  "local-nullability": (o, value) => o.localNullability = value,
-  "name-section": (o, value) => o.nameSection = value,
-  "nominal-types": (o, value) => o.nominalTypes = value,
-  "parameter-nullability": (o, value) => o.parameterNullability = value,
-  "polymorphic-specialization": (o, value) =>
-      o.polymorphicSpecialization = value,
-  "print-kernel": (o, value) => o.printKernel = value,
-  "print-wasm": (o, value) => o.printWasm = value,
-  "runtime-types": (o, value) => o.runtimeTypes = value,
-  "string-data-segments": (o, value) => o.stringDataSegments = value,
-};
-final Map<String, void Function(TranslatorOptions, int)> intOptionMap = {
-  "shared-memory-max-pages": (o, value) => o.sharedMemoryMaxPages = value,
-  "watch": (o, value) => (o.watchPoints ??= []).add(value),
-};
+// Used to allow us to keep defaults on their respective option structs.
+final CompilerOptions _d = CompilerOptions.defaultOptions();
 
-Never usage(String message) {
-  print("Usage: dart2wasm [<options>] <infile.dart> <outfile.wasm>");
-  print("");
-  print("*NOTE*: Wasm compilation is experimental.");
-  print("The support may change, or be removed, with no advance notice.");
-  print("");
-  print("Options:");
-  print("  --dart-sdk=<path>");
-  print("  --platform=<path>");
-  print("");
-  for (String option in boolOptionMap.keys) {
-    print("  --[no-]$option");
+final List<Option> options = [
+  Flag("help", (o, _) {}, abbr: "h", negatable: false, defaultsTo: false),
+  Flag("export-all", (o, value) => o.translatorOptions.exportAll = value,
+      defaultsTo: _d.translatorOptions.exportAll),
+  Flag("import-shared-memory",
+      (o, value) => o.translatorOptions.importSharedMemory = value,
+      defaultsTo: _d.translatorOptions.importSharedMemory),
+  Flag("inlining", (o, value) => o.translatorOptions.inlining = value,
+      defaultsTo: _d.translatorOptions.inlining),
+  Flag(
+      "lazy-constants", (o, value) => o.translatorOptions.lazyConstants = value,
+      defaultsTo: _d.translatorOptions.lazyConstants),
+  Flag("local-nullability",
+      (o, value) => o.translatorOptions.localNullability = value,
+      defaultsTo: _d.translatorOptions.localNullability),
+  Flag("name-section", (o, value) => o.translatorOptions.nameSection = value,
+      defaultsTo: _d.translatorOptions.nameSection),
+  Flag("nominal-types", (o, value) => o.translatorOptions.nominalTypes = value,
+      defaultsTo: _d.translatorOptions.nominalTypes),
+  Flag("parameter-nullability",
+      (o, value) => o.translatorOptions.parameterNullability = value,
+      defaultsTo: _d.translatorOptions.parameterNullability),
+  Flag("polymorphic-specialization",
+      (o, value) => o.translatorOptions.polymorphicSpecialization = value,
+      defaultsTo: _d.translatorOptions.polymorphicSpecialization),
+  Flag("print-kernel", (o, value) => o.translatorOptions.printKernel = value,
+      defaultsTo: _d.translatorOptions.printKernel),
+  Flag("print-wasm", (o, value) => o.translatorOptions.printWasm = value,
+      defaultsTo: _d.translatorOptions.printWasm),
+  Flag("runtime-types", (o, value) => o.translatorOptions.runtimeTypes = value,
+      defaultsTo: _d.translatorOptions.runtimeTypes),
+  Flag("string-data-segments",
+      (o, value) => o.translatorOptions.stringDataSegments = value,
+      defaultsTo: _d.translatorOptions.stringDataSegments),
+  IntOption(
+      "inlining-limit", (o, value) => o.translatorOptions.inliningLimit = value,
+      defaultsTo: "${_d.translatorOptions.inliningLimit}"),
+  IntOption("shared-memory-max-pages",
+      (o, value) => o.translatorOptions.sharedMemoryMaxPages = value),
+  UriOption("dart-sdk", (o, value) => o.sdkPath = value,
+      defaultsTo: "${_d.sdkPath}"),
+  UriOption("platform", (o, value) => o.platformPath = value),
+  IntMultiOption(
+      "watch", (o, values) => o.translatorOptions.watchPoints = values),
+];
+
+CompilerOptions parseArguments(List<String> arguments) {
+  args.ArgParser parser = args.ArgParser();
+  for (Option arg in options) {
+    arg.applyToParser(parser);
   }
-  print("");
-  for (String option in intOptionMap.keys) {
-    print("  --$option <value>");
-  }
-  print("");
 
-  throw message;
+  Never usage() {
+    print("Usage: dart2wasm [<options>] <infile.dart> <outfile.wasm>");
+    print("");
+    print("*NOTE*: Wasm compilation is experimental.");
+    print("The support may change, or be removed, with no advance notice.");
+    print("");
+    print("Options:");
+    for (String line in parser.usage.split('\n')) {
+      print('\t$line');
+    }
+    exit(64);
+  }
+
+  try {
+    args.ArgResults results = parser.parse(arguments);
+    if (results['help']) {
+      usage();
+    }
+    List<String> rest = results.rest;
+    if (rest.length != 2) {
+      throw ArgumentError('Requires two positional file arguments');
+    }
+    CompilerOptions compilerOptions =
+        CompilerOptions(mainUri: resolveInputUri(rest[0]), outputFile: rest[1]);
+    for (Option arg in options) {
+      if (results.wasParsed(arg.name)) {
+        arg.applyToOptions(compilerOptions, results[arg.name]);
+      }
+    }
+    return compilerOptions;
+  } catch (e, s) {
+    print(s);
+    print('Argument Error: ' + e.toString());
+    usage();
+  }
 }
 
 Future<int> main(List<String> args) async {
-  Uri sdkPath = Platform.script.resolve("../../../sdk");
-  Uri? platformPath = null;
-  TranslatorOptions options = TranslatorOptions();
-  List<String> nonOptions = [];
-  void Function(TranslatorOptions, int)? intOptionFun = null;
-  for (String arg in args) {
-    if (intOptionFun != null) {
-      intOptionFun(options, int.parse(arg));
-      intOptionFun = null;
-    } else if (arg.startsWith("--dart-sdk=")) {
-      String path = arg.substring("--dart-sdk=".length);
-      sdkPath = Uri.file(Directory(path).absolute.path);
-    } else if (arg.startsWith("--platform=")) {
-      String path = arg.substring("--platform=".length);
-      platformPath = Uri.file(Directory(path).absolute.path);
-    } else if (arg.startsWith("--no-")) {
-      var optionFun = boolOptionMap[arg.substring(5)];
-      if (optionFun == null) usage("Unknown option $arg");
-      optionFun(options, false);
-    } else if (arg.startsWith("--")) {
-      var optionFun = boolOptionMap[arg.substring(2)];
-      if (optionFun != null) {
-        optionFun(options, true);
-      } else {
-        intOptionFun = intOptionMap[arg.substring(2)];
-        if (intOptionFun == null) usage("Unknown option $arg");
-      }
-    } else {
-      nonOptions.add(arg);
-    }
-  }
-  if (intOptionFun != null) {
-    usage("Missing argument to ${args.last}");
-  }
-
-  if (options.importSharedMemory && options.sharedMemoryMaxPages == null) {
-    usage("--shared-memory-max-pages must be "
-        "specified if --import-shared-memory is used.");
-  }
-
-  if (nonOptions.length != 2) usage("Requires two file arguments");
-  String input = nonOptions[0];
-  String output = nonOptions[1];
-  Uri mainUri = resolveInputUri(input);
-
-  Uint8List? module = await compileToModule(mainUri, sdkPath, platformPath,
+  CompilerOptions options = parseArguments(args);
+  Uint8List? module = await compileToModule(
       options, (message) => printDiagnosticMessage(message, print));
 
   if (module == null) {
@@ -108,7 +115,7 @@
     return exitCode;
   }
 
-  await File(output).writeAsBytes(module);
+  await File(options.outputFile).writeAsBytes(module);
 
   return 0;
 }
diff --git a/pkg/dart2wasm/lib/compile.dart b/pkg/dart2wasm/lib/compile.dart
index f8c4739..990f8dbd 100644
--- a/pkg/dart2wasm/lib/compile.dart
+++ b/pkg/dart2wasm/lib/compile.dart
@@ -22,6 +22,7 @@
 import 'package:vm/transformations/type_flow/transformer.dart' as globalTypeFlow
     show transformComponent;
 
+import 'package:dart2wasm/compiler_options.dart' as compiler;
 import 'package:dart2wasm/target.dart';
 import 'package:dart2wasm/translator.dart';
 
@@ -30,11 +31,7 @@
 /// Returns `null` if an error occurred during compilation. The
 /// [handleDiagnosticMessage] callback will have received an error message
 /// describing the error.
-Future<Uint8List?> compileToModule(
-    Uri mainUri,
-    Uri sdkRoot,
-    Uri? platformDill,
-    TranslatorOptions options,
+Future<Uint8List?> compileToModule(compiler.CompilerOptions options,
     void Function(DiagnosticMessage) handleDiagnosticMessage) async {
   var succeeded = true;
   void diagnosticMessageHandler(DiagnosticMessage message) {
@@ -47,20 +44,20 @@
   Target target = WasmTarget();
   CompilerOptions compilerOptions = CompilerOptions()
     ..target = target
-    ..sdkRoot = sdkRoot
+    ..sdkRoot = options.sdkPath
     ..environmentDefines = {}
     ..verbose = false
     ..onDiagnostic = diagnosticMessageHandler
     ..nnbdMode = NnbdMode.Strong;
 
-  if (platformDill != null) {
-    compilerOptions.sdkSummary = platformDill;
+  if (options.platformPath != null) {
+    compilerOptions.sdkSummary = options.platformPath;
   } else {
     compilerOptions.compileSdk = true;
   }
 
   CompilerResult? compilerResult =
-      await kernelForProgram(mainUri, compilerOptions);
+      await kernelForProgram(options.mainUri, compilerOptions);
   if (compilerResult == null || !succeeded) {
     return null;
   }
@@ -78,7 +75,10 @@
     return true;
   }());
 
-  var translator = Translator(component, coreTypes,
-      TypeEnvironment(coreTypes, compilerResult.classHierarchy!), options);
+  var translator = Translator(
+      component,
+      coreTypes,
+      TypeEnvironment(coreTypes, compilerResult.classHierarchy!),
+      options.translatorOptions);
   return translator.translate();
 }
diff --git a/pkg/dart2wasm/lib/compiler_options.dart b/pkg/dart2wasm/lib/compiler_options.dart
new file mode 100644
index 0000000..b206711
--- /dev/null
+++ b/pkg/dart2wasm/lib/compiler_options.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2022, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+import 'package:dart2wasm/translator.dart';
+
+class CompilerOptions {
+  final TranslatorOptions translatorOptions = TranslatorOptions();
+
+  Uri sdkPath = Platform.script.resolve("../../../sdk");
+  Uri? platformPath;
+  Uri mainUri;
+  String outputFile;
+
+  factory CompilerOptions.defaultOptions() =>
+      CompilerOptions(mainUri: Uri(), outputFile: '');
+
+  CompilerOptions({required this.mainUri, required this.outputFile});
+
+  void validate() {
+    if (translatorOptions.importSharedMemory &&
+        translatorOptions.sharedMemoryMaxPages == null) {
+      throw ArgumentError("--shared-memory-max-pages must be specified if "
+          "--import-shared-memory is used.");
+    }
+  }
+}
diff --git a/pkg/dart2wasm/lib/option.dart b/pkg/dart2wasm/lib/option.dart
new file mode 100644
index 0000000..fc45d7d
--- /dev/null
+++ b/pkg/dart2wasm/lib/option.dart
@@ -0,0 +1,76 @@
+// Copyright (c) 2022, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+import 'package:args/args.dart';
+
+import 'package:dart2wasm/compiler_options.dart';
+
+class Option<T> {
+  final String name;
+  final void Function(ArgParser a) applyToParser;
+  final void Function(CompilerOptions o, T v) _applyToOptions;
+  final T Function(dynamic v) converter;
+
+  void applyToOptions(CompilerOptions o, dynamic v) =>
+      _applyToOptions(o, converter(v));
+
+  Option(this.name, this.applyToParser, this._applyToOptions, this.converter);
+}
+
+class Flag extends Option<bool> {
+  Flag(String name, void applyToOptions(CompilerOptions o, bool v),
+      {String? abbr,
+      String? help,
+      bool? defaultsTo = false,
+      bool negatable = true})
+      : super(
+            name,
+            (a) => a.addFlag(name,
+                abbr: abbr,
+                help: help,
+                defaultsTo: defaultsTo,
+                negatable: negatable),
+            applyToOptions,
+            (v) => v == 'true' ? true : false);
+}
+
+class ValueOption<T> extends Option<T> {
+  ValueOption(String name, void applyToOptions(CompilerOptions o, T v),
+      T converter(dynamic v), {String? defaultsTo})
+      : super(name, (a) => a.addOption(name, defaultsTo: defaultsTo),
+            applyToOptions, converter);
+}
+
+class IntOption extends ValueOption<int> {
+  IntOption(String name, void applyToOptions(CompilerOptions o, int v),
+      {String? defaultsTo})
+      : super(name, applyToOptions, (v) => int.parse(v),
+            defaultsTo: defaultsTo);
+}
+
+class UriOption extends ValueOption<Uri> {
+  UriOption(String name, void applyToOptions(CompilerOptions o, Uri v),
+      {String? defaultsTo})
+      : super(name, applyToOptions, (v) => Uri.file(Directory(v).absolute.path),
+            defaultsTo: defaultsTo);
+}
+
+class MultiValueOption<T> extends Option<List<T>> {
+  MultiValueOption(
+      String name,
+      void Function(CompilerOptions o, List<T> v) applyToOptions,
+      T converter(dynamic v),
+      {Iterable<String>? defaultsTo})
+      : super(name, (a) => a.addMultiOption(name, defaultsTo: defaultsTo),
+            applyToOptions, (vs) => vs.map(converter).cast<T>().toList());
+}
+
+class IntMultiOption extends MultiValueOption<int> {
+  IntMultiOption(name, void applyToOptions(CompilerOptions o, List<int> v),
+      {Iterable<String>? defaultsTo})
+      : super(name, applyToOptions, (v) => int.parse(v),
+            defaultsTo: defaultsTo);
+}
diff --git a/pkg/dart2wasm/pubspec.yaml b/pkg/dart2wasm/pubspec.yaml
index a8cd88a..cc153ea 100644
--- a/pkg/dart2wasm/pubspec.yaml
+++ b/pkg/dart2wasm/pubspec.yaml
@@ -7,6 +7,7 @@
 # Use 'any' constraints here; we get our versions from the DEPS file.
 dependencies:
   _js_interop_checks: any
+  args: any
   front_end: any
   kernel: any
   vm: any
diff --git a/tools/VERSION b/tools/VERSION
index 725f25d..8251f4b 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 19
 PATCH 0
-PRERELEASE 32
+PRERELEASE 33
 PRERELEASE_PATCH 0
\ No newline at end of file