Delete dart_backend from compiler.

R=sra@google.com

Review URL: https://codereview.chromium.org/2213673002 .
This commit is contained in:
Sigmund Cherem 2016-08-04 15:57:04 -07:00
parent 3c38f96a0a
commit 0eee4027a6
41 changed files with 29 additions and 10499 deletions

View file

@ -46,6 +46,9 @@
* Eliminate some false negatives when determining whether global executables
are on the user's executable path.
* dart2dart (aka `dart2js --output-type=dart`) has been removed (this was
deprecated in Dart 1.11)
[Flutter]: https://flutter.io/
## 1.18.1 - 2016-08-02

View file

@ -26,7 +26,6 @@
'<!@(["python", "tools/list_files.py",'
'"dart$",'
'"sdk/lib"])',
'sdk/lib/dart2dart.platform',
'sdk/lib/dart_client.platform',
'sdk/lib/dart_server.platform',
'sdk/lib/dart_shared.platform',

View file

@ -27,7 +27,6 @@ import 'common.dart';
import 'compile_time_constants.dart';
import 'constants/values.dart';
import 'core_types.dart' show CoreClasses, CoreTypes;
import 'dart_backend/dart_backend.dart' as dart_backend;
import 'dart_types.dart' show DartType, DynamicType, InterfaceType, Types;
import 'deferred_load.dart' show DeferredLoadTask;
import 'diagnostics/code_location.dart';
@ -302,19 +301,13 @@ abstract class Compiler implements LibraryLoaderListener {
if (makeBackend != null) {
backend = makeBackend(this);
} else if (options.emitJavaScript) {
} else {
js_backend.JavaScriptBackend jsBackend = new js_backend.JavaScriptBackend(
this,
generateSourceMap: options.generateSourceMap,
useStartupEmitter: options.useStartupEmitter,
useNewSourceInfo: options.useNewSourceInfo);
backend = jsBackend;
} else {
backend = new dart_backend.DartBackend(this, options.strips,
multiFile: options.dart2dartMultiFile);
if (options.dumpInfo) {
throw new ArgumentError('--dump-info is not supported for dart2dart.');
}
}
if (options.dumpInfo && options.useStartupEmitter) {

View file

@ -115,8 +115,6 @@ Future<api.CompilationResult> compile(List<String> argv) {
List<String> explicitOutputArguments = <String>[];
bool wantHelp = false;
bool wantVersion = false;
String outputLanguage = 'JavaScript';
bool stripArgumentSet = false;
bool analyzeOnly = false;
bool analyzeAll = false;
bool resolveOnly = false;
@ -173,20 +171,10 @@ Future<api.CompilationResult> compile(List<String> argv) {
optionsImplyCompilation.add(argument);
if (argument == '--output-type=dart' ||
argument == '--output-type=dart-multi') {
outputLanguage = OUTPUT_LANGUAGE_DART;
if (explicitOutputArguments.isNotEmpty) {
out = currentDirectory.resolve('out.dart');
sourceMapOut = currentDirectory.resolve('out.dart.map');
}
diagnosticHandler(
null,
null,
null,
"--output-type=dart is deprecated. It will remain available "
"in Dart 1.11, but will be removed in Dart 1.12.",
api.Diagnostic.WARNING);
helpAndFail(
"--output-type=dart is no longer supported. It was deprecated "
"since Dart 1.11 and removed in Dart 1.19.");
}
passThrough(argument);
}
void setResolutionInput(String argument) {
@ -208,14 +196,14 @@ Future<api.CompilationResult> compile(List<String> argv) {
return filenames.join("\n");
}
void implyCompilation(String argument) {
implyCompilation(String argument) {
optionsImplyCompilation.add(argument);
passThrough(argument);
}
void setStrip(String argument) {
stripArgumentSet = true;
implyCompilation(argument);
setStrip(String argument) {
helpAndFail("Option '--force-strip' is not in use now that"
"--output-type=dart is no longer supported.");
}
void setAnalyzeOnly(String argument) {
@ -326,6 +314,7 @@ Future<api.CompilationResult> compile(List<String> argv) {
new OptionHandler(Flags.fatalWarnings, passThrough),
new OptionHandler(
Flags.suppressHints, (_) => diagnosticHandler.showHints = false),
// TODO(sigmund): remove entirely after Dart 1.20
new OptionHandler(
'--output-type=dart|--output-type=dart-multi|--output-type=js',
setOutputType),
@ -370,7 +359,7 @@ Future<api.CompilationResult> compile(List<String> argv) {
new OptionHandler(Flags.disableTypeInference, implyCompilation),
new OptionHandler(Flags.terse, passThrough),
new OptionHandler('--deferred-map=.+', implyCompilation),
new OptionHandler(Flags.dumpInfo, setDumpInfo),
new OptionHandler(Flags.dumpInfo, implyCompilation),
new OptionHandler(
'--disallow-unsafe-eval', (_) => hasDisallowUnsafeEval = true),
new OptionHandler(Option.showPackageWarnings, passThrough),
@ -429,10 +418,6 @@ Future<api.CompilationResult> compile(List<String> argv) {
" '$precompiledName'.");
}
if (outputLanguage != OUTPUT_LANGUAGE_DART && stripArgumentSet) {
helpAndFail("Option '--force-strip' may only be used with "
"'--output-type=dart'.");
}
if (arguments.isEmpty) {
helpAndFail('No Dart file specified.');
}
@ -487,10 +472,6 @@ Future<api.CompilationResult> compile(List<String> argv) {
"in combination with the '${Flags.analyzeOnly}' option.");
}
}
if (dumpInfo && outputLanguage == OUTPUT_LANGUAGE_DART) {
helpAndFail("Option '${Flags.dumpInfo}' is not supported in "
"combination with the '--output-type=dart' option.");
}
options.add('--out=$out');
options.add('--source-map=$sourceMapOut');
@ -511,11 +492,11 @@ Future<api.CompilationResult> compile(List<String> argv) {
diagnosticHandler
.info('Compiled ${inputProvider.dartCharactersRead} characters Dart '
'-> ${outputProvider.totalCharactersWritten} characters '
'$outputLanguage in '
'JavaScript in '
'${relativize(currentDirectory, out, Platform.isWindows)}');
if (diagnosticHandler.verbose) {
String input = uriPathToNative(arguments[0]);
print('Dart file ($input) compiled to $outputLanguage.');
print('Dart file ($input) compiled to JavaScript.');
print('Wrote the following files:');
for (String filename in outputProvider.allOutputFiles) {
print(" $filename");
@ -523,7 +504,7 @@ Future<api.CompilationResult> compile(List<String> argv) {
} else if (explicitOutputArguments.isNotEmpty) {
String input = uriPathToNative(arguments[0]);
String output = relativize(currentDirectory, out, Platform.isWindows);
print('Dart file ($input) compiled to $outputLanguage: $output');
print('Dart file ($input) compiled to JavaScript: $output');
}
return result;
}
@ -672,9 +653,6 @@ Supported options:
The following options are only used for compiler development and may
be removed in a future version:
--output-type=dart
Output Dart code instead of JavaScript.
--throw-on-error
Throw an exception if a compile-time error is detected.
@ -703,8 +681,6 @@ be removed in a future version:
Generates an out.info.json file with information about the generated code.
You can inspect the generated file with the viewer at:
https://dart-lang.github.io/dump-info-visualizer/
This feature is currently not supported in combination with the
'--output-type=dart' option.
--generate-code-with-compile-time-errors
Generates output even if the program contains compile-time errors. Use the

View file

@ -1,546 +0,0 @@
// 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.
part of dart_backend;
// TODO(ahe): This class is simply wrong. This backend should use
// elements when it can, not AST nodes. Perhaps a [Map<Element,
// TreeElements>] is what is needed.
class ElementAst {
final Node ast;
final TreeElements treeElements;
ElementAst(this.ast, this.treeElements);
}
class DartBackend extends Backend {
final List<CompilerTask> tasks;
final bool stripAsserts;
bool get supportsReflection => true;
// TODO(zarah) Maybe change this to a command-line option.
// Right now, it is set by the tests.
bool useMirrorHelperLibrary = false;
/// Updated to a [MirrorRenamerImpl] instance if the [useMirrorHelperLibrary]
/// field is set and mirror are needed.
MirrorRenamer mirrorRenamer = const MirrorRenamer();
final DartOutputter outputter;
// Used in test.
PlaceholderRenamer get placeholderRenamer => outputter.renamer;
Map<ClassNode, List<Node>> get memberNodes => outputter.output.memberNodes;
ConstantSystem get constantSystem {
return constantCompilerTask.constantCompiler.constantSystem;
}
BackendConstantEnvironment get constants => constantCompilerTask;
DartConstantTask constantCompilerTask;
DartImpactTransformer impactTransformer;
final Set<ClassElement> usedTypeLiterals = new Set<ClassElement>();
/// The set of visible platform classes that are implemented by instantiated
/// user classes.
final Set<ClassElement> _userImplementedPlatformClasses =
new Set<ClassElement>();
bool enableCodegenWithErrorsIfSupported(Spannable node) {
reporter.reportHintMessage(node, MessageKind.GENERIC, {
'text': "Generation of code with compile time errors is not "
"supported for dart2dart."
});
return false;
}
/**
* Tells whether it is safe to remove type declarations from variables,
* functions parameters. It becomes not safe if:
* 1) TypeError is used somewhere in the code,
* 2) The code has typedefs in right hand side of IS checks,
* 3) The code has classes which extend typedefs, have type arguments typedefs
* or type variable bounds typedefs.
* These restrictions can be less strict.
*/
bool isSafeToRemoveTypeDeclarations(
Map<ClassElement, Iterable<Element>> classMembers) {
ClassElement typeErrorElement = compiler.coreLibrary.find('TypeError');
if (classMembers.containsKey(typeErrorElement) ||
compiler.resolverWorld.isChecks
.any((DartType type) => type.element == typeErrorElement)) {
return false;
}
Set<DartType> processedTypes = new Set<DartType>();
List<DartType> workQueue = new List<DartType>();
workQueue
.addAll(classMembers.keys.map((classElement) => classElement.thisType));
workQueue.addAll(compiler.resolverWorld.isChecks);
while (!workQueue.isEmpty) {
DartType type = workQueue.removeLast();
if (processedTypes.contains(type)) continue;
processedTypes.add(type);
if (type is FunctionType) return false;
if (type is TypedefType) return false;
if (type is InterfaceType) {
InterfaceType interfaceType = type;
// Check all type arguments.
interfaceType.typeArguments.forEach(workQueue.add);
ClassElement element = type.element;
// Check all supertypes.
if (element.allSupertypes != null) {
element.allSupertypes.forEach(workQueue.add);
}
}
}
return true;
}
DartBackend(Compiler compiler, List<String> strips, {bool multiFile})
: tasks = <CompilerTask>[],
stripAsserts = strips.indexOf('asserts') != -1,
constantCompilerTask = new DartConstantTask(compiler),
outputter = new DartOutputter(
compiler.reporter, compiler.outputProvider,
forceStripTypes: strips.indexOf('types') != -1,
multiFile: multiFile,
enableMinification: compiler.options.enableMinification),
super(compiler) {
impactTransformer = new DartImpactTransformer(this);
}
DiagnosticReporter get reporter => compiler.reporter;
Resolution get resolution => compiler.resolution;
bool classNeedsRti(ClassElement cls) => false;
bool methodNeedsRti(FunctionElement function) => false;
void enqueueHelpers(ResolutionEnqueuer world, Registry registry) {
// Right now resolver doesn't always resolve interfaces needed
// for literals, so force them. TODO(antonm): fix in the resolver.
final LITERAL_TYPE_NAMES = const [
'Map',
'List',
'num',
'int',
'double',
'bool'
];
final coreLibrary = compiler.coreLibrary;
for (final name in LITERAL_TYPE_NAMES) {
ClassElement classElement = coreLibrary.findLocal(name);
classElement.ensureResolved(resolution);
}
// Enqueue the methods that the VM might invoke on user objects because
// we don't trust the resolution to always get these included.
world.registerDynamicUse(new DynamicUse(Selectors.toString_, null));
world.registerDynamicUse(new DynamicUse(Selectors.hashCode_, null));
world.registerDynamicUse(
new DynamicUse(new Selector.binaryOperator('=='), null));
world.registerDynamicUse(new DynamicUse(Selectors.compareTo, null));
}
WorldImpact codegen(CodegenWorkItem work) {
return const WorldImpact();
}
/**
* Tells whether we should output given element. Corelib classes like
* Object should not be in the resulting code.
*/
@override
bool shouldOutput(Element element) {
return (!element.library.isPlatformLibrary &&
!element.isSynthesized &&
element is! AbstractFieldElement) ||
mirrorRenamer.isMirrorHelperLibrary(element.library);
}
int assembleProgram() {
ElementAst computeElementAst(AstElement element) {
return new ElementAst(
element.resolvedAst.node, element.resolvedAst.elements);
}
// TODO(johnniwinther): Remove the need for this method.
void postProcessElementAst(AstElement element, ElementAst elementAst,
newTypedefElementCallback, newClassElementCallback) {
ReferencedElementCollector collector = new ReferencedElementCollector(
reporter,
element,
elementAst,
newTypedefElementCallback,
newClassElementCallback);
collector.collect();
}
int totalSize = outputter.assembleProgram(
libraries: compiler.libraryLoader.libraries,
instantiatedClasses: compiler.resolverWorld.directlyInstantiatedClasses,
resolvedElements: compiler.enqueuer.resolution.processedElements,
usedTypeLiterals: usedTypeLiterals,
postProcessElementAst: postProcessElementAst,
computeElementAst: computeElementAst,
shouldOutput: shouldOutput,
isSafeToRemoveTypeDeclarations: isSafeToRemoveTypeDeclarations,
sortElements: Elements.sortedByPosition,
mirrorRenamer: mirrorRenamer,
mainFunction: compiler.mainFunction,
outputUri: compiler.options.outputUri);
// Output verbose info about size ratio of resulting bundle to all
// referenced non-platform sources.
logResultBundleSizeInfo(outputter.libraryInfo.userLibraries,
outputter.elementInfo.topLevelElements, totalSize);
return totalSize;
}
void logResultBundleSizeInfo(Iterable<LibraryElement> userLibraries,
Iterable<Element> topLevelElements, int totalOutputSize) {
// Sum total size of scripts in each referenced library.
int nonPlatformSize = 0;
for (LibraryElement lib in userLibraries) {
for (CompilationUnitElement compilationUnit in lib.compilationUnits) {
nonPlatformSize += compilationUnit.script.file.length;
}
}
int percentage = totalOutputSize * 100 ~/ nonPlatformSize;
log('Total used non-platform files size: ${nonPlatformSize} bytes, '
'Output total size: $totalOutputSize bytes (${percentage}%)');
}
log(String message) => reporter.log('[DartBackend] $message');
@override
Future onLibrariesLoaded(LoadedLibraries loadedLibraries) {
// All platform classes must be resolved to ensure that their member names
// are preserved.
loadedLibraries.forEachLibrary((LibraryElement library) {
if (library.isPlatformLibrary) {
library.forEachLocalMember((Element element) {
if (element.isClass) {
ClassElement classElement = element;
classElement.ensureResolved(resolution);
}
});
}
});
if (useMirrorHelperLibrary &&
loadedLibraries.containsLibrary(Uris.dart_mirrors)) {
return compiler.libraryLoader
.loadLibrary(compiler.resolvedUriTranslator.translate(
loadedLibraries.getLibrary(Uris.dart_mirrors),
MirrorRenamerImpl.DART_MIRROR_HELPER,
null))
.then((LibraryElement library) {
mirrorRenamer = new MirrorRenamerImpl(compiler, this, library);
});
}
return new Future.value();
}
@override
void registerStaticUse(Element element, Enqueuer enqueuer) {
if (element == compiler.mirrorSystemGetNameFunction) {
FunctionElement getNameFunction = mirrorRenamer.getNameFunction;
if (getNameFunction != null) {
enqueuer.addToWorkList(getNameFunction);
}
}
}
@override
void registerInstantiatedType(
InterfaceType type, Enqueuer enqueuer, Registry registry,
{bool mirrorUsage: false}) {
registerPlatformMembers(type, registerUse: registry.registerDynamicUse);
super.registerInstantiatedType(type, enqueuer, registry,
mirrorUsage: mirrorUsage);
}
/// Register dynamic access of members of [type] that implement members
/// of types defined in the platform libraries.
void registerPlatformMembers(InterfaceType type,
{void registerUse(DynamicUse dynamicUse)}) {
// Without patching, dart2dart has no way of performing sound tree-shaking
// in face external functions. Therefore we employ another scheme:
//
// Based on the assumption that the platform code only relies on the
// interfaces of it's own classes, we can approximate the semantics of
// external functions by eagerly registering dynamic invocation of instance
// members defined the platform interfaces.
//
// Since we only need to generate code for non-platform classes we can
// restrict this registration to platform interfaces implemented by
// instantiated non-platform classes.
//
// Consider for instance this program:
//
// import 'dart:math' show Random;
//
// class MyRandom implements Random {
// int nextInt() => 0;
// }
//
// main() {
// print([0, 1, 2].shuffle(new MyRandom()));
// }
//
// Here `MyRandom` is a subtype if `Random` defined in 'dart:math'. By the
// assumption, all methods defined `Random` are potentially called, and
// therefore, though there are no visible call sites from the user node,
// dynamic invocation of for instance `nextInt` should be registered. In
// this case, `nextInt` is actually called by the standard implementation of
// `shuffle`.
ClassElement cls = type.element;
if (!cls.library.isPlatformLibrary) {
for (Link<DartType> link = cls.allSupertypes;
!link.isEmpty;
link = link.tail) {
InterfaceType supertype = link.head;
ClassElement superclass = supertype.element;
LibraryElement library = superclass.library;
if (library.isPlatformLibrary) {
if (_userImplementedPlatformClasses.add(superclass)) {
// Register selectors for all instance methods since these might
// be called on user classes from within the platform
// implementation.
superclass.forEachLocalMember((MemberElement element) {
if (element.isConstructor || element.isStatic) return;
element.computeType(resolution);
Selector selector = new Selector.fromElement(element);
registerUse(new DynamicUse(selector, null));
});
}
}
}
}
}
@override
bool enableDeferredLoadingIfSupported(Spannable node, Registry registry) {
// TODO(sigurdm): Implement deferred loading for dart2dart.
reporter.reportWarningMessage(
node, MessageKind.DEFERRED_LIBRARY_DART_2_DART);
return false;
}
@override
Uri resolvePatchUri(String libraryName, Uri) {
// Dart2dart does not use patches.
return null;
}
}
class DartImpactTransformer extends ImpactTransformer {
final DartBackend backend;
DartImpactTransformer(this.backend);
@override
WorldImpact transformResolutionImpact(ResolutionImpact worldImpact) {
TransformedWorldImpact transformed =
new TransformedWorldImpact(worldImpact);
for (TypeUse typeUse in worldImpact.typeUses) {
if (typeUse.kind == TypeUseKind.TYPE_LITERAL &&
typeUse.type.isInterfaceType) {
backend.usedTypeLiterals.add(typeUse.type.element);
}
if (typeUse.kind == TypeUseKind.INSTANTIATION) {
backend.registerPlatformMembers(typeUse.type,
registerUse: transformed.registerDynamicUse);
}
}
return transformed;
}
}
class EmitterUnparser extends Unparser {
final Map<Node, String> renames;
EmitterUnparser(this.renames, {bool minify, bool stripTypes})
: super(minify: minify, stripTypes: stripTypes);
visit(Node node) {
if (node != null && renames.containsKey(node)) {
write(renames[node]);
} else {
super.visit(node);
}
}
unparseSendReceiver(Send node, {bool spacesNeeded: false}) {
// TODO(smok): Remove ugly hack for library prefices.
if (node.receiver != null && renames[node.receiver] == '') return;
super.unparseSendReceiver(node, spacesNeeded: spacesNeeded);
}
unparseFunctionName(Node name) {
if (name != null && renames.containsKey(name)) {
write(renames[name]);
} else {
super.unparseFunctionName(name);
}
}
}
/**
* Some elements are not recorded by resolver now,
* for example, typedefs or classes which are only
* used in signatures, as/is operators or in super clauses
* (just to name a few). Retraverse AST to pick those up.
*/
class ReferencedElementCollector extends Visitor {
final DiagnosticReporter reporter;
final Element element;
final ElementAst elementAst;
final newTypedefElementCallback;
final newClassElementCallback;
ReferencedElementCollector(this.reporter, this.element, this.elementAst,
this.newTypedefElementCallback, this.newClassElementCallback);
visitNode(Node node) {
node.visitChildren(this);
}
visitTypeAnnotation(TypeAnnotation typeAnnotation) {
TreeElements treeElements = elementAst.treeElements;
final DartType type = treeElements.getType(typeAnnotation);
assert(invariant(typeAnnotation, type != null,
message: "Missing type for type annotation: $treeElements."));
if (type.isTypedef) newTypedefElementCallback(type.element);
if (type.isInterfaceType) newClassElementCallback(type.element);
typeAnnotation.visitChildren(this);
}
void collect() {
reporter.withCurrentElement(element, () {
elementAst.ast.accept(this);
});
}
}
Comparator compareBy(f) => (x, y) => f(x).compareTo(f(y));
List sorted(Iterable l, comparison) {
final result = new List.from(l);
result.sort(comparison);
return result;
}
compareElements(e0, e1) {
int result = compareBy((e) => e.library.canonicalUri.toString())(e0, e1);
if (result != 0) return result;
return compareBy((e) => e.position.charOffset)(e0, e1);
}
/// [ConstantCompilerTask] for compilation of constants for the Dart backend.
///
/// Since this task needs no distinction between frontend and backend constants
/// it also serves as the [BackendConstantEnvironment].
class DartConstantTask extends ConstantCompilerTask
implements BackendConstantEnvironment {
final DartConstantCompiler constantCompiler;
DartConstantTask(Compiler compiler)
: this.constantCompiler = new DartConstantCompiler(compiler),
super(compiler.measurer);
String get name => 'ConstantHandler';
@override
ConstantSystem get constantSystem => constantCompiler.constantSystem;
@override
bool hasConstantValue(ConstantExpression expression) {
return constantCompiler.hasConstantValue(expression);
}
@override
ConstantValue getConstantValue(ConstantExpression expression) {
return constantCompiler.getConstantValue(expression);
}
@override
ConstantValue getConstantValueForVariable(VariableElement element) {
return constantCompiler.getConstantValueForVariable(element);
}
@override
ConstantExpression getConstantForNode(Node node, TreeElements elements) {
return constantCompiler.getConstantForNode(node, elements);
}
@override
ConstantValue getConstantValueForNode(Node node, TreeElements elements) {
return getConstantValue(
constantCompiler.getConstantForNode(node, elements));
}
@override
ConstantValue getConstantValueForMetadata(MetadataAnnotation metadata) {
return getConstantValue(metadata.constant);
}
@override
ConstantExpression compileConstant(VariableElement element) {
return measure(() {
return constantCompiler.compileConstant(element);
});
}
@override
void evaluate(ConstantExpression constant) {
return measure(() {
return constantCompiler.evaluate(constant);
});
}
@override
ConstantExpression compileVariable(VariableElement element) {
return measure(() {
return constantCompiler.compileVariable(element);
});
}
@override
ConstantExpression compileNode(Node node, TreeElements elements,
{bool enforceConst: true}) {
return measure(() {
return constantCompiler.compileNodeWithDefinitions(node, elements,
isConst: enforceConst);
});
}
@override
ConstantExpression compileMetadata(
MetadataAnnotation metadata, Node node, TreeElements elements) {
return measure(() {
return constantCompiler.compileMetadata(metadata, node, elements);
});
}
// TODO(johnniwinther): Remove this when values are computed from the
// expressions.
@override
void copyConstantValues(DartConstantTask task) {
constantCompiler.constantValueMap
.addAll(task.constantCompiler.constantValueMap);
}
@override
void registerLazyStatic(FieldElement element) {
// Do nothing.
}
}

View file

@ -1,93 +0,0 @@
// Copyright (c) 2014, 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 backend_ast_emitter;
import 'backend_ast_nodes.dart';
import '../dart_types.dart';
import '../elements/elements.dart';
class TypeGenerator {
/// TODO(johnniwinther): Remove this when issue 21283 has been resolved.
static int pseudoNameCounter = 0;
static Parameter emitParameter(DartType type,
{String name, Element element}) {
if (name == null && element != null) {
name = element.name;
}
if (name == null) {
name = '_${pseudoNameCounter++}';
}
Parameter parameter;
if (type.isFunctionType) {
FunctionType functionType = type;
TypeAnnotation returnType = createOptionalType(functionType.returnType);
Parameters innerParameters = createParametersFromType(functionType);
parameter = new Parameter.function(name, returnType, innerParameters);
} else {
TypeAnnotation typeAnnotation = createOptionalType(type);
parameter = new Parameter(name, type: typeAnnotation);
}
parameter.element = element;
return parameter;
}
static Parameters createParametersFromType(FunctionType functionType) {
pseudoNameCounter = 0;
if (functionType.namedParameters.isEmpty) {
return new Parameters(createParameters(functionType.parameterTypes),
createParameters(functionType.optionalParameterTypes), false);
} else {
return new Parameters(
createParameters(functionType.parameterTypes),
createParameters(functionType.namedParameterTypes,
names: functionType.namedParameters),
true);
}
}
static List<Parameter> createParameters(Iterable<DartType> parameterTypes,
{Iterable<String> names: const <String>[],
Iterable<Element> elements: const <Element>[]}) {
Iterator<String> name = names.iterator;
Iterator<Element> element = elements.iterator;
return parameterTypes.map((DartType type) {
name.moveNext();
element.moveNext();
return emitParameter(type, name: name.current, element: element.current);
}).toList();
}
/// Like [createTypeAnnotation] except the dynamic type is converted to null.
static TypeAnnotation createOptionalType(DartType type) {
if (type.treatAsDynamic) {
return null;
} else {
return createType(type);
}
}
/// Creates the [TypeAnnotation] for a [type] that is not function type.
static TypeAnnotation createType(DartType type) {
if (type is GenericType) {
if (type.treatAsRaw) {
return new TypeAnnotation(type.element.name)..dartType = type;
}
return new TypeAnnotation(type.element.name,
type.typeArguments.map(createType).toList(growable: false))
..dartType = type;
} else if (type is VoidType) {
return new TypeAnnotation('void')..dartType = type;
} else if (type is TypeVariableType) {
return new TypeAnnotation(type.name)..dartType = type;
} else if (type is DynamicType) {
return new TypeAnnotation("dynamic")..dartType = type;
} else if (type is MalformedType) {
return new TypeAnnotation(type.name)..dartType = type;
} else {
throw "Unsupported type annotation: $type";
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,40 +0,0 @@
// 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 dart_backend;
import 'dart:async' show Future;
import 'dart:math' show max;
import '../../compiler.dart' show CompilerOutputProvider;
import '../common.dart';
import '../common/backend_api.dart' show Backend, ImpactTransformer;
import '../common/codegen.dart' show CodegenWorkItem;
import '../common/names.dart' show Selectors, Uris;
import '../common/registry.dart' show Registry;
import '../common/resolution.dart' show Resolution, ResolutionImpact;
import '../common/tasks.dart' show CompilerTask;
import '../compiler.dart' show Compiler;
import '../compile_time_constants.dart';
import '../constants/constant_system.dart';
import '../constants/expressions.dart';
import '../constants/values.dart';
import '../dart_types.dart';
import '../elements/elements.dart';
import '../enqueue.dart' show Enqueuer, ResolutionEnqueuer;
import '../library_loader.dart' show LoadedLibraries;
import '../mirror_renamer/mirror_renamer.dart';
import '../resolution/tree_elements.dart' show TreeElements, TreeElementMapping;
import '../tokens/keyword.dart' show Keyword;
import '../tree/tree.dart';
import '../universe/selector.dart' show Selector;
import '../universe/use.dart' show DynamicUse, TypeUse, TypeUseKind;
import '../universe/world_impact.dart' show WorldImpact, TransformedWorldImpact;
import '../util/util.dart';
import 'backend_ast_to_frontend_ast.dart' as backend2frontend;
part 'backend.dart';
part 'renamer.dart';
part 'placeholder_collector.dart';
part 'outputter.dart';

View file

@ -1,576 +0,0 @@
// Copyright (c) 2014, 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.
part of dart_backend;
typedef bool IsSafeToRemoveTypeDeclarations(
Map<ClassElement, Iterable<Element>> classMembers);
typedef void ElementCallback<E>(E element);
typedef void ElementPostProcessFunction(
AstElement element,
ElementAst elementAst,
ElementCallback<TypedefElement> typedefCallback,
ElementCallback<ClassElement> classCallback);
typedef ElementAst ComputeElementAstFunction(AstElement element);
typedef bool ElementFilter(Element element);
typedef List<Element> ElementSorter(Iterable<Element> elements);
/// Output engine for dart2dart that is shared between the dart2js and the
/// analyzer implementations of dart2dart.
class DartOutputter {
final DiagnosticReporter reporter;
final CompilerOutputProvider outputProvider;
final bool forceStripTypes;
// TODO(antonm): make available from command-line options.
final bool outputAst = false;
final bool enableMinification;
/// If `true`, libraries are generated into separate files.
final bool multiFile;
/// Internal structures accessible for tests and logging.
// TODO(johnniwinther): Clean this up.
PlaceholderRenamer renamer;
MainOutputGenerator output;
LibraryInfo libraryInfo;
ElementInfo elementInfo;
// TODO(johnniwinther): Support recompilation.
DartOutputter(this.reporter, this.outputProvider,
{bool this.forceStripTypes: false,
bool this.enableMinification: false,
bool this.multiFile: false});
/// Generate Dart code for the program starting at [mainFunction].
///
/// [libraries] is the set of all libraries (user/package/sdk) that are
/// referenced in the program.
///
/// [instantiatedClasses] is the set of classes that are potentially
/// instantiated in the program.
///
/// [resolvedElements] is the set of methods, constructors, and fields that
/// are potentially accessed/called in the program.
///
/// The [sortElements] function is used to sort [instantiatedClasses] and
/// [resolvedElements] in the generated output.
///
/// Returns the total size of the generated code.
int assembleProgram(
{MirrorRenamer mirrorRenamer: const MirrorRenamer(),
Iterable<LibraryElement> libraries,
Iterable<Element> instantiatedClasses,
Iterable<Element> resolvedElements,
Iterable<ClassElement> usedTypeLiterals: const <ClassElement>[],
FunctionElement mainFunction,
Uri outputUri,
ElementPostProcessFunction postProcessElementAst,
ComputeElementAstFunction computeElementAst,
ElementFilter shouldOutput,
IsSafeToRemoveTypeDeclarations isSafeToRemoveTypeDeclarations,
ElementSorter sortElements}) {
assert(invariant(NO_LOCATION_SPANNABLE, libraries != null,
message: "'libraries' must be non-null."));
assert(invariant(NO_LOCATION_SPANNABLE, instantiatedClasses != null,
message: "'instantiatedClasses' must be non-null."));
assert(invariant(NO_LOCATION_SPANNABLE, resolvedElements != null,
message: "'resolvedElements' must be non-null."));
assert(invariant(NO_LOCATION_SPANNABLE, mainFunction != null,
message: "'mainFunction' must be non-null."));
assert(invariant(NO_LOCATION_SPANNABLE, computeElementAst != null,
message: "'computeElementAst' must be non-null."));
assert(invariant(NO_LOCATION_SPANNABLE, shouldOutput != null,
message: "'shouldOutput' must be non-null."));
assert(invariant(
NO_LOCATION_SPANNABLE, isSafeToRemoveTypeDeclarations != null,
message: "'isSafeToRemoveTypeDeclarations' must be non-null."));
if (sortElements == null) {
// Ensure deterministic output order.
sortElements = (Iterable<Element> elements) {
List<Element> list = elements.toList();
list.sort((Element a, Element b) => a.name.compareTo(b.name));
return list;
};
}
libraryInfo =
LibraryInfo.processLibraries(reporter, libraries, resolvedElements);
elementInfo = ElementInfoProcessor.createElementInfo(
instantiatedClasses, resolvedElements, usedTypeLiterals,
postProcessElementAst: postProcessElementAst,
parseElementAst: computeElementAst,
shouldOutput: shouldOutput,
sortElements: sortElements);
PlaceholderCollector collector = collectPlaceholders(
reporter, mirrorRenamer, mainFunction, libraryInfo, elementInfo);
renamer = createRenamer(collector, libraryInfo, elementInfo,
enableMinification: enableMinification,
forceStripTypes: forceStripTypes,
isSafeToRemoveTypeDeclarations: isSafeToRemoveTypeDeclarations);
if (outputAst) {
String code = astOutput(reporter, elementInfo);
outputProvider("", "dart")
..add(code)
..close();
return code.length;
} else {
output = new MainOutputGenerator();
return output.generateCode(libraryInfo, elementInfo, collector, renamer,
mainFunction, outputUri, outputProvider, mirrorRenamer,
multiFile: multiFile,
forceStripTypes: forceStripTypes,
enableMinification: enableMinification);
}
}
static PlaceholderCollector collectPlaceholders(
DiagnosticReporter reporter,
MirrorRenamer mirrorRenamer,
FunctionElement mainFunction,
LibraryInfo libraryInfo,
ElementInfo elementInfo) {
// Create all necessary placeholders.
PlaceholderCollector collector = new PlaceholderCollector(
reporter,
mirrorRenamer,
libraryInfo.fixedDynamicNames,
elementInfo.elementAsts,
mainFunction);
makePlaceholders(element) {
collector.collect(element);
if (element.isClass && !element.isEnumClass) {
elementInfo.classMembers[element].forEach(makePlaceholders);
}
}
elementInfo.topLevelElements.forEach(makePlaceholders);
return collector;
}
static PlaceholderRenamer createRenamer(PlaceholderCollector collector,
LibraryInfo libraryInfo, ElementInfo elementInfo,
{bool enableMinification: false,
bool forceStripTypes: false,
isSafeToRemoveTypeDeclarations}) {
// Create renames.
bool shouldCutDeclarationTypes = forceStripTypes ||
(enableMinification &&
isSafeToRemoveTypeDeclarations(elementInfo.classMembers));
PlaceholderRenamer placeholderRenamer = new PlaceholderRenamer(
libraryInfo.fixedDynamicNames,
libraryInfo.fixedStaticNames,
libraryInfo.reexportingLibraries,
cutDeclarationTypes: shouldCutDeclarationTypes,
enableMinification: enableMinification);
placeholderRenamer.computeRenames(collector);
return placeholderRenamer;
}
static String astOutput(
DiagnosticReporter reporter, ElementInfo elementInfo) {
// TODO(antonm): Ideally XML should be a separate backend.
// TODO(antonm): obey renames and minification, at least as an option.
StringBuffer sb = new StringBuffer();
outputElement(element) {
sb.write(element.parseNode(reporter).toDebugString());
}
// Emit XML for AST instead of the program.
for (Element topLevel in elementInfo.topLevelElements) {
if (topLevel.isClass &&
!elementInfo.emitNoMembersFor.contains(topLevel)) {
// TODO(antonm): add some class info.
elementInfo.classMembers[topLevel].forEach(outputElement);
} else {
outputElement(topLevel);
}
}
return '<Program>\n$sb</Program>\n';
}
}
class LibraryInfo {
final Set<String> fixedStaticNames;
final Set<String> fixedDynamicNames;
final Map<Element, LibraryElement> reexportingLibraries;
final List<LibraryElement> userLibraries;
LibraryInfo(this.fixedStaticNames, this.fixedDynamicNames,
this.reexportingLibraries, this.userLibraries);
static LibraryInfo processLibraries(
DiagnosticReporter reporter,
Iterable<LibraryElement> libraries,
Iterable<AstElement> resolvedElements) {
Set<String> fixedStaticNames = new Set<String>();
Set<String> fixedDynamicNames = new Set<String>();
Map<Element, LibraryElement> reexportingLibraries =
<Element, LibraryElement>{};
List<LibraryElement> userLibraries = <LibraryElement>[];
// Conservatively traverse all platform libraries and collect member names.
// TODO(antonm): ideally we should only collect names of used members,
// however as of today there are problems with names of some core library
// interfaces, most probably for interfaces of literals.
for (LibraryElement library in libraries) {
if (!library.isPlatformLibrary) {
userLibraries.add(library);
continue;
}
library.forEachLocalMember((Element element) {
if (element.isClass) {
ClassElement classElement = element;
assert(invariant(classElement, classElement.isResolved,
message: "Unresolved platform class."));
classElement.forEachLocalMember((member) {
if (member.isInstanceMember) {
fixedDynamicNames.add(member.name);
} else {
fixedStaticNames.add(member.name);
}
});
}
// Even class names are added due to a delicate problem we have:
// if one imports dart:core with a prefix, we cannot tell prefix.name
// from dynamic invocation (alas!). So we'd better err on preserving
// those names.
fixedStaticNames.add(element.name);
});
library.forEachExport((Element export) {
if (!library.isInternalLibrary && export.library.isInternalLibrary) {
// If an element of an internal library is reexported by a platform
// library, we have to import the reexporting library instead of the
// internal library, because the internal library is an
// implementation detail of dart2js.
reexportingLibraries[export] = library;
}
});
}
// Map to keep track of names of enum classes. Since these cannot be renamed
// we ensure that they are unique.
Map<String, ClassElement> enumClassMap = <String, ClassElement>{};
// As of now names of named optionals are not renamed. Therefore add all
// field names used as named optionals into [fixedMemberNames].
for (final element in resolvedElements) {
if (!element.isConstructor) continue;
for (ParameterElement parameter in element.parameters) {
if (parameter.isInitializingFormal && parameter.isNamed) {
fixedDynamicNames.add(parameter.name);
}
}
ClassElement cls = element.enclosingClass;
if (cls != null && cls.isEnumClass) {
fixedDynamicNames.add('index');
ClassElement existingEnumClass =
enumClassMap.putIfAbsent(cls.name, () => cls);
if (existingEnumClass != cls) {
reporter.reportError(
reporter.createMessage(cls, MessageKind.GENERIC, {
'text': "Duplicate enum names are not supported "
"in dart2dart."
}),
<DiagnosticMessage>[
reporter.createMessage(existingEnumClass, MessageKind.GENERIC, {
'text': "This is the other declaration of '${cls.name}'."
}),
]);
}
}
}
fixedStaticNames.addAll(enumClassMap.keys);
// The VM will automatically invoke the call method of objects
// that are invoked as functions. Make sure to not rename that.
fixedDynamicNames.add('call');
return new LibraryInfo(fixedStaticNames, fixedDynamicNames,
reexportingLibraries, userLibraries);
}
}
class ElementInfo {
final Map<Element, ElementAst> elementAsts;
final Iterable<Element> topLevelElements;
final Map<ClassElement, Iterable<Element>> classMembers;
final Iterable<ClassElement> emitNoMembersFor;
ElementInfo(this.elementAsts, this.topLevelElements, this.classMembers,
this.emitNoMembersFor);
}
class ElementInfoProcessor implements ElementInfo {
final Map<Element, ElementAst> elementAsts = new Map<Element, ElementAst>();
final Set<Element> topLevelElements = new Set<Element>();
final Map<ClassElement, Set<Element>> classMembers =
new Map<ClassElement, Set<Element>>();
final Set<ClassElement> emitNoMembersFor = new Set<ClassElement>();
final ElementPostProcessFunction postProcessElementAst;
final ComputeElementAstFunction parseElementAst;
final ElementFilter shouldOutput;
ElementInfoProcessor(
{this.postProcessElementAst, this.parseElementAst, this.shouldOutput});
static ElementInfo createElementInfo(
Iterable<ClassElement> instantiatedClasses,
Iterable<AstElement> resolvedElements,
Iterable<ClassElement> usedTypeLiterals,
{ElementPostProcessFunction postProcessElementAst,
ComputeElementAstFunction parseElementAst,
ElementFilter shouldOutput,
ElementSorter sortElements}) {
ElementInfoProcessor processor = new ElementInfoProcessor(
postProcessElementAst: postProcessElementAst,
parseElementAst: parseElementAst,
shouldOutput: shouldOutput);
return processor.process(
instantiatedClasses, resolvedElements, usedTypeLiterals,
sortElements: sortElements);
}
ElementInfo process(
Iterable<ClassElement> instantiatedClasses,
Iterable<AstElement> resolvedElements,
Iterable<ClassElement> usedTypeLiterals,
{ElementSorter sortElements}) {
// Build all top level elements to emit and necessary class members.
instantiatedClasses.where(shouldOutput).forEach(addClass);
resolvedElements.where(shouldOutput).forEach(addMember);
usedTypeLiterals.forEach((ClassElement element) {
if (shouldOutput(element)) {
if (!topLevelElements.contains(element)) {
// The class is only referenced by type literals.
emitNoMembersFor.add(element);
}
addClass(element);
}
});
// Sort elements.
List<Element> sortedTopLevels = sortElements(topLevelElements);
Map<ClassElement, List<Element>> sortedClassMembers =
new Map<ClassElement, List<Element>>();
classMembers.forEach((classElement, members) {
sortedClassMembers[classElement] = sortElements(members);
});
return new ElementInfo(
elementAsts, sortedTopLevels, sortedClassMembers, emitNoMembersFor);
}
void processElement(Element element, ElementAst elementAst) {
if (postProcessElementAst != null) {
postProcessElementAst(element, elementAst, newTypedefElementCallback,
newClassElementCallback);
}
elementAsts[element] = elementAst;
}
void addTopLevel(AstElement element, ElementAst elementAst) {
if (topLevelElements.contains(element)) return;
topLevelElements.add(element);
processElement(element, elementAst);
}
void addClass(ClassElement classElement) {
TreeElements treeElements = new TreeElementMapping(classElement);
backend2frontend.TreePrinter treePrinter =
new backend2frontend.TreePrinter(treeElements);
Node node = treePrinter.makeNodeForClassElement(classElement);
addTopLevel(classElement, new ElementAst(node, treeElements));
classMembers.putIfAbsent(classElement, () => new Set());
}
void newTypedefElementCallback(TypedefElement element) {
if (!shouldOutput(element)) return;
TreeElements treeElements = new TreeElementMapping(element);
backend2frontend.TreePrinter treePrinter =
new backend2frontend.TreePrinter(treeElements);
Node node = treePrinter.makeTypedef(element);
addTopLevel(element, new ElementAst(node, treeElements));
}
void newClassElementCallback(ClassElement classElement) {
if (!shouldOutput(classElement)) return;
addClass(classElement);
}
void addMember(element) {
if (element.isClassMember) {
ClassElement enclosingClass = element.enclosingClass;
assert(enclosingClass.isClass);
assert(shouldOutput(enclosingClass));
addClass(enclosingClass);
classMembers[enclosingClass].add(element);
if (enclosingClass.isEnumClass) return;
processElement(element, parseElementAst(element));
} else {
if (element.isTopLevel) {
addTopLevel(element, parseElementAst(element));
}
}
}
}
/// Main output generator for [DartOutputter] that emits dart code through a
/// [CompilerOutputProvider].
class MainOutputGenerator {
final Map<ClassNode, List<Node>> memberNodes =
new Map<ClassNode, List<Node>>();
final List<Node> topLevelNodes = <Node>[];
/// Generates the code and returns the total size.
int generateCode(
LibraryInfo libraryInfo,
ElementInfo elementInfo,
PlaceholderCollector collector,
PlaceholderRenamer placeholderRenamer,
FunctionElement mainFunction,
Uri outputUri,
CompilerOutputProvider outputProvider,
MirrorRenamer mirrorRenamer,
{bool multiFile: false,
bool forceStripTypes: false,
bool enableMinification: false}) {
for (Element element in elementInfo.topLevelElements) {
topLevelNodes.add(elementInfo.elementAsts[element].ast);
if (element.isClass) {
ClassElement cls = element;
if (cls.isMixinApplication || cls.isEnumClass) {
continue;
}
final members = <Node>[];
for (Element member in elementInfo.classMembers[cls]) {
members.add(elementInfo.elementAsts[member].ast);
}
memberNodes[elementInfo.elementAsts[cls].ast] = members;
}
}
mirrorRenamer.addRenames(
placeholderRenamer.renames, topLevelNodes, collector);
Map<LibraryElement, String> outputPaths = new Map<LibraryElement, String>();
Map<LibraryElement, EmitterUnparser> unparsers =
new Map<LibraryElement, EmitterUnparser>();
// The single unparser used if we collect all the output in one file.
EmitterUnparser mainUnparser = multiFile
? null
: new EmitterUnparser(placeholderRenamer.renames,
stripTypes: forceStripTypes, minify: enableMinification);
if (multiFile) {
// TODO(sigurdm): Factor handling of library-paths out from emitting.
String mainName = outputUri.pathSegments.last;
String mainBaseName = mainName.endsWith(".dart")
? mainName.substring(0, mainName.length - 5)
: mainName;
// Map each library to a path based on the uri of the original
// library and [compiler.options.outputUri].
Set<String> usedLibraryPaths = new Set<String>();
for (LibraryElement library in libraryInfo.userLibraries) {
if (library == mainFunction.library) {
outputPaths[library] = mainBaseName;
} else {
List<String> names =
library.canonicalUri.pathSegments.last.split(".");
if (names.last == "dart") {
names = names.sublist(0, names.length - 1);
}
outputPaths[library] =
"$mainBaseName.${makeUnique(names.join("."), usedLibraryPaths)}";
}
}
/// Rewrites imports/exports to refer to the paths given in [outputPaths].
for (LibraryElement outputLibrary in libraryInfo.userLibraries) {
EmitterUnparser unparser = new EmitterUnparser(
placeholderRenamer.renames,
stripTypes: forceStripTypes,
minify: enableMinification);
unparsers[outputLibrary] = unparser;
if (outputLibrary.hasLibraryName) {
unparser.unparseLibraryName(outputLibrary.libraryName);
}
for (ImportElement import in outputLibrary.imports) {
LibraryElement libraryElement = import.importedLibrary;
String uri = outputPaths.containsKey(libraryElement)
? "${outputPaths[libraryElement]}.dart"
: libraryElement.canonicalUri.toString();
unparser.unparseImportTag(uri);
}
for (ExportElement export in outputLibrary.exports) {
LibraryElement libraryElement = export.exportedLibrary;
String uri = outputPaths.containsKey(libraryElement)
? "${outputPaths[libraryElement]}.dart"
: libraryElement.canonicalUri.toString();
unparser.unparseExportTag(uri);
}
}
} else {
placeholderRenamer.platformImports
.forEach((LibraryElement library, String prefix) {
assert(library.isPlatformLibrary && !library.isInternalLibrary);
mainUnparser.unparseImportTag(library.canonicalUri.toString());
if (prefix != null) {
// Adding a prefixed import because (some) top-level access need
// it to avoid shadowing.
// TODO(johnniwinther): Avoid prefix-less import if not needed.
mainUnparser.unparseImportTag(library.canonicalUri.toString(),
prefix: prefix);
}
});
}
for (int i = 0; i < elementInfo.topLevelElements.length; i++) {
Element element = elementInfo.topLevelElements.elementAt(i);
Node node = topLevelNodes[i];
Unparser unparser = multiFile ? unparsers[element.library] : mainUnparser;
if (node is ClassNode) {
// TODO(smok): Filter out default constructors here.
unparser.unparseClassWithBody(node, memberNodes[node]);
} else {
unparser.unparse(node);
}
unparser.newline();
}
int totalSize = 0;
if (multiFile) {
for (LibraryElement outputLibrary in libraryInfo.userLibraries) {
// TODO(sigurdm): Make the unparser output directly into the buffer
// instead of caching in `.result`.
String code = unparsers[outputLibrary].result;
totalSize += code.length;
outputProvider(outputPaths[outputLibrary], "dart")
..add(code)
..close();
}
} else {
String code = mainUnparser.result;
outputProvider("", "dart")
..add(code)
..close();
totalSize = code.length;
}
return totalSize;
}
}

View file

@ -1,724 +0,0 @@
// 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.
part of dart_backend;
class LocalPlaceholder {
final String identifier;
final Set<Node> nodes;
LocalPlaceholder(this.identifier) : nodes = new Set<Node>();
int get hashCode => identifier.hashCode;
String toString() => 'local_placeholder[id($identifier), nodes($nodes)]';
}
class FunctionScope {
final Set<String> parameterIdentifiers;
final Set<LocalPlaceholder> localPlaceholders;
FunctionScope()
: parameterIdentifiers = new Set<String>(),
localPlaceholders = new Set<LocalPlaceholder>();
void registerParameter(Identifier node) {
parameterIdentifiers.add(node.source);
}
}
class ConstructorPlaceholder {
final Identifier node;
final ConstructorElement element;
ConstructorPlaceholder(this.node, this.element);
}
class DeclarationTypePlaceholder {
final TypeAnnotation typeNode;
final bool requiresVar;
DeclarationTypePlaceholder(this.typeNode, this.requiresVar);
}
class SendVisitor extends Visitor {
final TreeElements elements;
final PlaceholderCollector collector;
SendVisitor(this.collector, this.elements);
visitSend(Send node) {
Element element = elements[node];
if (elements.isTypeLiteral(node)) {
DartType type = elements.getTypeLiteralType(node);
if (!type.isDynamic) {
if (type is TypeVariableType) {
collector.makeTypeVariablePlaceholder(node.selector, type);
} else {
collector.makeTypePlaceholder(node.selector, type);
}
}
} else if (node.isSuperCall) {
if (element != null && element.isConstructor) {
collector.tryMakeConstructorPlaceholder(node, element);
} else {
collector.tryMakeMemberPlaceholder(node.selector);
}
} else if (node.isOperator) {
return;
} else if (node.isPropertyAccess) {
if (!Elements.isUnresolved(element) && element.impliesType) {
collector.makeElementPlaceholder(node, element);
} else {
visitGetterSend(node);
}
} else if (element != null && Initializers.isConstructorRedirect(node)) {
visitStaticSend(node);
} else if (Elements.isClosureSend(node, element)) {
if (element != null) {
collector.tryMakeLocalPlaceholder(element, node.selector);
}
} else {
if (Elements.isUnresolved(element)) {
if (element == null) {
// Example: f() with 'f' unbound.
// This can only happen inside an instance method.
visitDynamicSend(node);
} else {
visitStaticSend(node);
}
} else if (element.isInstanceMember) {
// Example: f() with 'f' bound to instance method.
visitDynamicSend(node);
} else if (!element.isInstanceMember) {
// Example: A.f() or f() with 'f' bound to a static function.
// Also includes new A() or new A.named() which is treated like a
// static call to a factory.
visitStaticSend(node);
}
}
}
visitDynamicSend(Send node) {
final element = elements[node];
if (element == null || !element.isMalformed) {
collector.tryMakeMemberPlaceholder(node.selector);
}
}
visitGetterSend(Send node) {
final element = elements[node];
// element == null means dynamic property access.
if (element == null) {
collector.tryMakeMemberPlaceholder(node.selector);
} else if (element.isMalformed) {
collector.makeUnresolvedPlaceholder(node);
return;
} else if (element.isPrefix) {
// Node is prefix part in case of source 'lib.somesetter = 5;'
collector.makeErasePrefixPlaceholder(node);
} else if (Elements.isStaticOrTopLevel(element)) {
// Unqualified or prefixed top level or static.
collector.makeElementPlaceholder(node.selector, element);
} else if (!element.isTopLevel) {
if (element.isInstanceMember) {
collector.tryMakeMemberPlaceholder(node.selector);
} else {
// May get FunctionExpression here in selector
// in case of A(int this.f());
if (node.selector is Identifier) {
collector.tryMakeLocalPlaceholder(element, node.selector);
} else {
assert(node.selector is FunctionExpression);
}
}
}
}
visitStaticSend(Send node) {
Element element = elements[node];
collector.mirrorRenamer
.registerStaticSend(collector.currentElement, element, node);
if (Elements.isUnresolved(element) || element.isDeferredLoaderGetter) {
return;
}
if (element.isConstructor || element.isFactoryConstructor) {
// Rename named constructor in redirection position:
// class C { C.named(); C.redirecting() : this.named(); }
if (node.receiver is Identifier &&
node.receiver.asIdentifier().isThis()) {
assert(node.selector is Identifier);
collector.tryMakeConstructorPlaceholder(node, element);
}
return;
}
collector.makeElementPlaceholder(node.selector, element);
// Another ugly case: <lib prefix>.<top level> is represented as
// receiver: lib prefix, selector: top level.
if (element.isTopLevel && node.receiver != null) {
assert(elements[node.receiver].isPrefix);
// Hack: putting null into map overrides receiver of original node.
collector.makeErasePrefixPlaceholder(node.receiver);
}
}
internalError(Spannable node, String reason) {
collector.internalError(reason, node: node);
}
visitNode(Node node) {
internalError(node, "Unhandled node");
}
}
class PlaceholderCollector extends Visitor {
final DiagnosticReporter reporter;
final MirrorRenamer mirrorRenamer;
final FunctionElement mainFunction;
final Set<String> fixedMemberNames; // member names which cannot be renamed.
final Map<Element, ElementAst> elementAsts;
final Set<Node> prefixNodesToErase = new Set<Node>();
final Set<Node> unresolvedNodes = new Set<Node>();
final Map<Element, Set<Node>> elementNodes = new Map<Element, Set<Node>>();
final Map<FunctionElement, FunctionScope> functionScopes =
new Map<FunctionElement, FunctionScope>();
final Map<LibraryElement, Set<Identifier>> privateNodes =
new Map<LibraryElement, Set<Identifier>>();
final List<DeclarationTypePlaceholder> declarationTypePlaceholders =
new List<DeclarationTypePlaceholder>();
final Map<String, Set<Identifier>> memberPlaceholders =
new Map<String, Set<Identifier>>();
final List<ConstructorPlaceholder> constructorPlaceholders =
new List<ConstructorPlaceholder>();
Map<String, LocalPlaceholder> currentLocalPlaceholders;
Element currentElement;
FunctionElement topmostEnclosingFunction;
TreeElements treeElements;
get currentFunctionScope => functionScopes.putIfAbsent(
topmostEnclosingFunction, () => new FunctionScope());
PlaceholderCollector(this.reporter, this.mirrorRenamer, this.fixedMemberNames,
this.elementAsts, this.mainFunction);
void collectFunctionDeclarationPlaceholders(
FunctionElement element, FunctionExpression node) {
if (element.isConstructor) {
ConstructorElement constructor = element;
tryMakeConstructorPlaceholder(node.name, element);
RedirectingFactoryBody bodyAsRedirectingFactoryBody =
node.body.asRedirectingFactoryBody();
if (bodyAsRedirectingFactoryBody != null) {
// Factory redirection.
FunctionElement redirectTarget = constructor.immediateRedirectionTarget;
assert(redirectTarget != null && redirectTarget != element);
tryMakeConstructorPlaceholder(
bodyAsRedirectingFactoryBody.constructorReference, redirectTarget);
}
} else if (Elements.isStaticOrTopLevel(element)) {
// Note: this code should only rename private identifiers for class'
// fields/getters/setters/methods. Top-level identifiers are renamed
// just to escape conflicts and that should be enough as we shouldn't
// be able to resolve private identifiers for other libraries.
makeElementPlaceholder(node.name, element);
} else if (element.isClassMember) {
if (node.name is Identifier) {
tryMakeMemberPlaceholder(node.name);
} else {
assert(node.name.asSend().isOperator);
}
}
}
void collectFieldDeclarationPlaceholders(Element element, Node node) {
Identifier name = node is Identifier ? node : node.asSend().selector;
if (Elements.isStaticOrTopLevel(element)) {
makeElementPlaceholder(name, element);
} else if (Elements.isInstanceField(element)) {
tryMakeMemberPlaceholder(name);
}
}
void collect(Element element) {
this.currentElement = element;
this.topmostEnclosingFunction = null;
final ElementAst elementAst = elementAsts[element];
this.treeElements = elementAst.treeElements;
Node elementNode = elementAst.ast;
if (element is FunctionElement) {
collectFunctionDeclarationPlaceholders(element, elementNode);
} else if (element is VariableElement) {
VariableDefinitions definitions = elementNode;
Node definition = definitions.definitions.nodes.head;
collectFieldDeclarationPlaceholders(element, definition);
makeVarDeclarationTypePlaceholder(definitions);
} else {
assert(element is ClassElement || element is TypedefElement);
}
currentLocalPlaceholders = new Map<String, LocalPlaceholder>();
if (!(element is ConstructorElement && element.isRedirectingFactory)) {
// Do not visit the body of redirecting factories.
reporter.withCurrentElement(element, () {
elementNode.accept(this);
});
}
}
// TODO(karlklose): should we create placeholders for these?
bool isTypedefParameter(Element element) {
return element != null &&
element.enclosingElement != null &&
element.enclosingElement.isTypedef;
}
void tryMakeLocalPlaceholder(Element element, Identifier node) {
bool isNamedOptionalParameter() {
FunctionTypedElement function = element.enclosingElement;
FunctionSignature signature = function.functionSignature;
if (!signature.optionalParametersAreNamed) return false;
for (Element parameter in signature.optionalParameters) {
if (identical(parameter, element)) return true;
}
return false;
}
if (element.isRegularParameter &&
!isTypedefParameter(element) &&
isNamedOptionalParameter()) {
currentFunctionScope.registerParameter(node);
} else if (Elements.isLocal(element) && !isTypedefParameter(element)) {
makeLocalPlaceholder(node);
}
}
void tryMakeMemberPlaceholder(Identifier node) {
assert(node != null);
if (node is Operator) return;
String identifier = node.source;
if (fixedMemberNames.contains(identifier)) return;
memberPlaceholders
.putIfAbsent(identifier, () => new Set<Identifier>())
.add(node);
}
void makeTypePlaceholder(Node node, DartType type) {
Send send = node.asSend();
if (send != null) {
// Prefix.
assert(send.receiver is Identifier);
assert(send.selector is Identifier);
makeErasePrefixPlaceholder(send.receiver);
node = send.selector;
}
makeElementPlaceholder(node, type.element);
}
void makeTypeVariablePlaceholder(Node node, TypeVariableType type) {
Send send = node.asSend();
if (send != null) {
// Prefix.
assert(send.receiver is Identifier);
assert(send.selector is Identifier);
makeErasePrefixPlaceholder(send.receiver);
node = send.selector;
}
tryMakeMemberPlaceholder(node);
}
void makeOmitDeclarationTypePlaceholder(TypeAnnotation type) {
if (type == null) return;
declarationTypePlaceholders
.add(new DeclarationTypePlaceholder(type, false));
}
void makeVarDeclarationTypePlaceholder(VariableDefinitions node) {
// TODO(smok): Maybe instead of calling this method and
// makeDeclaratioTypePlaceholder have type declaration placeholder
// collector logic in visitVariableDefinitions when resolver becomes better
// and/or catch syntax changes.
if (node.type == null) return;
bool requiresVar = !node.modifiers.isFinalOrConst;
declarationTypePlaceholders
.add(new DeclarationTypePlaceholder(node.type, requiresVar));
}
/// Marks [node] to be erased in the output.
/// This is done for library prefixes because they are not used in the output
/// because all imports are flattened and conflicts are renamed away.
void makeErasePrefixPlaceholder(Node node) {
assert(node is Identifier || node is Send);
prefixNodesToErase.add(node);
}
void makeElementPlaceholder(Node node, Element element) {
assert(node != null);
assert(element != null);
LibraryElement library = element.library;
if (identical(element, mainFunction)) return;
if (library.isDartCore) return;
if (library.isPlatformLibrary && !element.isTopLevel) {
return;
}
ClassElement cls = element.enclosingClass;
if (cls != null && cls.isEnumClass) {
// Enums and enum values cannot be changed, since the semantics of
// `toString` is defined by the names of the declarations.
return;
}
if (element.isAccessor) {
element = (element as AccessorElement).abstractField;
}
elementNodes.putIfAbsent(element, () => new Set<Node>()).add(node);
}
/// Marks [node] to be renamed per-library if it names an instance member
/// and has a private name.
void tryMakePrivateIdentifier(Node node, Element element) {
if (node is Identifier &&
!Elements.isStaticOrTopLevel(element) &&
!Elements.isLocal(element) &&
Name.isPrivateName(node.source)) {
privateNodes
.putIfAbsent(currentElement.library, () => new Set<Identifier>())
.add(node);
}
}
void makeUnresolvedPlaceholder(Node node) {
unresolvedNodes.add(node);
}
void makeLocalPlaceholder(Identifier identifier) {
LocalPlaceholder getLocalPlaceholder() {
String name = identifier.source;
return currentLocalPlaceholders.putIfAbsent(name, () {
LocalPlaceholder localPlaceholder = new LocalPlaceholder(name);
currentFunctionScope.localPlaceholders.add(localPlaceholder);
return localPlaceholder;
});
}
getLocalPlaceholder().nodes.add(identifier);
}
/// Finds the first constructor on the chain of definingConstructor from
/// [element] that is not in a synthetic class.
Element findDefiningConstructor(ConstructorElement element) {
while (element.definingConstructor != null) {
element = element.definingConstructor;
}
return element;
}
void tryMakeConstructorPlaceholder(Node node, ConstructorElement element) {
if (Elements.isUnresolved(element)) {
makeUnresolvedPlaceholder(node);
return;
}
// A library prefix.
Node prefix;
// The name of the class with the constructor.
Node className;
// Will be null for unnamed constructors.
Identifier constructorName;
// First deconstruct the constructor, there are 4 possibilities:
// ClassName()
// prefix.ClassName()
// ClassName.constructorName()
// prefix.ClassName.constructorName()
if (node is Send) {
if (node.receiver is Send) {
Send receiver = node.receiver;
// prefix.ClassName.constructorName()
assert(treeElements[receiver.receiver] != null &&
treeElements[receiver.receiver].isPrefix);
prefix = receiver.receiver;
className = receiver.selector;
constructorName = node.selector;
} else {
Element receiverElement = treeElements[node.receiver];
if (receiverElement != null && receiverElement.isPrefix) {
// prefix.ClassName()
prefix = node.receiver;
className = node.selector;
} else {
// ClassName.constructorName()
className = node.receiver;
constructorName = node.selector;
}
}
} else {
// ClassName()
className = node;
}
if (prefix != null) {
makeErasePrefixPlaceholder(prefix);
}
if (className is TypeAnnotation) {
visitTypeAnnotation(className);
} else if (Elements.isUnresolved(element)) {
// We handle unresolved nodes elsewhere.
} else if (className.isThis() || className.isSuper()) {
// Do not rename super and this.
} else if (className is Identifier) {
makeElementPlaceholder(className, element.contextClass);
} else {
throw "Bad type of constructor name $className";
}
if (constructorName != null) {
Element definingConstructor = findDefiningConstructor(element);
constructorPlaceholders.add(
new ConstructorPlaceholder(constructorName, definingConstructor));
tryMakePrivateIdentifier(constructorName, element);
}
}
void internalError(String reason, {Node node}) {
reporter.internalError(node, reason);
}
visit(Node node) => (node == null) ? null : node.accept(this);
visitNode(Node node) {
node.visitChildren(this);
} // We must go deeper.
visitNewExpression(NewExpression node) {
Send send = node.send;
DartType type = treeElements.getType(node);
assert(type != null);
Element constructor = treeElements[send];
assert(constructor != null);
assert(send.receiver == null);
if (!Elements.isMalformed(constructor)) {
tryMakeConstructorPlaceholder(node.send.selector, constructor);
// TODO(smok): Should this be in visitNamedArgument?
// Field names can be exposed as names of optional arguments, e.g.
// class C {
// final field;
// C([this.field]);
// }
// Do not forget to rename them as well.
FunctionElement constructorFunction = constructor;
List<Element> optionalParameters =
constructorFunction.functionSignature.optionalParameters;
for (final argument in send.argumentsNode) {
NamedArgument named = argument.asNamedArgument();
if (named == null) continue;
Identifier name = named.name;
String nameAsString = name.source;
for (final parameter in optionalParameters) {
if (parameter.isInitializingFormal) {
if (parameter.name == nameAsString) {
tryMakeMemberPlaceholder(name);
break;
}
}
}
}
} else {
makeUnresolvedPlaceholder(node.send.selector);
}
visit(node.send.argumentsNode);
}
visitSend(Send send) {
Element element = treeElements[send];
tryMakePrivateIdentifier(send.selector, element);
new SendVisitor(this, treeElements).visitSend(send);
send.visitChildren(this);
}
visitSendSet(SendSet send) {
Element element = treeElements[send];
if (Elements.isMalformed(element)) {
// Complicated case: constructs like receiver.selector++ can resolve
// to ErroneousElement. Fortunately, receiver.selector still
// can be resoved via treeElements[send.selector], that's all
// that is needed to rename the construct properly.
element = treeElements[send.selector];
}
tryMakePrivateIdentifier(send.selector, element);
if (element == null) {
if (send.receiver != null) tryMakeMemberPlaceholder(send.selector);
} else if (!element.isMalformed) {
if (Elements.isStaticOrTopLevel(element)) {
// TODO(smok): Worth investigating why sometimes we get getter/setter
// here and sometimes abstract field.
assert(element.isClass ||
element is VariableElement ||
element.isAccessor ||
element.isAbstractField ||
element.isFunction ||
element.isTypedef ||
element is TypeVariableElement);
makeElementPlaceholder(send.selector, element);
} else {
Identifier identifier = send.selector.asIdentifier();
if (identifier == null) {
// Handle optional function expression parameters with default values.
identifier = send.selector.asFunctionExpression().name;
}
if (Elements.isInstanceField(element)) {
tryMakeMemberPlaceholder(identifier);
} else {
tryMakeLocalPlaceholder(element, identifier);
}
}
}
send.visitChildren(this);
}
visitTypeAnnotation(TypeAnnotation node) {
final type = treeElements.getType(node);
assert(invariant(node, type != null,
message: "Missing type for type annotation: $treeElements"));
if (!type.isVoid) {
if (!type.treatAsDynamic) {
if (type is TypeVariableType) {
makeTypeVariablePlaceholder(node.typeName, type);
} else {
makeTypePlaceholder(node.typeName, type);
}
} else if (!type.isDynamic) {
makeUnresolvedPlaceholder(node.typeName);
}
}
// Visit only type arguments, otherwise in case of lib.Class type
// annotation typeName is Send and we go to visitGetterSend, as a result
// "Class" is added to member placeholders.
visit(node.typeArguments);
}
visitVariableDefinitions(VariableDefinitions node) {
// Collect only local placeholders.
for (Node definition in node.definitions.nodes) {
Element definitionElement = treeElements[definition];
// definitionElement may be null if we're inside variable definitions
// of a function that is a parameter of another function.
// TODO(smok): Fix this when resolver correctly deals with
// such cases.
if (definitionElement == null) continue;
Send send = definition.asSend();
Identifier identifier = definition is Identifier
? definition
: definition is Send
? (send.selector is Identifier ? send.selector : null)
: null;
tryMakePrivateIdentifier(identifier, definitionElement);
if (send != null) {
// May get FunctionExpression here in definition.selector
// in case of A(int this.f());
if (send.selector is Identifier) {
if (definitionElement.isInitializingFormal) {
tryMakeMemberPlaceholder(send.selector);
} else {
tryMakeLocalPlaceholder(definitionElement, send.selector);
}
} else {
assert(send.selector is FunctionExpression);
if (definitionElement.isInitializingFormal) {
tryMakeMemberPlaceholder(send.selector.asFunctionExpression().name);
}
}
} else if (definition is Identifier) {
tryMakeLocalPlaceholder(definitionElement, definition);
} else if (definition is FunctionExpression) {
// Skip, it will be processed in visitFunctionExpression.
} else {
internalError('Unexpected definition structure $definition');
}
}
node.visitChildren(this);
}
visitFunctionExpression(FunctionExpression node) {
bool isKeyword(Identifier id) =>
id != null && Keyword.keywords[id.source] != null;
Element element = treeElements[node];
// May get null;
if (element != null) {
tryMakePrivateIdentifier(node.name, element);
// Rename only local functions.
if (topmostEnclosingFunction == null &&
element is! LocalParameterElement &&
element is! InitializingFormalElement) {
topmostEnclosingFunction = element;
}
if (!identical(element, currentElement)) {
if (node.name != null) {
assert(node.name is Identifier);
tryMakeLocalPlaceholder(element, node.name);
}
}
}
node.visitChildren(this);
// Make sure we don't omit return type of methods which names are
// identifiers, because the following works fine:
// int interface() => 1;
// But omitting 'int' makes VM unhappy.
// TODO(smok): Remove it when http://dartbug.com/5278 is fixed.
if (node.name == null || !isKeyword(node.name.asIdentifier())) {
makeOmitDeclarationTypePlaceholder(node.returnType);
}
collectFunctionParameters(node.parameters);
}
void collectFunctionParameters(NodeList parameters) {
if (parameters == null) return;
for (Node parameter in parameters.nodes) {
if (parameter is NodeList) {
// Optional parameter list.
collectFunctionParameters(parameter);
} else {
assert(parameter is VariableDefinitions);
makeOmitDeclarationTypePlaceholder(
parameter.asVariableDefinitions().type);
}
}
}
visitClassNode(ClassNode node) {
ClassElement classElement = currentElement;
makeElementPlaceholder(node.name, classElement);
node.visitChildren(this);
}
visitNamedMixinApplication(NamedMixinApplication node) {
ClassElement classElement = currentElement;
makeElementPlaceholder(node.name, classElement);
node.visitChildren(this);
}
visitTypeVariable(TypeVariable node) {
DartType type = treeElements.getType(node);
assert(invariant(node, type != null,
message: "Missing type for type variable: $treeElements"));
makeTypeVariablePlaceholder(node.name, type);
node.visitChildren(this);
}
visitTypedef(Typedef node) {
assert(currentElement is TypedefElement);
makeElementPlaceholder(node.name, currentElement);
node.visitChildren(this);
makeOmitDeclarationTypePlaceholder(node.returnType);
collectFunctionParameters(node.formals);
}
visitBlock(Block node) {
for (Node statement in node.statements.nodes) {
if (statement is VariableDefinitions) {
makeVarDeclarationTypePlaceholder(statement);
}
}
node.visitChildren(this);
}
}

View file

@ -1,372 +0,0 @@
// 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.
part of dart_backend;
Comparator get _compareNodes => compareBy((n) => n.getBeginToken().charOffset);
abstract class Renamable implements Comparable {
final int RENAMABLE_TYPE_ELEMENT = 1;
final int RENAMABLE_TYPE_MEMBER = 2;
final int RENAMABLE_TYPE_LOCAL = 3;
final Set<Node> nodes;
Renamable(this.nodes);
int compareTo(Renamable other) {
int nodesDiff = other.nodes.length.compareTo(this.nodes.length);
if (nodesDiff != 0) return nodesDiff;
int typeDiff = this.kind.compareTo(other.kind);
return typeDiff != 0 ? typeDiff : compareInternals(other);
}
int compareInternals(Renamable other);
int get kind;
String createNewName(PlaceholderRenamer placeholderRenamer);
}
class GlobalRenamable extends Renamable {
final Entity entity;
GlobalRenamable(this.entity, Set<Node> nodes) : super(nodes);
int compareInternals(GlobalRenamable other) =>
compareElements(this.entity, other.entity);
int get kind => RENAMABLE_TYPE_ELEMENT;
String createNewName(PlaceholderRenamer placeholderRenamer) {
return placeholderRenamer._renameGlobal(entity);
}
}
class MemberRenamable extends Renamable {
final String identifier;
MemberRenamable(this.identifier, Set<Node> nodes) : super(nodes);
int compareInternals(MemberRenamable other) =>
this.identifier.compareTo(other.identifier);
int get kind => RENAMABLE_TYPE_MEMBER;
String createNewName(PlaceholderRenamer placeholderRenamer) {
return placeholderRenamer._generateMemberName(identifier);
}
}
class LocalRenamable extends Renamable {
LocalRenamable(Set<Node> nodes) : super(nodes);
int compareInternals(LocalRenamable other) => _compareNodes(
sorted(this.nodes, _compareNodes)[0],
sorted(other.nodes, _compareNodes)[0]);
int get kind => RENAMABLE_TYPE_LOCAL;
String createNewName(PlaceholderRenamer placeholderRenamer) {
return placeholderRenamer._generateUniqueTopLevelName("");
}
}
/**
* Renames only top-level elements that would lead to ambiguity if not renamed.
*/
class PlaceholderRenamer {
/// After running [computeRenames] this will contain the computed renames.
final Map<Node, String> renames = new Map<Node, String>();
/// After running [computeRenames] this will map the used platform
/// libraries to their respective prefixes.
final Map<LibraryElement, String> platformImports =
<LibraryElement, String>{};
final bool enableMinification;
final Set<String> fixedDynamicNames;
final Set<String> fixedStaticNames;
final Map<Element, LibraryElement> reexportingLibraries;
final bool cutDeclarationTypes;
final Map<Entity, String> _renamedCache = new Map<Entity, String>();
final Map<Entity, Map<String, String>> _privateCache =
new Map<Entity, Map<String, String>>();
// Identifiers that has already been used, or are reserved by the
// language/platform.
Set<String> _forbiddenIdentifiers;
Set<String> _allNamedParameterIdentifiers;
Generator _generator;
PlaceholderRenamer(
this.fixedDynamicNames, this.fixedStaticNames, this.reexportingLibraries,
{this.enableMinification, this.cutDeclarationTypes});
void _renameNodes(Iterable<Node> nodes, String renamer(Node node)) {
for (Node node in sorted(nodes, _compareNodes)) {
renames[node] = renamer(node);
}
}
String _generateUniqueTopLevelName(String originalName) {
String newName = _generator.generate(originalName, (name) {
return _forbiddenIdentifiers.contains(name) ||
_allNamedParameterIdentifiers.contains(name);
});
_forbiddenIdentifiers.add(newName);
return newName;
}
String _generateMemberName(String original) {
return _generator.generate(original, _forbiddenIdentifiers.contains);
}
/// Looks up [originalName] in the [_privateCache] cache of [library].
/// If [originalName] was not renamed before, generate a new name.
String _getPrivateName(LibraryElement library, String originalName) {
return _privateCache
.putIfAbsent(library, () => new Map<String, String>())
.putIfAbsent(
originalName, () => _generateUniqueTopLevelName(originalName));
}
String _renameConstructor(ConstructorPlaceholder placeholder) {
String name = placeholder.element.name;
if (name == '') return "";
String result = _renameGlobal(placeholder.element);
return result;
}
String _renameGlobal(Entity entity) {
assert(entity is! Element ||
Elements.isMalformed(entity) ||
Elements.isStaticOrTopLevel(entity) ||
entity is TypeVariableElement);
// TODO(smok): We may want to reuse class static field and method names.
if (entity is Element) {
LibraryElement library = entity.library;
if (reexportingLibraries.containsKey(entity)) {
library = reexportingLibraries[entity];
}
if (library.isPlatformLibrary) {
// TODO(johnniwinther): Handle prefixes for dart:core.
if (library.canonicalUri == Uris.dart_core) return entity.name;
if (library.isInternalLibrary) {
throw new SpannableAssertionFailure(
entity,
"Internal library $library should never have been imported from "
"the code compiled by dart2dart.");
}
String prefix = platformImports.putIfAbsent(library, () => null);
if (entity.isTopLevel && fixedDynamicNames.contains(entity.name)) {
if (prefix == null) {
prefix = _generateUniqueTopLevelName('');
platformImports[library] = prefix;
}
return '$prefix.${entity.name}';
}
return entity.name;
}
}
String name = _renamedCache.putIfAbsent(
entity, () => _generateUniqueTopLevelName(entity.name));
// Look up in [_renamedCache] for a name for [entity] .
// If it was not renamed before, generate a new name.
return name;
}
void _computeMinifiedRenames(PlaceholderCollector placeholderCollector) {
_generator = new MinifyingGenerator();
// Build a list sorted by usage of local nodes that will be renamed to
// the same identifier. So the top-used local variables in all functions
// will be renamed first and will all share the same new identifier.
int maxLength = placeholderCollector.functionScopes.values
.fold(0, (a, b) => max(a, b.localPlaceholders.length));
List<Set<Node>> allLocals =
new List<Set<Node>>.generate(maxLength, (_) => new Set<Node>());
for (FunctionScope functionScope
in placeholderCollector.functionScopes.values) {
// Add current sorted local identifiers to the whole sorted list
// of all local identifiers for all functions.
List<LocalPlaceholder> currentSortedPlaceholders = sorted(
functionScope.localPlaceholders,
compareBy((LocalPlaceholder ph) => -ph.nodes.length));
List<Set<Node>> currentSortedNodes = currentSortedPlaceholders
.map((LocalPlaceholder ph) => ph.nodes)
.toList();
for (int i = 0; i < currentSortedNodes.length; i++) {
allLocals[i].addAll(currentSortedNodes[i]);
}
}
// Rename elements, members and locals together based on their usage
// count, otherwise when we rename elements first there will be no good
// identifiers left for members even if they are used often.
List<Renamable> renamables = new List<Renamable>();
placeholderCollector.elementNodes
.forEach((Element element, Set<Node> nodes) {
renamables.add(new GlobalRenamable(element, nodes));
});
placeholderCollector.memberPlaceholders
.forEach((String memberName, Set<Identifier> identifiers) {
renamables.add(new MemberRenamable(memberName, identifiers));
});
for (Set<Node> localIdentifiers in allLocals) {
renamables.add(new LocalRenamable(localIdentifiers));
}
renamables.sort();
for (Renamable renamable in renamables) {
String newName = renamable.createNewName(this);
_renameNodes(renamable.nodes, (_) => newName);
}
}
void _computeNonMinifiedRenames(PlaceholderCollector placeholderCollector) {
_generator = new ConservativeGenerator();
// Rename elements.
placeholderCollector.elementNodes
.forEach((Element element, Set<Node> nodes) {
_renameNodes(nodes, (_) => _renameGlobal(element));
});
// Rename locals.
placeholderCollector.functionScopes
.forEach((functionElement, functionScope) {
Set<String> memberIdentifiers = new Set<String>();
Set<LocalPlaceholder> placeholders = functionScope.localPlaceholders;
if (functionElement != null && functionElement.enclosingClass != null) {
functionElement.enclosingClass.forEachMember((enclosingClass, member) {
memberIdentifiers.add(member.name);
});
}
Set<String> usedLocalIdentifiers = new Set<String>();
for (LocalPlaceholder placeholder in placeholders) {
String nextId = _generator.generate(placeholder.identifier, (name) {
return functionScope.parameterIdentifiers.contains(name) ||
_forbiddenIdentifiers.contains(name) ||
usedLocalIdentifiers.contains(name) ||
memberIdentifiers.contains(name);
});
usedLocalIdentifiers.add(nextId);
_renameNodes(placeholder.nodes, (_) => nextId);
}
});
// Do not rename members to top-levels, that allows to avoid renaming
// members to constructors.
placeholderCollector.memberPlaceholders.forEach((identifier, nodes) {
String newIdentifier = _generateMemberName(identifier);
_renameNodes(nodes, (_) => newIdentifier);
});
}
/// Finds renamings for all the placeholders in [placeholderCollector] and
/// stores them in [renames].
/// Also adds to [platformImports] all the platform-libraries that are used.
void computeRenames(PlaceholderCollector placeholderCollector) {
_allNamedParameterIdentifiers = new Set<String>();
for (FunctionScope functionScope
in placeholderCollector.functionScopes.values) {
_allNamedParameterIdentifiers.addAll(functionScope.parameterIdentifiers);
}
_forbiddenIdentifiers = new Set<String>.from(fixedDynamicNames);
_forbiddenIdentifiers.addAll(fixedStaticNames);
_forbiddenIdentifiers.addAll(Keyword.keywords.keys);
_forbiddenIdentifiers.add('main');
if (enableMinification) {
_computeMinifiedRenames(placeholderCollector);
} else {
_computeNonMinifiedRenames(placeholderCollector);
}
// Rename constructors.
for (ConstructorPlaceholder placeholder
in placeholderCollector.constructorPlaceholders) {
renames[placeholder.node] = _renameConstructor(placeholder);
}
;
// Rename private identifiers uniquely for each library.
placeholderCollector.privateNodes
.forEach((LibraryElement library, Set<Identifier> identifiers) {
for (Identifier identifier in identifiers) {
renames[identifier] = _getPrivateName(library, identifier.source);
}
});
// Rename unresolved nodes, to make sure they still do not resolve.
for (Node node in placeholderCollector.unresolvedNodes) {
renames[node] = _generateUniqueTopLevelName('Unresolved');
}
// Erase prefixes that are now not needed.
for (Node node in placeholderCollector.prefixNodesToErase) {
renames[node] = '';
}
if (cutDeclarationTypes) {
for (DeclarationTypePlaceholder placeholder
in placeholderCollector.declarationTypePlaceholders) {
renames[placeholder.typeNode] = placeholder.requiresVar ? 'var' : '';
}
}
}
}
/**
* Generates mini ID based on index.
* In other words, it converts index to visual representation
* as if digits are given characters.
*/
String generateMiniId(int index) {
const String firstCharAlphabet =
r'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
const String otherCharsAlphabet =
r'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_$';
// It's like converting index in decimal to [chars] radix.
if (index < firstCharAlphabet.length) return firstCharAlphabet[index];
StringBuffer resultBuilder = new StringBuffer();
resultBuilder.writeCharCode(
firstCharAlphabet.codeUnitAt(index % firstCharAlphabet.length));
index ~/= firstCharAlphabet.length;
int length = otherCharsAlphabet.length;
while (index >= length) {
resultBuilder.writeCharCode(otherCharsAlphabet.codeUnitAt(index % length));
index ~/= length;
}
resultBuilder.write(otherCharsAlphabet[index]);
return resultBuilder.toString();
}
abstract class Generator {
String generate(String originalName, bool isForbidden(String name));
}
/// Always tries to return original identifier name unless it is forbidden.
class ConservativeGenerator implements Generator {
String generate(String originalName, bool isForbidden(String name)) {
String result = originalName;
int index = 0;
while (isForbidden(result)) {
//|| result == originalName) {
result = '${originalName}_${generateMiniId(index++)}';
}
return result;
}
}
/// Always tries to generate the most compact identifier.
class MinifyingGenerator implements Generator {
int index = 0;
MinifyingGenerator();
String generate(String originalName, bool isForbidden(String name)) {
String result;
do {
result = generateMiniId(index++);
} while (isForbidden(result));
return result;
}
}

View file

@ -3626,15 +3626,18 @@ part of test.main;
MessageKind.EXTERNAL_WITH_BODY: const MessageTemplate(
MessageKind.EXTERNAL_WITH_BODY,
"External function '#{functionName}' cannot have a function body.",
options: const ["--output-type=dart"],
howToFix:
"Try removing the 'external' modifier or the function body.",
examples: const [
"""
import 'package:js/js.dart';
@JS()
external foo() => 0;
main() => foo();
""",
"""
import 'package:js/js.dart';
@JS()
external foo() {}
main() => foo();
"""

View file

@ -1,29 +0,0 @@
// Copyright (c) 2013, 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 mirror_renamer;
import '../compiler.dart' show Compiler;
import '../dart_backend/dart_backend.dart'
show DartBackend, PlaceholderCollector;
import '../elements/elements.dart';
import '../tokens/token.dart' show Token;
import '../tree/tree.dart';
part 'renamer.dart';
class MirrorRenamer {
const MirrorRenamer();
LibraryElement get helperLibrary => null;
FunctionElement get getNameFunction => null;
bool isMirrorHelperLibrary(LibraryElement element) => false;
void registerStaticSend(Element currentElement, Element target, Node node) {}
void addRenames(Map<Node, String> renames, List<Node> topLevelNodes,
PlaceholderCollector placeholderCollector) {}
}

View file

@ -1,118 +0,0 @@
// Copyright (c) 2013, 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.
part of mirror_renamer;
class MirrorRenamerImpl implements MirrorRenamer {
static const String MIRROR_HELPER_GET_NAME_FUNCTION = 'helperGetName';
static final Uri DART_MIRROR_HELPER =
new Uri(scheme: 'dart', path: '_mirror_helper');
static const String MIRROR_HELPER_SYMBOLS_MAP_NAME = '_SYMBOLS';
/// Initialized when dart:mirrors is loaded if the useMirrorHelperLibrary
/// field is set.
final LibraryElement helperLibrary;
/// Initialized when dart:mirrors is loaded if the useMirrorHelperLibrary
/// field is set.
final FunctionElement getNameFunction;
/// Initialized when dart:mirrors is loaded if the useMirrorHelperLibrary
/// field is set.
final FieldElement symbolsMapVariable;
/// Maps mangled name to original name.
Map<String, String> symbols = new Map<String, String>();
/// Contains all occurrencs of MirrorSystem.getName() calls in the user code.
List<Node> mirrorSystemGetNameNodes = <Node>[];
/**
* Initialized when the placeholderCollector collects the FunctionElement
* backend.mirrorHelperGetNameFunction which represents the helperGetName
* function in _mirror_helper.
*/
FunctionExpression get getNameFunctionNode => getNameFunction.node;
VariableDefinitions get symbolsMapNode => symbolsMapVariable.node;
Compiler compiler;
DartBackend backend;
MirrorRenamerImpl(this.compiler, this.backend, LibraryElement library)
: this.helperLibrary = library,
getNameFunction =
library.find(MirrorRenamerImpl.MIRROR_HELPER_GET_NAME_FUNCTION),
symbolsMapVariable =
library.find(MirrorRenamerImpl.MIRROR_HELPER_SYMBOLS_MAP_NAME);
bool isMirrorHelperLibrary(LibraryElement element) {
return element == helperLibrary;
}
void registerStaticSend(Element currentElement, Element target, Send node) {
if (target == compiler.mirrorSystemGetNameFunction &&
currentElement.library != helperLibrary) {
// Access to `MirrorSystem.getName` that needs to be redirected to the
// [getNameFunction].
mirrorSystemGetNameNodes.add(node);
}
}
/**
* Adds a toplevel node to the output containing a map from the mangled
* to the unmangled names and replaces calls to MirrorSystem.getName()
* with calls to the corresponding wrapper from _mirror_helper which has
* been added during resolution. [renames] is assumed to map nodes in user
* code to mangled names appearing in output code, and [topLevelNodes] should
* contain all the toplevel ast nodes that will be emitted in the output.
*/
void addRenames(Map<Node, String> renames, List<Node> topLevelNodes,
PlaceholderCollector placeholderCollector) {
// Right now we only support instances of MirrorSystem.getName,
// hence if there are no occurence of these we don't do anything.
if (mirrorSystemGetNameNodes.isEmpty) {
return;
}
Node parse(String text) {
Token tokens = compiler.scanner.tokenize(text);
return compiler.parser.parseCompilationUnit(tokens);
}
// Add toplevel map containing all renames of members.
symbols = new Map<String, String>();
for (Set<Identifier> s in placeholderCollector.memberPlaceholders.values) {
// All members in a set have the same name so we only need to look at one.
Identifier sampleNode = s.first;
symbols.putIfAbsent(renames[sampleNode], () => sampleNode.source);
}
Identifier symbolsMapIdentifier =
symbolsMapNode.definitions.nodes.head.asSend().selector;
assert(symbolsMapIdentifier != null);
topLevelNodes.remove(symbolsMapNode);
StringBuffer sb = new StringBuffer(
'const ${renames[symbolsMapIdentifier]} = const<String,String>{');
bool first = true;
for (String mangledName in symbols.keys) {
if (!first) {
sb.write(',');
} else {
first = false;
}
sb.write("'$mangledName' : '");
sb.write(symbols[mangledName]);
sb.write("'");
}
sb.write('};');
sb.writeCharCode(0); // Terminate the string with '0', see [StringScanner].
topLevelNodes.add(parse(sb.toString()));
// Replace calls to Mirrorsystem.getName with calls to helper function.
mirrorSystemGetNameNodes.forEach((node) {
renames[node.selector] = renames[getNameFunctionNode.name];
renames[node.receiver] = '';
});
}
}

View file

@ -245,12 +245,6 @@ class CompilerOptions implements DiagnosticOptions, ParserOptions {
/// Whether to preserve comments while scanning (only use for dart:mirrors).
final bool preserveComments;
/// Whether to emit JavaScript (false enables dart2dart).
final bool emitJavaScript;
/// When using dart2dart, whether to use the multi file format.
final bool dart2dartMultiFile;
/// Strip option used by dart2dart.
final List<String> strips;
@ -280,7 +274,6 @@ class CompilerOptions implements DiagnosticOptions, ParserOptions {
analyzeSignaturesOnly: _hasOption(options, Flags.analyzeSignaturesOnly),
buildId: _extractStringOption(
options, '--build-id=', _UNDETERMINED_BUILD_ID),
dart2dartMultiFile: _hasOption(options, '--output-type=dart-multi'),
deferredMapUri: _extractUriOption(options, '--deferred-map='),
fatalWarnings: _hasOption(options, Flags.fatalWarnings),
terseDiagnostics: _hasOption(options, Flags.terse),
@ -291,8 +284,6 @@ class CompilerOptions implements DiagnosticOptions, ParserOptions {
disableInlining: _hasOption(options, Flags.disableInlining),
disableTypeInference: _hasOption(options, Flags.disableTypeInference),
dumpInfo: _hasOption(options, Flags.dumpInfo),
emitJavaScript: !(_hasOption(options, '--output-type=dart') ||
_hasOption(options, '--output-type=dart-multi')),
enableAssertMessage: _hasOption(options, Flags.enableAssertMessage),
enableGenericMethodSyntax:
_hasOption(options, Flags.genericMethodSyntax),
@ -354,7 +345,6 @@ class CompilerOptions implements DiagnosticOptions, ParserOptions {
bool analyzeOnly: false,
bool analyzeSignaturesOnly: false,
String buildId: _UNDETERMINED_BUILD_ID,
bool dart2dartMultiFile: false,
Uri deferredMapUri: null,
bool fatalWarnings: false,
bool terseDiagnostics: false,
@ -364,7 +354,6 @@ class CompilerOptions implements DiagnosticOptions, ParserOptions {
bool disableInlining: false,
bool disableTypeInference: false,
bool dumpInfo: false,
bool emitJavaScript: true,
bool enableAssertMessage: false,
bool enableGenericMethodSyntax: false,
bool enableInitializingFormalAccess: false,
@ -428,7 +417,6 @@ class CompilerOptions implements DiagnosticOptions, ParserOptions {
analyzeOnly || analyzeSignaturesOnly || analyzeAll || resolveOnly,
analyzeSignaturesOnly: analyzeSignaturesOnly,
buildId: buildId,
dart2dartMultiFile: dart2dartMultiFile,
deferredMapUri: deferredMapUri,
fatalWarnings: fatalWarnings,
terseDiagnostics: terseDiagnostics,
@ -436,9 +424,8 @@ class CompilerOptions implements DiagnosticOptions, ParserOptions {
suppressHints: suppressHints,
shownPackageWarnings: shownPackageWarnings,
disableInlining: disableInlining || hasIncrementalSupport,
disableTypeInference: disableTypeInference || !emitJavaScript,
disableTypeInference: disableTypeInference,
dumpInfo: dumpInfo,
emitJavaScript: emitJavaScript,
enableAssertMessage: enableAssertMessage,
enableGenericMethodSyntax: enableGenericMethodSyntax,
enableInitializingFormalAccess: enableInitializingFormalAccess,
@ -452,8 +439,7 @@ class CompilerOptions implements DiagnosticOptions, ParserOptions {
hasIncrementalSupport: hasIncrementalSupport,
outputUri: outputUri,
platformConfigUri: platformConfigUri ??
_resolvePlatformConfig(
libraryRoot, null, !emitJavaScript, const []),
_resolvePlatformConfig(libraryRoot, null, const []),
preserveComments: preserveComments,
preserveUris: preserveUris,
resolutionInputs: resolutionInputs,
@ -482,7 +468,6 @@ class CompilerOptions implements DiagnosticOptions, ParserOptions {
this.analyzeOnly: false,
this.analyzeSignaturesOnly: false,
this.buildId: _UNDETERMINED_BUILD_ID,
this.dart2dartMultiFile: false,
this.deferredMapUri: null,
this.fatalWarnings: false,
this.terseDiagnostics: false,
@ -492,7 +477,6 @@ class CompilerOptions implements DiagnosticOptions, ParserOptions {
this.disableInlining: false,
this.disableTypeInference: false,
this.dumpInfo: false,
this.emitJavaScript: true,
this.enableAssertMessage: false,
this.enableGenericMethodSyntax: false,
this.enableInitializingFormalAccess: false,
@ -541,7 +525,6 @@ class CompilerOptions implements DiagnosticOptions, ParserOptions {
analyzeOnly,
analyzeSignaturesOnly,
buildId,
dart2dartMultiFile,
deferredMapUri,
fatalWarnings,
terseDiagnostics,
@ -551,7 +534,6 @@ class CompilerOptions implements DiagnosticOptions, ParserOptions {
disableInlining,
disableTypeInference,
dumpInfo,
emitJavaScript,
enableAssertMessage,
enableGenericMethodSyntax,
enableInitializingFormalAccess,
@ -599,7 +581,6 @@ class CompilerOptions implements DiagnosticOptions, ParserOptions {
analyzeSignaturesOnly:
analyzeSignaturesOnly ?? options.analyzeSignaturesOnly,
buildId: buildId ?? options.buildId,
dart2dartMultiFile: dart2dartMultiFile ?? options.dart2dartMultiFile,
deferredMapUri: deferredMapUri ?? options.deferredMapUri,
fatalWarnings: fatalWarnings ?? options.fatalWarnings,
terseDiagnostics: terseDiagnostics ?? options.terseDiagnostics,
@ -611,7 +592,6 @@ class CompilerOptions implements DiagnosticOptions, ParserOptions {
disableTypeInference:
disableTypeInference ?? options.disableTypeInference,
dumpInfo: dumpInfo ?? options.dumpInfo,
emitJavaScript: emitJavaScript ?? options.emitJavaScript,
enableAssertMessage: enableAssertMessage ?? options.enableAssertMessage,
enableGenericMethodSyntax:
enableGenericMethodSyntax ?? options.enableGenericMethodSyntax,
@ -722,11 +702,9 @@ List<String> _extractOptionalCsvOption(List<String> options, String flag) {
}
Uri _resolvePlatformConfig(Uri libraryRoot, String platformConfigPath,
bool isDart2Dart, Iterable<String> categories) {
Iterable<String> categories) {
if (platformConfigPath != null) {
return libraryRoot.resolve(platformConfigPath);
} else if (isDart2Dart) {
return libraryRoot.resolve(_dart2dartPlatform);
} else {
if (categories.length == 0) {
return libraryRoot.resolve(_clientPlatform);
@ -747,7 +725,6 @@ Uri _resolvePlatformConfigFromOptions(Uri libraryRoot, List<String> options) {
return _resolvePlatformConfig(
libraryRoot,
_extractStringOption(options, "--platform-config=", null),
_hasOption(options, '--output-type=dart'),
_extractCsvOption(options, '--categories='));
}
@ -755,7 +732,6 @@ Uri _resolvePlatformConfigFromOptions(Uri libraryRoot, List<String> options) {
const String _clientPlatform = "lib/dart_client.platform";
const String _serverPlatform = "lib/dart_server.platform";
const String _sharedPlatform = "lib/dart_shared.platform";
const String _dart2dartPlatform = "lib/dart2dart.platform";
const String _UNDETERMINED_BUILD_ID = "build number could not be determined";
const bool _forceIncrementalSupport =

View file

@ -18,10 +18,6 @@ sample_extension: Crash # Unable to compile UnsupportedError.message.
[ $compiler == dart2analyzer ]
build_dart: Skip
[ $compiler == dart2dart ]
# Skip until we stabilize language tests.
*: Skip
[ $arch == arm ]
sample_extension/test/sample_extension_test: Skip # Issue 14705

View file

@ -1,25 +0,0 @@
// Copyright (c) 2013, 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.
/**
* Helps dealing with reflection in the case that the source code has been
* changed as a result of compiling with dart2dart.
*/
library _mirror_helper;
import 'dart:mirrors';
/// The compiler will replace this variable with a map containing all the
/// renames made in dart2dart.
const Map<String, String> _SYMBOLS = null;
/// This method is a wrapper for MirrorSystem.getName() and will be inlined and
/// called in the generated output Dart code.
String helperGetName(Symbol sym) {
var name = MirrorSystem.getName(sym);
if (_SYMBOLS.containsKey(name)) {
return _SYMBOLS[name];
} else {
return name;
}
}

View file

@ -227,14 +227,6 @@ const Map<String, LibraryInfo> libraries = const {
documented: false,
platforms: DART2JS_PLATFORM),
// TODO(ahe): This library is only for dart2dart, perhaps it should use a
// different platform.
"_mirror_helper": const LibraryInfo(
"_internal/js_runtime/lib/mirror_helper.dart",
categories: "",
documented: false,
platforms: DART2JS_PLATFORM),
"_js_embedded_names": const LibraryInfo(
"_internal/js_runtime/lib/shared/embedded_names.dart",
categories: "",

View file

@ -1,49 +0,0 @@
# 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.
# The platform when compiling with dart2js for dart2dart.
#
# Includes the _mirror_helpers private libraries
[dart-spec]
spec:3rd edition.
[features]
# No extra features.
[libraries]
async: async/async.dart
_chrome: _chrome/dart2js/chrome_dart2js.dart
collection: collection/collection.dart
convert: convert/convert.dart
core: core/core.dart
developer: developer/developer.dart
html: html/dart2js/html_dart2js.dart
html_common: html/html_common/html_common_dart2js.dart
indexed_db: indexed_db/dart2js/indexed_db_dart2js.dart
io: io/io.dart
isolate: isolate/isolate.dart
js: js/dart2js/js_dart2js.dart
js_util: js_util/dart2js/js_util_dart2js.dart
math: math/math.dart
mirrors: mirrors/mirrors.dart
nativewrappers: html/dart2js/nativewrappers.dart
typed_data: typed_data/typed_data.dart
_native_typed_data: _internal/js_runtime/lib/native_typed_data.dart
svg: svg/dart2js/svg_dart2js.dart
web_audio: web_audio/dart2js/web_audio_dart2js.dart
web_gl: web_gl/dart2js/web_gl_dart2js.dart
web_sql: web_sql/dart2js/web_sql_dart2js.dart
_internal: internal/internal.dart
_js_helper: _internal/js_runtime/lib/js_helper.dart
_interceptors: _internal/js_runtime/lib/interceptors.dart
_foreign_helper: _internal/js_runtime/lib/foreign_helper.dart
_isolate_helper: _internal/js_runtime/lib/isolate_helper.dart
_js_mirrors: _internal/js_runtime/lib/js_mirrors.dart
_js_names: _internal/js_runtime/lib/js_names.dart
_js_primitives: _internal/js_runtime/lib/js_primitives.dart
_mirror_helper: _internal/js_runtime/lib/mirror_helper.dart
_js_embedded_names: _internal/js_runtime/lib/shared/embedded_names.dart
_async_await_error_codes: _internal/js_runtime/lib/shared/async_await_error_codes.dart
_metadata: html/html_common/metadata.dart

View file

@ -23,9 +23,6 @@ const Map<String, List<String>> WHITE_LIST = const {
"The method 'asAssert' is never called.",
"The method 'asLiteralBool' is never called."],
// Some things in dart_printer are not yet used
"lib/src/dart_backend/backend_ast_nodes.dart": const [" is never "],
// Uncalled methods in SemanticSendVisitor and subclasses.
"lib/src/resolution/semantic_visitor.dart": const [
"The method 'error"],
@ -56,10 +53,6 @@ const Map<String, List<String>> WHITE_LIST = const {
"accept", "CreateFunction",
],
"lib/src/dart_backend/backend_ast_to_frontend_ast.dart": const [
" is never "
],
// Useful utility functions that are not currently used.
"lib/src/cps_ir/cps_fragment.dart": const [
"The method 'beginLoop' is never called.",

File diff suppressed because it is too large Load diff

View file

@ -1,990 +0,0 @@
// Copyright (c) 2014, 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 dart_printer_test;
import 'dart:mirrors';
import 'package:expect/expect.dart';
import 'package:compiler/src/constants/values.dart';
import 'package:compiler/src/dart_backend/backend_ast_nodes.dart';
import 'package:compiler/src/dart_backend/backend_ast_to_frontend_ast.dart'
show TreePrinter;
import 'package:compiler/src/diagnostics/diagnostic_listener.dart';
import 'package:compiler/src/diagnostics/messages.dart';
import 'package:compiler/src/diagnostics/spannable.dart' show Spannable;
import 'package:compiler/src/parser/listener.dart';
import 'package:compiler/src/parser/parser.dart';
import 'package:compiler/src/scanner/scanner.dart';
import 'package:compiler/src/tokens/token.dart';
import 'package:compiler/src/tokens/token_constants.dart';
import 'package:compiler/src/io/source_file.dart';
import 'package:compiler/src/string_validator.dart';
import 'package:compiler/src/tree/tree.dart' show DartString;
import 'package:compiler/src/tree/tree.dart' as tree;
import '../options_helper.dart';
/// For debugging the [AstBuilder] stack. Prints information about [x].
void show(x) {
StringBuffer buf = new StringBuffer();
Unparser unparser = new Unparser(buf);
void unparse(x) {
if (x is Expression)
unparser.writeExpression(x);
else if (x is TypeAnnotation)
unparser.writeType(x);
else if (x is Statement)
unparser.writeStatement(x);
else if (x is List) {
buf.write('[');
bool first = true;
for (var y in x) {
if (first)
first = false;
else
buf.write(', ');
unparse(y);
}
buf.write(']');
}
}
unparse(x);
print("${x.runtimeType}: ${buf.toString()}");
}
class PrintDiagnosticListener implements DiagnosticReporter {
void log(message) {
print(message);
}
void internalError(Spannable spannable, message) {
print(message);
}
SourceSpan spanFromSpannable(Spannable node) {
return new SourceSpan(null, 0, 0);
}
void reportFatalError(Spannable node, MessageKind errorCode,
[Map arguments = const {}]) {
print(errorCode);
throw new Error();
}
void reportError(Spannable node, MessageKind errorCode,
[Map arguments = const {}]) {
print(errorCode);
}
void reportWarning(Spannable node, MessageKind errorCode,
[Map arguments = const {}]) {
print(errorCode);
}
void reportHint(Spannable node, MessageKind errorCode,
[Map arguments = const {}]) {
print(errorCode);
}
void reportInfo(Spannable node, MessageKind errorCode,
[Map arguments = const {}]) {
print(errorCode);
}
withCurrentElement(element, f()) {
f();
}
}
class AstBuilder extends Listener {
final List stack = [];
final StringValidator stringValidator
= new StringValidator(new PrintDiagnosticListener());
String asName(e) {
if (e is Identifier)
return e.name;
else if (e == null)
return null;
else
throw 'Expression is not a name: ${e.runtimeType}';
}
TypeAnnotation asType(x) {
if (x is TypeAnnotation)
return x;
if (x is Identifier)
return new TypeAnnotation(x.name);
if (x == null)
return null;
else
throw "Not a type: ${x.runtimeType}";
}
Parameter asParameter(x) {
if (x is Parameter)
return x;
if (x is Identifier)
return new Parameter(x.name);
else
throw "Not a parameter: ${x.runtimeType}";
}
void push(node) {
stack.add(node);
}
dynamic peek() {
return stack.last;
}
dynamic pop([coerce(x) = null]) {
var x = stack.removeLast();
if (coerce != null)
return coerce(x);
else
return x;
}
List popList(int count, [List result, coerce(x) = null]) {
if (result == null)
result = <Node>[];
for (int i=0; i<count; i++) {
var x = stack[stack.length-count+i];
if (coerce != null) {
x = coerce(x);
}
result.add(x);
}
stack.removeRange(stack.length-count, stack.length);
return result;
}
popTypeAnnotation() {
List<TypeAnnotation> args = pop();
if (args == null)
return null;
String name = pop(asName);
return new TypeAnnotation(name, args);
}
// EXPRESSIONS
endCascade() {
throw "Cascade not supported yet";
}
endIdentifierList(int count) {
push(popList(count, <Identifier>[]));
}
endTypeList(int count) {
push(popList(count, <TypeAnnotation>[], asType));
}
beginLiteralString(Token token) {
String source = token.value;
tree.StringQuoting quoting = StringValidator.quotingFromString(source);
push(quoting);
push(token); // collect token at the end
}
handleStringPart(Token token) {
push(token); // collect token at the end
}
endLiteralString(int interpCount) {
List parts = popList(2 * interpCount + 1, []);
tree.StringQuoting quoting = pop();
List<Expression> members = <Expression>[];
for (var i=0; i<parts.length; i++) {
var part = parts[i];
if (part is Expression) {
members.add(part);
} else {
assert(part is Token);
DartString str = stringValidator.validateInterpolationPart(
part as Token,
quoting,
isFirst: i == 0,
isLast: i == parts.length - 1);
members.add(new Literal(new StringConstantValue(str)));
}
}
push(new StringConcat(members));
}
handleStringJuxtaposition(int litCount) {
push(new StringConcat(popList(litCount, <Expression>[])));
}
endArguments(int count, begin, end) {
push(popList(count, <Argument>[]));
}
handleNoArguments(token) {
push(null);
}
handleNoTypeArguments(token) {
push(<TypeAnnotation>[]);
}
endTypeArguments(int count, t, y) {
List<TypeAnnotation> args = <TypeAnnotation>[];
for (var i=0; i<count; i++) {
args.add(popTypeAnnotation());
}
push(args.reversed.toList(growable:false));
}
handleVoidKeyword(token) {
push(new Identifier("void"));
push(<TypeAnnotation>[]); // prepare for popTypeAnnotation
}
handleQualified(Token period) {
String last = pop(asName);
String first = pop(asName);
push(new Identifier('$first.$last'));
}
endSend(t) {
List<Argument> arguments = pop();
pop(); // typeArguments
if (arguments == null)
return; // not a function call
Expression selector = pop();
push(new CallFunction(selector, arguments));
}
endThrowExpression(t, tt) {
push(new Throw(pop()));
}
handleAssignmentExpression(Token token) {
Expression right = pop();
Expression left = pop();
push(new Assignment(left, token.value, right));
}
handleBinaryExpression(Token token) {
Expression right = pop();
Receiver left = pop();
String tokenString = token.stringValue;
if (tokenString == '.') {
if (right is CallFunction) {
String name = (right.callee as Identifier).name;
push(new CallMethod(left, name, right.arguments));
} else {
push(new FieldExpression(left, (right as Identifier).name));
}
} else {
push(new BinaryOperator(left, tokenString, right));
}
}
handleConditionalExpression(question, colon) {
Expression elseExpression = pop();
Expression thenExpression = pop();
Expression condition = pop();
push(new Conditional(condition, thenExpression, elseExpression));
}
handleIdentifier(Token t) {
push(new Identifier(t.value));
}
handleOperator(t) {
push(new Identifier(t.value));
}
handleIndexedExpression(open, close) {
Expression index = pop();
Receiver object = pop();
push(new IndexExpression(object, index));
}
handleIsOperator(operathor, not, endToken) {
TypeAnnotation type = popTypeAnnotation();
Expression exp = pop();
TypeOperator r = new TypeOperator(exp, 'is', type);
if (not != null) {
push(new UnaryOperator('!', r));
} else {
push(r);
}
}
handleAsOperator(operathor, endToken) {
TypeAnnotation type = popTypeAnnotation();
Expression exp = pop();
push(new TypeOperator(exp, 'as', type));
}
handleLiteralBool(Token t) {
bool value = t.value == 'true';
push(new Literal(
value ? new TrueConstantValue() : new FalseConstantValue()));
}
handleLiteralDouble(t) {
push(new Literal(new DoubleConstantValue(double.parse(t.value))));
}
handleLiteralInt(Token t) {
push(new Literal(new IntConstantValue(int.parse(t.value))));
}
handleLiteralNull(t) {
push(new Literal(new NullConstantValue()));
}
endLiteralSymbol(Token hash, int idCount) {
List<Identifier> ids = popList(idCount, <Identifier>[]);
push(new LiteralSymbol(ids.map((id) => id.name).join('.')));
}
handleLiteralList(int count, begin, constKeyword, end) {
List<Expression> exps = popList(count, <Expression>[]);
List<TypeAnnotation> types = pop();
assert(types.length <= 1);
push(new LiteralList(exps,
isConst: constKeyword != null,
typeArgument: types.length == 0 ? null : types[0]
));
}
handleLiteralMap(int count, begin, constKeyword, end) {
List<LiteralMapEntry> entries = popList(count, <LiteralMapEntry>[]);
List<TypeAnnotation> types = pop();
assert(types.length == 0 || types.length == 2);
push(new LiteralMap(entries,
isConst: constKeyword != null,
typeArguments: types
));
}
endLiteralMapEntry(colon, endToken) {
Expression value = pop();
Expression key = pop();
push(new LiteralMapEntry(key,value));
}
handleNamedArgument(colon) {
Expression exp = pop();
Identifier name = pop();
push(new NamedArgument(name.name, exp));
}
endConstructorReference(Token start, Token period, Token end) {
if (period == null) {
push(null); // indicate missing constructor name
}
}
handleNewExpression(t) {
List<Argument> args = pop();
String constructorName = pop(asName);
TypeAnnotation type = popTypeAnnotation();
push(new CallNew(type, args, constructorName: constructorName));
}
handleConstExpression(t) {
List<Argument> args = pop();
String constructorName = pop(asName);
TypeAnnotation type = popTypeAnnotation();
push(new CallNew(type, args, constructorName: constructorName,
isConst:true));
}
handleParenthesizedExpression(t) {
// do nothing, just leave expression on top of stack
}
handleSuperExpression(t) {
push(new SuperReceiver());
}
handleThisExpression(t) {
push(new This());
}
handleUnaryPostfixAssignmentExpression(Token t) {
push(new Increment.postfix(pop(), t.value));
}
handleUnaryPrefixAssignmentExpression(Token t) {
push(new Increment.prefix(pop(), t.value));
}
handleUnaryPrefixExpression(Token t) {
push(new UnaryOperator(t.value, pop()));
}
handleFunctionTypedFormalParameter(tok) {
// handled in endFormalParameter
}
endFormalParameter(thisKeyword) {
Expression defaultValue = null;
var x = pop();
if (x is DefaultValue) {
defaultValue = x.expression;
x = pop();
}
if (x is Parameters) {
String name = pop(asName);
TypeAnnotation returnType = popTypeAnnotation();
push(new Parameter.function(name, returnType, x, defaultValue));
} else {
String name = asName(x);
TypeAnnotation type = popTypeAnnotation();
push(new Parameter(name, type:type, defaultValue:defaultValue));
}
}
handleValuedFormalParameter(eq, tok) {
push(new DefaultValue(pop()));
}
endOptionalFormalParameters(int count, begin, end) {
bool isNamed = end.value == '}';
push(popList(count, <Parameter>[], asParameter));
push(isNamed); // Indicate optional parameters to endFormalParameters.
}
endFormalParameters(count, begin, end) {
if (count == 0) {
push(new Parameters([]));
return;
}
var last = pop(); // Detect if optional parameters are present.
if (last is bool) { // See endOptionalFormalParameters.
List<Parameter> optional = pop();
List<Parameter> required = popList(count-1, <Parameter>[], asParameter);
push(new Parameters(required, optional, last));
} else {
// No optional parameters.
List<Parameter> required = popList(count-1, <Parameter>[], asParameter);
required.add(last);
push(new Parameters(required));
}
}
handleNoFormalParameters(tok) {
push(new Parameters([]));
}
endUnnamedFunction(t) {
Statement body = pop();
Parameters parameters = pop();
push(new FunctionExpression(parameters, body));
}
handleNoType(Token token) {
push(null);
}
endReturnStatement(bool hasExpression, begin, end) {
// This is also called for functions whose body is "=> expression"
if (hasExpression) {
push(new Return(pop()));
} else {
push(new Return());
}
}
endExpressionStatement(Token token) {
push(new ExpressionStatement(pop()));
}
endDoWhileStatement(Token doKeyword, Token whileKeyword, Token end) {
Expression condition = pop();
Statement body = pop();
push(new DoWhile(body, condition));
}
endWhileStatement(Token whileKeyword, Token end) {
Statement body = pop();
Expression condition = pop();
push(new While(condition, body));
}
endBlock(int count, Token begin, Token end) {
push(new Block(popList(count, <Statement>[])));
}
endRethrowStatement(Token throwToken, Token endToken) {
push(new Rethrow());
}
endTryStatement(int catchCount, Token tryKeyword, Token finallyKeyword) {
Statement finallyBlock = null;
if (finallyKeyword != null) {
finallyBlock = pop();
}
List<CatchBlock> catchBlocks = popList(catchCount, <CatchBlock>[]);
Statement tryBlock = pop();
push(new Try(tryBlock, catchBlocks, finallyBlock));
}
void handleCatchBlock(Token onKeyword, Token catchKeyword) {
Statement block = pop();
String exceptionVar = null;
String stackVar = null;
if (catchKeyword != null) {
Parameters params = pop();
exceptionVar = params.requiredParameters[0].name;
if (params.requiredParameters.length > 1) {
stackVar = params.requiredParameters[1].name;
}
}
TypeAnnotation type = onKeyword == null ? null : pop();
push(new CatchBlock(block,
onType: type,
exceptionVar: exceptionVar,
stackVar: stackVar
));
}
endSwitchStatement(Token switchKeyword, Token end) {
List<SwitchCase> cases = pop();
Expression expression = pop();
push(new Switch(expression, cases));
}
endSwitchBlock(int caseCount, Token begin, Token end) {
push(popList(caseCount, <SwitchCase>[]));
}
handleSwitchCase(int labelCount, int caseCount, Token defaultKeyword,
int statementCount, Token first, Token end) {
List<Statement> statements = popList(statementCount, <Statement>[]);
List<Expression> cases = popList(caseCount, <Expression>[]);
if (defaultKeyword != null) {
cases = null;
}
push(new SwitchCase(cases, statements));
}
handleCaseMatch(Token caseKeyword, Token colon) {
// do nothing, leave case expression on stack
}
handleBreakStatement(bool hasTarget, Token breakKeyword, Token end) {
String target = hasTarget ? pop(asName) : null;
push(new Break(target));
}
handleContinueStatement(bool hasTarget, Token continueKeyword, Token end) {
String target = hasTarget ? pop(asName) : null;
push(new Continue(target));
}
handleEmptyStatement(Token token) {
push(new EmptyStatement());
}
VariableDeclaration asVariableDeclaration(x) {
if (x is VariableDeclaration)
return x;
if (x is Identifier)
return new VariableDeclaration(x.name);
throw "Not a variable definition: ${x.runtimeType}";
}
endVariablesDeclaration(int count, Token end) {
List<VariableDeclaration> variables =
popList(count, <VariableDeclaration>[], asVariableDeclaration);
TypeAnnotation type = popTypeAnnotation();
push(new VariableDeclarations(variables,
type: type,
isFinal: false, // TODO(asgerf): Parse modifiers.
isConst: false
));
}
endInitializer(Token assign) {
Expression init = pop();
String name = pop(asName);
push(new VariableDeclaration(name, init));
}
endIfStatement(Token ifToken, Token elseToken) {
Statement elsePart = (elseToken == null) ? null : pop();
Statement thenPart = pop();
Expression condition = pop();
push(new If(condition, thenPart, elsePart));
}
endForStatement(int updateCount, Token begin, Token end) {
Statement body = pop();
List<Expression> updates = popList(updateCount, <Expression>[]);
ExpressionStatement condition = pop(); // parsed as expression statement
Expression exp = condition == null ? null : condition.expression;
Node initializer = pop();
push(new For(initializer, exp, updates, body));
}
handleNoExpression(Token token) {
push(null);
}
endForIn(Token await, Token begin, Token inKeyword, Token end) {
Statement body = pop();
Expression exp = pop();
Node declaredIdentifier = pop();
push(new ForIn(declaredIdentifier, exp, body));
}
handleAssertStatement(Token assertKeyword,
Token commaToken, Token semicolonToken) {
Expression message;
if (commaToken != null) message = pop();
Expression exp = pop();
var arguments = [exp];
if (message != null) arguments.add(message);
Expression call = new CallFunction(new Identifier("assert"), arguments);
push(new ExpressionStatement(call));
}
endLabeledStatement(int labelCount) {
Statement statement = pop();
for (int i=0; i<labelCount; i++) {
String label = pop(asName);
statement = new LabeledStatement(label, statement);
}
push(statement);
}
endFunctionDeclaration(Token end) {
Statement body = pop();
Parameters parameters = pop();
String name = pop(asName);
TypeAnnotation returnType = popTypeAnnotation();
push(new FunctionDeclaration(new FunctionExpression(parameters, body,
name: name,
returnType: returnType)));
}
endFunctionBody(int count, Token begin, Token end) {
push(new Block(popList(count, <Statement>[])));
}
}
class DefaultValue {
final Expression expression;
DefaultValue(this.expression);
}
/// Compares ASTs for structural equality.
void checkDeepEqual(x, y) {
if (x is List && y is List) {
if (x.length != y.length)
return;
for (var i=0; i<x.length; i++) {
checkDeepEqual(x[i], y[i]);
}
}
else if (x is Node && y is Node) {
if (x.runtimeType != y.runtimeType)
throw new Error();
InstanceMirror xm = reflect(x);
InstanceMirror ym = reflect(y);
for (Symbol name in xm.type.instanceMembers.keys) {
if (reflectClass(Object).declarations.containsKey(name)) {
continue; // do not check things from Object, such as hashCode
}
MethodMirror mm = xm.type.instanceMembers[name];
if (mm.isGetter) {
var xv = xm.getField(name).reflectee;
var yv = ym.getField(name).reflectee;
checkDeepEqual(xv,yv);
}
}
}
else if (x is PrimitiveConstantValue && y is PrimitiveConstantValue) {
checkDeepEqual(x.primitiveValue, y.primitiveValue);
}
else if (x is DartString && y is DartString) {
if (x.slowToString() != y.slowToString()) {
throw new Error();
}
}
else {
if (x != y) {
throw new Error();
}
}
}
Expression parseExpression(String code) {
SourceFile file = new StringSourceFile.fromName('', code);
Scanner scan = new Scanner(file);
Token tok = scan.tokenize();
AstBuilder builder = new AstBuilder();
Parser parser = new Parser(builder, new MockParserOptions());
tok = parser.parseExpression(tok);
if (builder.stack.length != 1 || tok.kind != EOF_TOKEN) {
throw "Parse error in $code";
}
return builder.pop();
}
Statement parseStatement(String code) {
SourceFile file = new StringSourceFile.fromName('', code);
Scanner scan = new Scanner(file);
Token tok = scan.tokenize();
AstBuilder builder = new AstBuilder();
Parser parser = new Parser(builder, new MockParserOptions());
tok = parser.parseStatement(tok);
if (builder.stack.length != 1 || tok.kind != EOF_TOKEN) {
throw "Parse error in $code";
}
return builder.pop();
}
String unparseExpression(Expression exp) {
StringBuffer buf = new StringBuffer();
new Unparser(buf).writeExpression(exp);
return buf.toString();
}
String unparseStatement(Statement stmt) {
StringBuffer buf = new StringBuffer();
new Unparser(buf).writeStatement(stmt);
return buf.toString();
}
/// Converts [exp] to an instance of the frontend AST and unparses that.
String frontUnparseExpression(Expression exp) {
tree.Node node = new TreePrinter().makeExpression(exp);
return tree.unparse(node);
}
/// Converts [stmt] to an instance of the frontend AST and unparses that.
String frontUnparseStatement(Statement stmt) {
tree.Node node = new TreePrinter().makeStatement(stmt);
return tree.unparse(node);
}
/// Parses [code], unparses the resulting AST, then parses the unparsed text.
/// The ASTs from the first and second parse are then compared for structural
/// equality. Alternatively, if [expected] is not an empty string, the second
/// parse must match the AST of parsing [expected].
void checkFn(String code, String expected, Function parse, Function unparse) {
var firstParse = parse(code);
String unparsed = unparse(firstParse);
try {
var secondParse = parse(unparsed);
var baseline = expected == "" ? firstParse : parse(expected);
checkDeepEqual(baseline, secondParse);
} catch (e, stack) {
Expect.fail('"$code" was unparsed as "$unparsed"');
}
}
void checkExpression(String code, [String expected="", String expected2=""]) {
checkFn(code, expected, parseExpression, unparseExpression);
checkFn(code, expected2, parseExpression, frontUnparseExpression);
}
void checkStatement(String code, [String expected="", String expected2=""]) {
checkFn(code, expected, parseStatement, unparseStatement);
checkFn(code, expected2, parseStatement, frontUnparseStatement);
}
void debugTokens(String code) {
SourceFile file = new StringSourceFile.fromName('', code);
Scanner scan = new Scanner(file);
Token tok = scan.tokenize();
while (tok.next != tok) {
print(tok.toString());
tok = tok.next;
}
}
void main() {
// To check if these tests are effective, one should manually alter
// something in [Unparser] and see if a test fails.
checkExpression(" a + b + c");
checkExpression("(a + b) + c");
checkExpression(" a + (b + c)");
checkExpression(" a + b - c");
checkExpression("(a + b) - c");
checkExpression(" a + (b - c)");
checkExpression(" a - b + c");
checkExpression("(a - b) + c");
checkExpression(" a - (b + c)");
checkExpression(" a * b + c");
checkExpression("(a * b) + c");
checkExpression(" a * (b + c)");
checkExpression(" a + b * c");
checkExpression("(a + b) * c");
checkExpression(" a + (b * c)");
checkExpression(" a * b * c");
checkExpression("(a * b) * c");
checkExpression(" a * (b * c)");
checkExpression("a is T");
checkExpression("a is! T");
checkExpression("!(a is T)");
checkExpression("a is T.x");
checkExpression("a is! T.x");
checkExpression("!(a is T.x)");
checkExpression("!(a is T).x");
checkExpression("a as T.x");
checkExpression("(a as T).x");
checkExpression("a == b");
checkExpression("a != b");
checkExpression("!(a == b)", "a != b");
checkExpression("a && b ? c : d");
checkExpression("(a && b) ? c : d");
checkExpression("a && (b ? c : d)");
checkExpression("a || b ? c : d");
checkExpression("(a || b) ? c : d");
checkExpression("a || (b ? c : d)");
checkExpression(" a ? b : c && d");
checkExpression(" a ? b : (c && d)");
checkExpression("(a ? b : c) && d");
checkExpression(" a ? b : c = d");
checkExpression(" a ? b : (c = d)");
checkExpression("(a == b) == c");
checkExpression("a == (b == c)");
checkExpression(" a < b == c");
checkExpression("(a < b) == c");
checkExpression(" a < (b == c)");
checkExpression(" a == b < c");
checkExpression("(a == b) < c");
checkExpression(" a == (b < c)");
checkExpression("x.f()");
checkExpression("(x.f)()");
checkExpression("x.f()()");
checkExpression("(x.f)()()");
checkExpression("x.f().g()");
checkExpression("(x.f)().g()");
checkExpression("x.f()");
checkExpression("x.f(1 + 2)");
checkExpression("x.f(1 + 2, 3 + 4)");
checkExpression("x.f(1 + 2, foo:3 + 4)");
checkExpression("x.f(1 + 2, foo:3 + 4, bar: 5)");
checkExpression("x.f(foo:3 + 4)");
checkExpression("x.f(foo:3 + 4, bar: 5)");
checkExpression("x.f.g.h");
checkExpression("(x.f).g.h");
checkExpression("(x.f.g).h");
checkExpression(" a = b + c");
checkExpression(" a = (b + c)");
checkExpression("(a = b) + c");
checkExpression("a + (b = c)");
checkExpression("dx * dx + dy * dy < r * r",
"((dx * dx) + (dy * dy)) < (r * r)");
checkExpression("mid = left + right << 1",
"mid = ((left + right) << 1)");
checkExpression("a + b % c * -d ^ e - f ~/ x & ++y / z++ | w > a ? b : c");
checkExpression("a + b % c * -d ^ (e - f) ~/ x & ++y / z++ | w > a ? b : c");
checkExpression("'foo'");
checkExpression("'foo' 'bar'", "'foobar'");
checkExpression("{}.length");
checkExpression("{x: 1+2}.length");
checkExpression("<String,int>{}.length");
checkExpression("<String,int>{x: 1+2}.length");
checkExpression("[].length");
checkExpression("[1+2].length");
checkExpression("<num>[].length");
checkExpression("<num>[1+2].length");
checkExpression("x + -y");
checkExpression("x + --y");
checkExpression("x++ + y");
checkExpression("x + ++y");
checkExpression("x-- - y");
checkExpression("x-- - -y");
checkExpression("x - --y");
checkExpression("x && !y");
checkExpression("!x && y");
checkExpression("!(x && y)");
checkExpression(" super + 1 * 2");
checkExpression("(super + 1) * 2");
checkExpression(" super + (1 * 2)");
checkExpression("x + -super");
checkExpression("x-- - -super");
checkExpression("x - -super");
checkExpression("x && !super");
checkExpression("super.f(1, 2) + 3");
checkExpression("super.f + 3");
checkExpression(r"'foo\nbar'");
checkExpression(r"'foo\r\nbar'");
checkExpression(r"'foo\rbar'");
checkExpression(r"'foo\'bar'");
checkExpression(r"""'foo"bar'""");
checkExpression(r"r'foo\nbar'");
checkExpression("''");
checkExpression("r''");
var sq = "'";
var dq = '"';
checkExpression("'$dq$dq' \"$sq$sq\"");
checkExpression("'$dq$dq$dq$dq' \"$sq$sq$sq$sq\"");
checkExpression(r"'\$\$\$\$\$\$\$\$\$'");
checkExpression("'$dq$dq$dq' '\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n' \"$sq$sq$sq\"");
checkExpression("'$dq$dq$dq' '\\r\\r\\r\\r\\r\\r\\r\\r\\r\\r' \"$sq$sq$sq\"");
checkExpression("'$dq$dq$dq' '\\r\\n\\r\\n\\r\\n\\r\\n\\r\\n' \"$sq$sq$sq\"");
checkExpression(r"'$foo'");
checkExpression(r"'${foo}x'");
checkExpression(r"'${foo}x\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'");
checkExpression(r"'abc' '${foo}' r'\\\\\\\'");
checkExpression(r"'${$x}'");
checkExpression(r"'${$x}y'");
checkExpression("null + null");
checkExpression("(x) => x",
'',
'(x){return x;}');
checkStatement("fn(x) => x;",
'',
'fn(x){return x;}');
checkExpression("throw x");
checkStatement("throw x;");
checkStatement("var x, y, z;");
checkStatement("final x, y, z;");
checkStatement("dynamic x, y, z;");
checkStatement("String x, y, z;");
checkStatement("List<int> x, y, z;");
checkStatement("final dynamic x, y, z;");
checkStatement("final String x, y, z;");
checkStatement("final List<int> x, y, z;");
checkStatement("var x = y, z;");
checkStatement("var x, y = z;");
checkStatement("var x = y = z;");
// Note: We sometimes have to pass an expected string to account for
// block flattening which does not preserve structural AST equality
checkStatement("if (x) if (y) foo(); else bar(); ");
checkStatement("if (x) { if (y) foo(); } else bar(); ");
checkStatement("if (x) { if (y) foo(); else bar(); }",
"if (x) if (y) foo(); else bar(); ");
checkStatement("if (x) while (y) if (z) foo(); else bar(); ");
checkStatement("if (x) while (y) { if (z) foo(); } else bar(); ");
checkStatement("if (x) while (y) { if (z) foo(); else bar(); }",
"if (x) while (y) if (z) foo(); else bar(); ");
checkStatement("{var x = 1; {var x = 2;} return x;}");
checkStatement("{var x = 1; {x = 2;} return x;}",
"{var x = 1; x = 2; return x;}",
"{var x = 1; x = 2; return x;}");
checkStatement("if (x) {var x = 1;}");
checkStatement("({'foo': 1}).bar();");
checkStatement("({'foo': 1}).length;");
checkStatement("({'foo': 1}).length + 1;");
checkStatement("({'foo': 1})['foo'].toString();");
checkStatement("({'foo': 1})['foo'] = 3;");
checkStatement("({'foo': 1}['foo']());");
checkStatement("({'foo': 1}['foo'])();");
checkStatement("({'foo': 1})['foo'].x++;");
checkStatement("({'foo': 1}) is Map;");
checkStatement("({'foo': 1}) as Map;");
checkStatement("({'foo': 1}) is util.Map;");
checkStatement("({'foo': 1}) + 1;");
checkStatement("[1].bar();");
checkStatement("1.bar();");
checkStatement("'foo'.bar();");
checkStatement("do while(x); while (y);");
checkStatement("{do; while(x); while (y);}");
checkStatement('switch(x) { case 1: case 2: return y; }');
checkStatement('switch(x) { default: return y; }');
checkStatement('switch(x) { case 1: x=y; default: return y; }');
checkStatement('switch(x) { case 1: x=y; y=z; break; default: return y; }');
}

View file

@ -1,37 +0,0 @@
// Copyright (c) 2014, 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.
/// End-to-end test of the dart2dart compiler.
library dart_backend.end2end_test;
import 'package:async_helper/async_helper.dart';
import 'package:compiler/src/compiler.dart';
import 'package:compiler/src/dart_backend/dart_backend.dart';
import 'package:expect/expect.dart';
import '../../../../pkg/analyzer2dart/test/test_helper.dart' hide TestSpec;
import '../../../../pkg/analyzer2dart/test/end2end_data.dart';
import 'test_helper.dart';
import '../output_collector.dart';
main(List<String> args) {
performTests(TEST_DATA, asyncTester, runTest, args);
}
runTest(TestSpec result) {
OutputCollector outputCollector = new OutputCollector();
asyncTest(() => compilerFor(result.input, outputProvider: outputCollector)
.then((Compiler compiler) {
String expectedOutput = result.output.trim();
compiler.phase = Compiler.PHASE_COMPILING;
DartBackend backend = compiler.backend;
backend.assembleProgram();
String output = outputCollector.getOutput('', 'dart').trim();
Expect.equals(expectedOutput, output,
'\nInput:\n${result.input}\n'
'Expected:\n$expectedOutput\n'
'Actual:\n$output\n');
}));
}

View file

@ -1,528 +0,0 @@
// Copyright (c) 2014, 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 '../mock_compiler.dart';
import 'sexpr_unstringifier.dart';
import 'package:async_helper/async_helper.dart';
import "package:expect/expect.dart";
import 'package:compiler/src/cps_ir/cps_ir_nodes_sexpr.dart';
import 'package:compiler/src/cps_ir/optimizers.dart';
import 'package:compiler/src/constant_system_dart.dart';
// The tests in this file that ensure that sparse constant propagation on the
// CPS IR works as expected.
// CP1 represents the following incoming dart code:
//
// int main() {
// int i = 1;
// int j;
// if (i == 1) {
// j = 2;
// } else {
// j = 3;
// }
// return j;
// }
String CP1_IN = """
(FunctionDefinition main () () return
(LetPrim (v0 (Constant (Int 1)))
(LetPrim (v1 (Constant (Int 1)))
(LetCont
((k0 (v2)
(LetCont
((k1 ()
(LetPrim (v3 (Constant (Int 2)))
(InvokeContinuation return (v3))))
(k2 ()
(LetPrim (v4 (Constant (Int 3)))
(InvokeContinuation return (v4)))))
(Branch (IsTrue v2) k1 k2))))
(InvokeMethod v0 == (v1) k0)))))
""";
String CP1_OUT = """
(FunctionDefinition main () () return
(LetPrim (v0 (Constant (Int 1)))
(LetPrim (v1 (Constant (Int 1)))
(LetCont
((k0 (v2)
(LetCont
((k1 ()
(LetPrim (v3 (Constant (Int 2)))
(InvokeContinuation return (v3))))
(k2 ()
(LetPrim (v4 (Constant (Int 3)))
(InvokeContinuation return (v4)))))
(InvokeContinuation k1 ()))))
(LetPrim (v5 (Constant (Bool true)))
(InvokeContinuation k0 (v5)))))))
""";
// CP2 represents the following incoming dart code:
//
// int main() {
// int i = 1;
// while (true) {
// if (false || false) {
// return i;
// }
// if (true && i == 1) {
// return i;
// }
// }
// return 42;
// }
String CP2_IN = """
(FunctionDefinition main () () return
(LetPrim (v0 (Constant (Int 1)))
(LetCont
((rec k0 ()
(LetCont
((k1 ()
(LetPrim (v1 (Constant (Int 42)))
(InvokeContinuation return (v1))))
(k2 ()
(LetPrim (v2 (Constant (Bool false)))
(LetCont
((k3 (v3)
(LetCont
((k4 ()
(InvokeContinuation return (v0)))
(k5 ()
(LetPrim (v4 (Constant (Bool true)))
(LetCont
((k6 (v5)
(LetCont
((k7 ()
(InvokeContinuation return (v0)))
(k8 ()
(InvokeContinuation rec k0 ())))
(Branch (IsTrue v5) k7 k8))))
(LetCont
((k9 ()
(LetPrim (v6 (Constant (Int 1)))
(LetCont
((k10 (v7)
(LetCont
((k11 ()
(LetPrim (v8 (Constant (Bool true)))
(InvokeContinuation k6 (v8))))
(k12 ()
(LetPrim (v9 (Constant (Bool false)))
(InvokeContinuation k6 (v9)))))
(Branch (IsTrue v7) k11 k12))))
(InvokeMethod v0 == (v6) k10))))
(k13 ()
(LetPrim (v10 (Constant (Bool false)))
(InvokeContinuation k6 (v10)))))
(Branch (IsTrue v4) k9 k13))))))
(Branch (IsTrue v3) k4 k5))))
(LetCont
((k14 ()
(LetPrim (v11 (Constant (Bool true)))
(InvokeContinuation k3 (v11))))
(k15 ()
(LetPrim (v12 (Constant (Bool false)))
(LetCont
((k16 ()
(LetPrim (v13 (Constant (Bool true)))
(InvokeContinuation k3 (v13))))
(k17 ()
(LetPrim (v14 (Constant (Bool false)))
(InvokeContinuation k3 (v14)))))
(Branch (IsTrue v12) k16 k17)))))
(Branch (IsTrue v2) k14 k15))))))
(LetPrim (v15 (Constant (Bool true)))
(Branch (IsTrue v15) k2 k1)))))
(InvokeContinuation k0 ()))))
""";
String CP2_OUT = """
(FunctionDefinition main () () return
(LetPrim (v0 (Constant (Int 1)))
(LetCont
((rec k0 ()
(LetCont
((k1 ()
(LetPrim (v1 (Constant (Int 42)))
(InvokeContinuation return (v1))))
(k2 ()
(LetPrim (v2 (Constant (Bool false)))
(LetCont
((k3 (v3)
(LetCont
((k4 ()
(InvokeContinuation return (v0)))
(k5 ()
(LetPrim (v4 (Constant (Bool true)))
(LetCont
((k6 (v5)
(LetCont
((k7 ()
(InvokeContinuation return (v0)))
(k8 ()
(InvokeContinuation rec k0 ())))
(InvokeContinuation k7 ()))))
(LetCont
((k9 ()
(LetPrim (v6 (Constant (Int 1)))
(LetCont
((k10 (v7)
(LetCont
((k11 ()
(LetPrim (v8 (Constant (Bool true)))
(InvokeContinuation k6 (v8))))
(k12 ()
(LetPrim (v9 (Constant (Bool false)))
(InvokeContinuation k6 (v9)))))
(InvokeContinuation k11 ()))))
(LetPrim (v10 (Constant (Bool true)))
(InvokeContinuation k10 (v10))))))
(k13 ()
(LetPrim (v11 (Constant (Bool false)))
(InvokeContinuation k6 (v11)))))
(InvokeContinuation k9 ()))))))
(InvokeContinuation k5 ()))))
(LetCont
((k14 ()
(LetPrim (v12 (Constant (Bool true)))
(InvokeContinuation k3 (v12))))
(k15 ()
(LetPrim (v13 (Constant (Bool false)))
(LetCont
((k16 ()
(LetPrim (v14 (Constant (Bool true)))
(InvokeContinuation k3 (v14))))
(k17 ()
(LetPrim (v15 (Constant (Bool false)))
(InvokeContinuation k3 (v15)))))
(InvokeContinuation k17 ())))))
(InvokeContinuation k15 ()))))))
(LetPrim (v16 (Constant (Bool true)))
(InvokeContinuation k2 ())))))
(InvokeContinuation k0 ()))))
""";
// CP3 represents the following incoming dart code:
//
// int main() {
// int i = 1;
// i = f();
// if (i == 1) {
// return 42;
// }
// return i;
// }
String CP3_IN = """
(FunctionDefinition main () () return
(LetPrim (v0 (Constant (Int 1)))
(LetCont
((k0 (v1)
(LetPrim (v2 (Constant (Int 1)))
(LetCont
((k1 (v3)
(LetCont
((k2 ()
(LetPrim (v4 (Constant (Int 42)))
(InvokeContinuation return (v4))))
(k3 ()
(InvokeContinuation return (v1))))
(Branch (IsTrue v3) k2 k3))))
(InvokeMethod v1 == (v2) k1)))))
(InvokeStatic f () k0))))
""";
String CP3_OUT = CP3_IN;
// Addition.
String CP4_IN = """
(FunctionDefinition main () () return
(LetPrim (v0 (Constant (Int 1)))
(LetPrim (v1 (Constant (Int 2)))
(LetCont
((k0 (v2)
(InvokeContinuation return (v2))))
(InvokeMethod v0 + (v1) k0)))))
""";
String CP4_OUT = """
(FunctionDefinition main () () return
(LetPrim (v0 (Constant (Int 1)))
(LetPrim (v1 (Constant (Int 2)))
(LetCont
((k0 (v2)
(InvokeContinuation return (v2))))
(LetPrim (v3 (Constant (Int 3)))
(InvokeContinuation k0 (v3)))))))
""";
// Array access operator (no optimization).
String CP5_IN = """
(FunctionDefinition main () () return
(LetPrim (v0 (Constant (Int 1)))
(LetPrim (v1 (Constant (Int 2)))
(LetCont
((k0 (v2)
(InvokeContinuation return (v2))))
(InvokeMethod v0 [] (v1) k0)))))
""";
String CP5_OUT = CP5_IN;
// Division by 0.
String CP6_IN = """
(FunctionDefinition main () () return
(LetPrim (v0 (Constant (Int 1)))
(LetPrim (v1 (Constant (Int 0)))
(LetCont
((k0 (v2)
(InvokeContinuation return (v2))))
(InvokeMethod v0 / (v1) k0)))))
""";
String CP6_OUT = """
(FunctionDefinition main () () return
(LetPrim (v0 (Constant (Int 1)))
(LetPrim (v1 (Constant (Int 0)))
(LetCont
((k0 (v2)
(InvokeContinuation return (v2))))
(LetPrim (v3 (Constant (Double Infinity)))
(InvokeContinuation k0 (v3)))))))
""";
// Concatenate strings.
String CP7_IN = """
(FunctionDefinition main () () return
(LetPrim (v0 (Constant (String "b")))
(LetPrim (v1 (Constant (String "d")))
(LetPrim (v2 (Constant (String "a")))
(LetPrim (v3 (Constant (String "c")))
(LetPrim (v4 (Constant (String "")))
(LetCont
((k0 (v5)
(LetCont
((k1 (v6)
(InvokeContinuation return (v6))))
(InvokeMethod v5 length () k1))))
(ConcatenateStrings (v2 v0 v3 v1 v4) k0))))))))
""";
String CP7_OUT = """
(FunctionDefinition main () () return
(LetPrim (v0 (Constant (String "b")))
(LetPrim (v1 (Constant (String "d")))
(LetPrim (v2 (Constant (String "a")))
(LetPrim (v3 (Constant (String "c")))
(LetPrim (v4 (Constant (String "")))
(LetCont
((k0 (v5)
(LetCont
((k1 (v6)
(InvokeContinuation return (v6))))
(InvokeMethod v5 length () k1))))
(LetPrim (v7 (Constant (String "abcd")))
(InvokeContinuation k0 (v7))))))))))
""";
// TODO(jgruber): We can't test is-check optimization because the unstringifier
// does not recreate accurate types for the TypeOperator node.
// Simple branch removal.
String CP8_IN = """
(FunctionDefinition main () () return
(LetPrim (v0 (Constant (Int 1)))
(LetPrim (v1 (Constant (Int 1)))
(LetCont
((k0 (v2)
(LetCont
((k1 ()
(LetPrim (v3 (Constant (Int 42)))
(InvokeContinuation return (v3))))
(k2 ()
(InvokeContinuation return (v0))))
(Branch (IsTrue v2) k1 k2))))
(InvokeMethod v0 == (v1) k0)))))
""";
String CP8_OUT = """
(FunctionDefinition main () () return
(LetPrim (v0 (Constant (Int 1)))
(LetPrim (v1 (Constant (Int 1)))
(LetCont
((k0 (v2)
(LetCont
((k1 ()
(LetPrim (v3 (Constant (Int 42)))
(InvokeContinuation return (v3))))
(k2 ()
(InvokeContinuation return (v0))))
(InvokeContinuation k1 ()))))
(LetPrim (v4 (Constant (Bool true)))
(InvokeContinuation k0 (v4)))))))
""";
// While loop.
String CP9_IN = """
(FunctionDefinition main () () return
(LetPrim (v0 (Constant (Int 1)))
(LetCont
((rec k0 (v1)
(LetCont
((k1 ()
(InvokeContinuation return (v1)))
(k2 ()
(LetPrim (v2 (Constant (Int 1)))
(LetCont
((k3 (v3)
(LetCont
((k4 (v4)
(LetCont
((k5 ()
(LetPrim (v5 (Constant (Int 42)))
(InvokeContinuation return (v5))))
(k6 ()
(LetPrim (v6 (Constant (Int 1)))
(LetCont
((k7 (v7)
(InvokeContinuation rec k0 (v7))))
(InvokeMethod v1 + (v6) k7)))))
(Branch (IsTrue v4) k5 k6))))
(LetCont
((k8 ()
(LetPrim (v8 (Constant (Bool false)))
(InvokeContinuation k4 (v8))))
(k9 ()
(LetPrim (v9 (Constant (Bool true)))
(InvokeContinuation k4 (v9)))))
(Branch (IsTrue v3) k8 k9)))))
(InvokeMethod v1 == (v2) k3)))))
(LetPrim (v10 (Constant (Bool true)))
(Branch (IsTrue v10) k2 k1)))))
(InvokeContinuation k0 (v0)))))
""";
String CP9_OUT = """
(FunctionDefinition main () () return
(LetPrim (v0 (Constant (Int 1)))
(LetCont
((rec k0 (v1)
(LetCont
((k1 ()
(InvokeContinuation return (v1)))
(k2 ()
(LetPrim (v2 (Constant (Int 1)))
(LetCont
((k3 (v3)
(LetCont
((k4 (v4)
(LetCont
((k5 ()
(LetPrim (v5 (Constant (Int 42)))
(InvokeContinuation return (v5))))
(k6 ()
(LetPrim (v6 (Constant (Int 1)))
(LetCont
((k7 (v7)
(InvokeContinuation rec k0 (v7))))
(InvokeMethod v1 + (v6) k7)))))
(Branch (IsTrue v4) k5 k6))))
(LetCont
((k8 ()
(LetPrim (v8 (Constant (Bool false)))
(InvokeContinuation k4 (v8))))
(k9 ()
(LetPrim (v9 (Constant (Bool true)))
(InvokeContinuation k4 (v9)))))
(Branch (IsTrue v3) k8 k9)))))
(InvokeMethod v1 == (v2) k3)))))
(LetPrim (v10 (Constant (Bool true)))
(InvokeContinuation k2 ())))))
(InvokeContinuation k0 (v0)))))
""";
// While loop, from:
//
// int main() {
// for (int i = 0; i < 2; i++) {
// print(42 + i);
// }
// }
String CP10_IN = """
(FunctionDefinition main () () return
(LetPrim (v0 (Constant (Int 0)))
(LetCont
((rec k0 (v1)
(LetCont
((k1 ()
(LetPrim (v2 (Constant (Null)))
(InvokeContinuation return (v2))))
(k2 ()
(LetPrim (v3 (Constant (Int 42)))
(LetCont
((k3 (v4)
(LetCont
((k4 (v5)
(LetPrim (v6 (Constant (Int 1)))
(LetCont
((k5 (v7)
(InvokeContinuation rec k0 (v7))))
(InvokeMethod v1 + (v6) k5)))))
(InvokeStatic print (v4) k4))))
(InvokeMethod v3 + (v1) k3)))))
(LetPrim (v8 (Constant (Int 2)))
(LetCont
((k6 (v9)
(Branch (IsTrue v9) k2 k1)))
(InvokeMethod v1 < (v8) k6))))))
(InvokeContinuation k0 (v0)))))
""";
String CP10_OUT = CP10_IN;
/// Normalizes whitespace by replacing all whitespace sequences by a single
/// space and trimming leading and trailing whitespace.
String normalizeSExpr(String input) {
return input.replaceAll(new RegExp(r'[ \n\t]+'), ' ').trim();
}
/// Parses the given input IR, runs an optimization pass over it, and compares
/// the stringification of the result against the expected output.
Future testConstantPropagator(String input, String expectedOutput) {
final compiler = new MockCompiler.internal(
emitJavaScript: false,
enableMinification: false);
return compiler.init().then((_) {
final unstringifier = new SExpressionUnstringifier();
final stringifier = new SExpressionStringifier();
final optimizer = new TypePropagator(
compiler.types,
DART_CONSTANT_SYSTEM,
new UnitTypeSystem(),
compiler.internalError);
final f = unstringifier.unstringify(input);
optimizer.rewrite(f);
String expected = normalizeSExpr(expectedOutput);
String actual = normalizeSExpr(stringifier.visit(f));
Expect.equals(expected, actual);
});
}
void main() {
asyncTest(() => testConstantPropagator(CP1_IN, CP1_OUT));
asyncTest(() => testConstantPropagator(CP2_IN, CP2_OUT));
asyncTest(() => testConstantPropagator(CP3_IN, CP3_OUT));
asyncTest(() => testConstantPropagator(CP4_IN, CP4_OUT));
asyncTest(() => testConstantPropagator(CP5_IN, CP5_OUT));
asyncTest(() => testConstantPropagator(CP6_IN, CP6_OUT));
asyncTest(() => testConstantPropagator(CP7_IN, CP7_OUT));
asyncTest(() => testConstantPropagator(CP8_IN, CP8_OUT));
asyncTest(() => testConstantPropagator(CP9_IN, CP9_OUT));
asyncTest(() => testConstantPropagator(CP10_IN, CP10_OUT));
}

View file

@ -1,97 +0,0 @@
// Copyright (c) 2014, 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 'opt_redundant_phi_test.dart';
// The 'cyclic deps' IR tests removal of redundant phis with cyclic
// dependencies.
//
// void main() {
// var x = 0;
// var y = x;
// for (int i = 0; i < 10; i++) {
// if (i == -1) x = y;
// if (i == -1) y = x;
// }
// print(x);
// print(y);
// }
String CYCLIC_DEPS_IN = """
(FunctionDefinition main (return) (LetPrim v0 (Constant 0))
(LetPrim v1 (Constant 0))
(LetCont* (k0 v2 v3 v4)
(LetCont (k1)
(LetCont (k2 v5)
(LetCont (k3 v6) (LetPrim v7 (Constant null))
(InvokeContinuation return v7))
(InvokeStatic print v3 k3))
(InvokeStatic print v2 k2))
(LetCont (k4) (LetPrim v8 (Constant 1))
(LetCont (k5 v9)
(LetCont (k6 v10)
(LetCont (k7 v11) (LetPrim v12 (Constant 1))
(LetCont (k8 v13)
(LetCont (k9 v14)
(LetCont (k10 v15)
(LetPrim v16 (Constant 1))
(LetCont (k11 v17)
(InvokeContinuation* k0 v11 v15 v17))
(InvokeMethod v4 + v16 k11))
(LetCont (k12) (InvokeContinuation k10 v11))
(LetCont (k13) (InvokeContinuation k10 v3))
(Branch (IsTrue v14) k12 k13))
(InvokeMethod v4 == v13 k9))
(InvokeMethod v12 unary- k8))
(LetCont (k14) (InvokeContinuation k7 v3))
(LetCont (k15) (InvokeContinuation k7 v2))
(Branch (IsTrue v10) k14 k15))
(InvokeMethod v4 == v9 k6))
(InvokeMethod v8 unary- k5))
(LetPrim v18 (Constant 10))
(LetCont (k16 v19) (Branch (IsTrue v19) k4 k1))
(InvokeMethod v4 < v18 k16))
(InvokeContinuation k0 v0 v0 v1))
""";
String CYCLIC_DEPS_OUT = """
(FunctionDefinition main (return) (LetPrim v0 (Constant 0))
(LetPrim v1 (Constant 0))
(LetCont* (k0 v2)
(LetCont (k1)
(LetCont (k2 v3)
(LetCont (k3 v4) (LetPrim v5 (Constant null))
(InvokeContinuation return v5))
(InvokeStatic print v0 k3))
(InvokeStatic print v0 k2))
(LetCont (k4) (LetPrim v6 (Constant 1))
(LetCont (k5 v7)
(LetCont (k6 v8)
(LetCont (k7) (LetPrim v9 (Constant 1))
(LetCont (k8 v10)
(LetCont (k9 v11)
(LetCont (k10)
(LetPrim v12 (Constant 1))
(LetCont (k11 v13)
(InvokeContinuation* k0 v13))
(InvokeMethod v2 + v12 k11))
(LetCont (k12) (InvokeContinuation k10))
(LetCont (k13) (InvokeContinuation k10))
(Branch (IsTrue v11) k12 k13))
(InvokeMethod v2 == v10 k9))
(InvokeMethod v9 unary- k8))
(LetCont (k14) (InvokeContinuation k7))
(LetCont (k15) (InvokeContinuation k7))
(Branch (IsTrue v8) k14 k15))
(InvokeMethod v2 == v7 k6))
(InvokeMethod v6 unary- k5))
(LetPrim v14 (Constant 10))
(LetCont (k16 v15) (Branch (IsTrue v15) k4 k1))
(InvokeMethod v2 < v14 k16))
(InvokeContinuation k0 v1))
""";
void main() {
testRedundantPhi(CYCLIC_DEPS_IN, CYCLIC_DEPS_OUT);
}

View file

@ -1,309 +0,0 @@
// Copyright (c) 2014, 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 'sexpr_unstringifier.dart';
import "package:expect/expect.dart";
import 'package:compiler/src/cps_ir/cps_ir_nodes.dart';
import 'package:compiler/src/cps_ir/cps_ir_nodes_sexpr.dart';
import 'package:compiler/src/cps_ir/optimizers.dart';
// The 'read in loop' IR tests the most basic case of redundant phi removal
// and represents the following source code:
//
// void main() {
// int j = 42;
// for (int i = 0; i < 2; i++) {
// print(j.toString());
// }
// }
String READ_IN_LOOP_IN = """
(FunctionDefinition main () () return
(LetPrim (v0 (Constant (Int 42)))
(LetPrim (v1 (Constant (Int 0)))
(LetCont
((rec k0 (v2 v3)
(LetCont
((k1 ()
(LetPrim (v4 (Constant (Null)))
(InvokeContinuation return (v4))))
(k2 ()
(LetCont
((k3 (v5)
(LetCont
((k4 (v6)
(LetPrim (v7 (Constant (Int 1)))
(LetCont
((k5 (v8)
(InvokeContinuation rec k0 (v2 v8))))
(InvokeMethod v3 + (v7) k5)))))
(InvokeStatic print (v5) k4))))
(InvokeMethod v2 toString () k3))))
(LetPrim (v9 (Constant (Int 2)))
(LetCont
((k6 (v10)
(Branch (IsTrue v10) k2 k1)))
(InvokeMethod v3 < (v9) k6))))))
(InvokeContinuation k0 (v0 v1))))))
""";
String READ_IN_LOOP_OUT = """
(FunctionDefinition main () () return
(LetPrim (v0 (Constant (Int 42)))
(LetPrim (v1 (Constant (Int 0)))
(LetCont
((rec k0 (v2)
(LetCont
((k1 ()
(LetPrim (v3 (Constant (Null)))
(InvokeContinuation return (v3))))
(k2 ()
(LetCont
((k3 (v4)
(LetCont
((k4 (v5)
(LetPrim (v6 (Constant (Int 1)))
(LetCont
((k5 (v7)
(InvokeContinuation rec k0 (v7))))
(InvokeMethod v2 + (v6) k5)))))
(InvokeStatic print (v4) k4))))
(InvokeMethod v0 toString () k3))))
(LetPrim (v8 (Constant (Int 2)))
(LetCont
((k6 (v9)
(Branch (IsTrue v9) k2 k1)))
(InvokeMethod v2 < (v8) k6))))))
(InvokeContinuation k0 (v1))))))
""";
// The 'inner loop' IR represents the following source code:
//
// void main() {
// int j = 42;
// for (int i = 0; i < 2; i++) {
// for (int k = 0; k < 2; k++) {
// print(i.toString());
// }
// }
// print(j.toString());
// }
//
// This test case ensures that iterative optimization works: first, v8 and v9
// are removed from k5, and only then can k0 be optimized as well.
const String INNER_LOOP_IN = """
(FunctionDefinition main () () return
(LetPrim (v0 (Constant (Int 42)))
(LetPrim (v1 (Constant (Int 0)))
(LetCont
((rec k0 (v2 v3)
(LetCont
((k1 ()
(LetCont
((k2 (v4)
(LetCont
((k3 (v5)
(LetPrim (v6 (Constant (Null)))
(InvokeContinuation return (v6)))))
(InvokeStatic print (v4) k3))))
(InvokeMethod v2 toString () k2)))
(k4 ()
(LetPrim (v7 (Constant (Int 0)))
(LetCont
((rec k5 (v8 v9 v10)
(LetCont
((k6 ()
(LetPrim (v11 (Constant (Int 1)))
(LetCont
((k7 (v12)
(InvokeContinuation rec k0 (v8 v12))))
(InvokeMethod v9 + (v11) k7))))
(k8 ()
(LetCont
((k9 (v13)
(LetCont
((k10 (v14)
(LetPrim (v15 (Constant (Int 1)))
(LetCont
((k11 (v16)
(InvokeContinuation rec k5 (v8 v9 v16))))
(InvokeMethod v10 + (v15) k11)))))
(InvokeStatic print (v13) k10))))
(InvokeMethod v9 toString () k9))))
(LetPrim (v17 (Constant (Int 2)))
(LetCont
((k12 (v18)
(Branch (IsTrue v18) k8 k6)))
(InvokeMethod v10 < (v17) k12))))))
(InvokeContinuation k5 (v2 v3 v7))))))
(LetPrim (v19 (Constant (Int 2)))
(LetCont
((k13 (v20)
(Branch (IsTrue v20) k4 k1)))
(InvokeMethod v3 < (v19) k13))))))
(InvokeContinuation k0 (v0 v1))))))
""";
const String INNER_LOOP_OUT = """
(FunctionDefinition main () () return
(LetPrim (v0 (Constant (Int 42)))
(LetPrim (v1 (Constant (Int 0)))
(LetCont
((rec k0 (v2)
(LetCont
((k1 ()
(LetCont
((k2 (v3)
(LetCont
((k3 (v4)
(LetPrim (v5 (Constant (Null)))
(InvokeContinuation return (v5)))))
(InvokeStatic print (v3) k3))))
(InvokeMethod v0 toString () k2)))
(k4 ()
(LetPrim (v6 (Constant (Int 0)))
(LetCont
((rec k5 (v7)
(LetCont
((k6 ()
(LetPrim (v8 (Constant (Int 1)))
(LetCont
((k7 (v9)
(InvokeContinuation rec k0 (v9))))
(InvokeMethod v2 + (v8) k7))))
(k8 ()
(LetCont
((k9 (v10)
(LetCont
((k10 (v11)
(LetPrim (v12 (Constant (Int 1)))
(LetCont
((k11 (v13)
(InvokeContinuation rec k5 (v13))))
(InvokeMethod v7 + (v12) k11)))))
(InvokeStatic print (v10) k10))))
(InvokeMethod v2 toString () k9))))
(LetPrim (v14 (Constant (Int 2)))
(LetCont
((k12 (v15)
(Branch (IsTrue v15) k8 k6)))
(InvokeMethod v7 < (v14) k12))))))
(InvokeContinuation k5 (v6))))))
(LetPrim (v16 (Constant (Int 2)))
(LetCont
((k13 (v17)
(Branch (IsTrue v17) k4 k1)))
(InvokeMethod v2 < (v16) k13))))))
(InvokeContinuation k0 (v1))))))
""";
// There are no redundant phis in the 'basic loop' IR, and this test ensures
// simply that the optimization does not alter the IR. It represents the
// following program:
//
// void main() {
// for (int i = 0; i < 2; i++) {
// print(i.toString());
// }
// }
String BASIC_LOOP_IN = """
(FunctionDefinition main () () return
(LetPrim (v0 (Constant (Int 0)))
(LetCont
((rec k0 (v1)
(LetCont
((k1 ()
(LetPrim (v2 (Constant (Null)))
(InvokeContinuation return (v2))))
(k2 ()
(LetCont
((k3 (v3)
(LetCont
((k4 (v4)
(LetPrim (v5 (Constant (Int 1)))
(LetCont
((k5 (v6)
(InvokeContinuation rec k0 (v6))))
(InvokeMethod v1 + (v5) k5)))))
(InvokeStatic print (v3) k4))))
(InvokeMethod v1 toString () k3))))
(LetPrim (v7 (Constant (Int 2)))
(LetCont
((k6 (v8)
(Branch (IsTrue v8) k2 k1)))
(InvokeMethod v1 < (v7) k6))))))
(InvokeContinuation k0 (v0)))))
""";
String BASIC_LOOP_OUT = BASIC_LOOP_IN;
// Ensures that proper scoping is preserved, i.e. that the optimized
// continuation body does reference out of scope primitives.
// IR written by hand since this case is currently not being generated.
String SCOPING_IN = """
(FunctionDefinition main () () return
(LetCont
((k0 (v1)
(InvokeStatic print (v1) return)))
(LetPrim (v0 (Constant (Int 0)))
(LetPrim (v2 (Constant (Null)))
(InvokeContinuation k0 (v0))))))
""";
String SCOPING_OUT = """
(FunctionDefinition main () () return
(LetPrim (v0 (Constant (Int 0)))
(LetCont
((k0 ()
(InvokeStatic print (v0) return)))
(LetPrim (v1 (Constant (Null)))
(InvokeContinuation k0 ())))))
""";
// Ensures that continuations which are never invoked are not optimized.
// IR written by hand.
String NEVER_INVOKED_IN = """
(FunctionDefinition main () () return
(LetPrim (v0 (Constant (Int 0)))
(LetCont
((k0 (v1)
(InvokeStatic print (v1) return)))
(InvokeContinuation return (v0)))))
""";
String NEVER_INVOKED_OUT = NEVER_INVOKED_IN;
/// Normalizes whitespace by replacing all whitespace sequences by a single
/// space and trimming leading and trailing whitespace.
String normalizeSExpr(String input) {
return input.replaceAll(new RegExp(r'[ \n\t]+'), ' ').trim();
}
/// Parses the given input IR, runs a redundant phi pass over it, and compares
/// the stringification of the result against the expected output.
void testRedundantPhi(String input, String expectedOutput) {
final unstringifier = new SExpressionUnstringifier();
final stringifier = new SExpressionStringifier();
final optimizer = new RedundantPhiEliminator();
FunctionDefinition f = unstringifier.unstringify(input);
optimizer.rewrite(f);
String expected = normalizeSExpr(expectedOutput);
String actual = normalizeSExpr(stringifier.visit(f));
Expect.equals(expected, actual, "Actual:\n$actual");
}
void main() {
testRedundantPhi(READ_IN_LOOP_IN, READ_IN_LOOP_OUT);
testRedundantPhi(INNER_LOOP_IN, INNER_LOOP_OUT);
testRedundantPhi(BASIC_LOOP_IN, BASIC_LOOP_OUT);
testRedundantPhi(SCOPING_IN, SCOPING_OUT);
testRedundantPhi(NEVER_INVOKED_IN, NEVER_INVOKED_OUT);
}

View file

@ -1,331 +0,0 @@
// Copyright (c) 2014, 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 'sexpr_unstringifier.dart';
import "package:expect/expect.dart";
import 'package:compiler/src/cps_ir/cps_ir_nodes.dart';
import 'package:compiler/src/cps_ir/cps_ir_nodes_sexpr.dart';
import 'package:compiler/src/cps_ir/optimizers.dart';
// The tests in this file that ensure shrinking reductions work as expected.
// Reductions and their corresponding names are taken from
// 'Compiling with Continuations, Continued' by Andrew Kennedy.
// Basic dead-val: letprim x = V in K -> K (x not free in K).
//
// int main() {
// int i = 42;
// return 0;
// }
String DEAD_VAL_IN = """
(FunctionDefinition main () () return
(LetPrim (v0 (Constant (Int 42)))
(LetPrim (v1 (Constant (Int 0)))
(InvokeContinuation return (v1)))))
""";
String DEAD_VAL_OUT = """
(FunctionDefinition main () () return
(LetPrim (v0 (Constant (Int 0)))
(InvokeContinuation return (v0))))
""";
// Iterative dead-val. No optimizations possible since the continuation to
// InvokeMethod must have one argument, even if it is unused.
//
// int main() {
// int i = 42;
// int j = i + 1;
// return 0;
// }
String ITERATIVE_DEAD_VAL1_IN = """
(FunctionDefinition main () () return
(LetPrim (v0 (Constant (Int 42)))
(LetPrim (v1 (Constant (Int 1)))
(LetCont ((k0 (v2)
(LetPrim (v3 (Constant (Int 0)))
(InvokeContinuation return (v3)))))
(InvokeMethod v0 + (v1) k0)))))
""";
String ITERATIVE_DEAD_VAL1_OUT = ITERATIVE_DEAD_VAL1_IN;
// Iterative dead-val. IR written by hand.
String ITERATIVE_DEAD_VAL2_IN = """
(FunctionDefinition main () () return
(LetPrim (v0 (Constant (Int 42)))
(LetPrim (v1
(CreateFunction
(FunctionDefinition f () (i) return
(InvokeContinuation return (v0)))))
(LetPrim (v2 (Constant (Int 0)))
(InvokeContinuation return (v2))))))
""";
String ITERATIVE_DEAD_VAL2_OUT = """
(FunctionDefinition main () () return
(LetPrim (v0 (Constant (Int 0)))
(InvokeContinuation return (v0))))
""";
// Basic dead-cont: letcont k x = L in K -> K (k not free in K).
// IR written by hand.
String DEAD_CONT_IN = """
(FunctionDefinition main () () return
(LetPrim (v4 (Constant (Int 0)))
(LetCont ((k0 (v0)
(InvokeConstructor List () return)))
(LetCont ((k1 (v1)
(LetCont ((k2 (v2)
(LetPrim (v3 (Constant (Int 0)))
(InvokeContinuation return (v3)))))
(InvokeStatic print (v4) k2))))
(InvokeStatic print (v4) k1)))))
""";
String DEAD_CONT_OUT = """
(FunctionDefinition main () () return
(LetPrim (v0 (Constant (Int 0)))
(LetCont ((k0 (v1)
(LetCont ((k1 (v2)
(LetPrim (v3 (Constant (Int 0)))
(InvokeContinuation return (v3)))))
(InvokeStatic print (v0) k1))))
(InvokeStatic print (v0) k0))))
""";
// Iterative dead-cont. IR written by hand.
String ITERATIVE_DEAD_CONT_IN = """
(FunctionDefinition main () () return
(LetPrim (v4 (Constant (Int 0)))
(LetCont ((k0 (v0)
(InvokeConstructor List () return)))
(LetCont ((k3 (v5)
(InvokeContinuation k0 (v5))))
(LetCont ((k1 (v1)
(LetCont ((k2 (v2)
(LetPrim (v3 (Constant (Int 0)))
(InvokeContinuation return (v3)))))
(InvokeStatic print (v4) k2))))
(InvokeStatic print (v4) k1))))))
""";
String ITERATIVE_DEAD_CONT_OUT = """
(FunctionDefinition main () () return
(LetPrim (v0 (Constant (Int 0)))
(LetCont ((k0 (v1)
(LetCont ((k1 (v2)
(LetPrim (v3 (Constant (Int 0)))
(InvokeContinuation return (v3)))))
(InvokeStatic print (v0) k1))))
(InvokeStatic print (v0) k0))))
""";
// Beta-cont-lin: letcont k x = K in C[k y] -> C[K[y/x]] (k not free in C).
// IR written by hand.
String BETA_CONT_LIN_IN = """
(FunctionDefinition main () () return
(LetCont ((k0 (v0)
(LetCont ((k1 (v1)
(LetCont ((k2 (v2)
(LetPrim (v3 (Constant (Int 0)))
(InvokeContinuation return (v3)))))
(InvokeStatic print (v0) k2))))
(InvokeStatic print (v0) k1))))
(LetPrim (v4 (Constant (Int 0)))
(InvokeContinuation k0 (v4)))))
""";
String BETA_CONT_LIN_OUT = """
(FunctionDefinition main () () return
(LetPrim (v0 (Constant (Int 0)))
(LetCont ((k0 (v1)
(LetCont ((k1 (v2)
(LetPrim (v3 (Constant (Int 0)))
(InvokeContinuation return (v3)))))
(InvokeStatic print (v0) k1))))
(InvokeStatic print (v0) k0))))
""";
// Beta-cont-lin with recursive continuation. IR written by hand.
String RECURSIVE_BETA_CONT_LIN_IN = """
(FunctionDefinition main () () return
(LetCont ((rec k0 (v0)
(InvokeContinuation rec k0 (v0))))
(LetPrim (v1 (Constant (Int 0)))
(InvokeContinuation k0 (v1)))))
""";
String RECURSIVE_BETA_CONT_LIN_OUT = RECURSIVE_BETA_CONT_LIN_IN;
// Beta-cont-lin used inside body. IR written by hand.
String USED_BETA_CONT_LIN_IN = """
(FunctionDefinition main () () return
(LetPrim (v0 (Constant (Int 0)))
(LetCont ((k0 (v1)
(LetCont ((k1 (v2)
(LetCont ((k2 (v3)
(LetPrim (v4 (Constant (Int 0)))
(InvokeContinuation return (v4)))))
(InvokeStatic print (v1) k2))))
(InvokeStatic print (v1) k1))))
(LetPrim (v5
(CreateFunction
(FunctionDefinition f () () return
(InvokeContinuation return (v1)))))
(InvokeContinuation k0 (v0))))))
""";
String USED_BETA_CONT_LIN_OUT = """
(FunctionDefinition main () () return
(LetPrim (v0 (Constant (Int 0)))
(LetCont ((k0 (v1)
(LetCont ((k1 (v2)
(LetPrim (v3 (Constant (Int 0)))
(InvokeContinuation return (v3)))))
(InvokeStatic print (v0) k1))))
(InvokeStatic print (v0) k0))))
""";
// Eta-cont: letcont k x = j x in K -> K[j/k].
// IR written by hand.
//
// This test is incorrectly named: with the current implementation, there is no
// eta reduction. Instead, dead-parameter, beta-cont-lin, and dead-val
// reductions are performed, which in turn creates a second beta-cont-lin
// reduction.
//
// TODO(kmillikin): To test continuation eta reduction, use eta redexes that are
// not overlapping beta redexes.
String ETA_CONT_IN = """
(FunctionDefinition main () () return
(LetPrim (v0 (Constant (Int 0)))
(LetCont ((rec k0 (v1)
(InvokeContinuation return (v0))))
(LetCont ((k1 (v2)
(InvokeContinuation k0 (v2))))
(LetPrim (v3
(CreateFunction
(FunctionDefinition f () () return
(InvokeContinuation k0 (v0)))))
(InvokeContinuation k1 (v0)))))))
""";
String ETA_CONT_OUT = """
(FunctionDefinition main () () return
(LetPrim (v0 (Constant (Int 0)))
(InvokeContinuation return (v0))))
""";
// Dead-parameter:
// letcont k x = E0 in E1 -> letcont k () = E0 in E1,
// if x does not occur free in E0.
// Parameter v1 is unused in k0.
String DEAD_PARAMETER_IN = """
(FunctionDefinition main () (x) return
(LetCont ((k0 (v0 v1 v2)
(InvokeStatic foo (v0 v2) return)))
(LetCont ((k1 ()
(LetPrim (v3 (Constant (Int 0)))
(LetPrim (v4 (Constant (Int 1)))
(LetPrim (v5 (Constant (Int 2)))
(InvokeContinuation k0 (v3 v4 v5))))))
(k2 ()
(LetPrim (v6 (Constant (Int 3)))
(LetPrim (v7 (Constant (Int 4)))
(LetPrim (v8 (Constant (Int 5)))
(InvokeContinuation k0 (v6 v7 v8)))))))
(Branch (IsTrue x) k1 k2))))
""";
String DEAD_PARAMETER_OUT = """
(FunctionDefinition main () (x) return
(LetCont ((k0 (v0 v1)
(InvokeStatic foo (v0 v1) return)))
(LetCont ((k1 ()
(LetPrim (v2 (Constant (Int 0)))
(LetPrim (v3 (Constant (Int 2)))
(InvokeContinuation k0 (v2 v3)))))
(k2 ()
(LetPrim (v4 (Constant (Int 3)))
(LetPrim (v5 (Constant (Int 5)))
(InvokeContinuation k0 (v4 v5))))))
(Branch (IsTrue x) k1 k2))))
""";
// Create an eta-cont redex:
// Dead parameter reductions can create an eta-cont redex by removing unused
// continuation parameters and thus creating the eta redex.
String CREATE_ETA_CONT_IN = """
(FunctionDefinition main () (x) return
(LetCont ((rec loop (v0)
(InvokeContinuation rec loop (v0))))
(LetCont ((created (v1 v2 v3)
(InvokeContinuation loop (v2))))
(LetCont ((then ()
(LetPrim (v4 (Constant (Int 0)))
(LetPrim (v5 (Constant (Int 1)))
(LetPrim (v6 (Constant (Int 2)))
(InvokeContinuation created (v4 v5 v6))))))
(else ()
(LetPrim (v6 (Constant (Int 3)))
(LetPrim (v7 (Constant (Int 4)))
(LetPrim (v8 (Constant (Int 5)))
(InvokeContinuation created (v6 v7 v8)))))))
(Branch (IsTrue x) then else)))))
""";
String CREATE_ETA_CONT_OUT = """
(FunctionDefinition main () (x) return
(LetCont ((rec k0 (v0)
(InvokeContinuation rec k0 (v0))))
(LetCont ((k1 ()
(LetPrim (v1 (Constant (Int 1)))
(InvokeContinuation k0 (v1))))
(k2 ()
(LetPrim (v2 (Constant (Int 4)))
(InvokeContinuation k0 (v2)))))
(Branch (IsTrue x) k1 k2))))
""";
// Beta-fun-lin and eta-fun might not apply to us, since
// a. in (InvokeMethod v0 call k0), v0 might carry state, and
// b. there is no way to generate static nested functions that we could
// use InvokeStatic on.
/// Normalizes whitespace by replacing all whitespace sequences by a single
/// space and trimming leading and trailing whitespace.
String normalizeSExpr(String input) {
return input.replaceAll(new RegExp(r'[ \n\t]+'), ' ').trim();
}
/// Parses the given input IR, runs an optimization pass over it, and compares
/// the stringification of the result against the expected output.
void testShrinkingReducer(String input, String expectedOutput) {
final unstringifier = new SExpressionUnstringifier();
final stringifier = new SExpressionStringifier();
final optimizer = new ShrinkingReducer();
FunctionDefinition f = unstringifier.unstringify(input);
optimizer.rewrite(f);
String expected = normalizeSExpr(expectedOutput);
String actual = normalizeSExpr(stringifier.visit(f));
Expect.equals(expected, actual);
}
void main() {
testShrinkingReducer(DEAD_VAL_IN, DEAD_VAL_OUT);
testShrinkingReducer(ITERATIVE_DEAD_VAL1_IN, ITERATIVE_DEAD_VAL1_OUT);
testShrinkingReducer(ITERATIVE_DEAD_VAL2_IN, ITERATIVE_DEAD_VAL2_OUT);
testShrinkingReducer(DEAD_CONT_IN, DEAD_CONT_OUT);
testShrinkingReducer(ITERATIVE_DEAD_CONT_IN, ITERATIVE_DEAD_CONT_OUT);
testShrinkingReducer(BETA_CONT_LIN_IN, BETA_CONT_LIN_OUT);
testShrinkingReducer(RECURSIVE_BETA_CONT_LIN_IN, RECURSIVE_BETA_CONT_LIN_OUT);
testShrinkingReducer(USED_BETA_CONT_LIN_IN, USED_BETA_CONT_LIN_OUT);
testShrinkingReducer(ETA_CONT_IN, ETA_CONT_OUT);
testShrinkingReducer(DEAD_PARAMETER_IN, DEAD_PARAMETER_OUT);
testShrinkingReducer(CREATE_ETA_CONT_IN, CREATE_ETA_CONT_OUT);
}

View file

@ -1,62 +0,0 @@
// Copyright (c) 2014, 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.
/// Unittest test of the CPS ir generated by the dart2dart compiler.
library dart_backend.sexpr2_test;
import 'package:compiler/src/compiler.dart';
import 'package:compiler/src/cps_ir/cps_ir_nodes.dart';
import 'package:compiler/src/cps_ir/cps_ir_nodes_sexpr.dart';
import 'package:compiler/src/elements/elements.dart';
import 'package:expect/expect.dart';
import '../../../../pkg/analyzer2dart/test/test_helper.dart';
import '../../../../pkg/analyzer2dart/test/sexpr_data.dart';
import 'test_helper.dart';
main(List<String> args) {
performTests(TEST_DATA, asyncTester, runTest, args);
}
runTest(TestSpec result) {
return compilerFor(result.input).then((Compiler compiler) {
void checkOutput(String elementName,
Element element,
String expectedOutput) {
FunctionDefinition ir = compiler.irBuilder.getIr(element);
if (expectedOutput == null) {
Expect.isNull(ir, "\nInput:\n${result.input}\n"
"No CPS IR expected for $element");
} else {
Expect.isNotNull(ir, "\nInput:\n${result.input}\n"
"No CPS IR for $element");
expectedOutput = expectedOutput.trim();
String output = ir.accept(new SExpressionStringifier()).trim();
Expect.equals(expectedOutput, output,
"\nInput:\n${result.input}\n"
"Expected for '$elementName':\n$expectedOutput\n"
"Actual for '$elementName':\n$output\n");
}
}
if (result.output is String) {
checkOutput('main', compiler.mainFunction, result.output);
} else {
assert(result.output is Map<String, String>);
result.output.forEach((String elementName, String output) {
Element element;
if (elementName.contains('.')) {
ClassElement cls = compiler.mainApp.localLookup(
elementName.substring(0, elementName.indexOf('.')));
element = cls.localLookup(
elementName.substring(elementName.indexOf('.') + 1));
} else {
element = compiler.mainApp.localLookup(elementName);
}
checkOutput(elementName, element, output);
});
}
});
}

View file

@ -1,177 +0,0 @@
// Copyright (c) 2014, 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 dart_backend.sexpr_test;
import 'dart:async';
import 'package:async_helper/async_helper.dart';
import 'package:compiler/src/compiler.dart';
import 'package:compiler/src/cps_ir/cps_ir_nodes.dart';
import 'package:compiler/src/cps_ir/cps_ir_nodes_sexpr.dart';
import 'package:expect/expect.dart';
import '../compiler_helper.dart' hide compilerFor;
import 'sexpr_unstringifier.dart';
import 'test_helper.dart';
const String CODE = """
class Foo {
static int x = 1;
foo() => 42;
}
class Bar extends Foo {
int y = 2;
Bar() {
Foo.x = 2;
}
foo() => this.y + super.foo();
}
class FooBar<T> {
bool foobar() => T is int;
}
main() {
Foo foo;
if (foo is Foo) {
print("Surprise");
}
String inner() => "Inner function";
print(inner());
int j = 42;
for (int i = 0; i < 2; i++) {
print(i.toString());
}
print(Foo.x);
String recursive(int h) {
if (h < 1) {
return j.toString();
}
j++;
return "h\$\{recursive(h - 1)\}";
}
print(recursive(5));
Bar bar = new Bar();
print(bar.foo().toString());
bar = foo as Bar;
if (bar == null) {
var list = [1, 2, 3, 4];
var map = { 1: "one"
, 2: "two"
, 3: "three"
};
var double = 3.14;
list.forEach((i) => print(i.toString()));
print("\$list \$map \$double");
}
print(new FooBar<int>().foobar());
}
""";
bool shouldOutput(Element element) {
return (!element.library.isPlatformLibrary &&
!element.isSynthesized &&
element.kind == ElementKind.FUNCTION);
}
/// Compiles the given dart code (which must include a 'main' function) and
/// returns a list of all generated CPS IR definitions.
Future<List<FunctionDefinition>> compile(String code) {
return compilerFor(code).then((Compiler compiler) {
return compiler.enqueuer.resolution.resolvedElements
.where(shouldOutput)
.map(compiler.irBuilder.getIr)
.toList();
});
}
/// Returns an S-expression string for each compiled function.
List<String> stringifyAll(Iterable<FunctionDefinition> functions) {
final stringifier = new SExpressionStringifier();
return functions.map((f) => stringifier.visitFunctionDefinition(f)).toList();
}
Future<List<String>> testStringifier(String code,
Iterable<String> expectedTokens) {
return compile(code)
.then((List<FunctionDefinition> functions) {
List<String> sexprs = stringifyAll(functions);
String combined = sexprs.join();
String withoutNullConstants = combined.replaceAll("Constant null", "");
Expect.isFalse(withoutNullConstants.contains("null"));
for (String token in expectedTokens) {
Expect.isTrue(combined.contains(token),
"'$combined' doesn't contain '$token' in test:\n$code");
}
return sexprs;
});
}
/// Checks if the generated S-expressions can be processed by the unstringifier,
/// returns the resulting definitions.
List<FunctionDefinition> testUnstringifier(List<String> sexprs) {
return sexprs.map((String sexpr) {
try {
final function = new SExpressionUnstringifier().unstringify(sexpr);
Expect.isNotNull(function, "Unstringification failed:\n\n$sexpr");
return function;
} catch (e, s) {
print('$e\n$s');
Expect.fail('Error unstringifying "$sexpr": $e');
}
}).toList();
}
void main() {
final tokens =
[ "FunctionDefinition"
, "IsTrue"
// Expressions
, "Branch"
, "ConcatenateStrings"
, "DeclareFunction"
, "InvokeConstructor"
, "InvokeContinuation"
, "InvokeMethod"
, "InvokeStatic"
, "InvokeMethodDirectly"
, "LetCont"
, "LetPrim"
, "SetMutableVariable"
, "TypeOperator"
// Primitives
, "Constant"
, "CreateFunction"
, "GetMutableVariable"
, "LiteralList"
, "LiteralMap"
// Parameters are encoded by name only and hence are not in this list.
, "ReifyTypeVar"
, "(this)" // 'this' Parameter declarations
, "this" // 'this' Parameter uses
];
asyncTest(() => testStringifier(CODE, tokens).then((List<String> sexprs) {
final functions = testUnstringifier(sexprs);
// Ensure that
// stringified(CODE) == stringified(unstringified(stringified(CODE)))
Expect.listEquals(sexprs, stringifyAll(functions));
}));
}

View file

@ -1,885 +0,0 @@
// Copyright (c) 2014, 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.
// SExpressionUnstringifier implements the inverse operation to
// [SExpressionStringifier].
library sexpr_unstringifier;
import 'package:compiler/src/constants/expressions.dart';
import 'package:compiler/src/constants/values.dart';
import 'package:compiler/src/dart_types.dart' as dart_types
show DartType;
import 'package:compiler/src/diagnostics/messages.dart'
show MessageKind;
import 'package:compiler/src/elements/elements.dart';
import 'package:compiler/src/elements/modelx.dart'
show ErroneousElementX, TypeVariableElementX;
import 'package:compiler/src/tree/tree.dart' show LiteralDartString;
import 'package:compiler/src/universe/call_structure.dart'
show CallStructure;
import 'package:compiler/src/universe/selector.dart'
show Selector, SelectorKind;
import 'package:compiler/src/cps_ir/cps_ir_nodes.dart';
/// Used whenever a node constructed by [SExpressionUnstringifier] needs a
/// named entity.
class DummyEntity extends Entity {
final String name;
DummyEntity(this.name);
}
/// Used whenever a node constructed by [SExpressionUnstringifier] needs a
/// local.
class DummyLocal extends DummyEntity implements Local {
DummyLocal(String name) : super(name);
ExecutableElement get executableContext => null;
}
// TODO(karlklose): we should remove all references to [ErroneousElement] from
// the CPS IR. Instead, the builder must construct appropriate terms for ASTs
// that could not be resolved correctly. Perhaps the IR should not rely on
// elements at all for naming.
/// Used whenever a node constructed by [SExpressionUnstringifier] requires
/// an [Element] or [FunctionElement]. Extends [ErroneousElementX] since there
/// is currently a large amount of overhead when extending the base abstract
/// classes, and erroneous elements conveniently also skip several assertion
/// checks in CPS IR nodes that are irrelevant to us.
class DummyElement extends ErroneousElementX
implements TypeVariableElement, FieldElement {
DummyElement(String name)
: super(MessageKind.GENERIC, {}, name, null);
final dart_types.DartType bound = null;
final TypeDeclarationElement typeDeclaration = null;
noSuchMethod(inv) => super.noSuchMethod(inv);
}
/// Used whenever a node constructed by [SExpressionUnstringifier] requires
/// a named type.
class DummyNamedType extends dart_types.DartType {
final String name;
final kind = null;
final element = null;
DummyNamedType(this.name);
subst(arguments, parameters) => null;
unalias(compiler) => null;
accept(visitor, argument) => null;
String toString() => name;
}
/// Represents a list of tokens, but is basically a partial view into a list
/// with appropriate convenience methods.
class Tokens {
final List<String> _list;
int _index; // Current index into the list.
Tokens(List<String> this._list) : _index = 0;
String get current => _list[_index];
String get next => _list[_index + 1];
String read([String expected]) {
if (expected != null) {
if (current != expected) {
print('expected "$expected", found "$current"');
int start = _index - 15;
String dotdotdot = '... ';
if (start < 0) {
start = 0;
dotdotdot = '';
}
print('${dotdotdot}${_list.sublist(start, _index + 1).join(' ')}');
assert(current == expected);
}
}
return _list[_index++];
}
/// Consumes the preamble to a new node, consisting of an opening parenthesis
/// and a tag.
void consumeStart([String tag]) {
read("(");
if (tag != null) {
read(tag);
}
}
void consumeEnd() {
read(")");
}
bool get hasNext => _index < _list.length;
String toString() => _list.sublist(_index).toString();
}
/// Constructs a minimal in-memory representation of the IR represented
/// by the given string. Many fields are currently simply set to null.
class SExpressionUnstringifier {
// Expressions
static const String BRANCH = "Branch";
static const String CONCATENATE_STRINGS = "ConcatenateStrings";
static const String DECLARE_FUNCTION = "DeclareFunction";
static const String INVOKE_CONSTRUCTOR = "InvokeConstructor";
static const String INVOKE_CONTINUATION = "InvokeContinuation";
static const String INVOKE_STATIC = "InvokeStatic";
static const String INVOKE_METHOD_DIRECTLY = "InvokeMethodDirectly";
static const String INVOKE_METHOD = "InvokeMethod";
static const String LET_PRIM = "LetPrim";
static const String LET_CONT = "LetCont";
static const String LET_MUTABLE = "LetMutable";
static const String TYPE_CAST = "TypeCast";
static const String GET_LAZY_STATIC = "GetLazyStatic";
static const String UNREACHABLE = "Unreachable";
// Primitives
static const String CONSTANT = "Constant";
static const String CREATE_FUNCTION = "CreateFunction";
static const String GET_MUTABLE = "GetMutable";
static const String SET_MUTABLE = "SetMutable";
static const String LITERAL_LIST = "LiteralList";
static const String LITERAL_MAP = "LiteralMap";
static const String REIFY_TYPE_VAR = "ReifyTypeVar";
static const String GET_STATIC = "GetStatic";
static const String SET_STATIC = "SetStatic";
static const String TYPE_TEST = "TypeTest";
static const String APPLY_BUILTIN_OPERATOR = "ApplyBuiltinOperator";
static const String GET_LENGTH = "GetLength";
static const String GET_INDEX = "GetIndex";
static const String SET_INDEX = "SetIndex";
static const String GET_FIELD = "GetField";
static const String SET_FIELD = "SetField";
// Other
static const String FUNCTION_DEFINITION = "FunctionDefinition";
static const String IS_TRUE = "IsTrue";
// Constants
static const String BOOL = "Bool";
static const String DOUBLE = "Double";
static const String INT = "Int";
static const String NULL = "Null";
static const String STRING = "String";
final Map<String, Definition> name2variable =
<String, Definition>{ "return": new Continuation.retrn() };
// Operator names used for canonicalization. In theory, we could simply use
// Elements.isOperatorName() on the parsed tokens; however, comparisons are
// done using identical() for performance reasons, which are reliable only for
// compile-time literal strings.
static Set<String> OPERATORS = new Set<String>.from(
[ '~', '==', '[]', '*', '/', '%', '~/', '+', '<<', 'unary-'
, '>>', '>=', '>', '<=', '<', '&', '^', '|', '[]=', '-'
]);
// The tokens currently being parsed.
Tokens tokens;
FunctionDefinition unstringify(String s) {
tokens = tokenize(s);
FunctionDefinition def = parseFunctionDefinition();
assert(!tokens.hasNext);
return def;
}
/// Returns a new named dummy selector with a roughly appropriate kind.
Selector dummySelector(String name, int argumentCount) {
SelectorKind kind;
if (name == "[]") {
kind = SelectorKind.INDEX;
} else if (Elements.isOperatorName(name)) {
kind = SelectorKind.OPERATOR;
} else {
kind = SelectorKind.CALL;
}
return new Selector(kind, new PublicName(name),
new CallStructure.unnamed(argumentCount));
}
/// Returns the tokens in s. Note that string literals are not necessarily
/// preserved; for instance, "(literalString)" is transformed to
/// " ( literalString ) ".
Tokens tokenize(String s) =>
new Tokens(
s.replaceAll("(", " ( ")
.replaceAll(")", " ) ")
.replaceAll("{", " { ")
.replaceAll("}", " } ")
.replaceAll(new RegExp(r"[ \t\n]+"), " ")
.trim()
.split(" ")
.map(canonicalizeOperators)
.toList());
/// Canonicalizes strings containing operator names.
String canonicalizeOperators(String token) {
String opname = OPERATORS.lookup(token);
if (opname != null) {
return opname;
}
return token;
}
Expression parseExpression() {
assert(tokens.current == "(");
switch (tokens.next) {
case BRANCH:
return parseBranch();
case CONCATENATE_STRINGS:
return parseConcatenateStrings();
case DECLARE_FUNCTION:
return parseDeclareFunction();
case INVOKE_CONSTRUCTOR:
return parseInvokeConstructor();
case INVOKE_CONTINUATION:
return parseInvokeContinuation();
case INVOKE_METHOD:
return parseInvokeMethod();
case INVOKE_STATIC:
return parseInvokeStatic();
case INVOKE_METHOD_DIRECTLY:
return parseInvokeMethodDirectly();
case LET_PRIM:
return parseLetPrim();
case LET_CONT:
return parseLetCont();
case LET_MUTABLE:
return parseLetMutable();
case TYPE_CAST:
return parseTypeCast();
case GET_LAZY_STATIC:
return parseGetLazyStatic();
case UNREACHABLE:
return parseUnreachable();
default:
assert(false);
}
return null;
}
/// (prim1 prim2 ... primn)
List<Primitive> parsePrimitiveList() {
tokens.consumeStart();
List<Primitive> prims = <Primitive>[];
while (tokens.current != ")") {
Primitive prim = name2variable[tokens.read()];
assert(prim != null);
prims.add(prim);
}
tokens.consumeEnd();
return prims;
}
/// (FunctionDefinition name (parameters) continuation body)
FunctionDefinition parseFunctionDefinition() {
tokens.consumeStart(FUNCTION_DEFINITION);
// name
Element element = new DummyElement("");
if (tokens.current != '(') {
// This is a named function.
element = new DummyElement(tokens.read());
}
// (this) or ()
Definition thisParameter = null;
tokens.consumeStart();
if (tokens.current != ')') {
String thisName = tokens.read();
if (name2variable.containsKey(thisName)) {
thisParameter = name2variable[thisName];
} else {
thisParameter = new Parameter(new DummyElement(thisName));
name2variable[thisName] = thisParameter;
}
}
tokens.consumeEnd();
// (parameters)
List<Definition> parameters = <Definition>[];
tokens.consumeStart();
while (tokens.current != ")") {
String paramName = tokens.read();
if (name2variable.containsKey(paramName)) {
parameters.add(name2variable[paramName]);
} else {
Parameter param = new Parameter(new DummyElement(paramName));
name2variable[paramName] = param;
parameters.add(param);
}
}
tokens.consumeEnd();
// continuation
String contName = tokens.read("return");
Continuation cont = name2variable[contName];
assert(cont != null);
// body
Expression body = parseExpression();
tokens.consumeEnd();
return new FunctionDefinition(element, thisParameter, parameters,
new Body(body, cont), null, null);
}
/// (IsTrue arg)
Condition parseCondition() {
// Handles IsTrue only for now.
tokens.consumeStart(IS_TRUE);
Definition value = name2variable[tokens.read()];
assert(value != null);
tokens.consumeEnd();
return new IsTrue(value);
}
/// (Branch condition cont cont)
Branch parseBranch() {
tokens.consumeStart(BRANCH);
Condition cond = parseCondition();
Continuation trueCont = name2variable[tokens.read()];
Continuation falseCont = name2variable[tokens.read()];
assert(trueCont != null && falseCont != null);
tokens.consumeEnd();
return new Branch(cond, trueCont, falseCont);
}
/// (ConcatenateStrings (args) cont)
ConcatenateStrings parseConcatenateStrings() {
tokens.consumeStart(CONCATENATE_STRINGS);
List<Primitive> args = parsePrimitiveList();
Continuation cont = name2variable[tokens.read()];
assert(cont != null);
tokens.consumeEnd();
return new ConcatenateStrings(args, cont);
}
/// (DeclareFunction name = function in body)
DeclareFunction parseDeclareFunction() {
tokens.consumeStart(DECLARE_FUNCTION);
// name =
MutableVariable local = addMutableVariable(tokens.read());
tokens.read("=");
// function in
FunctionDefinition def = parseFunctionDefinition();
tokens.read("in");
// body
Expression body = parseExpression();
tokens.consumeEnd();
return new DeclareFunction(local, def)..plug(body);
}
/// (InvokeConstructor name (args) cont)
InvokeConstructor parseInvokeConstructor() {
tokens.consumeStart(INVOKE_CONSTRUCTOR);
String constructorName = tokens.read();
List<String> split = constructorName.split(".");
assert(split.length < 3);
dart_types.DartType type = new DummyNamedType(split[0]);
Element element = new DummyElement((split.length == 1) ? "" : split[1]);
List<Primitive> args = parsePrimitiveList();
Continuation cont = name2variable[tokens.read()];
assert(cont != null);
tokens.consumeEnd();
Selector selector = dummySelector(constructorName, args.length);
return new InvokeConstructor(type, element, selector, args, cont);
}
/// (InvokeContinuation rec? name (args))
InvokeContinuation parseInvokeContinuation() {
tokens.consumeStart(INVOKE_CONTINUATION);
String name = tokens.read();
bool isRecursive = name == "rec";
if (isRecursive) name = tokens.read();
Continuation cont = name2variable[name];
assert(cont != null);
List<Primitive> args = parsePrimitiveList();
tokens.consumeEnd();
return new InvokeContinuation(cont, args, isRecursive: isRecursive);
}
/// (InvokeMethod receiver method (args) cont)
InvokeMethod parseInvokeMethod() {
tokens.consumeStart(INVOKE_METHOD);
Definition receiver = name2variable[tokens.read()];
assert(receiver != null);
String methodName = tokens.read();
List<Primitive> args = parsePrimitiveList();
Continuation cont = name2variable[tokens.read()];
assert(cont != null);
tokens.consumeEnd();
Selector selector = dummySelector(methodName, args.length);
return new InvokeMethod(receiver, selector, args, cont);
}
/// (InvokeStatic method (args) cont)
InvokeStatic parseInvokeStatic() {
tokens.consumeStart(INVOKE_STATIC);
String methodName = tokens.read();
List<Primitive> args = parsePrimitiveList();
Continuation cont = name2variable[tokens.read()];
assert(cont != null);
Entity entity = new DummyEntity(methodName);
Selector selector = dummySelector(methodName, args.length);
tokens.consumeEnd();
return new InvokeStatic(entity, selector, args, cont, null);
}
/// (InvokeMethodDirectly receiver method (args) cont)
InvokeMethodDirectly parseInvokeMethodDirectly() {
tokens.consumeStart(INVOKE_METHOD_DIRECTLY);
Definition receiver = name2variable[tokens.read()];
assert(receiver != null);
String methodName = tokens.read();
List<Primitive> args = parsePrimitiveList();
Continuation cont = name2variable[tokens.read()];
assert(cont != null);
tokens.consumeEnd();
Element element = new DummyElement(methodName);
Selector selector = dummySelector(methodName, args.length);
return new InvokeMethodDirectly(receiver, element, selector, args, cont);
}
// (rec? name (args) body)
Continuation parseContinuation() {
// (rec? name
tokens.consumeStart();
String name = tokens.read();
bool isRecursive = name == "rec";
if (isRecursive) name = tokens.read();
// (args)
tokens.consumeStart();
List<Parameter> params = <Parameter>[];
while (tokens.current != ")") {
String paramName = tokens.read();
Parameter param = new Parameter(new DummyElement(paramName));
name2variable[paramName] = param;
params.add(param);
}
tokens.consumeEnd();
Continuation cont = new Continuation(params);
name2variable[name] = cont;
cont.isRecursive = isRecursive;
// cont_body
cont.body = parseExpression();
tokens.consumeEnd();
return cont;
}
/// (LetCont (continuations) body)
LetCont parseLetCont() {
tokens.consumeStart(LET_CONT);
tokens.consumeStart();
List<Continuation> continuations = <Continuation>[];
while (tokens.current != ")") {
continuations.add(parseContinuation());
}
tokens.consumeEnd();
// body)
Expression body = parseExpression();
tokens.consumeEnd();
return new LetCont.many(continuations, body);
}
/// (LetMutable (name value) body)
LetMutable parseLetMutable() {
tokens.consumeStart(LET_MUTABLE);
tokens.consumeStart();
String name = tokens.read();
MutableVariable local = addMutableVariable(name);
Primitive value = name2variable[tokens.read()];
tokens.consumeEnd();
Expression body = parseExpression();
tokens.consumeEnd();
return new LetMutable(local, value)..plug(body);
}
/// (SetMutable name value)
SetMutable parseSetMutable() {
tokens.consumeStart(SET_MUTABLE);
MutableVariable local = name2variable[tokens.read()];
Primitive value = name2variable[tokens.read()];
assert(value != null);
tokens.consumeEnd();
return new SetMutable(local, value);
}
/// (TypeCast value type args cont)
TypeCast parseTypeCast() {
tokens.consumeStart(TYPE_CAST);
Primitive value = name2variable[tokens.read()];
assert(value != null);
dart_types.DartType type = new DummyNamedType(tokens.read());
List<ir.Primitive> typeArguments = parsePrimitiveList();
Continuation cont = name2variable[tokens.read()];
assert(cont != null);
tokens.consumeEnd();
return new TypeCast(value, type, typeArguments, cont);
}
/// (TypeTest value type args)
TypeTest parseTypeTest() {
tokens.consumeStart(TYPE_TEST);
Primitive value = name2variable[tokens.read()];
assert(value != null);
dart_types.DartType type = new DummyNamedType(tokens.read());
List<ir.Primitive> typeArguments = parsePrimitiveList();
tokens.consumeEnd();
return new TypeTest(value, type, typeArguments);
}
/// (ApplyBuiltinOperator operator args)
ApplyBuiltinOperator parseApplyBuiltinOperator() {
tokens.consumeStart(APPLY_BUILTIN_OPERATOR);
String operatorName = tokens.read();
BuiltinOperator operator;
for (BuiltinOperator op in BuiltinOperator.values) {
if (op.toString() == operatorName) {
operator = op;
break;
}
}
assert(operator != null);
List<ir.Primitive> arguments = parsePrimitiveList();
tokens.consumeEnd();
return new ApplyBuiltinOperator(operator, arguments);
}
/// (GetLength object)
GetLength parseGetLength() {
tokens.consumeStart(GET_LENGTH);
Primitive object = name2variable[tokens.read()];
tokens.consumeEnd();
return new GetLength(object);
}
/// (GetIndex object index)
GetIndex parseGetIndex() {
tokens.consumeStart(GET_INDEX);
Primitive object = name2variable[tokens.read()];
Primitive index = name2variable[tokens.read()];
tokens.consumeEnd();
return new GetIndex(object, index);
}
/// (SetIndex object index value)
SetIndex parseSetIndex() {
tokens.consumeStart(SET_INDEX);
Primitive object = name2variable[tokens.read()];
Primitive index = name2variable[tokens.read()];
Primitive value = name2variable[tokens.read()];
tokens.consumeEnd();
return new SetIndex(object, index, value);
}
/// (SetStatic field value)
SetStatic parseSetStatic() {
tokens.consumeStart(SET_STATIC);
Element fieldElement = new DummyElement(tokens.read());
Primitive value = name2variable[tokens.read()];
assert(value != null);
tokens.consumeEnd();
return new SetStatic(fieldElement, value, null);
}
/// (GetLazyStatic field cont)
GetLazyStatic parseGetLazyStatic() {
tokens.consumeStart(GET_LAZY_STATIC);
Element fieldElement = new DummyElement(tokens.read());
Continuation cont = name2variable[tokens.read()];
assert(cont != null);
tokens.consumeEnd();
return new GetLazyStatic(fieldElement, cont, null);
}
/// (Unreachable)
Unreachable parseUnreachable() {
tokens.consumeStart(UNREACHABLE);
tokens.consumeEnd();
return new Unreachable();
}
/// (LetPrim (name primitive) body)
LetPrim parseLetPrim() {
tokens.consumeStart(LET_PRIM);
// (name
tokens.consumeStart();
String name = tokens.read();
// primitive)
Primitive primitive = parsePrimitive();
name2variable[name] = primitive;
tokens.consumeEnd();
// body)
Expression body = parseExpression();
tokens.consumeEnd();
return new LetPrim(primitive)..plug(body);
}
Primitive parsePrimitive() {
assert(tokens.current == "(");
switch (tokens.next) {
case CONSTANT:
return parseConstant();
case CREATE_FUNCTION:
return parseCreateFunction();
case GET_MUTABLE:
return parseGetMutable();
case SET_MUTABLE:
return parseSetMutable();
case LITERAL_LIST:
return parseLiteralList();
case LITERAL_MAP:
return parseLiteralMap();
case REIFY_TYPE_VAR:
return parseReifyTypeVar();
case GET_STATIC:
return parseGetStatic();
case SET_STATIC:
return parseSetStatic();
case TYPE_TEST:
return parseTypeTest();
case APPLY_BUILTIN_OPERATOR:
return parseApplyBuiltinOperator();
case GET_LENGTH:
return parseGetLength();
case GET_INDEX:
return parseGetIndex();
case SET_INDEX:
return parseSetIndex();
case GET_FIELD:
return parseGetField();
case SET_FIELD:
return parseSetField();
default:
assert(false);
}
return null;
}
/// (Constant (constant))
Constant parseConstant() {
tokens.consumeStart(CONSTANT);
tokens.consumeStart();
Constant result;
String tag = tokens.read();
switch (tag) {
case NULL:
result = new Constant(
new NullConstantExpression(new NullConstantValue()));
break;
case BOOL:
String value = tokens.read();
if (value == "true") {
result = new Constant(
new BoolConstantExpression(true, new TrueConstantValue()));
} else if (value == "false") {
result = new Constant(
new BoolConstantExpression(false, new FalseConstantValue()));
} else {
throw "Invalid Boolean value '$value'.";
}
break;
case STRING:
List<String> strings = <String>[];
do {
strings.add(tokens.read());
} while (tokens.current != ")");
String string = strings.join(" ");
assert(string.startsWith('"') && string.endsWith('"'));
String text = string.substring(1, string.length - 1);
StringConstantValue value = new StringConstantValue(
new LiteralDartString(text));
result = new Constant(new StringConstantExpression(text, value));
break;
case INT:
String value = tokens.read();
int intValue = int.parse(value, onError: (_) => null);
if (intValue == null) {
throw "Invalid int value 'value'.";
}
result = new Constant(new IntConstantExpression(
intValue, new IntConstantValue(intValue)));
break;
case DOUBLE:
String value = tokens.read();
double doubleValue = double.parse(value, (_) => null);
if (doubleValue == null) {
throw "Invalid double value '$value'.";
}
result = new Constant(new DoubleConstantExpression(
doubleValue, new DoubleConstantValue(doubleValue)));
break;
default:
throw "Unexpected constant tag '$tag'.";
}
tokens.consumeEnd();
tokens.consumeEnd();
return result;
}
/// (CreateFunction (definition))
CreateFunction parseCreateFunction() {
tokens.consumeStart(CREATE_FUNCTION);
FunctionDefinition def = parseFunctionDefinition();
tokens.consumeEnd();
return new CreateFunction(def);
}
MutableVariable addMutableVariable(String name) {
assert(!name2variable.containsKey(name));
MutableVariable variable = new MutableVariable(new DummyElement(name));
name2variable[name] = variable;
return variable;
}
/// (GetMutable name)
GetMutable parseGetMutable() {
tokens.consumeStart(GET_MUTABLE);
MutableVariable local = name2variable[tokens.read()];
tokens.consumeEnd();
return new GetMutable(local);
}
/// (LiteralList (values))
LiteralList parseLiteralList() {
tokens.consumeStart(LITERAL_LIST);
List<Primitive> values = parsePrimitiveList();
tokens.consumeEnd();
return new LiteralList(null, values);
}
/// (LiteralMap (keys) (values))
LiteralMap parseLiteralMap() {
tokens.consumeStart(LITERAL_MAP);
List<Primitive> keys = parsePrimitiveList();
List<Primitive> values = parsePrimitiveList();
List<LiteralMapEntry> entries = <LiteralMapEntry>[];
for (int i = 0; i < keys.length; i++) {
entries.add(new LiteralMapEntry(keys[i], values[i]));
}
tokens.consumeEnd();
return new LiteralMap(null, entries);
}
/// (ReifyTypeVar type)
ReifyTypeVar parseReifyTypeVar() {
tokens.consumeStart(REIFY_TYPE_VAR);
TypeVariableElement type = new DummyElement(tokens.read());
tokens.consumeEnd();
return new ReifyTypeVar(type);
}
/// (GetStatic field)
GetStatic parseGetStatic() {
tokens.consumeStart(GET_STATIC);
Element field = new DummyElement(tokens.read());
tokens.consumeEnd();
return new GetStatic(field, null);
}
/// (GetField object field)
GetField parseGetField() {
tokens.consumeStart(GET_FIELD);
Primitive object = name2variable[tokens.read()];
Element field = new DummyElement(tokens.read());
tokens.consumeEnd();
return new GetField(object, field);
}
/// (SetField object field value)
SetField parseSetField() {
tokens.consumeStart(SET_FIELD);
Primitive object = name2variable[tokens.read()];
Element field = new DummyElement(tokens.read());
Primitive value = name2variable[tokens.read()];
tokens.consumeEnd();
return new SetField(object, field, value);
}
}

View file

@ -1,46 +0,0 @@
// Copyright (c) 2014, 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 dart_backend.test_helper;
import 'dart:async';
import 'package:async_helper/async_helper.dart';
import 'package:compiler/compiler.dart' as api;
import 'package:compiler/src/compiler.dart';
import '../../../../pkg/analyzer2dart/test/test_helper.dart';
import '../compiler_helper.dart';
/// Compiles the given dart code (which must include a 'main' function) and
/// returns the compiler.
Future<Compiler> compilerFor(String code,
{api.CompilerOutputProvider outputProvider}) {
MockCompiler compiler = new MockCompiler.internal(
emitJavaScript: false,
enableMinification: false,
outputProvider: outputProvider);
compiler.diagnosticHandler = createHandler(compiler, code);
return compiler.init().then((_) {
compiler.parseScript(code);
Element element = compiler.mainApp.find('main');
if (element == null) return null;
compiler.mainFunction = element;
compiler.phase = Compiler.PHASE_RESOLVING;
compiler.backend.enqueueHelpers(compiler.enqueuer.resolution,
compiler.globalDependencies);
compiler.processQueue(compiler.enqueuer.resolution, element);
compiler.world.populate();
compiler.backend.onResolutionComplete();
compiler.irBuilder.buildNodes();
return compiler;
});
}
/// Test group using async_helper.
asyncTester(Group group, RunTest runTest) {
asyncTest(() => Future.forEach(group.results, runTest));
}

View file

@ -10,7 +10,6 @@ library dart2js.test.generate_code_with_compile_time_errors;
import 'package:expect/expect.dart';
import 'package:async_helper/async_helper.dart';
import 'package:compiler/src/compiler.dart';
import 'package:compiler/src/dart_backend/dart_backend.dart';
import 'package:compiler/src/js_backend/js_backend.dart';
import 'memory_compiler.dart';
import 'output_collector.dart';
@ -53,14 +52,8 @@ test(List<String> options,
collector.hints.isNotEmpty,
"Unexpected hints: ${collector.warnings}");
bool isCodeGenerated;
if (options.contains('--output-type=dart')) {
DartBackend backend = compiler.backend;
isCodeGenerated = backend.outputter.libraryInfo != null;
} else {
JavaScriptBackend backend = compiler.backend;
isCodeGenerated = backend.generatedCode.isNotEmpty;
}
JavaScriptBackend backend = compiler.backend;
bool isCodeGenerated = backend.generatedCode.isNotEmpty;
Expect.equals(
expectedCodeGenerated,
isCodeGenerated,
@ -114,26 +107,5 @@ void main() {
expectedCodeGenerated: false,
expectedOutput: false,
expectHint: true);
await test(
['--output-type=dart'],
expectedCodeGenerated: false,
expectedOutput: false);
await test(
['--output-type=dart', '--test-mode'],
expectedCodeGenerated: false,
expectedOutput: false);
await test(
['--output-type=dart', '--generate-code-with-compile-time-errors'],
expectedCodeGenerated: false,
expectedOutput: false,
expectHint: true);
await test(
['--output-type=dart',
'--generate-code-with-compile-time-errors',
'--test-mode'],
expectedCodeGenerated: false,
expectedOutput: false,
expectHint: true);
});
}

View file

@ -10,8 +10,6 @@ import 'dart:async';
import 'package:compiler/src/commandline_options.dart';
import 'package:compiler/src/compiler.dart' show
Compiler;
import 'package:compiler/src/dart_backend/dart_backend.dart' show
DartBackend;
import 'package:compiler/src/diagnostics/messages.dart' show
MessageKind,
MessageTemplate;
@ -71,21 +69,12 @@ Future<Compiler> check(MessageTemplate template, Compiler cachedCompiler) {
}
DiagnosticCollector collector = new DiagnosticCollector();
bool oldBackendIsDart;
if (cachedCompiler != null) {
oldBackendIsDart = cachedCompiler.backend is DartBackend;
}
bool newBackendIsDart = template.options.contains('--output-type=dart');
Compiler compiler = compilerFor(
memorySourceFiles: example,
diagnosticHandler: collector,
options: [Flags.analyzeOnly,
Flags.enableExperimentalMirrors]..addAll(template.options),
cachedCompiler:
// TODO(johnniwinther): Remove this restriction when constant
// values can be computed directly from the expressions.
oldBackendIsDart == newBackendIsDart ? cachedCompiler : null);
cachedCompiler: cachedCompiler);
return compiler.run(Uri.parse('memory:main.dart')).then((_) {
Iterable<CollectedMessage> messages = collector.filterMessagesByKinds(

View file

@ -1,108 +0,0 @@
// Copyright (c) 2013, 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 "package:expect/expect.dart";
import 'dart:async';
import "package:async_helper/async_helper.dart";
import 'memory_compiler.dart' show runCompiler, OutputCollector;
import 'package:compiler/src/apiimpl.dart' show
CompilerImpl;
import 'package:compiler/src/tree/tree.dart' show
Node;
import 'package:compiler/src/dart_backend/dart_backend.dart';
import 'package:compiler/src/mirror_renamer/mirror_renamer.dart';
main() {
asyncTest(() async {
await testWithMirrorHelperLibrary(minify: true);
await testWithMirrorHelperLibrary(minify: false);
await testWithoutMirrorHelperLibrary(minify: true);
await testWithoutMirrorHelperLibrary(minify: false);
});
}
Future<CompilerImpl> run({OutputCollector outputCollector,
bool useMirrorHelperLibrary: false,
bool minify: false}) async {
List<String> options = ['--output-type=dart'];
if (minify) {
options.add('--minify');
}
var result = await runCompiler(
memorySourceFiles: MEMORY_SOURCE_FILES,
outputProvider: outputCollector,
options: options,
beforeRun: (CompilerImpl compiler) {
DartBackend backend = compiler.backend;
backend.useMirrorHelperLibrary = useMirrorHelperLibrary;
});
return result.compiler;
}
Future testWithMirrorHelperLibrary({bool minify}) async {
OutputCollector outputCollector = new OutputCollector();
CompilerImpl compiler = await run(
outputCollector: outputCollector,
useMirrorHelperLibrary: true,
minify: minify);
DartBackend backend = compiler.backend;
MirrorRenamerImpl mirrorRenamer = backend.mirrorRenamer;
Map<Node, String> renames = backend.placeholderRenamer.renames;
Map<String, String> symbols = mirrorRenamer.symbols;
Expect.isFalse(null == mirrorRenamer.helperLibrary);
Expect.isFalse(null == mirrorRenamer.getNameFunction);
for (Node n in renames.keys) {
if (symbols.containsKey(renames[n])) {
if(n.toString() == 'getName') {
Expect.equals(
MirrorRenamerImpl.MIRROR_HELPER_GET_NAME_FUNCTION,
symbols[renames[n]]);
} else {
Expect.equals(n.toString(), symbols[renames[n]]);
}
}
}
String output = outputCollector.getOutput('', 'dart');
String getNameMatch = MirrorRenamerImpl.MIRROR_HELPER_GET_NAME_FUNCTION;
Iterable i = getNameMatch.allMatches(output);
print(output);
if (minify) {
Expect.equals(0, i.length);
} else {
// Appears twice in code (defined & called).
Expect.equals(2, i.length);
}
RegExp mapMatch = new RegExp('const<String,( )?String>');
i = mapMatch.allMatches(output);
Expect.equals(1, i.length);
}
Future testWithoutMirrorHelperLibrary({bool minify}) async {
CompilerImpl compiler =
await run(useMirrorHelperLibrary: false, minify: minify);
DartBackend backend = compiler.backend;
MirrorRenamer mirrorRenamer = backend.mirrorRenamer;
Expect.equals(null, mirrorRenamer.helperLibrary);
Expect.equals(null, mirrorRenamer.getNameFunction);
}
const MEMORY_SOURCE_FILES = const <String, String> {
'main.dart': """
import 'dart:mirrors';
class Foo {
noSuchMethod(Invocation invocation) {
MirrorSystem.getName(invocation.memberName);
}
}
void main() {
new Foo().fisk();
}
"""};

View file

@ -1,94 +0,0 @@
// Copyright (c) 2013, 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 "package:expect/expect.dart";
import 'dart:async';
import "package:async_helper/async_helper.dart";
import 'memory_compiler.dart' show runCompiler;
import 'package:compiler/src/apiimpl.dart' show
CompilerImpl;
import 'package:compiler/src/elements/elements.dart' show
Element, LibraryElement, ClassElement;
import 'package:compiler/src/tree/tree.dart' show
Block, ExpressionStatement, FunctionExpression, Node, Send;
import 'package:compiler/src/dart_backend/dart_backend.dart' show
DartBackend, ElementAst;
import 'package:compiler/src/mirror_renamer/mirror_renamer.dart' show
MirrorRenamerImpl;
main() {
asyncTest(() async {
await testWithMirrorRenaming(minify: true);
await testWithMirrorRenaming(minify: false);
await testWithoutMirrorRenaming(minify: true);
await testWithoutMirrorRenaming(minify: false);
});
}
Future<CompilerImpl> run({useMirrorHelperLibrary: false, minify: false}) async {
List<String> options = ['--output-type=dart'];
if (minify) {
options.add('--minify');
}
var result = await runCompiler(
memorySourceFiles: MEMORY_SOURCE_FILES,
options: options,
beforeRun: (CompilerImpl compiler) {
DartBackend backend = compiler.backend;
backend.useMirrorHelperLibrary = useMirrorHelperLibrary;
});
return result.compiler;
}
Future testWithMirrorRenaming({bool minify}) async {
CompilerImpl compiler =
await run(useMirrorHelperLibrary: true, minify: minify);
DartBackend backend = compiler.backend;
MirrorRenamerImpl mirrorRenamer = backend.mirrorRenamer;
Map<Node, String> renames = backend.placeholderRenamer.renames;
Iterable<LibraryElement> imports =
backend.placeholderRenamer.platformImports.keys;
FunctionExpression node = backend.memberNodes.values.first.first;
Block block = node.body;
ExpressionStatement getNameFunctionNode = block.statements.nodes.head;
Send send = getNameFunctionNode.expression;
Expect.equals(renames[mirrorRenamer.getNameFunctionNode.name],
renames[send.selector]);
Expect.equals("",
renames[send.receiver]);
Expect.equals(1, imports.length);
}
Future testWithoutMirrorRenaming({bool minify}) async {
CompilerImpl compiler =
await run(useMirrorHelperLibrary: false, minify: minify);
DartBackend backend = compiler.backend;
Map<Node, String> renames = backend.placeholderRenamer.renames;
Iterable<LibraryElement> imports =
backend.placeholderRenamer.platformImports.keys;
FunctionExpression node = backend.memberNodes.values.first.first;
Block block = node.body;
ExpressionStatement getNameFunctionNode = block.statements.nodes.head;
Send send = getNameFunctionNode.expression;
Expect.isFalse(renames.containsKey(send.selector));
Expect.equals(1, imports.length);
}
const MEMORY_SOURCE_FILES = const <String, String> {
'main.dart': """
import 'dart:mirrors';
class Foo {
noSuchMethod(Invocation invocation) {
MirrorSystem.getName(invocation.memberName);
}
}
void main() {
new Foo().fisk();
}
"""};

View file

@ -1,89 +0,0 @@
// Copyright (c) 2013, 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 "package:expect/expect.dart";
import 'dart:async';
import "package:async_helper/async_helper.dart";
import 'memory_compiler.dart' show runCompiler;
import 'package:compiler/src/apiimpl.dart' show
CompilerImpl;
import 'package:compiler/src/dart_backend/dart_backend.dart' show
DartBackend;
import 'package:compiler/src/tree/tree.dart' show
Identifier, Node, Send;
import 'package:compiler/src/mirror_renamer/mirror_renamer.dart' show
MirrorRenamerImpl;
main() {
asyncTest(() async {
await testUniqueMinification();
await testNoUniqueMinification();
});
}
Future<CompilerImpl> run({useMirrorHelperLibrary: false, minify: false}) async {
List<String> options = ['--output-type=dart'];
if (minify) {
options.add('--minify');
}
var result = await runCompiler(
memorySourceFiles: MEMORY_SOURCE_FILES,
options: options,
beforeRun: (CompilerImpl compiler) {
DartBackend backend = compiler.backend;
backend.useMirrorHelperLibrary = useMirrorHelperLibrary;
});
return result.compiler;
}
Future testUniqueMinification() async {
CompilerImpl compiler = await run(useMirrorHelperLibrary: true, minify: true);
DartBackend backend = compiler.backend;
MirrorRenamerImpl mirrorRenamer = backend.mirrorRenamer;
Map<Node, String> renames = backend.placeholderRenamer.renames;
Map<String, String> symbols = mirrorRenamer.symbols;
// Check that no two different source code names get the same mangled name,
// with the exception of MirrorSystem.getName that gets renamed to the same
// mangled name as the getNameHelper from _mirror_helper.dart.
for (Node node in renames.keys) {
Identifier identifier = node.asIdentifier();
if (identifier != null) {
String source = identifier.source;
Send send = mirrorRenamer.mirrorSystemGetNameNodes.first;
if (send.selector == node)
continue;
if (symbols.containsKey(renames[node])) {
print(node);
Expect.equals(source, symbols[renames[node]]);
}
}
}
}
Future testNoUniqueMinification() async {
CompilerImpl compiler =
await run(useMirrorHelperLibrary: false, minify: true);
DartBackend backend = compiler.backend;
Map<Node, String> renames = backend.placeholderRenamer.renames;
// 'Foo' appears twice and 'invocation' and 'hest' get the same mangled
// name.
Expect.equals(renames.values.toSet().length, renames.values.length - 2);
}
const MEMORY_SOURCE_FILES = const <String, String> {
'main.dart': """
import 'dart:mirrors';
class Foo {
noSuchMethod(invocation) {
MirrorSystem.getName(null);
}
}
main(hest) {
new Foo().fisk();
}
"""};

View file

@ -80,7 +80,6 @@ class MockCompiler extends Compiler {
bool disableTypeInference: false,
bool analyzeAll: false,
bool analyzeOnly: false,
bool emitJavaScript: true,
bool preserveComments: false,
// Our unit tests check code generation output that is
// affected by inlining support.
@ -106,7 +105,6 @@ class MockCompiler extends Compiler {
disableTypeInference: disableTypeInference,
analyzeAll: analyzeAll,
analyzeOnly: analyzeOnly,
emitJavaScript: emitJavaScript,
preserveComments: preserveComments,
trustTypeAnnotations: trustTypeAnnotations,
trustJSInteropTypeAnnotations: trustJSInteropTypeAnnotations,

View file

@ -20,12 +20,8 @@ main() async {
Map<String, Uri> shared = await load(
Uri.base.resolve("sdk/lib/dart_shared.platform"),
input);
Map<String, Uri> dart2dart = await load(
Uri.base.resolve("sdk/lib/dart2dart.platform"),
input);
Expect.setEquals(new Set.from(shared.keys), new Set.from(client.keys));
Expect.setEquals(new Set.from(shared.keys), new Set.from(server.keys));
Expect.setEquals(new Set.from(shared.keys), new Set.from(dart2dart.keys));
for (String libraryName in shared.keys) {
test(Map<String, Uri> m) {
@ -36,6 +32,5 @@ main() async {
}
test(client);
test(server);
test(dart2dart);
}
}

View file

@ -1,8 +1,8 @@
// 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.
// Tests dangling else. The VM should not have any problems, but dart2js or
// dart2dart could get this wrong.
// Tests dangling else. The VM should not have any problems, but dart2js could
// get this wrong.
import "package:expect/expect.dart";

View file

@ -44,7 +44,6 @@
# ......dart_client.platform
# ......dart_server.platform
# ......dart_shared.platform
# ......dart2dart.platform
# ......_internal/
#.........spec.sum
#.........strong.sum
@ -267,8 +266,7 @@ def Main():
# Copy the platform descriptors.
for file_name in ["dart_client.platform",
"dart_server.platform",
"dart_shared.platform",
"dart2dart.platform"]:
"dart_shared.platform"]:
copyfile(join(HOME, 'sdk', 'lib', file_name), join(LIB, file_name));
# Copy libraries.dart to lib/_internal/libraries.dart for backwards