// Copyright (c) 2015, 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. /// New Compiler API. This API is under construction, use only internally or /// in unittests. library compiler_new; import 'dart:async'; import 'package:front_end/src/api_unstable/dart2js.dart' as fe; import 'compiler.dart' show Diagnostic; import 'src/apiimpl.dart'; import 'src/options.dart' show CompilerOptions; export 'compiler.dart' show Diagnostic; // 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 can be represented either as /// a zero-terminated `List` of UTF-8 bytes or as a [String]. If /// [inputKind] is `InputKind.binary` the source is a read a `List`. /// /// The following text is non-normative: /// /// It is recommended to return a UTF-8 encoded list of bytes because the /// scanner is more efficient in this case. In either case, the data structure /// is expected to hold a zero element at the last position. If this is not /// the case, the entire data structure is copied before scanning. Future readFromUri(Uri uri, {InputKind inputKind: InputKind.UTF8}); } /// 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, /// Implementation specific output used for debugging the compiler. debug, } /// Sink interface used for generating output from the compiler. abstract class OutputSink { /// Adds [text] to the sink. void add(String text); /// Closes the sink. void close(); } /// Sink interface used for generating binary data from the compiler. abstract class BinaryOutputSink { /// Writes indices [start] to [end] of [buffer] to the sink. void write(List buffer, [int start = 0, int end]); /// Closes the sink. 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 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( var 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; /// Shared state between compilations. /// /// This is used to speed up batch mode. final fe.InitializedCompilerState kernelInitializedCompilerState; CompilationResult(this.compiler, {this.isSuccess: true, this.kernelInitializedCompilerState: null}); } /// 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) { if (compilerOptions == null) { throw new ArgumentError("compilerOptions must be non-null"); } if (compilerInput == null) { throw new ArgumentError("compilerInput must be non-null"); } if (compilerDiagnostics == null) { throw new ArgumentError("compilerDiagnostics must be non-null"); } if (compilerOutput == null) { throw new ArgumentError("compilerOutput must be non-null"); } CompilerImpl compiler = new CompilerImpl( compilerInput, compilerOutput, compilerDiagnostics, compilerOptions); return compiler.run(compilerOptions.entryPoint).then((bool success) { return new CompilationResult(compiler, isSuccess: success, kernelInitializedCompilerState: compiler.kernelLoader.initializedCompilerState); }); }