| // 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; | |
| import 'dart:async'; | |
| import 'dart:typed_data'; | |
| // ignore: implementation_imports | |
| 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 << 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<Uint8List>> readFromUri( | |
| Uri uri, { | |
| InputKind inputKind = InputKind.utf8, | |
| }); | |
| /// Register that [uri] should be an `InputKind.UTF8` input with the | |
| /// given [source] 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, Uint8List 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, | |
| /// Recorded usages of definitions (after tree-shaking). | |
| recordedUses, | |
| /// 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, | |
| ); | |
| }); | |
| } |