Index: sdk/lib/_internal/pub_generated/lib/src/dart.dart |
diff --git a/sdk/lib/_internal/pub_generated/lib/src/dart.dart b/sdk/lib/_internal/pub_generated/lib/src/dart.dart |
index 0a84847de163b5d662ccad374035ab485183e26f..35ff526defae487c783808af93bf47512feae612 100644 |
--- a/sdk/lib/_internal/pub_generated/lib/src/dart.dart |
+++ b/sdk/lib/_internal/pub_generated/lib/src/dart.dart |
@@ -1,21 +1,60 @@ |
+// Copyright (c) 2013, 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. |
+ |
+/// A library for compiling Dart code and manipulating analyzer parse trees. |
library pub.dart; |
+ |
import 'dart:async'; |
import 'dart:io'; |
import 'dart:isolate'; |
+ |
import 'package:analyzer/analyzer.dart'; |
import 'package:path/path.dart' as path; |
+ |
import '../../../compiler/compiler.dart' as compiler; |
import '../../../compiler/implementation/filenames.dart' show appendSlash; |
+ |
import '../../asset/dart/serialize.dart'; |
import 'io.dart'; |
import 'log.dart' as log; |
+ |
+/// Interface to communicate with dart2js. |
+/// |
+/// This is basically an amalgamation of dart2js's |
+/// [compiler.CompilerInputProvider], [compiler.CompilerOutputProvider], and |
+/// [compiler.DiagnosticHandler] function types so that we can provide them |
+/// as a single unit. |
abstract class CompilerProvider { |
+ /// The URI to the root directory where "dart:" libraries can be found. |
+ /// |
+ /// This is used as the base URL to generate library URLs that are then sent |
+ /// back to [provideInput]. |
Uri get libraryRoot; |
- Future provideInput(Uri uri); |
+ |
+ /// Given [uri], responds with a future that completes to the contents of |
+ /// the input file at that URI. |
+ /// |
+ /// The future can complete to a string or a list of bytes. |
+ Future /*<String | List<int>>*/ provideInput(Uri uri); |
+ |
+ /// Reports a diagnostic message from dart2js to the user. |
void handleDiagnostic(Uri uri, int begin, int end, String message, |
compiler.Diagnostic kind); |
+ |
+ /// Given a [name] (which will be "" for the entrypoint) and a file extension, |
+ /// returns an [EventSink] that dart2js can write to to emit an output file. |
EventSink<String> provideOutput(String name, String extension); |
} |
+ |
+/// Compiles [entrypoint] to JavaScript (or to Dart if [toDart] is true) as |
+/// well as any ancillary outputs dart2js creates. |
+/// |
+/// Uses [provider] to communcate between dart2js and the caller. Returns a |
+/// future that completes when compilation is done. |
+/// |
+/// By default, the package root is assumed to be adjacent to [entrypoint], but |
+/// if [packageRoot] is passed that will be used instead. |
Future compile(String entrypoint, CompilerProvider provider, |
{Iterable<String> commandLineOptions, bool checked: false, bool csp: false, |
bool minify: true, bool verbose: false, Map<String, String> environment, |
@@ -34,16 +73,22 @@ Future compile(String entrypoint, CompilerProvider provider, |
if (!suppressPackageWarnings) options.add('--show-package-warnings'); |
if (terse) options.add('--terse'); |
if (toDart) options.add('--output-type=dart'); |
+ |
var sourceUrl = path.toUri(entrypoint); |
options.add("--out=$sourceUrl.js"); |
+ |
+ // Add the source map URLs. |
if (includeSourceMapUrls) { |
options.add("--source-map=$sourceUrl.js.map"); |
} |
+ |
if (environment == null) environment = {}; |
if (commandLineOptions != null) options.addAll(commandLineOptions); |
+ |
if (packageRoot == null) { |
packageRoot = path.join(path.dirname(entrypoint), 'packages'); |
} |
+ |
return compiler.compile( |
path.toUri(entrypoint), |
provider.libraryRoot, |
@@ -55,22 +100,50 @@ Future compile(String entrypoint, CompilerProvider provider, |
environment); |
}); |
} |
+ |
+/// Returns whether [dart] looks like an entrypoint file. |
bool isEntrypoint(CompilationUnit dart) { |
+ // Allow two or fewer arguments so that entrypoints intended for use with |
+ // [spawnUri] get counted. |
+ // |
+ // TODO(nweiz): this misses the case where a Dart file doesn't contain main(), |
+ // but it parts in another file that does. |
return dart.declarations.any((node) { |
return node is FunctionDeclaration && |
node.name.name == "main" && |
node.functionExpression.parameters.parameters.length <= 2; |
}); |
} |
+ |
+/// Efficiently parses the import and export directives in [contents]. |
+/// |
+/// If [name] is passed, it's used as the filename for error reporting. |
List<UriBasedDirective> parseImportsAndExports(String contents, {String name}) { |
var collector = new _DirectiveCollector(); |
parseDirectives(contents, name: name).accept(collector); |
return collector.directives; |
} |
+ |
+/// A simple visitor that collects import and export nodes. |
class _DirectiveCollector extends GeneralizingAstVisitor { |
final directives = <UriBasedDirective>[]; |
+ |
visitUriBasedDirective(UriBasedDirective node) => directives.add(node); |
} |
+ |
+/// Runs [code] in an isolate. |
+/// |
+/// [code] should be the contents of a Dart entrypoint. It may contain imports; |
+/// they will be resolved in the same context as the host isolate. [message] is |
+/// passed to the [main] method of the code being run; the caller is responsible |
+/// for using this to establish communication with the isolate. |
+/// |
+/// [packageRoot] controls the package root of the isolate. It may be either a |
+/// [String] or a [Uri]. |
+/// |
+/// If [snapshot] is passed, the isolate will be loaded from that path if it |
+/// exists. Otherwise, a snapshot of the isolate's code will be saved to that |
+/// path once the isolate is loaded. |
Future runInIsolate(String code, message, {packageRoot, String snapshot}) { |
final completer0 = new Completer(); |
scheduleMicrotask(() { |
@@ -111,19 +184,17 @@ Future runInIsolate(String code, message, {packageRoot, String snapshot}) { |
log.warning( |
"Failed to compile a snapshot to " "${path.relative(snapshot)}:\n" + |
result.stderr.join("\n")); |
- completer0.complete(null); |
+ completer0.complete(); |
} |
if (result.success) { |
completer0.complete(null); |
} else { |
join4(); |
} |
- } catch (e2) { |
- completer0.completeError(e2); |
+ } catch (e0, s0) { |
+ completer0.completeError(e0, s0); |
} |
- }, onError: (e3) { |
- completer0.completeError(e3); |
- }); |
+ }, onError: completer0.completeError); |
} |
if (packageRoot != null) { |
snapshotArgs.add('--package-root=${packageRoot}'); |
@@ -139,77 +210,74 @@ Future runInIsolate(String code, message, {packageRoot, String snapshot}) { |
} |
} |
if (response['type'] == 'error') { |
- completer0.completeError( |
- new CrossIsolateException.deserialize(response['error'])); |
+ throw new CrossIsolateException.deserialize( |
+ response['error']); |
+ join1(); |
} else { |
join1(); |
} |
- } catch (e1) { |
- completer0.completeError(e1); |
+ } catch (e1, s1) { |
+ completer0.completeError(e1, s1); |
} |
- }, onError: (e4) { |
- completer0.completeError(e4); |
- }); |
- } catch (e0) { |
- completer0.completeError(e0); |
+ }, onError: completer0.completeError); |
+ } catch (e2, s2) { |
+ completer0.completeError(e2, s2); |
} |
- }, onError: (e5) { |
- completer0.completeError(e5); |
- }); |
+ }, onError: completer0.completeError); |
} |
if (packageRoot == null) { |
join0(null); |
} else { |
join0(packageRoot.toString()); |
} |
- } catch (e6) { |
- completer0.completeError(e6); |
+ } catch (e, s) { |
+ completer0.completeError(e, s); |
} |
}); |
return completer0.future; |
})).then((x0) { |
try { |
x0; |
- completer0.complete(null); |
- } catch (e0) { |
- completer0.completeError(e0); |
+ completer0.complete(); |
+ } catch (e0, s0) { |
+ completer0.completeError(e0, s0); |
} |
- }, onError: (e1) { |
- completer0.completeError(e1); |
- }); |
+ }, onError: completer0.completeError); |
} |
if (snapshot != null && fileExists(snapshot)) { |
log.fine("Spawning isolate from ${snapshot}."); |
join1() { |
- join2(x1) { |
+ join2() { |
join0(); |
} |
- finally0(cont0, v0) { |
- cont0(v0); |
- } |
- catch0(error) { |
- log.fine("Couldn't load existing snapshot ${snapshot}:\n${error}"); |
- finally0(join2, null); |
+ catch0(error, s1) { |
+ try { |
+ if (error is IsolateSpawnException) { |
+ log.fine( |
+ "Couldn't load existing snapshot ${snapshot}:\n${error}"); |
+ join2(); |
+ } else { |
+ throw error; |
+ } |
+ } catch (error, s1) { |
+ completer0.completeError(error, s1); |
+ } |
} |
try { |
Isolate.spawnUri( |
path.toUri(snapshot), |
[], |
message, |
- packageRoot: packageRoot).then((x2) { |
+ packageRoot: packageRoot).then((x1) { |
try { |
- x2; |
- finally0((v1) { |
- completer0.complete(v1); |
- }, null); |
- } catch (e2) { |
- catch0(e2); |
+ x1; |
+ completer0.complete(null); |
+ } catch (e1, s2) { |
+ catch0(e1, s2); |
} |
- }, onError: (e3) { |
- catch0(e3); |
- }); |
- } catch (e4) { |
- catch0(e4); |
+ }, onError: catch0); |
+ } catch (e2, s3) { |
+ catch0(e2, s3); |
} |
} |
if (packageRoot != null) { |
@@ -221,12 +289,19 @@ Future runInIsolate(String code, message, {packageRoot, String snapshot}) { |
} else { |
join0(); |
} |
- } catch (e5) { |
- completer0.completeError(e5); |
+ } catch (e, s) { |
+ completer0.completeError(e, s); |
} |
}); |
return completer0.future; |
} |
+ |
+// TODO(nweiz): remove this when issue 12617 is fixed. |
+/// A function used as a buffer between the host isolate and [spawnUri]. |
+/// |
+/// [spawnUri] synchronously loads the file and its imports, which can deadlock |
+/// the host isolate if there's an HTTP import pointing at a server in the host. |
+/// Adding an additional isolate in the middle works around this. |
void _isolateBuffer(message) { |
var replyTo = message['replyTo']; |
var packageRoot = message['packageRoot']; |