blob: bb05db919adf734d5fbb75780eed7f93861eb914 [file] [log] [blame]
// Copyright (c) 2012, 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 compiler;
import 'dart:async';
import 'package:front_end/src/api_unstable/dart2js.dart' as fe;
import 'src/compiler.dart';
import 'src/diagnostics/messages.dart';
import 'src/options.dart';
/// Kind of diagnostics that the compiler can report.
enum Diagnostic {
/// An error as identified by the "Dart Programming Language
/// Specification" [https://dart.dev/guides/language/spec].
///
/// Note: the compiler may still produce an executable result after
/// reporting a compilation error. The specification says:
///
/// "A compile-time error must be reported by a Dart compiler before
/// the erroneous code is executed." and "If a compile-time error
/// occurs within the code of a running isolate A, A is immediately
/// suspended."
///
/// This means that the compiler can generate code that when executed
/// terminates execution.
error('error'),
/// A warning as identified by the "Dart Programming Language
/// Specification" [https://dart.dev/guides/language/spec].
warning('warning'),
/// Any other warning that is not covered by [warning].
hint('hint'),
/// Informational message about the compiler.
info('info'),
/// Informational messages that shouldn't be printed unless
/// explicitly requested by the user of a compiler.
verboseInfo('verbose info'),
/// An internal error in the compiler.
crash('crash'),
/// Additional information about the preceding non-info diagnostic from the
/// compiler.
///
/// For example, consider a duplicated definition. The compiler first emits a
/// message about the duplicated definition, then emits an info message about
/// the location of the existing definition.
context('context'),
;
/// An [int] representation of this kind. The ordinals are designed
/// to be used as bitsets.
int get ordinal => 2 << this.index;
/// The name of this kind.
final String name;
const Diagnostic(this.name);
@override
String toString() => name;
}
// Unless explicitly allowed, passing `null` for any argument to the
// methods of library will result in an Error being thrown.
/// Input kinds used by [CompilerInput.readFromUri].
enum InputKind {
/// Data is read as UTF8 either as a [String] or a zero-terminated
/// `List<int>`.
UTF8,
/// Data is read as bytes in a `List<int>`.
binary,
}
/// Interface for data read through [CompilerInput.readFromUri].
abstract class Input<T> {
/// The URI from which data was read.
Uri get uri;
/// The format of the read [data].
InputKind get inputKind;
/// The raw data read from [uri].
T get data;
/// Release any resources held by the input. After releasing, a call to `get
/// data` will fail, and previously returned data may be invalid.
void release();
}
/// Interface for providing the compiler with input. That is, Dart source files,
/// package config files, etc.
abstract class CompilerInput {
/// Returns a future that completes to the source corresponding to [uri].
/// If an exception occurs, the future completes with this exception.
///
/// If [inputKind] is `InputKind.UTF8` the source is represented as a
/// zero-terminated list of encoded bytes. If the input kind is
/// `InputKind.binary` the resulting list is the raw bytes from the input
/// source.
Future<Input<List<int>>> readFromUri(Uri uri,
{InputKind inputKind = InputKind.UTF8});
/// Register that [uri] should be an `InputKind.UTF8` input with the
/// given [source] as its zero-terminated list of contents.
///
/// If [uri] was read prior to this call, this registration has no effect,
/// otherwise it is expected that a future [readFromUri] will return the
/// contents provided here.
///
/// The main purpose of this API is to assist in error reporting when
/// compiling from kernel binary files. Binary files embed the contents
/// of source files that may not be available on disk. By using these
/// registered contents, dart2js will be able to provide accurate line/column
/// information on an error.
void registerUtf8ContentsForDiagnostics(Uri uri, List<int> source);
}
/// Output types used in `CompilerOutput.createOutputSink`.
enum OutputType {
/// The main JavaScript output.
js,
/// A deferred JavaScript output part.
jsPart,
/// A source map for a JavaScript output.
sourceMap,
/// Dump info output.
dumpInfo,
/// Deferred map output.
deferredMap,
/// Deferred load ids map output.
deferredLoadIds,
/// Unused libraries output.
dumpUnusedLibraries,
/// Resource identifiers output.
resourceIdentifiers,
/// Implementation specific output used for debugging the compiler.
debug,
}
/// Sink interface used for generating output from the compiler.
abstract class OutputSink implements Sink<String> {
/// Adds [text] to the sink.
@override
void add(String text);
/// Closes the sink.
@override
void close();
}
/// Sink interface used for generating binary data from the compiler.
abstract class BinaryOutputSink implements Sink<List<int>> {
/// Writes indices [start] to [end] of [buffer] to the sink.
@override
void add(List<int> buffer, [int start = 0, int? end]);
/// Closes the sink.
@override
void close();
}
/// Interface for producing output from the compiler. That is, JavaScript target
/// files, source map files, dump info files, etc.
abstract class CompilerOutput {
/// Returns an [OutputSink] that will serve as compiler output for the given
/// component.
///
/// Components are identified by [name], [extension], and [type]. By
/// convention, the empty string `""` will represent the main output of the
/// provided [type]. [name] and [extension] are otherwise suggestive.
// TODO(johnniwinther): Replace [name] and [extension] with something like
// [id] and [uri].
OutputSink createOutputSink(String name, String extension, OutputType type);
/// Returns an [BinaryOutputSink] that will serve as compiler output for the
/// given URI.
BinaryOutputSink createBinarySink(Uri uri);
}
/// Interface for receiving diagnostic message from the compiler. That is,
/// errors, warnings, hints, etc.
abstract class CompilerDiagnostics {
/// Invoked by the compiler to report diagnostics. If [uri] is `null`, so are
/// [begin] and [end]. No other arguments may be `null`. If [uri] is not
/// `null`, neither are [begin] and [end]. [uri] indicates the compilation
/// unit from where the diagnostic originates. [begin] and [end] are
/// zero-based character offsets from the beginning of the compilation unit.
/// [message] is the diagnostic message, and [kind] indicates what
/// kind of diagnostic it is.
///
/// Experimental: [code] gives access to an id for the messages. Currently it
/// is the [Message] used to create the diagnostic, if available, from which
/// the [MessageKind] is accessible.
void report(Message? code, Uri? uri, int? begin, int? end, String text,
Diagnostic kind);
}
/// Information resulting from the compilation.
class CompilationResult {
/// `true` if the compilation succeeded, that is, compilation didn't fail due
/// to compile-time errors and/or internal errors.
final bool isSuccess;
/// The compiler object used for the compilation.
///
/// Note: The type of [compiler] is implementation dependent and may vary.
/// Use only for debugging and testing.
final Compiler? compiler;
/// Shared state between compilations.
///
/// This is used to speed up batch mode.
final fe.InitializedCompilerState? kernelInitializedCompilerState;
CompilationResult(this.compiler,
{this.isSuccess = true, this.kernelInitializedCompilerState});
}
// Unless explicitly allowed, passing [:null:] for any argument to the
// methods of library will result in an Error being thrown.
/// Returns a future that completes to a [CompilationResult] when the Dart
/// sources in [options] have been compiled.
///
/// The generated compiler output is obtained by providing a [compilerOutput].
///
/// If the compilation fails, the future's `CompilationResult.isSuccess` is
/// `false` and [CompilerDiagnostics.report] on [compilerDiagnostics]
/// is invoked at least once with `kind == Diagnostic.ERROR` or
/// `kind == Diagnostic.CRASH`.
Future<CompilationResult> compile(
CompilerOptions compilerOptions,
CompilerInput compilerInput,
CompilerDiagnostics compilerDiagnostics,
CompilerOutput compilerOutput) {
var compiler = Compiler(
compilerInput, compilerOutput, compilerDiagnostics, compilerOptions);
return compiler.run().then((bool success) {
return CompilationResult(compiler,
isSuccess: success,
kernelInitializedCompilerState: compiler.initializedCompilerState);
});
}