blob: 38df5239a2404c89e52a970dc7b731eca3b0577e [file] [log] [blame]
// Copyright (c) 2017, 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.
library fasta.compiler_context;
import 'dart:async' show Future, Zone, runZoned;
import 'package:_fe_analyzer_shared/src/messages/severity.dart' show Severity;
import 'package:_fe_analyzer_shared/src/util/colors.dart' as colors;
import 'package:_fe_analyzer_shared/src/scanner/token_impl.dart'
show StringToken;
import 'package:kernel/ast.dart' show Source;
import '../api_prototype/file_system.dart' show FileSystem;
import '../base/processed_options.dart' show ProcessedOptions;
import 'command_line_reporting.dart' as command_line_reporting;
import 'fasta_codes.dart'
show LocatedMessage, Message, messageInternalProblemMissingContext;
final Object compilerContextKey = new Object();
/// Shared context used throughout the compiler.
/// The compiler works with a single instance of this class. To avoid
/// passing it around as an argument everywhere, it is stored as a zone-value.
/// For convenience the static getter [CompilerContext.current] retrieves the
/// context stored in the current zone.
class CompilerContext {
// TODO(sigmund): Move here any method in ProcessedOptions that doesn't seem
// appropriate as an "option", or consider merging ProcessedOptions entirely
// within this class, and depend only on the raw options here.
final ProcessedOptions options;
/// Sources seen by the compiler.
/// This is populated as the compiler reads files, and it is used for error
/// reporting and to generate source location information in the compiled
/// programs.
final Map<Uri, Source> uriToSource = <Uri, Source>{};
// TODO(ahe): Remove this.
final List<Object> errors = <Object>[];
final List<Uri> dependencies = <Uri>[];
FileSystem get fileSystem => options.fileSystem;
Uri cachedSdkRoot = null;
bool compilingPlatform = false;
CompilerContext(this.options) {
if (options.verbose) {
colors.printEnableColorsReason = print;
/// Report [message], for example, by printing it.
void report(LocatedMessage message, Severity severity,
{List<LocatedMessage> context}) {, severity, context: context);
/// Report [message], for example, by printing it.
// TODO(askesc): Remove this and direct callers directly to report.
void reportWithoutLocation(Message message, Severity severity) {
options.reportWithoutLocation(message, severity);
/// Format [message] as a text string that can be included in generated code.
String format(LocatedMessage message, Severity severity) {
return command_line_reporting.format(message, severity);
/// Format [message] as a text string that can be included in generated code.
// TODO(askesc): Remove this and direct callers directly to format.
String formatWithoutLocation(Message message, Severity severity) {
return command_line_reporting.format(message.withoutLocation(), severity);
// TODO(ahe): Remove this.
void logError(Object message, Severity severity) {
static void recordDependency(Uri uri) {
if (uri.scheme != "file" && uri.scheme != "http") {
throw new ArgumentError("Expected a file or http URI, but got: '$uri'.");
CompilerContext context = Zone.current[compilerContextKey];
if (context != null) {
static CompilerContext get current {
CompilerContext context = Zone.current[compilerContextKey];
if (context == null) {
// Note: we throw directly and don't use internalProblem, because
// internalProblem depends on having a compiler context available.
String message = messageInternalProblemMissingContext.message;
String tip = messageInternalProblemMissingContext.tip;
throw "Internal problem: $message\nTip: $tip";
return context;
static bool get isActive => Zone.current[compilerContextKey] != null;
/// Perform [action] in a [Zone] where [this] will be available as
/// `CompilerContext.current`.
Future<T> runInContext<T>(Future<T> action(CompilerContext c)) {
return runZoned(
() => new Future<T>.sync(() => action(this)).whenComplete(clear),
zoneValues: {compilerContextKey: this});
/// Perform [action] in a [Zone] where [options] will be available as
/// `CompilerContext.current.options`.
static Future<T> runWithOptions<T>(
ProcessedOptions options, Future<T> action(CompilerContext c),
{bool errorOnMissingInput: true}) {
return new CompilerContext(options)
.runInContext<T>((CompilerContext c) async {
await options.validateOptions(errorOnMissingInput: errorOnMissingInput);
return action(c);
static Future<T> runWithDefaultOptions<T>(
Future<T> action(CompilerContext c)) {
return new CompilerContext(new ProcessedOptions()).runInContext<T>(action);
void clear() {