b4d5272d99
From: lib/src/kernel/command.dart To: lib/src/command/command.dart This is a step towards organizing the code from shared_command.dart and eventually deleting it. Change-Id: I1ca9fcfd3d7d74511957d516c01544f4a68e4e89 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/388050 Reviewed-by: Nate Biggs <natebiggs@google.com> Reviewed-by: Mark Zhou <markzipan@google.com> Reviewed-by: Sigmund Cherem <sigmund@google.com> Commit-Queue: Nicholas Shahan <nshahan@google.com>
165 lines
5.9 KiB
Dart
165 lines
5.9 KiB
Dart
// Copyright (c) 2023, 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.
|
|
|
|
import 'dart:async';
|
|
import 'dart:convert';
|
|
import 'dart:io' show File;
|
|
|
|
import 'package:dev_compiler/src/command/command.dart';
|
|
import 'package:dev_compiler/src/command/options.dart' show Options;
|
|
import 'package:dev_compiler/src/kernel/compiler.dart' show ProgramCompiler;
|
|
import 'package:dev_compiler/src/kernel/expression_compiler.dart'
|
|
show ExpressionCompiler;
|
|
import 'package:dev_compiler/src/kernel/module_metadata.dart';
|
|
import 'package:front_end/src/api_unstable/ddc.dart' as fe;
|
|
import 'package:kernel/ast.dart' show Component, Library;
|
|
import 'package:path/path.dart' as p;
|
|
import 'package:source_maps/source_maps.dart' as source_maps;
|
|
|
|
import '../shared_test_options.dart';
|
|
|
|
class TestCompilationResult {
|
|
final String? result;
|
|
final bool isSuccess;
|
|
|
|
TestCompilationResult(this.result, this.isSuccess);
|
|
}
|
|
|
|
class TestExpressionCompiler {
|
|
final SetupCompilerOptions setup;
|
|
final Component component;
|
|
final ExpressionCompiler compiler;
|
|
final ModuleMetadata? metadata;
|
|
final source_maps.SingleMapping sourceMap;
|
|
|
|
TestExpressionCompiler._(
|
|
this.setup, this.component, this.compiler, this.metadata, this.sourceMap);
|
|
|
|
static Future<TestExpressionCompiler> init(SetupCompilerOptions setup,
|
|
{required Uri input,
|
|
required Uri output,
|
|
Uri? packages,
|
|
Map<String, bool> experiments = const {}}) async {
|
|
setup.diagnosticMessages.clear();
|
|
setup.errors.clear();
|
|
// Initialize the incremental compiler and module component.
|
|
// TODO: extend this for multi-module compilations by storing separate
|
|
// compilers/components/names per module.
|
|
setup.options.packagesFileUri = packages;
|
|
setup.options.explicitExperimentalFlags.addAll(fe.parseExperimentalFlags(
|
|
experiments,
|
|
onError: (message) => throw Exception(message)));
|
|
var frontend = DevelopmentIncrementalCompiler(setup.options, input);
|
|
var compilerResult = await frontend.computeDelta();
|
|
var component = compilerResult.component;
|
|
component.computeCanonicalNames();
|
|
// Initialize DDC.
|
|
var moduleName = p.basenameWithoutExtension(output.toFilePath());
|
|
|
|
var classHierarchy = compilerResult.classHierarchy!;
|
|
var compilerOptions = Options(
|
|
replCompile: true,
|
|
moduleName: moduleName,
|
|
experiments: experiments,
|
|
soundNullSafety: setup.soundNullSafety,
|
|
emitDebugMetadata: true,
|
|
canaryFeatures: setup.canaryFeatures,
|
|
enableAsserts: setup.enableAsserts,
|
|
);
|
|
var coreTypes = compilerResult.coreTypes;
|
|
|
|
final importToSummary = Map<Library, Component>.identity();
|
|
final summaryToModule = Map<Component, String>.identity();
|
|
for (var lib in component.libraries) {
|
|
importToSummary[lib] = component;
|
|
}
|
|
summaryToModule[component] = moduleName;
|
|
|
|
var kernel2jsCompiler = ProgramCompiler(component, classHierarchy,
|
|
compilerOptions, importToSummary, summaryToModule,
|
|
coreTypes: coreTypes);
|
|
var module = kernel2jsCompiler.emitModule(component);
|
|
|
|
// Perform a full compile, writing the compiled JS + sourcemap.
|
|
var code = jsProgramToCode(
|
|
module,
|
|
setup.moduleFormat,
|
|
inlineSourceMap: compilerOptions.inlineSourceMap,
|
|
buildSourceMap: compilerOptions.sourceMap,
|
|
emitDebugMetadata: compilerOptions.emitDebugMetadata,
|
|
emitDebugSymbols: compilerOptions.emitDebugSymbols,
|
|
jsUrl: '$output',
|
|
mapUrl: '$output.map',
|
|
compiler: kernel2jsCompiler,
|
|
component: component,
|
|
);
|
|
var codeBytes = utf8.encode(code.code);
|
|
var sourceMapBytes = utf8.encode(json.encode(code.sourceMap));
|
|
|
|
File(output.toFilePath()).writeAsBytesSync(codeBytes);
|
|
File('${output.toFilePath()}.map').writeAsBytesSync(sourceMapBytes);
|
|
|
|
// Save the expression compiler for future compilation.
|
|
var compiler = ExpressionCompiler(
|
|
setup.options,
|
|
setup.moduleFormat,
|
|
setup.errors,
|
|
frontend,
|
|
kernel2jsCompiler,
|
|
component,
|
|
);
|
|
|
|
if (setup.errors.isNotEmpty) {
|
|
throw Exception('Compilation failed with: ${setup.errors}');
|
|
}
|
|
setup.diagnosticMessages.clear();
|
|
setup.errors.clear();
|
|
|
|
var sourceMap = source_maps.SingleMapping.fromJson(code.sourceMap!);
|
|
return TestExpressionCompiler._(
|
|
setup, component, compiler, code.metadata, sourceMap);
|
|
}
|
|
|
|
// Line and column are 1-based.
|
|
Future<TestCompilationResult> compileExpression(
|
|
{required Uri libraryUri,
|
|
Uri? scriptUri,
|
|
required int line,
|
|
required int column,
|
|
required Map<String, String> scope,
|
|
required String expression}) async {
|
|
// clear previous errors
|
|
setup.errors.clear();
|
|
|
|
// At this time, no metadata is stored for the Dart SDK. This is one of the
|
|
// reasons debugging and expression evaluation support is so limited within
|
|
// the SDK. When requesting evaluation of library level expressions, we can
|
|
// ignore the lack of metadata and simply use the URI directly.
|
|
String importUri;
|
|
if (libraryUri.isScheme('dart')) {
|
|
importUri = libraryUri.toString();
|
|
} else {
|
|
var libraryMetadata = metadataForLibraryUri(libraryUri);
|
|
importUri = libraryMetadata.importUri;
|
|
}
|
|
var jsExpression = await compiler.compileExpressionToJs(
|
|
importUri, scriptUri?.toString(), line, column, scope, expression);
|
|
if (setup.errors.isNotEmpty) {
|
|
jsExpression = setup.errors.toString().replaceAll(
|
|
RegExp(
|
|
r'org-dartlang-debug:synthetic_debug_expression:[0-9]*:[0-9]*:'),
|
|
'');
|
|
|
|
return TestCompilationResult(jsExpression, false);
|
|
}
|
|
|
|
return TestCompilationResult(jsExpression, true);
|
|
}
|
|
|
|
LibraryMetadata metadataForLibraryUri(Uri libraryUri) =>
|
|
metadata!.libraries.entries
|
|
.firstWhere((entry) => entry.value.fileUri == '$libraryUri')
|
|
.value;
|
|
}
|