// 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`. utf8, /// Data is read as bytes in a `List`. binary, } /// Interface for data read through [CompilerInput.readFromUri]. abstract class Input { /// 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> 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, /// 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 { /// 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> { /// Writes indices [start] to [end] of [buffer] to the sink. @override void add(List 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 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, ); }); }