mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 23:09:48 +00:00
[dart2js] Convert first argument to main
- When `main` has arguments, use a callMain shim to convert first argument passed to `main` to a `List<String>`. - Make js_runtime/preambles/{d8,jsshell}.js pass command line arguments to Dart `main`. Change-Id: I8c04bbe49366e756cfe84d1c705767e0366ee74c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/158373 Reviewed-by: Sigmund Cherem <sigmund@google.com> Commit-Queue: Stephen Adams <sra@google.com>
This commit is contained in:
parent
60ec210866
commit
cc3c70159d
|
@ -449,6 +449,8 @@ abstract class CommonElements {
|
|||
|
||||
FunctionEntity getInstantiateFunction(int typeArgumentCount);
|
||||
|
||||
FunctionEntity get convertMainArgumentList;
|
||||
|
||||
// From dart:_rti
|
||||
|
||||
FunctionEntity get setRuntimeTypeInfo;
|
||||
|
@ -1834,6 +1836,10 @@ class CommonElementsImpl
|
|||
cls.name.startsWith('Instantiation');
|
||||
}
|
||||
|
||||
@override
|
||||
FunctionEntity get convertMainArgumentList =>
|
||||
_findHelperFunction('convertMainArgumentList');
|
||||
|
||||
// From dart:_rti
|
||||
|
||||
ClassEntity _findRtiClass(String name) => _findClass(rtiLibrary, name);
|
||||
|
|
|
@ -117,10 +117,13 @@ class BackendImpacts {
|
|||
BackendImpact _mainWithArguments;
|
||||
|
||||
BackendImpact get mainWithArguments {
|
||||
return _mainWithArguments ??= new BackendImpact(instantiatedClasses: [
|
||||
_commonElements.jsArrayClass,
|
||||
_commonElements.jsStringClass
|
||||
]);
|
||||
return _mainWithArguments ??= new BackendImpact(
|
||||
globalUses: [_commonElements.convertMainArgumentList],
|
||||
instantiatedClasses: [
|
||||
_commonElements.jsArrayClass,
|
||||
_commonElements.jsStringClass
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
BackendImpact _asyncBody;
|
||||
|
|
|
@ -9,16 +9,58 @@ import 'package:js_runtime/shared/embedded_names.dart' as embeddedNames;
|
|||
import '../elements/entities.dart';
|
||||
import '../js/js.dart' as jsAst;
|
||||
import '../js/js.dart' show js;
|
||||
import '../common_elements.dart';
|
||||
|
||||
import 'code_emitter_task.dart' show Emitter;
|
||||
|
||||
class MainCallStubGenerator {
|
||||
static jsAst.Statement generateInvokeMain(
|
||||
Emitter emitter, FunctionEntity main) {
|
||||
jsAst.Expression mainCallClosure = emitter.staticFunctionAccess(main);
|
||||
CommonElements commonElements, Emitter emitter, FunctionEntity main) {
|
||||
jsAst.Expression mainAccess = emitter.staticFunctionAccess(main);
|
||||
jsAst.Expression currentScriptAccess =
|
||||
emitter.generateEmbeddedGlobalAccess(embeddedNames.CURRENT_SCRIPT);
|
||||
|
||||
// TODO(https://github.com/dart-lang/language/issues/1120#issuecomment-670802088):
|
||||
// Validate constraints on `main()` in resolution for dart2js, and in DDC.
|
||||
|
||||
final parameterStructure = main.parameterStructure;
|
||||
|
||||
// The forwarding stub passes all arguments, i.e. both required and optional
|
||||
// positional arguments. We ignore named arguments, assuming the `main()`
|
||||
// has been validated earlier.
|
||||
int positionalParameters = parameterStructure.positionalParameters;
|
||||
|
||||
jsAst.Expression mainCallClosure;
|
||||
if (positionalParameters == 0) {
|
||||
if (parameterStructure.namedParameters.isEmpty) {
|
||||
// e.g. `void main()`.
|
||||
// No parameters. The compiled Dart `main` has no parameters and will
|
||||
// ignore any extra parameters passed in, so it can be used directly.
|
||||
mainCallClosure = mainAccess;
|
||||
} else {
|
||||
// e.g. `void main({arg})`. We should not get here. Drop the named
|
||||
// arguments as we don't know how to convert them.
|
||||
mainCallClosure = js(r'''function() { return #(); }''', mainAccess);
|
||||
}
|
||||
} else {
|
||||
jsAst.Expression convertArgumentList =
|
||||
emitter.staticFunctionAccess(commonElements.convertMainArgumentList);
|
||||
if (positionalParameters == 1) {
|
||||
// e.g. `void main(List<String> args)`, `main([args])`.
|
||||
mainCallClosure = js(
|
||||
r'''function(args) { return #(#(args)); }''',
|
||||
[mainAccess, convertArgumentList],
|
||||
);
|
||||
} else {
|
||||
// positionalParameters == 2.
|
||||
// e.g. `void main(List<String> args, Object? extra)`
|
||||
mainCallClosure = js(
|
||||
r'''function(args, extra) { return #(#(args), extra); }''',
|
||||
[mainAccess, convertArgumentList],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// This code finds the currently executing script by listening to the
|
||||
// onload event of all script tags and getting the first script which
|
||||
// finishes. Since onload is called immediately after execution this should
|
||||
|
@ -48,11 +90,11 @@ class MainCallStubGenerator {
|
|||
}
|
||||
})(function(currentScript) {
|
||||
#currentScript = currentScript;
|
||||
|
||||
var callMain = #mainCallClosure;
|
||||
if (typeof dartMainRunner === "function") {
|
||||
dartMainRunner(#mainCallClosure, []);
|
||||
dartMainRunner(callMain, []);
|
||||
} else {
|
||||
#mainCallClosure([]);
|
||||
callMain([]);
|
||||
}
|
||||
})''', {
|
||||
'currentScript': currentScriptAccess,
|
||||
|
|
|
@ -388,7 +388,7 @@ class ProgramBuilder {
|
|||
|
||||
js.Statement _buildInvokeMain() {
|
||||
return MainCallStubGenerator.generateInvokeMain(
|
||||
_task.emitter, _mainFunction);
|
||||
_commonElements, _task.emitter, _mainFunction);
|
||||
}
|
||||
|
||||
DeferredFragment _buildDeferredFragment(LibrariesMap librariesMap) {
|
||||
|
|
|
@ -2960,24 +2960,20 @@ Future<Null> _loadHunk(String hunkName) {
|
|||
return completer.future;
|
||||
}
|
||||
|
||||
class MainError extends Error implements NoSuchMethodError {
|
||||
final String _message;
|
||||
|
||||
MainError(this._message);
|
||||
|
||||
String toString() => 'NoSuchMethodError: $_message';
|
||||
}
|
||||
|
||||
void missingMain() {
|
||||
throw new MainError("No top-level function named 'main'.");
|
||||
}
|
||||
|
||||
void badMain() {
|
||||
throw new MainError("'main' is not a function.");
|
||||
}
|
||||
|
||||
void mainHasTooManyParameters() {
|
||||
throw new MainError("'main' expects too many parameters.");
|
||||
/// Converts a raw JavaScript array into a `List<String>`.
|
||||
/// Called from generated code.
|
||||
List<String> convertMainArgumentList(Object? args) {
|
||||
List<String> result = [];
|
||||
if (args == null) return result;
|
||||
if (args is JSArray) {
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
JS('', '#.push(String(#[#]))', result, args, i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
// Single non-Array element. Convert to a String.
|
||||
JS('', '#.push(String(#))', result, args);
|
||||
return result;
|
||||
}
|
||||
|
||||
class _AssertionError extends AssertionError {
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
var self = this;
|
||||
if (typeof global != "undefined") self = global; // Node.js.
|
||||
|
||||
(function(self) {
|
||||
(function(self, scriptArguments) {
|
||||
// Using strict mode to avoid accidentally defining global variables.
|
||||
"use strict"; // Should be first statement of this function.
|
||||
|
||||
|
@ -270,9 +270,9 @@ if (typeof global != "undefined") self = global; // Node.js.
|
|||
// Global properties. "self" refers to the global object, so adding a
|
||||
// property to "self" defines a global variable.
|
||||
self.self = self;
|
||||
self.dartMainRunner = function(main, args) {
|
||||
self.dartMainRunner = function(main, ignored_args) {
|
||||
// Initialize.
|
||||
var action = function() { main(args); }
|
||||
var action = function() { main(scriptArguments, null); }
|
||||
eventLoop(action);
|
||||
};
|
||||
self.setTimeout = addTimer;
|
||||
|
@ -345,4 +345,4 @@ if (typeof global != "undefined") self = global; // Node.js.
|
|||
// so pretend they don't exist.
|
||||
// TODO(30217): Try to use D8's worker.
|
||||
delete self.Worker;
|
||||
})(self);
|
||||
})(self, arguments);
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
// Javascript preamble, that lets the output of dart2js run on JSShell.
|
||||
|
||||
(function(self) {
|
||||
(function(self, scriptArguments) {
|
||||
// Using strict mode to avoid accidentally defining global variables.
|
||||
"use strict"; // Should be first statement of this function.
|
||||
|
||||
|
@ -262,9 +262,9 @@
|
|||
}
|
||||
}
|
||||
|
||||
self.dartMainRunner = function(main, args) {
|
||||
self.dartMainRunner = function(main, ignored_args) {
|
||||
// Initialize.
|
||||
var action = function() { main(args); }
|
||||
var action = function() { main(scriptArguments, null); }
|
||||
eventLoop(action);
|
||||
};
|
||||
self.setTimeout = addTimer;
|
||||
|
@ -329,7 +329,7 @@
|
|||
array[i] = Math.random() * 256;
|
||||
}
|
||||
}};
|
||||
})(this)
|
||||
})(this, typeof scriptArgs == "undefined" ? [] : scriptArgs)
|
||||
|
||||
var getKeys = function(obj){
|
||||
var keys = [];
|
||||
|
|
Loading…
Reference in a new issue