svn merge -r 26292:26492 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
git-svn-id: http://dart.googlecode.com/svn/trunk@26504 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 9206a32..f850b03 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -14,6 +14,5 @@
input_api,
output_api,
json_url='http://dart-status.appspot.com/current?format=json')
- # TODO(ricow): reenable when status page is back in shape
- # results.extend(status_check)
+ results.extend(status_check)
return results
diff --git a/README.dart-sdk b/README.dart-sdk
index c0c4b0d..04e9d4b 100644
--- a/README.dart-sdk
+++ b/README.dart-sdk
@@ -1,4 +1,4 @@
-The Dark SDK is a set of tools and libraries for the Dart programming language.
+The Dart SDK is a set of tools and libraries for the Dart programming language.
You can find information about Dart online at dartlang.org.
diff --git a/pkg/analyzer_experimental/bin/analyzer.dart b/pkg/analyzer_experimental/bin/analyzer.dart
index 5fed0a8..119376f 100644
--- a/pkg/analyzer_experimental/bin/analyzer.dart
+++ b/pkg/analyzer_experimental/bin/analyzer.dart
@@ -8,6 +8,7 @@
library analyzer;
import 'dart:async';
+import 'dart:convert';
import 'dart:io';
import 'package:analyzer_experimental/src/generated/engine.dart';
@@ -80,7 +81,7 @@
// read line from stdin
Stream cmdLine = stdin
.transform(new StringDecoder())
- .transform(new LineTransformer());
+ .transform(new LineSplitter());
var subscription = cmdLine.listen((String line) {
// may be finish
if (line.isEmpty) {
diff --git a/pkg/analyzer_experimental/lib/src/services/formatter_impl.dart b/pkg/analyzer_experimental/lib/src/services/formatter_impl.dart
index 22e0d2a..a3745ec 100644
--- a/pkg/analyzer_experimental/lib/src/services/formatter_impl.dart
+++ b/pkg/analyzer_experimental/lib/src/services/formatter_impl.dart
@@ -150,6 +150,13 @@
/// Cached previous token for calculating preceding whitespace.
Token previousToken;
+ /// A flag to indicate that a newline should be emitted before the next token.
+ bool needsNewline = false;
+
+ /// A flag to indicate that user introduced newlines should be emitted before
+ /// the next token.
+ bool preservePrecedingNewlines = false;
+
/// Initialize a newly created visitor to write source code representing
/// the visited nodes to the given [writer].
SourceVisitor(FormatterOptions options, this.lineInfo) :
@@ -161,49 +168,59 @@
}
visitAnnotation(Annotation node) {
- emitToken(node.atSign);
+ token(node.atSign);
visit(node.name);
visitPrefixed('.', node.constructorName);
visit(node.arguments);
}
visitArgumentDefinitionTest(ArgumentDefinitionTest node) {
- emitToken(node.question);
+ token(node.question);
visit(node.identifier);
}
visitArgumentList(ArgumentList node) {
- emitToken(node.leftParenthesis);
+ token(node.leftParenthesis);
visitList(node.arguments, ', ');
- emitToken(node.rightParenthesis);
+ token(node.rightParenthesis);
}
visitAsExpression(AsExpression node) {
visit(node.expression);
- emitToken(node.asOperator, prefix: ' ', suffix: ' ');
+ space();
+ token(node.asOperator);
+ space();
visit(node.type);
}
visitAssertStatement(AssertStatement node) {
- emitToken(node.keyword, suffix: ' (');
+ token(node.keyword);
+ space();
+ token(node.leftParenthesis);
visit(node.condition);
- emitToken(node.semicolon, prefix: ')');
+ token(node.rightParenthesis);
+ token(node.semicolon);
}
visitAssignmentExpression(AssignmentExpression node) {
visit(node.leftHandSide);
- emitToken(node.operator, prefix: ' ', suffix: ' ');
+ space();
+ token(node.operator);
+ space();
visit(node.rightHandSide);
}
visitBinaryExpression(BinaryExpression node) {
visit(node.leftOperand);
- emitToken(node.operator, prefix: ' ', suffix: ' ');
+ space();
+ token(node.operator);
+ space();
visit(node.rightOperand);
}
visitBlock(Block node) {
- emitToken(node.leftBracket);
+ token(node.leftBracket);
+ needsNewline = true;
indent();
for (var stmt in node.statements) {
@@ -211,11 +228,9 @@
}
unindent();
- newline();
- print('}');
-//TODO(pquitslund): make this work
-// emitToken(node.rightBracket);
- previousToken = node.rightBracket;
+ preservePrecedingNewlines = true;
+ needsNewline = true;
+ token(node.rightBracket);
}
visitBlockFunctionBody(BlockFunctionBody node) {
@@ -223,13 +238,15 @@
}
visitBooleanLiteral(BooleanLiteral node) {
- emitToken(node.literal);
+ token(node.literal);
}
visitBreakStatement(BreakStatement node) {
- emitToken(node.keyword);
+ preservePrecedingNewlines = true;
+ token(node.keyword);
visitPrefixed(' ', node.label);
- emitToken(node.semicolon);
+ token(node.semicolon);
+ needsNewline = true;
}
visitCascadeExpression(CascadeExpression node) {
@@ -241,28 +258,34 @@
visitPrefixed('on ', node.exceptionType);
if (node.catchKeyword != null) {
if (node.exceptionType != null) {
- print(' ');
+ space();
}
- print('catch (');
+ token(node.catchKeyword);
+ space();
+ token(node.leftParenthesis);
visit(node.exceptionParameter);
visitPrefixed(', ', node.stackTraceParameter);
- print(') ');
+ token(node.rightParenthesis);
+ space();
} else {
- print(' ');
+ space();
}
visit(node.body);
- newline();
+ needsNewline = true;
}
visitClassDeclaration(ClassDeclaration node) {
- emitToken(node.abstractKeyword, suffix: ' ');
- emitToken(node.classKeyword, suffix: ' ');
+ preservePrecedingNewlines = true;
+ modifier(node.abstractKeyword);
+ token(node.classKeyword);
+ space();
visit(node.name);
visit(node.typeParameters);
visitPrefixed(' ', node.extendsClause);
visitPrefixed(' ', node.withClause);
visitPrefixed(' ', node.implementsClause);
- emitToken(node.leftBracket, prefix: ' ');
+ space();
+ token(node.leftBracket);
indent();
for (var i = 0; i < node.members.length; i++) {
@@ -271,21 +294,26 @@
unindent();
- emitToken(node.rightBracket, minNewlines: 1);
+ emitPrecedingNewlines(node.rightBracket, min: 1);
+ token(node.rightBracket);
}
visitClassTypeAlias(ClassTypeAlias node) {
- emitToken(node.keyword, suffix: ' ');
+ token(node.keyword);
+ space();
visit(node.name);
visit(node.typeParameters);
- print(' = ');
+ space();
+ token(node.equals);
+ space();
if (node.abstractKeyword != null) {
- print('abstract ');
+ token(node.abstractKeyword);
+ space();
}
visit(node.superclass);
visitPrefixed(' ', node.withClause);
visitPrefixed(' ', node.implementsClause);
- emitToken(node.semicolon);
+ token(node.semicolon);
}
visitComment(Comment node) => null;
@@ -293,31 +321,40 @@
visitCommentReference(CommentReference node) => null;
visitCompilationUnit(CompilationUnit node) {
+
+ // Cache EOF for leading whitespace calculation
+ var start = node.beginToken.previous;
+ if (start != null && start.type is TokenType_EOF) {
+ previousToken = start;
+ }
+
var scriptTag = node.scriptTag;
var directives = node.directives;
visit(scriptTag);
- var prefix = scriptTag == null ? '' : ' ';
- visitPrefixedList(prefix, directives, ' ');
- //prefix = scriptTag == null && directives.isEmpty ? '' : ' ';
- prefix = '';
- visitPrefixedList(prefix, node.declarations);
+ visitList(directives);
+ visitList(node.declarations);
- //TODO(pquitslund): move this?
- newline();
+ // Handle trailing whitespace
+ preservePrecedingNewlines = true;
+ token(node.endToken /* EOF */);
}
visitConditionalExpression(ConditionalExpression node) {
visit(node.condition);
- print(' ? ');
+ space();
+ token(node.question);
+ space();
visit(node.thenExpression);
- print(' : ');
+ space();
+ token(node.colon);
+ space();
visit(node.elseExpression);
}
visitConstructorDeclaration(ConstructorDeclaration node) {
- emitToken(node.externalKeyword, suffix: ' ');
- emitToken(node.constKeyword, suffix: ' ');
- emitToken(node.factoryKeyword, suffix: ' ');
+ modifier(node.externalKeyword);
+ modifier(node.constKeyword);
+ modifier(node.factoryKeyword);
visit(node.returnType);
visitPrefixed('.', node.name);
visit(node.parameters);
@@ -327,9 +364,12 @@
}
visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
- emitToken(node.keyword, suffix: '.');
+ token(node.keyword);
+ token(node.period);
visit(node.fieldName);
- print(' = ');
+ space();
+ token(node.equals);
+ space();
visit(node.expression);
}
@@ -339,150 +379,179 @@
}
visitContinueStatement(ContinueStatement node) {
- emitToken(node.keyword);
+ token(node.keyword);
visitPrefixed(' ', node.label);
- emitToken(node.semicolon);
+ token(node.semicolon);
}
visitDeclaredIdentifier(DeclaredIdentifier node) {
- emitToken(node.keyword, suffix: ' ');
- visitSuffixed(node.type, ' ');
+ token(node.keyword);
+ space();
+ visit(node.type);
+ //TODO(pquitslund): avoiding visitSuffixed(..) but we can do better
+ if (node.type != null) {
+ space();
+ }
visit(node.identifier);
}
visitDefaultFormalParameter(DefaultFormalParameter node) {
visit(node.parameter);
if (node.separator != null) {
- print(' ');
- print(node.separator.lexeme);
+ space();
+ token(node.separator);
visitPrefixed(' ', node.defaultValue);
}
}
visitDoStatement(DoStatement node) {
- emitToken(node.doKeyword, suffix: ' ');
+ token(node.doKeyword);
+ space();
visit(node.body);
- emitToken(node.whileKeyword, prefix: ' ', suffix: ' (');
+ space();
+ token(node.whileKeyword);
+ space();
+ token(node.leftParenthesis);
visit(node.condition);
- emitToken(node.semicolon, prefix: ')');
+ token(node.rightParenthesis);
+ token(node.semicolon);
}
visitDoubleLiteral(DoubleLiteral node) {
- print(node.literal.lexeme);
+ token(node.literal);
}
visitEmptyFunctionBody(EmptyFunctionBody node) {
- emitToken(node.semicolon);
+ token(node.semicolon);
}
visitEmptyStatement(EmptyStatement node) {
- emitToken(node.semicolon);
+ token(node.semicolon);
}
visitExportDirective(ExportDirective node) {
- emitToken(node.keyword, suffix: ' ');
+ token(node.keyword);
+ space();
visit(node.uri);
visitPrefixedList(' ', node.combinators, ' ');
- emitToken(node.semicolon);
+ token(node.semicolon);
}
visitExpressionFunctionBody(ExpressionFunctionBody node) {
- emitToken(node.functionDefinition, suffix: ' ');
+ token(node.functionDefinition);
+ space();
visit(node.expression);
- emitToken(node.semicolon);
+ token(node.semicolon);
}
visitExpressionStatement(ExpressionStatement node) {
visit(node.expression);
- emitToken(node.semicolon);
+ token(node.semicolon);
}
visitExtendsClause(ExtendsClause node) {
- emitToken(node.keyword, suffix: ' ');
+ token(node.keyword);
+ space();
visit(node.superclass);
}
visitFieldDeclaration(FieldDeclaration node) {
- emitToken(node.keyword, suffix: ' ');
+ needsNewline = true;
+ preservePrecedingNewlines = true;
+ modifier(node.keyword);
visit(node.fields);
- emitToken(node.semicolon);
+ token(node.semicolon);
}
visitFieldFormalParameter(FieldFormalParameter node) {
- emitToken(node.keyword, suffix: ' ');
- visitSuffixed(node.type, ' ');
- print('this.');
+ token(node.keyword);
+ space();
+ visit(node.type);
+ space();
+ token(node.thisToken);
+ token(node.period);
visit(node.identifier);
visit(node.parameters);
}
visitForEachStatement(ForEachStatement node) {
- print('for (');
+ token(node.forKeyword);
+ space();
+ token(node.leftParenthesis);
visit(node.loopVariable);
- print(' in ');
+ space();
+ token(node.inKeyword);
+ space();
visit(node.iterator);
- print(') ');
+ token(node.rightParenthesis);
+ space();
visit(node.body);
}
visitFormalParameterList(FormalParameterList node) {
var groupEnd = null;
- print('(');
+ token(node.leftParenthesis);
var parameters = node.parameters;
var size = parameters.length;
for (var i = 0; i < size; i++) {
var parameter = parameters[i];
if (i > 0) {
- print(', ');
+ append(', ');
}
if (groupEnd == null && parameter is DefaultFormalParameter) {
if (identical(parameter.kind, ParameterKind.NAMED)) {
groupEnd = '}';
- print('{');
+ append('{');
} else {
groupEnd = ']';
- print('[');
+ append('[');
}
}
parameter.accept(this);
}
if (groupEnd != null) {
- print(groupEnd);
+ append(groupEnd);
}
- print(')');
+ token(node.rightParenthesis);
}
visitForStatement(ForStatement node) {
+ token(node.forKeyword);
+ space();
+ token(node.leftParenthesis);
var initialization = node.initialization;
- print('for (');
if (initialization != null) {
visit(initialization);
} else {
visit(node.variables);
}
- print(';');
+ token(node.leftSeparator);
visitPrefixed(' ', node.condition);
- print(';');
+ token(node.rightSeparator);
visitPrefixedList(' ', node.updaters, ', ');
- print(') ');
+ token(node.leftParenthesis);
+ space();
visit(node.body);
}
visitFunctionDeclaration(FunctionDeclaration node) {
+ needsNewline = true;
+ preservePrecedingNewlines = true;
visitSuffixed(node.returnType, ' ');
- emitToken(node.propertyKeyword, suffix: ' ');
+ token(node.propertyKeyword, followedBy: space);
visit(node.name);
visit(node.functionExpression);
}
visitFunctionDeclarationStatement(FunctionDeclarationStatement node) {
visit(node.functionDeclaration);
- print(';');
+ // TODO(pquitslund): fix and handle in function body
+ append(';');
}
visitFunctionExpression(FunctionExpression node) {
visit(node.parameters);
- print(' ');
+ space();
visit(node.body);
}
@@ -492,12 +561,13 @@
}
visitFunctionTypeAlias(FunctionTypeAlias node) {
- emitToken(node.keyword, suffix: ' ');
+ token(node.keyword);
+ space();
visitSuffixed(node.returnType, ' ');
visit(node.name);
visit(node.typeParameters);
visit(node.parameters);
- emitToken(node.semicolon);
+ token(node.semicolon);
}
visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
@@ -507,81 +577,96 @@
}
visitHideCombinator(HideCombinator node) {
- emitToken(node.keyword, suffix: ' ');
+ token(node.keyword);
+ space();
visitList(node.hiddenNames, ', ');
}
visitIfStatement(IfStatement node) {
- emitToken(node.ifKeyword);
- print(' (');
+ preservePrecedingNewlines = true;
+ token(node.ifKeyword);
+ space();
+ token(node.leftParenthesis);
visit(node.condition);
- print(') ');
+ token(node.rightParenthesis);
+ space();
visit(node.thenStatement);
- visitPrefixed(' else ', node.elseStatement);
+ //visitPrefixed(' else ', node.elseStatement);
+ if (node.elseStatement != null) {
+ space();
+ token(node.elseKeyword);
+ space();
+ visit(node.elseStatement);
+ }
+ needsNewline = true;
}
-
+
visitImplementsClause(ImplementsClause node) {
- emitToken(node.keyword, suffix: ' ');
+ token(node.keyword);
+ space();
visitList(node.interfaces, ', ');
}
visitImportDirective(ImportDirective node) {
- emitToken(node.keyword, suffix: ' ');
+ preservePrecedingNewlines = true;
+ token(node.keyword);
+ space();
visit(node.uri);
visitPrefixed(' as ', node.prefix);
visitPrefixedList(' ', node.combinators, ' ');
- emitToken(node.semicolon);
+ token(node.semicolon);
+ needsNewline = true;
}
visitIndexExpression(IndexExpression node) {
if (node.isCascaded) {
- print('..');
+ token(node.period);
} else {
visit(node.target);
}
- print('[');
+ token(node.leftBracket);
visit(node.index);
- print(']');
+ token(node.rightBracket);
}
visitInstanceCreationExpression(InstanceCreationExpression node) {
- emitToken(node.keyword, suffix: ' ');
+ token(node.keyword);
+ space();
visit(node.constructorName);
visit(node.argumentList);
}
visitIntegerLiteral(IntegerLiteral node) {
- print(node.literal.lexeme);
+ token(node.literal);
}
visitInterpolationExpression(InterpolationExpression node) {
if (node.rightBracket != null) {
- print('\${');
+ token(node.leftBracket);
visit(node.expression);
- print('}');
+ token(node.rightBracket);
} else {
- print('\$');
+ token(node.leftBracket);
visit(node.expression);
}
}
visitInterpolationString(InterpolationString node) {
- print(node.contents.lexeme);
+ token(node.contents);
}
visitIsExpression(IsExpression node) {
visit(node.expression);
- if (node.notOperator == null) {
- print(' is ');
- } else {
- print(' is! ');
- }
+ space();
+ token(node.isOperator);
+ token(node.notOperator);
+ space();
visit(node.type);
}
visitLabel(Label node) {
visit(node.label);
- print(':');
+ token(node.colon);
}
visitLabeledStatement(LabeledStatement node) {
@@ -590,49 +675,51 @@
}
visitLibraryDirective(LibraryDirective node) {
- emitToken(node.keyword, suffix: ' ');
+ token(node.keyword);
+ space();
visit(node.name);
- emitToken(node.semicolon);
+ token(node.semicolon);
}
visitLibraryIdentifier(LibraryIdentifier node) {
- print(node.name);
+ append(node.name);
}
visitListLiteral(ListLiteral node) {
if (node.modifier != null) {
- print(node.modifier.lexeme);
- print(' ');
+ token(node.modifier);
+ space();
}
visit(node.typeArguments);
- print('[');
+ token(node.leftBracket);
visitList(node.elements, ', ');
- print(']');
+ token(node.rightBracket);
}
visitMapLiteral(MapLiteral node) {
- if (node.modifier != null) {
- print(node.modifier.lexeme);
- print(' ');
- }
+ modifier(node.modifier);
visitSuffixed(node.typeArguments, ' ');
- print('{');
+ token(node.leftBracket);
visitList(node.entries, ', ');
- print('}');
+ token(node.rightBracket);
}
visitMapLiteralEntry(MapLiteralEntry node) {
visit(node.key);
- print(' : ');
+ space();
+ token(node.separator);
+ space();
visit(node.value);
}
visitMethodDeclaration(MethodDeclaration node) {
- emitToken(node.externalKeyword, suffix: ' ');
- emitToken(node.modifierKeyword, suffix: ' ');
+ needsNewline = true;
+ preservePrecedingNewlines = true;
+ modifier(node.externalKeyword);
+ modifier(node.modifierKeyword);
visitSuffixed(node.returnType, ' ');
- emitToken(node.propertyKeyword, suffix: ' ');
- emitToken(node.operatorKeyword, suffix: ' ');
+ modifier(node.propertyKeyword);
+ modifier(node.operatorKeyword);
visit(node.name);
if (!node.isGetter) {
visit(node.parameters);
@@ -642,7 +729,7 @@
visitMethodInvocation(MethodInvocation node) {
if (node.isCascaded) {
- print('..');
+ token(node.period);
} else {
visitSuffixed(node.target, '.');
}
@@ -656,107 +743,114 @@
}
visitNativeClause(NativeClause node) {
- emitToken(node.keyword, suffix: ' ');
+ token(node.keyword);
+ space();
visit(node.name);
}
visitNativeFunctionBody(NativeFunctionBody node) {
- emitToken(node.nativeToken, suffix: ' ');
+ token(node.nativeToken);
+ space();
visit(node.stringLiteral);
- emitToken(node.semicolon);
+ token(node.semicolon);
}
visitNullLiteral(NullLiteral node) {
- emitToken(node.literal);
+ token(node.literal);
}
visitParenthesizedExpression(ParenthesizedExpression node) {
- emitToken(node.leftParenthesis);
+ token(node.leftParenthesis);
visit(node.expression);
- emitToken(node.rightParenthesis);
+ token(node.rightParenthesis);
}
visitPartDirective(PartDirective node) {
- emitToken(node.keyword, suffix: ' ');
+ token(node.keyword);
+ space();
visit(node.uri);
- emitToken(node.semicolon);
+ token(node.semicolon);
}
visitPartOfDirective(PartOfDirective node) {
- emitToken(node.keyword, suffix: ' ');
+ token(node.keyword);
+ space();
visit(node.libraryName);
- emitToken(node.semicolon);
+ token(node.semicolon);
}
visitPostfixExpression(PostfixExpression node) {
visit(node.operand);
- print(node.operator.lexeme);
+ token(node.operator);
}
visitPrefixedIdentifier(PrefixedIdentifier node) {
visit(node.prefix);
- print('.');
+ token(node.period);
visit(node.identifier);
}
visitPrefixExpression(PrefixExpression node) {
- emitToken(node.operator);
+ token(node.operator);
visit(node.operand);
}
visitPropertyAccess(PropertyAccess node) {
if (node.isCascaded) {
- print('..');
+ token(node.operator);
} else {
visit(node.target);
- print('.');
+ token(node.operator);
}
visit(node.propertyName);
}
visitRedirectingConstructorInvocation(RedirectingConstructorInvocation node) {
- emitToken(node.keyword);
+ token(node.keyword);
visitPrefixed('.', node.constructorName);
visit(node.argumentList);
}
visitRethrowExpression(RethrowExpression node) {
- emitToken(node.keyword);
+ token(node.keyword);
}
visitReturnStatement(ReturnStatement node) {
+ preservePrecedingNewlines = true;
var expression = node.expression;
if (expression == null) {
- emitToken(node.keyword, minNewlines: 1);
- emitToken(node.semicolon);
+ token(node.keyword);
+ token(node.semicolon);
} else {
- emitToken(node.keyword, suffix: ' ', minNewlines: 1);
+ token(node.keyword);
+ space();
expression.accept(this);
- emitToken(node.semicolon);
+ token(node.semicolon);
}
}
visitScriptTag(ScriptTag node) {
- print(node.scriptTag.lexeme);
+ token(node.scriptTag);
}
visitShowCombinator(ShowCombinator node) {
- emitToken(node.keyword, suffix: ' ');
+ token(node.keyword);
+ space();
visitList(node.shownNames, ', ');
}
visitSimpleFormalParameter(SimpleFormalParameter node) {
- emitToken(node.keyword, suffix: ' ');
+ modifier(node.keyword);
visitSuffixed(node.type, ' ');
visit(node.identifier);
}
visitSimpleIdentifier(SimpleIdentifier node) {
- emitToken(node.token);
+ token(node.token);
}
visitSimpleStringLiteral(SimpleStringLiteral node) {
- emitToken(node.literal);
+ token(node.literal);
}
visitStringInterpolation(StringInterpolation node) {
@@ -764,42 +858,50 @@
}
visitSuperConstructorInvocation(SuperConstructorInvocation node) {
- emitToken(node.keyword);
+ token(node.keyword);
visitPrefixed('.', node.constructorName);
visit(node.argumentList);
}
visitSuperExpression(SuperExpression node) {
- emitToken(node.keyword);
+ token(node.keyword);
}
visitSwitchCase(SwitchCase node) {
+ preservePrecedingNewlines = true;
visitSuffixedList(node.labels, ' ', ' ');
- emitToken(node.keyword, suffix: ' ');
+ token(node.keyword);
+ space();
visit(node.expression);
- print(':');
+ token(node.colon);
indent();
+ needsNewline = true;
visitList(node.statements);
unindent();
}
visitSwitchDefault(SwitchDefault node) {
+ preservePrecedingNewlines = true;
visitSuffixedList(node.labels, ' ', ' ');
- emitToken(node.keyword, suffix: ': ');
+ token(node.keyword);
+ token(node.colon);
+ space();
visitList(node.statements, ' ');
}
visitSwitchStatement(SwitchStatement node) {
- emitToken(node.keyword);
- print(' (');
+ token(node.keyword);
+ space();
+ token(node.leftParenthesis);
visit(node.expression);
- print(') ');
- emitToken(node.leftBracket);
+ token(node.rightParenthesis);
+ space();
+ token(node.leftBracket);
indent();
visitList(node.members);
unindent();
- emitToken(node.rightBracket);
- newline();
+ token(node.rightBracket);
+ needsNewline = true;
}
visitSymbolLiteral(SymbolLiteral node) {
@@ -807,29 +909,34 @@
}
visitThisExpression(ThisExpression node) {
- emitToken(node.keyword);
+ token(node.keyword);
}
visitThrowExpression(ThrowExpression node) {
- emitToken(node.keyword, suffix: ' ');
+ token(node.keyword);
+ space();
visit(node.expression);
}
visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
- visitSuffixed(node.variables, ';');
+ preservePrecedingNewlines = true;
+ visit(node.variables);
+ token(node.semicolon);
}
visitTryStatement(TryStatement node) {
- emitToken(node.tryKeyword, suffix: ' ');
+ preservePrecedingNewlines = true;
+ token(node.tryKeyword);
+ space();
visit(node.body);
visitPrefixedList(' ', node.catchClauses, ' ');
visitPrefixed(' finally ', node.finallyClause);
}
visitTypeArgumentList(TypeArgumentList node) {
- emitToken(node.leftBracket);
+ token(node.leftBracket);
visitList(node.arguments, ', ');
- emitToken(node.rightBracket);
+ token(node.rightBracket);
}
visitTypeName(TypeName node) {
@@ -843,36 +950,47 @@
}
visitTypeParameterList(TypeParameterList node) {
- emitToken(node.leftBracket);
+ token(node.leftBracket);
visitList(node.typeParameters, ', ');
- emitToken(node.rightBracket);
+ token(node.rightBracket);
}
visitVariableDeclaration(VariableDeclaration node) {
visit(node.name);
- visitPrefixed(' = ', node.initializer);
+ if (node.initializer != null) {
+ space();
+ token(node.equals);
+ space();
+ visit(node.initializer);
+ }
}
visitVariableDeclarationList(VariableDeclarationList node) {
- emitToken(node.keyword, suffix: ' ');
+ token(node.keyword);
+ space();
visitSuffixed(node.type, ' ');
visitList(node.variables, ', ');
}
visitVariableDeclarationStatement(VariableDeclarationStatement node) {
visit(node.variables);
- emitToken(node.semicolon);
+ token(node.semicolon);
+ needsNewline = true;
}
visitWhileStatement(WhileStatement node) {
- emitToken(node.keyword, suffix: ' (');
+ token(node.keyword);
+ space();
+ token(node.leftParenthesis);
visit(node.condition);
- print(') ');
+ token(node.rightParenthesis);
+ space();
visit(node.body);
}
visitWithClause(WithClause node) {
- emitToken(node.withKeyword, suffix: ' ');
+ token(node.withKeyword);
+ space();
visitList(node.mixinTypes, ', ');
}
@@ -888,7 +1006,7 @@
visitSuffixed(ASTNode node, String suffix) {
if (node != null) {
node.accept(this);
- print(suffix);
+ append(suffix);
}
}
@@ -896,7 +1014,7 @@
/// it is non-null.
visitPrefixed(String prefix, ASTNode node) {
if (node != null) {
- print(prefix);
+ append(prefix);
node.accept(this);
}
}
@@ -905,7 +1023,7 @@
/// body is not empty.
visitPrefixedBody(String prefix, FunctionBody body) {
if (body is! EmptyFunctionBody) {
- print(prefix);
+ append(prefix);
}
visit(body);
}
@@ -916,7 +1034,7 @@
var size = nodes.length;
for (var i = 0; i < size; i++) {
if (i > 0) {
- print(separator);
+ append(separator);
}
nodes[i].accept(this);
}
@@ -930,11 +1048,11 @@
if (size > 0) {
for (var i = 0; i < size; i++) {
if (i > 0) {
- print(separator);
+ append(separator);
}
nodes[i].accept(this);
}
- print(suffix);
+ append(suffix);
}
}
}
@@ -945,10 +1063,10 @@
if (nodes != null) {
var size = nodes.length;
if (size > 0) {
- print(prefix);
+ append(prefix);
for (var i = 0; i < size; i++) {
if (i > 0 && separator != null) {
- print(separator);
+ append(separator);
}
nodes[i].accept(this);
}
@@ -956,37 +1074,50 @@
}
}
-
- /// Emit the given [token], if it's non-null, preceded by any detected
- /// newlines or a minimum as specified by [minNewlines], printing a [prefix]
- /// before and a [suffix] after.
- emitToken(Token token, {String prefix, String suffix,
- int minNewlines: 0}) {
+ /// Emit the given [modifier] if it's non null, followed by non-breaking
+ /// whitespace.
+ modifier(Token modifier) {
+ token(modifier, followedBy: space);
+ }
+
+ token(Token token, {followedBy(), int minNewlines: 0}) {
if (token != null) {
- print(prefix);
- emitPrecedingNewlines(token, min: minNewlines);
- print(token.lexeme);
- print(suffix);
- }
+ if (needsNewline) {
+ minNewlines = max(1, minNewlines);
+ }
+ if (preservePrecedingNewlines || minNewlines > 0) {
+ var emitted = emitPrecedingNewlines(token, min: minNewlines);
+ preservePrecedingNewlines = false;
+ if (emitted > 0) {
+ needsNewline = false;
+ }
+ }
+ append(token.lexeme);
+ if (followedBy != null) {
+ followedBy();
+ }
+ previousToken = token;
+ }
+ }
+
+ /// Emit a non-breakable space.
+ space() {
+ //TODO(pquitslund): replace with a proper space token
+ append(' ');
}
- /// Print the given [string] to the source writer if it's non-null.
- print(String string) {
+ /// Emit a breakable space
+ breakableSpace() {
+ //Implement
+ }
+
+ /// Append the given [string] to the source writer if it's non-null.
+ append(String string) {
if (string != null) {
writer.print(string);
}
}
-
- /// Emit a newline.
- newline() {
- writer.newline();
- }
-
- /// Emit [n] newlines.
- newlines(n) {
- writer.newlines(n);
- }
-
+
/// Indent.
indent() {
writer.indent();
@@ -998,18 +1129,19 @@
}
/// Emit any detected newlines or a minimum as specified by [minNewlines].
- emitPrecedingNewlines(Token token, {min: 0}) {
+ int emitPrecedingNewlines(Token token, {min: 0}) {
var comment = token.precedingComments;
var currentToken = comment != null ? comment : token;
var lines = max(min, countNewlinesBetween(previousToken, currentToken));
- newlines(lines);
+ writer.newlines(lines);
while (comment != null) {
- print(comment.toString().trim());
- newline();
+ append(comment.toString().trim());
+ writer.newline();
comment = comment.next;
}
previousToken = token;
+ return lines;
}
/// Count the blanks between these two nodes.
diff --git a/pkg/analyzer_experimental/test/services/formatter_test.dart b/pkg/analyzer_experimental/test/services/formatter_test.dart
index 3f21446..2ad1d13 100644
--- a/pkg/analyzer_experimental/test/services/formatter_test.dart
+++ b/pkg/analyzer_experimental/test/services/formatter_test.dart
@@ -21,9 +21,13 @@
test('CU (1)', () {
expectCUFormatsTo(
- 'class A {\n'
- '}',
'class A {\n'
+ ' var z;\n'
+ ' inc(int x) => ++x;\n'
+ '}\n',
+ 'class A {\n'
+ ' var z;\n'
+ ' inc(int x) => ++x;\n'
'}\n'
);
});
@@ -31,7 +35,7 @@
test('CU (2)', () {
expectCUFormatsTo(
'class A { \n'
- '}',
+ '}\n',
'class A {\n'
'}\n'
);
@@ -42,19 +46,78 @@
'class A {\n'
' }',
'class A {\n'
- '}\n'
+ '}'
);
});
test('CU (4)', () {
expectCUFormatsTo(
' class A {\n'
- '}',
+ '}\n',
'class A {\n'
'}\n'
);
});
+ test('CU (5)', () {
+ expectCUFormatsTo(
+ 'class A { int meaningOfLife() => 42; }',
+ 'class A {\n'
+ ' int meaningOfLife() => 42;\n'
+ '}'
+ );
+ });
+
+
+// test('CU - comments', () {
+// expectCUFormatsTo(
+// 'library foo;\n'
+// '\n'
+// '//comment one\n\n'
+// '//comment two\n\n'
+// 'class C {\n}\n',
+// 'library foo;\n'
+// '\n'
+// '//comment one\n\n'
+// '//comment two\n\n'
+// 'class C {\n}\n'
+// );
+// });
+
+ test('CU - top level', () {
+ expectCUFormatsTo(
+ '\n\n'
+ 'foo() {\n'
+ '}\n'
+ 'bar() {\n'
+ '}\n',
+ '\n\n'
+ 'foo() {\n'
+ '}\n'
+ 'bar() {\n'
+ '}\n'
+ );
+ expectCUFormatsTo(
+ 'const A = 42;\n'
+ 'final foo = 32;\n',
+ 'const A = 42;\n'
+ 'final foo = 32;\n'
+ );
+ });
+
+ test('CU - imports', () {
+ expectCUFormatsTo(
+ 'import "dart:io";\n\n'
+ 'import "package:unittest/unittest.dart";\n'
+ 'foo() {\n'
+ '}\n',
+ 'import "dart:io";\n\n'
+ 'import "package:unittest/unittest.dart";\n'
+ 'foo() {\n'
+ '}\n'
+ );
+ });
+
test('CU w/class decl comment', () {
expectCUFormatsTo(
'import "foo";\n\n'
@@ -64,29 +127,64 @@
'import "foo";\n\n'
'//Killer class\n'
'class A {\n'
- '}\n'
+ '}'
);
});
-
+ test('CU (method body)', () {
+ expectCUFormatsTo(
+ 'class A {\n'
+ ' foo(path) {\n'
+ ' var buffer = new StringBuffer();\n'
+ ' var file = new File(path);\n'
+ ' return file;\n'
+ ' }\n'
+ '}\n',
+ 'class A {\n'
+ ' foo(path) {\n'
+ ' var buffer = new StringBuffer();\n'
+ ' var file = new File(path);\n'
+ ' return file;\n'
+ ' }\n'
+ '}\n'
+ );
+ expectCUFormatsTo(
+ 'class A {\n'
+ ' foo(files) {\n'
+ ' for (var file in files) {\n'
+ ' print(file);\n'
+ ' }\n'
+ ' }\n'
+ '}\n',
+ 'class A {\n'
+ ' foo(files) {\n'
+ ' for (var file in files) {\n'
+ ' print(file);\n'
+ ' }\n'
+ ' }\n'
+ '}\n'
+ );
+ });
+
test('CU (method indent)', () {
expectCUFormatsTo(
'class A {\n'
'void x(){\n'
'}\n'
- '}',
+ '}\n',
'class A {\n'
' void x() {\n'
' }\n'
'}\n'
- );
+ );
});
test('CU (method indent - 2)', () {
expectCUFormatsTo(
'class A {\n'
- ' static bool x(){ return true; }\n'
- ' }',
+ ' static bool x(){\n'
+ 'return true; }\n'
+ ' }\n',
'class A {\n'
' static bool x() {\n'
' return true;\n'
@@ -99,7 +197,7 @@
expectCUFormatsTo(
'class A {\n'
' int x() => 42 + 3 ; \n'
- ' }',
+ ' }\n',
'class A {\n'
' int x() => 42 + 3;\n'
'}\n'
@@ -110,10 +208,12 @@
expectCUFormatsTo(
'class A {\n'
' int x() { \n'
- 'if (true) {return 42;\n'
- '} else { return 13; }\n'
+ 'if (true) {\n'
+ 'return 42;\n'
+ '} else {\n'
+ 'return 13;\n }\n'
' }'
- '}',
+ '}\n',
'class A {\n'
' int x() {\n'
' if (true) {\n'
@@ -192,7 +292,7 @@
'case "fig":\n'
'print("bleh");\n'
'break;\n'
- '}\n',
+ '}',
'switch (fruit) {\n'
' case "apple":\n'
' print("delish");\n'
@@ -200,7 +300,7 @@
' case "fig":\n'
' print("bleh");\n'
' break;\n'
- '}\n'
+ '}'
);
});
@@ -217,12 +317,12 @@
'doSomething();\n'
'} catch (e) {\n'
'print(e);\n'
- '}\n',
+ '}',
'try {\n'
' doSomething();\n'
'} catch (e) {\n'
' print(e);\n'
- '}\n'
+ '}'
);
});
diff --git a/pkg/barback/lib/barback.dart b/pkg/barback/lib/barback.dart
index a211873..e37bd1b 100644
--- a/pkg/barback/lib/barback.dart
+++ b/pkg/barback/lib/barback.dart
@@ -6,9 +6,10 @@
export 'src/asset.dart';
export 'src/asset_id.dart';
+export 'src/asset_set.dart';
export 'src/barback.dart';
export 'src/build_result.dart';
-export 'src/errors.dart';
+export 'src/errors.dart' hide flattenAggregateExceptions;
export 'src/package_provider.dart';
export 'src/transform.dart' show Transform;
export 'src/transform_logger.dart';
diff --git a/pkg/barback/lib/src/asset_cascade.dart b/pkg/barback/lib/src/asset_cascade.dart
index 341480d..e8e9355 100644
--- a/pkg/barback/lib/src/asset_cascade.dart
+++ b/pkg/barback/lib/src/asset_cascade.dart
@@ -10,10 +10,10 @@
import 'asset.dart';
import 'asset_id.dart';
import 'asset_node.dart';
+import 'asset_set.dart';
import 'build_result.dart';
import 'cancelable_future.dart';
import 'errors.dart';
-import 'change_batch.dart';
import 'package_graph.dart';
import 'phase.dart';
import 'transformer.dart';
@@ -83,31 +83,14 @@
/// last began.
var _newChanges = false;
+ /// Returns all currently-available output assets from this cascade.
+ AssetSet get availableOutputs => _phases.last.availableOutputs;
+
/// Creates a new [AssetCascade].
///
- /// It loads source assets within [package] using [provider] and then uses
- /// [transformerPhases] to generate output files from them.
- //TODO(rnystrom): Better way of specifying transformers and their ordering.
- AssetCascade(this.graph, this.package,
- Iterable<Iterable<Transformer>> transformerPhases) {
- // Flatten the phases to a list so we can traverse backwards to wire up
- // each phase to its next.
- var phases = transformerPhases.toList();
-
- // Each phase writes its outputs as inputs to the next phase after it.
- // Add a phase at the end for the final outputs of the last phase.
- phases.add([]);
-
- Phase nextPhase = null;
- for (var transformers in phases.reversed) {
- nextPhase = new Phase(this, _phases.length, transformers.toList(),
- nextPhase);
- nextPhase.onDirty.listen((_) {
- _newChanges = true;
- _waitForProcess();
- });
- _phases.insert(0, nextPhase);
- }
+ /// It loads source assets within [package] using [provider].
+ AssetCascade(this.graph, this.package) {
+ _addPhase(new Phase(this, []));
}
/// Gets the asset identified by [id].
@@ -128,7 +111,7 @@
// * If [id] has never been generated and all active transformers provide
// metadata about the file names of assets it can emit, we can prove that
// none of them can emit [id] and fail early.
- return _phases.last.getInput(id).then((node) {
+ return _phases.last.getOutput(id).then((node) {
// If the requested asset is available, we can just return it.
if (node != null && node.state.isAvailable) return node;
@@ -190,11 +173,42 @@
});
}
+ /// Sets this cascade's transformer phases to [transformers].
+ void updateTransformers(Iterable<Iterable<Transformer>> transformers) {
+ transformers = transformers.toList();
+
+ for (var i = 0; i < transformers.length; i++) {
+ if (_phases.length > i) {
+ _phases[i].updateTransformers(transformers[i]);
+ continue;
+ }
+
+ _addPhase(_phases.last.addPhase(transformers[i]));
+ }
+
+ if (transformers.length < _phases.length) {
+ for (var i = transformers.length; i < _phases.length; i++) {
+ // TODO(nweiz): actually remove phases rather than emptying them of
+ // transformers.
+ _phases[i].updateTransformers([]);
+ }
+ }
+ }
+
void reportError(BarbackException error) {
_accumulatedErrors.add(error);
_errorsController.add(error);
}
+ /// Add [phase] to the end of [_phases] and watch its [onDirty] stream.
+ void _addPhase(Phase phase) {
+ phase.onDirty.listen((_) {
+ _newChanges = true;
+ _waitForProcess();
+ });
+ _phases.add(phase);
+ }
+
/// Starts the build process asynchronously if there is work to be done.
///
/// Returns a future that completes with the background processing is done.
diff --git a/pkg/barback/lib/src/asset_forwarder.dart b/pkg/barback/lib/src/asset_forwarder.dart
new file mode 100644
index 0000000..7dc74dc
--- /dev/null
+++ b/pkg/barback/lib/src/asset_forwarder.dart
@@ -0,0 +1,53 @@
+// 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 barback.asset_forwarder;
+
+import 'dart:async';
+
+import 'asset_node.dart';
+
+/// A wrapper for an [AssetNode] that forwards events to a new node.
+///
+/// A forwarder is used when a class wants to forward an [AssetNode] that it
+/// gets as an input, but also wants to have control over when that node is
+/// marked as removed. The forwarder can be closed, thus removing its output
+/// node, without the original node having been removed.
+class AssetForwarder {
+ /// The subscription on the input node.
+ StreamSubscription _subscription;
+
+ /// The controller for the output node.
+ final AssetNodeController _controller;
+
+ /// The node to which events are forwarded.
+ AssetNode get node => _controller.node;
+
+ AssetForwarder(AssetNode node)
+ : _controller = new AssetNodeController(node.id, node.transform) {
+ _subscription = node.onStateChange.listen((state) {
+ if (state.isAvailable) {
+ _controller.setAvailable(node.asset);
+ } else if (state.isDirty) {
+ _controller.setDirty();
+ } else {
+ assert(state.isRemoved);
+ close();
+ }
+ });
+
+ if (node.state.isAvailable) {
+ _controller.setAvailable(node.asset);
+ } else if (node.state.isRemoved) {
+ close();
+ }
+ }
+
+ /// Closes the forwarder and marks [node] as removed.
+ void close() {
+ if (_controller.node.state.isRemoved) return;
+ _subscription.cancel();
+ _controller.setRemoved();
+ }
+}
diff --git a/pkg/barback/lib/src/asset_id.dart b/pkg/barback/lib/src/asset_id.dart
index d9cef32..c4ed1d8 100644
--- a/pkg/barback/lib/src/asset_id.dart
+++ b/pkg/barback/lib/src/asset_id.dart
@@ -4,9 +4,6 @@
library barback.asset_id;
-import 'dart:async';
-import 'dart:io';
-
import 'package:path/path.dart' as pathos;
/// AssetIDs always use POSIX style paths regardless of the host platform.
diff --git a/pkg/barback/lib/src/asset_node.dart b/pkg/barback/lib/src/asset_node.dart
index 587f2bd..edc7408 100644
--- a/pkg/barback/lib/src/asset_node.dart
+++ b/pkg/barback/lib/src/asset_node.dart
@@ -9,7 +9,6 @@
import 'asset.dart';
import 'asset_id.dart';
import 'errors.dart';
-import 'phase.dart';
import 'transform_node.dart';
/// Describes the current state of an asset as part of a transformation graph.
diff --git a/pkg/barback/lib/src/asset_set.dart b/pkg/barback/lib/src/asset_set.dart
index b432425..08c2db9 100644
--- a/pkg/barback/lib/src/asset_set.dart
+++ b/pkg/barback/lib/src/asset_set.dart
@@ -4,9 +4,7 @@
library barback.asset_set;
-import 'dart:async';
import 'dart:collection';
-import 'dart:io';
import 'asset.dart';
import 'asset_id.dart';
diff --git a/pkg/barback/lib/src/barback.dart b/pkg/barback/lib/src/barback.dart
index 3dcb23e..313d42c 100644
--- a/pkg/barback/lib/src/barback.dart
+++ b/pkg/barback/lib/src/barback.dart
@@ -8,10 +8,12 @@
import 'asset.dart';
import 'asset_id.dart';
+import 'asset_set.dart';
import 'build_result.dart';
import 'errors.dart';
import 'package_graph.dart';
import 'package_provider.dart';
+import 'transformer.dart';
/// A general-purpose asynchronous build dependency graph manager.
///
@@ -88,4 +90,19 @@
/// Removes [removed] from the graph's known set of source assets.
void removeSources(Iterable<AssetId> removed) =>
_graph.removeSources(removed);
-}
\ No newline at end of file
+
+ /// Gets all output assets.
+ ///
+ /// If a build is currently in progress, waits until it completes. The
+ /// returned future will complete with a [BarbackException] if the build is
+ /// not successful.
+ Future<AssetSet> getAllAssets() => _graph.getAllAssets();
+
+ /// Sets the transformer phases for [package]'s assets to [transformers].
+ ///
+ /// To the extent that [transformers] is similar to the previous transformer
+ /// phases for [package], the existing asset graph will be preserved.
+ void updateTransformers(String package,
+ Iterable<Iterable<Transformer>> transformers) =>
+ _graph.updateTransformers(package, transformers);
+}
diff --git a/pkg/barback/lib/src/build_result.dart b/pkg/barback/lib/src/build_result.dart
index 89ee681..2cb305c 100644
--- a/pkg/barback/lib/src/build_result.dart
+++ b/pkg/barback/lib/src/build_result.dart
@@ -8,6 +8,7 @@
import 'package:stack_trace/stack_trace.dart';
+import 'errors.dart';
import 'utils.dart';
/// An event indicating that the cascade has finished building all assets.
@@ -23,7 +24,7 @@
bool get succeeded => errors.isEmpty;
BuildResult(Iterable<BarbackException> errors)
- : errors = errors.toSet();
+ : errors = flattenAggregateExceptions(errors).toSet();
/// Creates a build result indicating a successful build.
///
diff --git a/pkg/barback/lib/src/change_batch.dart b/pkg/barback/lib/src/change_batch.dart
index aa2a1c4..8f98995 100644
--- a/pkg/barback/lib/src/change_batch.dart
+++ b/pkg/barback/lib/src/change_batch.dart
@@ -4,7 +4,6 @@
library barback.change_batch;
-import 'asset.dart';
import 'asset_id.dart';
/// Represents a batch of source asset changes: additions, removals and
diff --git a/pkg/barback/lib/src/errors.dart b/pkg/barback/lib/src/errors.dart
index f356066..a240bb4 100644
--- a/pkg/barback/lib/src/errors.dart
+++ b/pkg/barback/lib/src/errors.dart
@@ -5,12 +5,12 @@
library barback.errors;
import 'dart:async';
-import 'dart:io';
import 'package:stack_trace/stack_trace.dart';
import 'asset_id.dart';
import 'transformer.dart';
+import 'utils.dart';
/// Error thrown when an asset with [id] cannot be found.
class AssetNotFoundException implements Exception {
@@ -21,10 +21,54 @@
String toString() => "Could not find asset $id.";
}
+/// Replaces any occurrences of [AggregateException] in [errors] with the list
+/// of errors it contains.
+Iterable<BarbackException> flattenAggregateExceptions(
+ Iterable<BarbackException> errors) {
+ return errors.expand((error) {
+ if (error is! AggregateException) return [error];
+ return error.errors;
+ });
+}
+
/// The interface for exceptions from the barback graph or its transformers.
///
/// These exceptions are never produced by programming errors in barback.
-abstract class BarbackException implements Exception {}
+abstract class BarbackException implements Exception {
+ /// Takes a collection of [BarbackExceptions] and returns a single exception
+ /// that contains them all.
+ ///
+ /// If [errors] is empty, returns `null`. If it only has one error, that
+ /// error is returned. Otherwise, an [AggregateException] is returned.
+ static BarbackException aggregate(Iterable<BarbackException> errors) {
+ if (errors.isEmpty) return null;
+ if (errors.length == 1) return errors.single;
+ return new AggregateException(errors);
+ }
+}
+
+/// An error that wraps a collection of other [BarbackException]s.
+///
+/// It implicitly flattens any [AggregateException]s that occur in the list of
+/// exceptions it wraps.
+class AggregateException implements BarbackException {
+ final Set<BarbackException> errors;
+
+ AggregateException(Iterable<BarbackException> errors)
+ : errors = flattenAggregateExceptions(errors).toSet();
+
+ String toString() {
+ var buffer = new StringBuffer();
+ buffer.writeln("Multiple errors occurred:\n");
+
+ for (var error in errors) {
+ buffer.writeln(prefixLines(error.toString(),
+ prefix: " ", firstPrefix: "- "));
+ }
+
+ return buffer.toString();
+ }
+}
/// Error thrown when two or more transformers both output an asset with [id].
class AssetCollisionException implements BarbackException {
@@ -67,34 +111,49 @@
"same package (${transform.primaryId.package}).";
}
-/// Error wrapping an exception thrown by a transform.
-class TransformerException implements BarbackException {
- /// The transform that threw the exception.
- final TransformInfo transform;
-
+/// Base class for an error that wraps another.
+abstract class _WrappedException implements BarbackException {
/// The wrapped exception.
final error;
- TransformerException(this.transform, this.error);
+ _WrappedException(this.error);
- String toString() => "Transform $transform threw error: $error\n" +
- new Trace.from(getAttachedStackTrace(error)).terse.toString();
+ String get _message;
+
+ String toString() {
+ var result = "$_message: $error";
+
+ var stack = getAttachedStackTrace(error);
+ if (stack != null) {
+ result = "$result\n${new Trace.from(stack).terse}";
+ }
+
+ return result;
+ }
+}
+
+/// Error wrapping an exception thrown by a transform.
+class TransformerException extends _WrappedException {
+ /// The transform that threw the exception.
+ final TransformInfo transform;
+
+ TransformerException(this.transform, error)
+ : super(error);
+
+ String get _message => "Transform $transform threw error";
}
/// Error thrown when a source asset [id] fails to load.
///
/// This can be thrown either because the source asset was expected to exist and
/// did not or because reading it failed somehow.
-class AssetLoadException implements BarbackException {
+class AssetLoadException extends _WrappedException {
final AssetId id;
- /// The wrapped exception.
- final error;
+ AssetLoadException(this.id, error)
+ : super(error);
- AssetLoadException(this.id, this.error);
-
- String toString() => "Failed to load source asset $id: $error\n"
- "${new Trace.from(getAttachedStackTrace(error)).terse}";
+ String get _message => "Failed to load source asset $id";
}
/// Information about a single transform in the barback graph.
diff --git a/pkg/barback/lib/src/package_graph.dart b/pkg/barback/lib/src/package_graph.dart
index c46ed55..a402a27 100644
--- a/pkg/barback/lib/src/package_graph.dart
+++ b/pkg/barback/lib/src/package_graph.dart
@@ -6,15 +6,14 @@
import 'dart:async';
-import 'package:stack_trace/stack_trace.dart';
-
-import 'asset.dart';
import 'asset_cascade.dart';
import 'asset_id.dart';
import 'asset_node.dart';
+import 'asset_set.dart';
import 'build_result.dart';
import 'errors.dart';
import 'package_provider.dart';
+import 'transformer.dart';
import 'utils.dart';
/// The collection of [AssetCascade]s for an entire application.
@@ -55,12 +54,17 @@
Stream<BarbackException> get errors => _errors;
Stream<BarbackException> _errors;
+ /// The most recent error emitted from a cascade's result stream.
+ ///
+ /// This is used to pipe an unexpected error from a build to the resulting
+ /// [Future] returned by [getAllAssets].
+ var _lastUnexpectedError;
+
/// Creates a new [PackageGraph] that will transform assets in all packages
/// made available by [provider].
PackageGraph(this.provider) {
for (var package in provider.packages) {
- var cascade = new AssetCascade(this, package,
- provider.getTransformers(package));
+ var cascade = new AssetCascade(this, package);
// The initial result for each cascade is "success" since the cascade
// doesn't start building until some source in that graph is updated.
_cascadeResults[package] = new BuildResult.success();
@@ -76,7 +80,10 @@
// errors, the result will automatically be considered a success.
_resultsController.add(new BuildResult(unionAll(
_cascadeResults.values.map((result) => result.errors))));
- }, onError: _resultsController.addError);
+ }, onError: (error) {
+ _lastUnexpectedError = error;
+ _resultsController.addError(error);
+ });
}
_errors = mergeStreams(_cascades.values.map((cascade) => cascade.errors));
@@ -95,6 +102,38 @@
return new Future.value(null);
}
+ /// Gets all output assets.
+ ///
+ /// If a build is currently in progress, waits until it completes. The
+ /// returned future will complete with an error if the build is not
+ /// successful.
+ Future<AssetSet> getAllAssets() {
+ if (_cascadeResults.values.contains(null)) {
+ // A build is still ongoing, so wait for it to complete and try again.
+ return results.first.then((_) => getAllAssets());
+ }
+
+ // If an unexpected error occurred, complete with that.
+ if (_lastUnexpectedError != null) {
+ var error = _lastUnexpectedError;
+ _lastUnexpectedError = null;
+ return new Future.error(error);
+ }
+
+ // If the build completed with an error, complete the future with it.
+ var errors = unionAll(
+ _cascadeResults.values.map((result) => result.errors));
+ if (errors.isNotEmpty) {
+ return new Future.error(BarbackException.aggregate(errors));
+ }
+
+ // Otherwise, return all of the final output assets.
+ var assets = unionAll(_cascades.values.map(
+ (cascade) => cascade.availableOutputs.toSet()));
+
+ return new Future.value(new AssetSet.from(assets));
+ }
+
/// Adds [sources] to the graph's known set of source assets.
///
/// Begins applying any transforms that can consume any of the sources. If a
@@ -118,4 +157,10 @@
cascade.removeSources(ids);
});
}
+
+ void updateTransformers(String package,
+ Iterable<Iterable<Transformer>> transformers) {
+ _cascadeResults[package] = null;
+ _cascades[package].updateTransformers(transformers);
+ }
}
diff --git a/pkg/barback/lib/src/package_provider.dart b/pkg/barback/lib/src/package_provider.dart
index 031caf8..349785c 100644
--- a/pkg/barback/lib/src/package_provider.dart
+++ b/pkg/barback/lib/src/package_provider.dart
@@ -8,7 +8,6 @@
import 'asset.dart';
import 'asset_id.dart';
-import 'transformer.dart';
/// API for locating and accessing packages on disk.
///
@@ -21,12 +20,6 @@
/// dependencies.
Iterable<String> get packages;
- /// Returns the list of transformer phases that are applicable to [package].
- ///
- /// The phases will be run in sequence, with the outputs of one pipelined into
- /// the next. All [Transformer]s in a single phase will be run in parallel.
- Iterable<Iterable<Transformer>> getTransformers(String package);
-
/// Loads an asset from disk.
///
/// This should be re-entrant; it may be called multiple times with the same
diff --git a/pkg/barback/lib/src/phase.dart b/pkg/barback/lib/src/phase.dart
index 86444ad..690126a 100644
--- a/pkg/barback/lib/src/phase.dart
+++ b/pkg/barback/lib/src/phase.dart
@@ -7,14 +7,13 @@
import 'dart:async';
import 'dart:collection';
-import 'asset.dart';
import 'asset_cascade.dart';
import 'asset_id.dart';
import 'asset_node.dart';
import 'asset_set.dart';
import 'errors.dart';
+import 'phase_input.dart';
import 'stream_pool.dart';
-import 'transform_node.dart';
import 'transformer.dart';
import 'utils.dart';
@@ -34,47 +33,16 @@
/// The cascade that owns this phase.
final AssetCascade cascade;
- /// This phase's position relative to the other phases. Zero-based.
- final int _index;
-
/// The transformers that can access [inputs].
///
/// Their outputs will be available to the next phase.
- final List<Transformer> _transformers;
+ final Set<Transformer> _transformers;
- /// The inputs that are available for transforms in this phase to consume.
+ /// The inputs for this phase.
///
/// For the first phase, these will be the source assets. For all other
/// phases, they will be the outputs from the previous phase.
- final _inputs = new Map<AssetId, AssetNode>();
-
- /// The transforms currently applicable to assets in [inputs], indexed by
- /// the ids of their primary inputs.
- ///
- /// These are the transforms that have been "wired up": they represent a
- /// repeatable transformation of a single concrete set of inputs. "dart2js"
- /// is a transformer. "dart2js on web/main.dart" is a transform.
- final _transforms = new Map<AssetId, Set<TransformNode>>();
-
- /// Controllers for assets that aren't consumed by transforms in this phase.
- ///
- /// These assets are passed to the next phase unmodified. They need
- /// intervening controllers to ensure that the outputs can be marked dirty
- /// when determining whether transforms apply, and removed if they do.
- final _passThroughControllers = new Map<AssetId, AssetNodeController>();
-
- /// Futures that will complete once the transformers that can consume a given
- /// asset are determined.
- ///
- /// Whenever an asset is added or modified, we need to asynchronously
- /// determine which transformers can use it as their primary input. We can't
- /// start processing until we know which transformers to run, and this allows
- /// us to wait until we do.
- var _adjustTransformersFutures = new Map<AssetId, Future>();
-
- /// New asset nodes that were added while [_adjustTransformers] was still
- /// being run on an old version of that asset.
- var _pendingNewInputs = new Map<AssetId, AssetNode>();
+ final _inputs = new Map<AssetId, PhaseInput>();
/// A map of output ids to the asset node outputs for those ids and the
/// transforms that produced those asset nodes.
@@ -97,18 +65,25 @@
/// A controller whose stream feeds into [_onDirtyPool].
///
- /// This is used whenever an input is added, changed, or removed. It's
- /// sometimes redundant with the events collected from [_transforms], but this
- /// stream is necessary for new and removed inputs, and the transform stream
- /// is necessary for modified secondary inputs.
+ /// This is used whenever an input is added or transforms are changed.
final _onDirtyController = new StreamController.broadcast(sync: true);
/// The phase after this one.
///
/// Outputs from this phase will be passed to it.
- final Phase _next;
+ Phase get next => _next;
+ Phase _next;
- Phase(this.cascade, this._index, this._transformers, this._next) {
+ /// Returns all currently-available output assets for this phase.
+ AssetSet get availableOutputs {
+ return new AssetSet.from(_outputs.values
+ .map((queue) => queue.first)
+ .where((node) => node.state.isAvailable)
+ .map((node) => node.asset));
+ }
+
+ Phase(this.cascade, Iterable<Transformer> transformers)
+ : _transformers = transformers.toSet() {
_onDirtyPool.add(_onDirtyController.stream);
}
@@ -123,51 +98,13 @@
/// removed and re-created. The phase will automatically handle updated assets
/// using the [AssetNode.onStateChange] stream.
void addInput(AssetNode node) {
- // We remove [node.id] from [inputs] as soon as the node is removed rather
- // than at the same time [node.id] is removed from [_transforms] so we don't
- // have to wait on [_adjustTransformers]. It's important that [inputs] is
- // always up-to-date so that the [AssetCascade] can look there for available
- // assets.
- _inputs[node.id] = node;
- node.whenRemoved.then((_) => _inputs.remove(node.id));
+ if (_inputs.containsKey(node.id)) _inputs[node.id].remove();
- if (!_adjustTransformersFutures.containsKey(node.id)) {
- _transforms[node.id] = new Set<TransformNode>();
- _adjustTransformers(node);
- return;
- }
-
- // If an input is added while the same input is still being processed,
- // that means that the asset was removed and recreated while
- // [_adjustTransformers] was being run on the old value. We have to wait
- // until that finishes, then run it again on whatever the newest version
- // of that asset is.
-
- // We may already be waiting for the existing [_adjustTransformers] call to
- // finish. If so, all we need to do is change the node that will be loaded
- // after it completes.
- var containedKey = _pendingNewInputs.containsKey(node.id);
- _pendingNewInputs[node.id] = node;
- if (containedKey) return;
-
- // If we aren't already waiting, start doing so.
- _adjustTransformersFutures[node.id].then((_) {
- assert(!_adjustTransformersFutures.containsKey(node.id));
- assert(_pendingNewInputs.containsKey(node.id));
- _transforms[node.id] = new Set<TransformNode>();
- _adjustTransformers(_pendingNewInputs.remove(node.id));
- }, onError: (_) {
- // If there was a programmatic error while processing the old input,
- // we don't want to just ignore it; it may have left the system in an
- // inconsistent state. We also don't want to top-level it, so we
- // ignore it here but don't start processing the new input. That way
- // when [process] is called, the error will be piped through its
- // return value.
- }).catchError((e) {
- // If our code above has a programmatic error, ensure it will be piped
- // through [process] by putting it into [_adjustTransformersFutures].
- _adjustTransformersFutures[node.id] = new Future.error(e);
- });
+ var input = new PhaseInput(this, node, _transformers);
+ _inputs[node.id] = input;
+ input.input.whenRemoved.then((_) => _inputs.remove(node.id));
+ _onDirtyPool.add(input.onDirty);
+ _onDirtyController.add(null);
}
/// Gets the asset node for an input [id].
@@ -175,189 +112,60 @@
/// If an input with that ID cannot be found, returns null.
Future<AssetNode> getInput(AssetId id) {
return newFuture(() {
- if (id.package == cascade.package) return _inputs[id];
- return cascade.graph.getAssetNode(id);
+ if (id.package != cascade.package) return cascade.graph.getAssetNode(id);
+ if (_inputs.containsKey(id)) return _inputs[id].input;
+ return null;
});
}
- /// Asynchronously determines which transformers can consume [node] as a
- /// primary input and creates transforms for them.
+ /// Gets the asset node for an output [id].
///
- /// This ensures that if [node] is modified or removed during or after the
- /// time it takes to adjust its transformers, they're appropriately
- /// re-adjusted. Its progress can be tracked in [_adjustTransformersFutures].
- void _adjustTransformers(AssetNode node) {
- // Mark the phase as dirty. This may not actually end up creating any new
- // transforms, but we want adding or removing a source asset to consistently
- // kick off a build, even if that build does nothing.
+ /// If an output with that ID cannot be found, returns null.
+ Future<AssetNode> getOutput(AssetId id) {
+ return newFuture(() {
+ if (id.package != cascade.package) return cascade.graph.getAssetNode(id);
+ if (!_outputs.containsKey(id)) return null;
+ return _outputs[id].first;
+ });
+ }
+
+ /// Set this phase's transformers to [transformers].
+ void updateTransformers(Iterable<Transformer> transformers) {
_onDirtyController.add(null);
-
- // If there's a pass-through for this node, mark it dirty while we figure
- // out whether we need to add any transforms for it.
- var controller = _passThroughControllers[node.id];
- if (controller != null) controller.setDirty();
-
- // Once the input is available, hook up transformers for it. If it changes
- // while that's happening, try again.
- _adjustTransformersFutures[node.id] = node.tryUntilStable((asset) {
- var oldTransformers = _transforms[node.id]
- .map((transform) => transform.transformer).toSet();
-
- return _removeStaleTransforms(asset)
- .then((_) => _addFreshTransforms(node, oldTransformers));
- }).then((_) {
- _adjustPassThrough(node);
-
- // Now all the transforms are set up correctly and the asset is available
- // for the time being. Set up handlers for when the asset changes in the
- // future.
- node.onStateChange.first.then((state) {
- if (state.isRemoved) {
- _onDirtyController.add(null);
- _transforms.remove(node.id);
- var passThrough = _passThroughControllers.remove(node.id);
- if (passThrough != null) passThrough.setRemoved();
- } else {
- _adjustTransformers(node);
- }
- }).catchError((e) {
- _adjustTransformersFutures[node.id] = new Future.error(e);
- });
- }).catchError((error) {
- if (error is! AssetNotFoundException || error.id != node.id) throw error;
-
- // If the asset is removed, [tryUntilStable] will throw an
- // [AssetNotFoundException]. In that case, just remove all transforms for
- // the node, and its pass-through.
- _transforms.remove(node.id);
- var passThrough = _passThroughControllers.remove(node.id);
- if (passThrough != null) passThrough.setRemoved();
- }).whenComplete(() {
- _adjustTransformersFutures.remove(node.id);
- });
-
- // Don't top-level errors coming from the input processing. Any errors will
- // eventually be piped through [process]'s returned Future.
- _adjustTransformersFutures[node.id].catchError((_) {});
- }
-
- // Remove any old transforms that used to have [asset] as a primary asset but
- // no longer apply to its new contents.
- Future _removeStaleTransforms(Asset asset) {
- return Future.wait(_transforms[asset.id].map((transform) {
- // TODO(rnystrom): Catch all errors from isPrimary() and redirect to
- // results.
- return transform.transformer.isPrimary(asset).then((isPrimary) {
- if (isPrimary) return;
- _transforms[asset.id].remove(transform);
- _onDirtyPool.remove(transform.onDirty);
- transform.remove();
- });
- }));
- }
-
- // Add new transforms for transformers that consider [node]'s asset to be a
- // primary input.
- //
- // [oldTransformers] is the set of transformers that had [node] as a primary
- // input prior to this. They don't need to be checked, since they were removed
- // or preserved in [_removeStaleTransforms].
- Future _addFreshTransforms(AssetNode node, Set<Transformer> oldTransformers) {
- return Future.wait(_transformers.map((transformer) {
- if (oldTransformers.contains(transformer)) return new Future.value();
-
- // If the asset is unavailable, the results of this [_adjustTransformers]
- // run will be discarded, so we can just short-circuit.
- if (node.asset == null) return new Future.value();
-
- // We can safely access [node.asset] here even though it might have
- // changed since (as above) if it has, [_adjustTransformers] will just be
- // re-run.
- // TODO(rnystrom): Catch all errors from isPrimary() and redirect to
- // results.
- return transformer.isPrimary(node.asset).then((isPrimary) {
- if (!isPrimary) return;
- var transform = new TransformNode(this, transformer, node);
- _transforms[node.id].add(transform);
- _onDirtyPool.add(transform.onDirty);
- });
- }));
- }
-
- /// Adjust whether [node] is passed through the phase unmodified, based on
- /// whether it's consumed by other transforms in this phase.
- ///
- /// If [node] was already passed-through, this will update the passed-through
- /// value.
- void _adjustPassThrough(AssetNode node) {
- assert(node.state.isAvailable);
-
- if (_transforms[node.id].isEmpty) {
- var controller = _passThroughControllers[node.id];
- if (controller != null) {
- controller.setAvailable(node.asset);
- } else {
- _passThroughControllers[node.id] =
- new AssetNodeController.available(node.asset, node.transform);
- }
- } else {
- var controller = _passThroughControllers.remove(node.id);
- if (controller != null) controller.setRemoved();
+ _transformers.clear();
+ _transformers.addAll(transformers);
+ for (var input in _inputs.values) {
+ input.updateTransformers(_transformers);
}
}
+ /// Add a new phase after this one with [transformers].
+ ///
+ /// This may only be called on a phase with no phase following it.
+ Phase addPhase(Iterable<Transformer> transformers) {
+ assert(_next == null);
+ _next = new Phase(cascade, transformers);
+ for (var outputs in _outputs.values) {
+ _next.addInput(outputs.first);
+ }
+ return _next;
+ }
+
/// Processes this phase.
///
/// Returns a future that completes when processing is done. If there is
/// nothing to process, returns `null`.
Future process() {
- if (_adjustTransformersFutures.isEmpty) return _processTransforms();
- return _waitForInputs().then((_) => _processTransforms());
- }
+ if (!_inputs.values.any((input) => input.isDirty)) return null;
- Future _waitForInputs() {
- if (_adjustTransformersFutures.isEmpty) return new Future.value();
- return Future.wait(_adjustTransformersFutures.values)
- .then((_) => _waitForInputs());
- }
-
- /// Applies all currently wired up and dirty transforms.
- Future _processTransforms() {
- if (_next == null) return;
-
- var newPassThroughs = _passThroughControllers.values
- .map((controller) => controller.node)
- .where((output) {
- return !_outputs.containsKey(output.id) ||
- !_outputs[output.id].contains(output);
- }).toSet();
-
- // Convert this to a list so we can safely modify _transforms while
- // iterating over it.
- var dirtyTransforms =
- flatten(_transforms.values.map((transforms) => transforms.toList()))
- .where((transform) => transform.isDirty).toList();
-
- if (dirtyTransforms.isEmpty && newPassThroughs.isEmpty) return null;
-
- var collisions = _passAssetsThrough(newPassThroughs);
- return Future.wait(dirtyTransforms.map((transform) {
- return transform.apply().then((outputs) {
- for (var output in outputs) {
- if (_outputs.containsKey(output.id)) {
- _outputs[output.id].add(output);
- collisions.add(output.id);
- } else {
- _outputs[output.id] = new Queue<AssetNode>.from([output]);
- _next.addInput(output);
- }
-
- _handleOutputRemoval(output);
- }
+ return Future.wait(_inputs.values.map((input) {
+ if (!input.isDirty) return new Future.value(new Set());
+ return input.process().then((outputs) {
+ return outputs.where(_addOutput).map((output) => output.id).toSet();
});
- })).then((_) {
+ })).then((collisionsList) {
// Report collisions in a deterministic order.
- collisions = collisions.toList();
+ var collisions = unionAll(collisionsList).toList();
collisions.sort((a, b) => a.compareTo(b));
for (var collision in collisions) {
// Ensure that there's still a collision. It's possible it was resolved
@@ -371,28 +179,21 @@
});
}
- /// Pass all new assets that aren't consumed by transforms through to the next
- /// phase.
+ /// Add [output] as an output of this phase, forwarding it to the next phase
+ /// if necessary.
///
- /// Returns a set of asset ids that have collisions between new passed-through
- /// assets and pre-existing transform outputs.
- Set<AssetId> _passAssetsThrough(Set<AssetId> newPassThroughs) {
- var collisions = new Set<AssetId>();
- for (var output in newPassThroughs) {
- if (_outputs.containsKey(output.id)) {
- // There shouldn't be another pass-through asset with the same id.
- assert(!_outputs[output.id].any((asset) => asset.transform == null));
+ /// Returns whether or not [output] collides with another pre-existing output.
+ bool _addOutput(AssetNode output) {
+ _handleOutputRemoval(output);
- _outputs[output.id].add(output);
- collisions.add(output.id);
- } else {
- _outputs[output.id] = new Queue<AssetNode>.from([output]);
- _next.addInput(output);
- }
-
- _handleOutputRemoval(output);
+ if (_outputs.containsKey(output.id)) {
+ _outputs[output.id].add(output);
+ return true;
}
- return collisions;
+
+ _outputs[output.id] = new Queue<AssetNode>.from([output]);
+ if (_next != null) _next.addInput(output);
+ return false;
}
/// Properly resolve collisions when [output] is removed.
@@ -414,7 +215,7 @@
// (chronologically) to the next phase. Pump the event queue first to give
// [_next] a chance to handle the removal of its input before getting a
// new input.
- if (wasFirst) {
+ if (wasFirst && _next != null) {
newFuture(() => _next.addInput(assets.first));
}
diff --git a/pkg/barback/lib/src/phase_input.dart b/pkg/barback/lib/src/phase_input.dart
new file mode 100644
index 0000000..7ba6c20
--- /dev/null
+++ b/pkg/barback/lib/src/phase_input.dart
@@ -0,0 +1,296 @@
+// 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 barback.phase_input;
+
+import 'dart:async';
+import 'dart:collection';
+
+import 'asset.dart';
+import 'asset_forwarder.dart';
+import 'asset_node.dart';
+import 'errors.dart';
+import 'stream_pool.dart';
+import 'transform_node.dart';
+import 'transformer.dart';
+import 'utils.dart';
+
+/// A class for watching a single [AssetNode] and running any transforms that
+/// take that node as a primary input.
+class PhaseInput {
+ /// The phase for which this is an input.
+ final Phase _phase;
+
+ /// The transformers to (potentially) run against [input].
+ final Set<Transformer> _transformers;
+
+ /// The transforms currently applicable to [input].
+ ///
+ /// These are the transforms that have been "wired up": they represent a
+ /// repeatable transformation of a single concrete set of inputs. "dart2js" is
+ /// a transformer. "dart2js on web/main.dart" is a transform.
+ final _transforms = new Set<TransformNode>();
+
+ /// A forwarder for the input [AssetNode] for this phase.
+ ///
+ /// This is used to mark the node as removed should the input ever be removed.
+ final AssetForwarder _inputForwarder;
+
+ /// The asset node for this input.
+ AssetNode get input => _inputForwarder.node;
+
+ /// The controller that's used for the output node if [input] isn't consumed
+ /// by any transformers.
+ ///
+ /// This needs an intervening controller to ensure that the output can be
+ /// marked dirty when determining whether transforms apply, and removed if
+ /// they do. It's null if the asset is not being passed through.
+ AssetNodeController _passThroughController;
+
+ /// Whether [_passThroughController] has been newly created since [process]
+ /// last completed.
+ bool _newPassThrough = false;
+
+ /// A Future that will complete once the transformers that consume [input] are
+ /// determined.
+ Future _adjustTransformersFuture;
+
+ /// A stream that emits an event whenever this input becomes dirty and needs
+ /// [process] to be called.
+ ///
+ /// This may emit events when the input was already dirty or while processing
+ /// transforms. Events are emitted synchronously to ensure that the dirty
+ /// state is thoroughly propagated as soon as any assets are changed.
+ Stream get onDirty => _onDirtyPool.stream;
+ final _onDirtyPool = new StreamPool.broadcast();
+
+ /// A controller whose stream feeds into [_onDirtyPool].
+ ///
+ /// This is used whenever the input is changed or removed. It's sometimes
+ /// redundant with the events collected from [_transforms], but this stream is
+ /// necessary for removed inputs, and the transform stream is necessary for
+ /// modified secondary inputs.
+ final _onDirtyController = new StreamController.broadcast(sync: true);
+
+ /// Whether this input is dirty and needs [process] to be called.
+ bool get isDirty => _adjustTransformersFuture != null ||
+ _newPassThrough || _transforms.any((transform) => transform.isDirty);
+
+ PhaseInput(this._phase, AssetNode input, Iterable<Transformer> transformers)
+ : _transformers = transformers.toSet(),
+ _inputForwarder = new AssetForwarder(input) {
+ _onDirtyPool.add(_onDirtyController.stream);
+
+ input.onStateChange.listen((state) {
+ if (state.isRemoved) {
+ remove();
+ } else if (_adjustTransformersFuture == null) {
+ _adjustTransformers();
+ }
+ });
+
+ _adjustTransformers();
+ }
+
+ /// Removes this input.
+ ///
+ /// This marks all outputs of the input as removed.
+ void remove() {
+ _onDirtyController.add(null);
+ _onDirtyPool.close();
+ _inputForwarder.close();
+ if (_passThroughController != null) {
+ _passThroughController.setRemoved();
+ _passThroughController = null;
+ }
+ }
+
+ /// Set this input's transformers to [transformers].
+ void updateTransformers(Set<Transformer> newTransformers) {
+ var oldTransformers = _transformers.toSet();
+ for (var removedTransformer in
+ oldTransformers.difference(newTransformers)) {
+ _transformers.remove(removedTransformer);
+
+ // If the transformers are being adjusted for [id], it will
+ // automatically pick up on [removedTransformer] being gone.
+ if (_adjustTransformersFuture != null) continue;
+
+ _transforms.removeWhere((transform) {
+ if (transform.transformer != removedTransformer) return false;
+ transform.remove();
+ return true;
+ });
+ }
+
+ if (_transforms.isEmpty && _adjustTransformersFuture == null &&
+ _passThroughController == null) {
+ _passThroughController =
+ new AssetNodeController.available(input.asset, input.transform);
+ _newPassThrough = true;
+ }
+
+ var brandNewTransformers = newTransformers.difference(oldTransformers);
+ if (brandNewTransformers.isEmpty) return;
+
+ brandNewTransformers.forEach(_transformers.add);
+ _adjustTransformers();
+ }
+
+ /// Asynchronously determines which transformers can consume [input] as a
+ /// primary input and creates transforms for them.
+ ///
+ /// This ensures that if [input] is modified or removed during or after the
+ /// time it takes to adjust its transformers, they're appropriately
+ /// re-adjusted. Its progress can be tracked in [_adjustTransformersFuture].
+ void _adjustTransformers() {
+ // Mark the input as dirty. This may not actually end up creating any new
+ // transforms, but we want adding or removing a source asset to consistently
+ // kick off a build, even if that build does nothing.
+ _onDirtyController.add(null);
+
+ // If there's a pass-through for this input, mark it dirty while we figure
+ // out whether we need to add any transforms for it.
+ if (_passThroughController != null) _passThroughController.setDirty();
+
+ // Once the input is available, hook up transformers for it. If it changes
+ // while that's happening, try again.
+ _adjustTransformersFuture = _tryUntilStable((asset, transformers) {
+ var oldTransformers =
+ _transforms.map((transform) => transform.transformer).toSet();
+
+ return _removeStaleTransforms(asset, transformers).then((_) =>
+ _addFreshTransforms(transformers, oldTransformers));
+ }).then((_) => _adjustPassThrough()).catchError((error) {
+ if (error is! AssetNotFoundException || error.id != input.id) {
+ throw error;
+ }
+
+ // If the asset is removed, [_tryUntilStable] will throw an
+ // [AssetNotFoundException]. In that case, just remove it.
+ remove();
+ }).whenComplete(() {
+ _adjustTransformersFuture = null;
+ });
+
+ // Don't top-level errors coming from the input processing. Any errors will
+ // eventually be piped through [process]'s returned Future.
+ _adjustTransformersFuture.catchError((_) {});
+ }
+
+ // Remove any old transforms that used to have [asset] as a primary asset but
+ // no longer apply to its new contents.
+ Future _removeStaleTransforms(Asset asset, Set<Transformer> transformers) {
+ return Future.wait(_transforms.map((transform) {
+ return newFuture(() {
+ if (!transformers.contains(transform.transformer)) return false;
+
+ // TODO(rnystrom): Catch all errors from isPrimary() and redirect to
+ // results.
+ return transform.transformer.isPrimary(asset);
+ }).then((isPrimary) {
+ if (isPrimary) return;
+ _transforms.remove(transform);
+ transform.remove();
+ });
+ }));
+ }
+
+ // Add new transforms for transformers that consider [input]'s asset to be a
+ // primary input.
+ //
+ // [oldTransformers] is the set of transformers for which there were
+ // transforms that had [input] as a primary input prior to this. They don't
+ // need to be checked, since their transforms were removed or preserved in
+ // [_removeStaleTransforms].
+ Future _addFreshTransforms(Set<Transformer> transformers,
+ Set<Transformer> oldTransformers) {
+ return Future.wait(transformers.map((transformer) {
+ if (oldTransformers.contains(transformer)) return new Future.value();
+
+ // If the asset is unavailable, the results of this [_adjustTransformers]
+ // run will be discarded, so we can just short-circuit.
+ if (input.asset == null) return new Future.value();
+
+ // We can safely access [input.asset] here even though it might have
+ // changed since (as above) if it has, [_adjustTransformers] will just be
+ // re-run.
+ // TODO(rnystrom): Catch all errors from isPrimary() and redirect to
+ // results.
+ return transformer.isPrimary(input.asset).then((isPrimary) {
+ if (!isPrimary) return;
+ var transform = new TransformNode(_phase, transformer, input);
+ _transforms.add(transform);
+ _onDirtyPool.add(transform.onDirty);
+ });
+ }));
+ }
+
+ /// Adjust whether [input] is passed through the phase unmodified, based on
+ /// whether it's consumed by other transforms in this phase.
+ ///
+ /// If [input] was already passed-through, this will update the passed-through
+ /// value.
+ void _adjustPassThrough() {
+ assert(input.state.isAvailable);
+
+ if (_transforms.isEmpty) {
+ if (_passThroughController != null) {
+ _passThroughController.setAvailable(input.asset);
+ } else {
+ _passThroughController =
+ new AssetNodeController.available(input.asset, input.transform);
+ _newPassThrough = true;
+ }
+ } else if (_passThroughController != null) {
+ _passThroughController.setRemoved();
+ _passThroughController = null;
+ _newPassThrough = false;
+ }
+ }
+
+ /// Like [AssetNode.tryUntilStable], but also re-runs [callback] if this
+ /// phase's transformers are modified.
+ Future _tryUntilStable(
+ Future callback(Asset asset, Set<Transformer> transformers)) {
+ var oldTransformers;
+ return input.tryUntilStable((asset) {
+ oldTransformers = _transformers.toSet();
+ return callback(asset, _transformers);
+ }).then((result) {
+ if (setEquals(oldTransformers, _transformers)) return result;
+ return _tryUntilStable(callback);
+ });
+ }
+
+ /// Processes the transforms for this input.
+ Future<Set<AssetNode>> process() {
+ if (_adjustTransformersFuture == null) return _processTransforms();
+ return _waitForInputs().then((_) => _processTransforms());
+ }
+
+ Future _waitForInputs() {
+ // Return a synchronous future so we can be sure [_adjustTransformers] isn't
+ // called between now and when the Future completes.
+ if (_adjustTransformersFuture == null) return new Future.sync(() {});
+ return _adjustTransformersFuture.then((_) => _waitForInputs());
+ }
+
+ /// Applies all currently wired up and dirty transforms.
+ Future<Set<AssetNode>> _processTransforms() {
+ if (input.state.isRemoved) return new Future.value(new Set());
+
+ if (_passThroughController != null) {
+ if (!_newPassThrough) return new Future.value(new Set());
+ _newPassThrough = false;
+ return new Future.value(
+ new Set<AssetNode>.from([_passThroughController.node]));
+ }
+
+ return Future.wait(_transforms.map((transform) {
+ if (!transform.isDirty) return new Future.value(new Set());
+ return transform.apply();
+ })).then((outputs) => unionAll(outputs));
+ }
+}
diff --git a/pkg/barback/lib/src/transform.dart b/pkg/barback/lib/src/transform.dart
index c254778..d5d7176 100644
--- a/pkg/barback/lib/src/transform.dart
+++ b/pkg/barback/lib/src/transform.dart
@@ -13,7 +13,6 @@
import 'errors.dart';
import 'transform_logger.dart';
import 'transform_node.dart';
-import 'utils.dart';
/// Creates a [Transform] by forwarding to the private constructor.
///
diff --git a/pkg/barback/lib/src/transform_node.dart b/pkg/barback/lib/src/transform_node.dart
index 1d3d1dd..578b2fa 100644
--- a/pkg/barback/lib/src/transform_node.dart
+++ b/pkg/barback/lib/src/transform_node.dart
@@ -14,7 +14,6 @@
import 'phase.dart';
import 'transform.dart';
import 'transformer.dart';
-import 'utils.dart';
/// Describes a transform on a set of assets and its relationship to the build
/// dependency graph.
@@ -133,7 +132,7 @@
// Don't allow partial results from a failed transform.
newOutputs.clear();
}).then((_) {
- if (_isDirty) return [];
+ if (_isDirty) return new Set();
return _adjustOutputs(newOutputs);
});
diff --git a/pkg/barback/lib/src/transformer.dart b/pkg/barback/lib/src/transformer.dart
index 422066f..e8479f1 100644
--- a/pkg/barback/lib/src/transformer.dart
+++ b/pkg/barback/lib/src/transformer.dart
@@ -5,7 +5,6 @@
library barback.transformer;
import 'dart:async';
-import 'dart:io';
import 'asset.dart';
import 'transform.dart';
@@ -17,6 +16,15 @@
/// files are all examples of transformers. To define your own transformation
/// step, extend (or implement) this class.
abstract class Transformer {
+ /// Override this to return a space-separated list of file extensions
+ /// (with leading `.`) that are allowed for the primary inputs to this
+ /// transformer.
+ ///
+ /// If you don't override [isPrimary] yourself, it defaults to allowing any
+ /// asset whose extension matches one of the ones returned by this. If you
+ /// don't override [isPrimary] *or* this, it allows all files.
+ String get allowedExtensions => null;
+
/// Returns `true` if [input] can be a primary input for this transformer.
///
/// While a transformer can read from multiple input files, one must be the
@@ -29,7 +37,20 @@
/// of those to generate the final JS. However you still run dart2js "on" a
/// single file: the entrypoint Dart file that has your `main()` method.
/// This entrypoint file would be the primary input.
- Future<bool> isPrimary(Asset input);
+ ///
+ /// If this is not overridden, defaults to allow any asset whose extension
+ /// matches one of the ones returned by [allowedExtensions]. If *that* is
+ /// not overridden, allows all assets.
+ Future<bool> isPrimary(Asset input) {
+ // Allow all files if [primaryExtensions] is not overridden.
+ if (allowedExtensions == null) return new Future.value(true);
+
+ for (var extension in allowedExtensions.split(" ")) {
+ if (input.id.extension == extension) return new Future.value(true);
+ }
+
+ return new Future.value(false);
+ }
/// Run this transformer on on the primary input specified by [transform].
///
diff --git a/pkg/barback/lib/src/utils.dart b/pkg/barback/lib/src/utils.dart
index bee6084..3272e9e 100644
--- a/pkg/barback/lib/src/utils.dart
+++ b/pkg/barback/lib/src/utils.dart
@@ -72,6 +72,10 @@
Map mapMapValues(Map map, fn(key, value)) =>
new Map.fromIterable(map.keys, value: (key) => fn(key, map[key]));
+/// Returns whether [set1] has exactly the same elements as [set2].
+bool setEquals(Set set1, Set set2) =>
+ set1.length == set2.length && set1.containsAll(set2);
+
/// Merges [streams] into a single stream that emits events from all sources.
Stream mergeStreams(Iterable<Stream> streams) {
streams = streams.toList();
diff --git a/pkg/barback/test/asset_id_test.dart b/pkg/barback/test/asset_id_test.dart
index 6e4a7d8..a55bb18 100644
--- a/pkg/barback/test/asset_id_test.dart
+++ b/pkg/barback/test/asset_id_test.dart
@@ -4,8 +4,6 @@
library barback.test.asset_id_test;
-import 'dart:async';
-
import 'package:barback/barback.dart';
import 'package:unittest/unittest.dart';
diff --git a/pkg/barback/test/asset_set_test.dart b/pkg/barback/test/asset_set_test.dart
index 5b6b652..3208329 100644
--- a/pkg/barback/test/asset_set_test.dart
+++ b/pkg/barback/test/asset_set_test.dart
@@ -4,11 +4,7 @@
library barback.test.asset_set_test;
-import 'dart:async';
-import 'dart:io';
-
import 'package:barback/barback.dart';
-import 'package:barback/src/asset_set.dart';
import 'package:unittest/unittest.dart';
import 'utils.dart';
diff --git a/pkg/barback/test/package_graph/add_remove_transform_test.dart b/pkg/barback/test/package_graph/add_remove_transform_test.dart
new file mode 100644
index 0000000..b79c69a
--- /dev/null
+++ b/pkg/barback/test/package_graph/add_remove_transform_test.dart
@@ -0,0 +1,240 @@
+// 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 barback.test.package_graph.transform_test;
+
+import 'package:barback/src/utils.dart';
+import 'package:scheduled_test/scheduled_test.dart';
+
+import '../utils.dart';
+
+main() {
+ initConfig();
+ test("a new transformer is applied to a matching asset", () {
+ initGraph(["app|foo.blub"]);
+
+ updateSources(["app|foo.blub"]);
+ expectAsset("app|foo.blub", "foo");
+ buildShouldSucceed();
+
+ updateTransformers("app", [[new RewriteTransformer("blub", "blab")]]);
+ expectAsset("app|foo.blab", "foo.blab");
+ expectNoAsset("app|foo.blub");
+ buildShouldSucceed();
+ });
+
+ test("a new transformer is not applied to a non-matching asset", () {
+ initGraph(["app|foo.blub"]);
+
+ updateSources(["app|foo.blub"]);
+ expectAsset("app|foo.blub", "foo");
+ buildShouldSucceed();
+
+ updateTransformers("app", [[new RewriteTransformer("zip", "zap")]]);
+ expectAsset("app|foo.blub", "foo");
+ expectNoAsset("app|foo.zap");
+ buildShouldSucceed();
+ });
+
+ test("updateTransformers doesn't re-run an old transformer", () {
+ var rewrite = new RewriteTransformer("blub", "blab");
+ initGraph(["app|foo.blub"], {"app": [[rewrite]]});
+
+ updateSources(["app|foo.blub"]);
+ expectAsset("app|foo.blab", "foo.blab");
+ expectNoAsset("app|foo.blub");
+ buildShouldSucceed();
+
+ updateTransformers("app", [[rewrite]]);
+ expectAsset("app|foo.blab", "foo.blab");
+ expectNoAsset("app|foo.blub");
+ buildShouldSucceed();
+
+ expect(rewrite.numRuns, completion(equals(1)));
+ });
+
+ test("updateTransformers re-runs old transformers in a new phase", () {
+ var rewrite1 = new RewriteTransformer("txt", "blub");
+ var rewrite2 = new RewriteTransformer("blub", "blab");
+ initGraph(["app|foo.txt"], {"app": [[rewrite1], [rewrite2]]});
+
+ updateSources(["app|foo.txt"]);
+ expectAsset("app|foo.blab", "foo.blub.blab");
+ expectNoAsset("app|foo.blub");
+ buildShouldSucceed();
+
+ updateTransformers("app", [[rewrite2], [rewrite1]]);
+ expectAsset("app|foo.blub", "foo.blub");
+ expectNoAsset("app|foo.blab");
+ buildShouldSucceed();
+ });
+
+ test("updateTransformers re-runs an old transformer when a previous phase "
+ "changes", () {
+ var rewrite = new RewriteTransformer("txt", "out");
+ initGraph(["app|foo.txt"], {"app": [[], [rewrite]]});
+
+ updateSources(["app|foo.txt"]);
+ expectAsset("app|foo.out", "foo.out");
+ buildShouldSucceed();
+
+ updateTransformers("app", [
+ [new RewriteTransformer("txt", "txt")],
+ [rewrite]
+ ]);
+ expectAsset("app|foo.out", "foo.txt.out");
+ buildShouldSucceed();
+ });
+
+ test("a removed transformer is no longer applied", () {
+ initGraph(["app|foo.blub"], {"app": [
+ [new RewriteTransformer("blub", "blab")]
+ ]});
+
+ updateSources(["app|foo.blub"]);
+ expectAsset("app|foo.blab", "foo.blab");
+ expectNoAsset("app|foo.blub");
+ buildShouldSucceed();
+
+ updateTransformers("app", []);
+ expectAsset("app|foo.blub", "foo");
+ expectNoAsset("app|foo.blab");
+ buildShouldSucceed();
+ });
+
+ test("a new transformer is pipelined", () {
+ var rewrite1 = new RewriteTransformer("source", "phase1");
+ var rewrite3 = new RewriteTransformer("phase2", "phase3");
+ initGraph(["app|foo.source"], {"app": [
+ [rewrite1],
+ [rewrite3]
+ ]});
+
+ updateSources(["app|foo.source"]);
+ expectNoAsset("app|foo.phase3");
+ buildShouldSucceed();
+
+ updateTransformers("app", [
+ [rewrite1],
+ [new RewriteTransformer("phase1", "phase2")],
+ [rewrite3]
+ ]);
+ expectAsset("app|foo.phase3", "foo.phase1.phase2.phase3");
+ buildShouldSucceed();
+ });
+
+ test("a removed transformer is un-pipelined", () {
+ var rewrite1 = new RewriteTransformer("source", "phase1");
+ var rewrite3 = new RewriteTransformer("phase2", "phase3");
+ initGraph(["app|foo.source"], {"app": [
+ [rewrite1],
+ [new RewriteTransformer("phase1", "phase2")],
+ [rewrite3]
+ ]});
+
+ updateSources(["app|foo.source"]);
+ expectAsset("app|foo.phase3", "foo.phase1.phase2.phase3");
+ buildShouldSucceed();
+
+ updateTransformers("app", [[rewrite1], [rewrite3]]);
+ expectNoAsset("app|foo.phase3");
+ buildShouldSucceed();
+ });
+
+ test("a transformer is removed during isPrimary", () {
+ var rewrite = new RewriteTransformer("blub", "blab");
+ initGraph(["app|foo.blub"], {"app": [[rewrite]]});
+
+ rewrite.pauseIsPrimary("app|foo.blub");
+ updateSources(["app|foo.blub"]);
+ // Ensure we're waiting on [rewrite.isPrimary].
+ schedule(pumpEventQueue);
+
+ updateTransformers("app", []);
+ rewrite.resumeIsPrimary("app|foo.blub");
+ expectAsset("app|foo.blub", "foo");
+ expectNoAsset("app|foo.blab");
+ buildShouldSucceed();
+ });
+
+ test("a transformer is removed during apply", () {
+ var rewrite = new RewriteTransformer("blub", "blab");
+ initGraph(["app|foo.blub"], {"app": [[rewrite]]});
+
+ rewrite.pauseApply();
+ updateSources(["app|foo.blub"]);
+ // Ensure we're waiting on [rewrite.apply].
+ schedule(pumpEventQueue);
+
+ updateTransformers("app", []);
+ rewrite.resumeApply();
+ expectAsset("app|foo.blub", "foo");
+ expectNoAsset("app|foo.blab");
+ buildShouldSucceed();
+ });
+
+ test("a new transformer can see pass-through assets", () {
+ var rewrite = new RewriteTransformer("zip", "zap");
+ initGraph(["app|foo.blub"], {"app": [[rewrite]]});
+
+ updateSources(["app|foo.blub"]);
+ buildShouldSucceed();
+
+ updateTransformers("app", [
+ [rewrite],
+ [new RewriteTransformer("blub", "blab")]
+ ]);
+ expectAsset("app|foo.blab", "foo.blab");
+ expectNoAsset("app|foo.blub");
+ buildShouldSucceed();
+ });
+
+ test("a cross-package transform sees a new transformer in a new phase", () {
+ // TODO(nweiz): make this work.
+ return;
+
+ var rewrite = new RewriteTransformer("inc", "inc");
+ initGraph({
+ "pkg1|foo.txt": "pkg2|foo.inc",
+ "pkg2|foo.inc": "foo"
+ }, {
+ "pkg1": [[new ManyToOneTransformer("txt")]],
+ "pkg2": [[rewrite]]
+ });
+
+ updateSources(["pkg1|foo.txt", "pkg2|foo.inc"]);
+ expectAsset("pkg1|foo.out", "foo");
+ buildShouldSucceed();
+
+ updateTransformers("pkg2", [
+ [rewrite],
+ [new RewriteTransformer("inc", "inc")]
+ ]);
+ expectAsset("pkg1|foo.out", "foo.inc.inc");
+ buildShouldSucceed();
+ });
+
+ test("a cross-package transform doesn't see a removed transformer in a "
+ "removed phase", () {
+ var rewrite = new RewriteTransformer("inc", "inc");
+ initGraph({
+ "pkg1|foo.txt": "pkg2|foo.inc",
+ "pkg2|foo.inc": "foo"
+ }, {
+ "pkg1": [[new ManyToOneTransformer("txt")]],
+ "pkg2": [
+ [rewrite],
+ [new RewriteTransformer("inc", "inc")]
+ ]
+ });
+
+ updateSources(["pkg1|foo.txt", "pkg2|foo.inc"]);
+ expectAsset("pkg1|foo.out", "foo.inc.inc");
+ buildShouldSucceed();
+
+ updateTransformers("pkg2", [[rewrite]]);
+ expectAsset("pkg1|foo.out", "foo.inc");
+ buildShouldSucceed();
+ });
+}
\ No newline at end of file
diff --git a/pkg/barback/test/package_graph/errors_test.dart b/pkg/barback/test/package_graph/errors_test.dart
index 8e4fd89..8c74991 100644
--- a/pkg/barback/test/package_graph/errors_test.dart
+++ b/pkg/barback/test/package_graph/errors_test.dart
@@ -4,9 +4,6 @@
library barback.test.package_graph.source_test;
-import 'dart:async';
-
-import 'package:barback/barback.dart';
import 'package:barback/src/utils.dart';
import 'package:scheduled_test/scheduled_test.dart';
diff --git a/pkg/barback/test/package_graph/get_all_assets_test.dart b/pkg/barback/test/package_graph/get_all_assets_test.dart
new file mode 100644
index 0000000..0ece84b
--- /dev/null
+++ b/pkg/barback/test/package_graph/get_all_assets_test.dart
@@ -0,0 +1,77 @@
+// 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 barback.test.barback_test;
+
+import 'package:scheduled_test/scheduled_test.dart';
+
+import '../utils.dart';
+
+main() {
+ initConfig();
+
+ test("gets all source assets", () {
+ initGraph(["app|a.txt", "app|b.txt", "app|c.txt"]);
+ updateSources(["app|a.txt", "app|b.txt", "app|c.txt"]);
+ expectAllAssets(["app|a.txt", "app|b.txt", "app|c.txt"]);
+ buildShouldSucceed();
+ });
+
+ test("includes transformed outputs, but not consumed ones", () {
+ initGraph(["app|a.txt", "app|foo.blub"], {"app": [
+ [new RewriteTransformer("blub", "blab")]
+ ]});
+ updateSources(["app|a.txt", "app|foo.blub"]);
+ expectAllAssets(["app|a.txt", "app|foo.blab"]);
+ buildShouldSucceed();
+ });
+
+ test("includes non-primary inputs to transformers", () {
+ var transformer = new ManyToOneTransformer("txt");
+ initGraph({
+ "app|a.txt": "a.inc",
+ "app|a.inc": "a"
+ }, {"app": [[transformer]]});
+
+ updateSources(["app|a.txt", "app|a.inc"]);
+ expectAllAssets(["app|a.inc", "app|a.out"]);
+ buildShouldSucceed();
+ });
+
+ test("completes to an error if two transformers output the same file", () {
+ initGraph(["app|foo.a"], {"app": [
+ [
+ new RewriteTransformer("a", "b"),
+ new RewriteTransformer("a", "b")
+ ]
+ ]});
+ updateSources(["app|foo.a"]);
+ expectAllAssetsShouldFail(isAssetCollisionException("app|foo.b"));
+ });
+
+ test("completes to an error if a transformer fails", () {
+ initGraph(["app|foo.txt"], {"app": [
+ [new BadTransformer(["app|foo.out"])]
+ ]});
+
+ updateSources(["app|foo.txt"]);
+ expectAllAssetsShouldFail(isTransformerException(
+ equals(BadTransformer.ERROR)));
+ });
+
+ test("completes to an aggregate error if there are multiple errors", () {
+ initGraph(["app|foo.txt"], {"app": [
+ [
+ new BadTransformer(["app|foo.out"]),
+ new BadTransformer(["app|foo.out2"])
+ ]
+ ]});
+
+ updateSources(["app|foo.txt"]);
+ expectAllAssetsShouldFail(isAggregateException([
+ isTransformerException(equals(BadTransformer.ERROR)),
+ isTransformerException(equals(BadTransformer.ERROR))
+ ]));
+ });
+}
diff --git a/pkg/barback/test/package_graph/source_test.dart b/pkg/barback/test/package_graph/source_test.dart
index 4c47df3..b5763a8 100644
--- a/pkg/barback/test/package_graph/source_test.dart
+++ b/pkg/barback/test/package_graph/source_test.dart
@@ -4,10 +4,6 @@
library barback.test.package_graph.source_test;
-import 'dart:async';
-
-import 'package:barback/barback.dart';
-import 'package:barback/src/utils.dart';
import 'package:scheduled_test/scheduled_test.dart';
import '../utils.dart';
diff --git a/pkg/barback/test/package_graph/transform_test.dart b/pkg/barback/test/package_graph/transform_test.dart
index 4d7b97e..8c108b3 100644
--- a/pkg/barback/test/package_graph/transform_test.dart
+++ b/pkg/barback/test/package_graph/transform_test.dart
@@ -4,9 +4,6 @@
library barback.test.package_graph.transform_test;
-import 'dart:async';
-
-import 'package:barback/barback.dart';
import 'package:barback/src/utils.dart';
import 'package:scheduled_test/scheduled_test.dart';
@@ -1058,5 +1055,45 @@
expectNoAsset("pkg1|c.done");
buildShouldSucceed();
});
+
+ test("sees a transformer that's newly applied to a cross-package "
+ "dependency", () {
+ initGraph({
+ "pkg1|a.txt": "pkg2|a.inc",
+ "pkg2|a.inc": "a"
+ }, {
+ "pkg1": [[new ManyToOneTransformer("txt")]],
+ "pkg2": [[new CheckContentTransformer("b", " transformed")]]
+ });
+
+ updateSources(["pkg1|a.txt", "pkg2|a.inc"]);
+ expectAsset("pkg1|a.out", "a");
+ buildShouldSucceed();
+
+ modifyAsset("pkg2|a.inc", "b");
+ updateSources(["pkg2|a.inc"]);
+ expectAsset("pkg1|a.out", "b transformed");
+ buildShouldSucceed();
+ });
+
+ test("doesn't see a transformer that's newly not applied to a "
+ "cross-package dependency", () {
+ initGraph({
+ "pkg1|a.txt": "pkg2|a.inc",
+ "pkg2|a.inc": "a"
+ }, {
+ "pkg1": [[new ManyToOneTransformer("txt")]],
+ "pkg2": [[new CheckContentTransformer("a", " transformed")]]
+ });
+
+ updateSources(["pkg1|a.txt", "pkg2|a.inc"]);
+ expectAsset("pkg1|a.out", "a transformed");
+ buildShouldSucceed();
+
+ modifyAsset("pkg2|a.inc", "b");
+ updateSources(["pkg2|a.inc"]);
+ expectAsset("pkg1|a.out", "b");
+ buildShouldSucceed();
+ });
});
}
diff --git a/pkg/barback/test/transformer/many_to_one.dart b/pkg/barback/test/transformer/many_to_one.dart
index 45f8f25..59a190c 100644
--- a/pkg/barback/test/transformer/many_to_one.dart
+++ b/pkg/barback/test/transformer/many_to_one.dart
@@ -7,7 +7,6 @@
import 'dart:async';
import 'package:barback/barback.dart';
-import 'package:barback/src/utils.dart';
import 'mock.dart';
diff --git a/pkg/barback/test/transformer_test.dart b/pkg/barback/test/transformer_test.dart
new file mode 100644
index 0000000..9df3f4a
--- /dev/null
+++ b/pkg/barback/test/transformer_test.dart
@@ -0,0 +1,59 @@
+// 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 barback.test.transformer_test;
+
+import 'dart:async';
+
+import 'package:barback/barback.dart';
+import 'package:unittest/unittest.dart';
+
+import 'utils.dart';
+
+main() {
+ initConfig();
+
+ group("isPrimary", () {
+ test("defaults to allowedExtensions", () {
+ var transformer = new ExtensionTransformer(".txt .bin");
+ expect(transformer.isPrimary(makeAsset("foo.txt")),
+ completion(isTrue));
+
+ expect(transformer.isPrimary(makeAsset("foo.bin")),
+ completion(isTrue));
+
+ expect(transformer.isPrimary(makeAsset("foo.nottxt")),
+ completion(isFalse));
+ });
+
+ test("allows all files if allowedExtensions is not overridden", () {
+ var transformer = new MockTransformer();
+ expect(transformer.isPrimary(makeAsset("foo.txt")),
+ completion(isTrue));
+
+ expect(transformer.isPrimary(makeAsset("foo.bin")),
+ completion(isTrue));
+
+ expect(transformer.isPrimary(makeAsset("anything")),
+ completion(isTrue));
+ });
+ });
+}
+
+Asset makeAsset(String path) =>
+ new Asset.fromString(new AssetId.parse("app|$path"), "");
+
+class MockTransformer extends Transformer {
+ MockTransformer();
+
+ Future apply(Transform transform) => new Future.value();
+}
+
+class ExtensionTransformer extends Transformer {
+ final String allowedExtensions;
+
+ ExtensionTransformer(this.allowedExtensions);
+
+ Future apply(Transform transform) => new Future.value();
+}
\ No newline at end of file
diff --git a/pkg/barback/test/utils.dart b/pkg/barback/test/utils.dart
index 99a7ec1..73f4f8b 100644
--- a/pkg/barback/test/utils.dart
+++ b/pkg/barback/test/utils.dart
@@ -9,7 +9,6 @@
import 'dart:io';
import 'package:barback/barback.dart';
-import 'package:barback/src/asset_set.dart';
import 'package:barback/src/cancelable_future.dart';
import 'package:barback/src/utils.dart';
import 'package:path/path.dart' as pathos;
@@ -61,9 +60,38 @@
if (assets == null) assets = [];
if (transformers == null) transformers = {};
- _provider = new MockProvider(assets, transformers);
+ var assetList;
+ if (assets is Map) {
+ assetList = assets.keys.map((asset) {
+ var id = new AssetId.parse(asset);
+ return new _MockAsset(id, assets[asset]);
+ });
+ } else if (assets is Iterable) {
+ assetList = assets.map((asset) {
+ var id = new AssetId.parse(asset);
+ var contents = pathos.basenameWithoutExtension(id.path);
+ return new _MockAsset(id, contents);
+ });
+ }
+
+ var assetMap = mapMapValues(groupBy(assetList, (asset) => asset.id.package),
+ (package, assets) => new AssetSet.from(assets));
+
+ // Make sure that packages that have transformers but no assets are considered
+ // by MockProvider to exist.
+ for (var package in transformers.keys) {
+ assetMap.putIfAbsent(package, () => new AssetSet());
+ }
+
+ _provider = new MockProvider(assetMap);
_barback = new Barback(_provider);
_nextBuildResult = 0;
+
+ transformers.forEach(_barback.updateTransformers);
+
+ // There should be one successful build after adding all the transformers but
+ // before adding any sources.
+ if (!transformers.isEmpty) buildShouldSucceed();
}
/// Updates [assets] in the current [PackageProvider].
@@ -102,6 +130,13 @@
void removeSourcesSync(Iterable assets) =>
_barback.removeSources(_parseAssets(assets));
+/// Sets the transformers for [package] to [transformers].
+void updateTransformers(String package,
+ Iterable<Iterable<Transformer>> transformers) {
+ schedule(() => _barback.updateTransformers(package, transformers),
+ "updating transformers for $package");
+}
+
/// Parse a list of strings or [AssetId]s into a list of [AssetId]s.
List<AssetId> _parseAssets(Iterable assets) {
return assets.map((asset) {
@@ -223,6 +258,39 @@
}, "get asset $name");
}
+/// Schedules an expectation that the graph will output all of the given
+/// assets, and no others.
+///
+/// [assets] is a list of strings that can be parsed to [AssetID]s.
+void expectAllAssets(Iterable<String> assets) {
+ var expected = assets.map((asset) => new AssetId.parse(asset));
+
+ schedule(() {
+ return _barback.getAllAssets().then((actualAssets) {
+ var actualIds = actualAssets.map((asset) => asset.id).toSet();
+
+ for (var id in expected) {
+ expect(actualIds, contains(id));
+ actualIds.remove(id);
+ }
+
+ expect(actualIds, isEmpty);
+ });
+ }, "get all assets, expecting ${expected.join(', ')}");
+}
+
+/// Schedules an expectation that [Barback.getAllAssets] will return a [Future]
+/// that completes to a error that matches [matcher].
+///
+/// If [match] is a [List], then it expects the completed error to be an
+/// [AggregateException] whose errors match each matcher in the list. Otherwise,
+/// [match] should be a single matcher that the error should match.
+void expectAllAssetsShouldFail(Matcher matcher) {
+ schedule(() {
+ expect(_barback.getAllAssets(), throwsA(matcher));
+ }, "get all assets should fail");
+}
+
/// Schedules an expectation that a [getAssetById] call for the given asset
/// won't terminate at this point in the schedule.
void expectAssetDoesNotComplete(String name) {
@@ -236,6 +304,25 @@
}, "asset $id should not complete");
}
+/// Returns a matcher for an [AggregateException] containing errors that match
+/// [matchers].
+Matcher isAggregateException(Iterable<Matcher> errors) {
+ // Match the aggregate error itself.
+ var matchers = [
+ new isInstanceOf<AggregateException>(),
+ transform((error) => error.errors, hasLength(errors.length),
+ 'errors.length == ${errors.length}')
+ ];
+
+ // Make sure its contained errors match the matchers.
+ for (var error in errors) {
+ matchers.add(transform((error) => error.errors, contains(error),
+ error.toString()));
+ }
+
+ return allOf(matchers);
+}
+
/// Returns a matcher for an [AssetNotFoundException] with the given [id].
Matcher isAssetNotFoundException(String name) {
var id = new AssetId.parse(name);
@@ -340,9 +427,9 @@
/// An [AssetProvider] that provides the given set of assets.
class MockProvider implements PackageProvider {
- Iterable<String> get packages => _packages.keys;
+ Iterable<String> get packages => _assets.keys;
- Map<String, _MockPackage> _packages;
+ Map<String, AssetSet> _assets;
/// The set of assets for which [MockLoadException]s should be emitted if
/// they're loaded.
@@ -366,42 +453,19 @@
_pauseCompleter = null;
}
- MockProvider(assets,
- Map<String, Iterable<Iterable<Transformer>>> transformers) {
- var assetList;
- if (assets is Map) {
- assetList = assets.keys.map((asset) {
- var id = new AssetId.parse(asset);
- return new _MockAsset(id, assets[asset]);
- });
- } else if (assets is Iterable) {
- assetList = assets.map((asset) {
- var id = new AssetId.parse(asset);
- var contents = pathos.basenameWithoutExtension(id.path);
- return new _MockAsset(id, contents);
- });
- }
-
- _packages = mapMapValues(groupBy(assetList, (asset) => asset.id.package),
- (package, assets) {
- var packageTransformers = transformers[package];
- if (packageTransformers == null) packageTransformers = [];
- return new _MockPackage(
- new AssetSet.from(assets), packageTransformers.toList());
- });
-
+ MockProvider(this._assets) {
// If there are no assets or transformers, add a dummy package. This better
// simulates the real world, where there'll always be at least the
// entrypoint package.
- if (_packages.isEmpty) {
- _packages = {"app": new _MockPackage(new AssetSet(), [])};
+ if (_assets.isEmpty) {
+ _assets = {"app": new AssetSet()};
}
}
void _modifyAsset(String name, String contents) {
var id = new AssetId.parse(name);
_errors.remove(id);
- _packages[id.package].assets[id].contents = contents;
+ _assets[id.package][id].contents = contents;
}
void _setAssetError(String name) => _errors.add(new AssetId.parse(name));
@@ -411,23 +475,15 @@
throw new UnimplementedError("Doesn't handle 'within' yet.");
}
- return _packages[package].assets.map((asset) => asset.id);
- }
-
- Iterable<Iterable<Transformer>> getTransformers(String package) {
- var mockPackage = _packages[package];
- if (mockPackage == null) {
- throw new ArgumentError("No package named $package.");
- }
- return mockPackage.transformers;
+ return _assets[package].map((asset) => asset.id);
}
Future<Asset> getAsset(AssetId id) {
// Eagerly load the asset so we can test an asset's value changing between
// when a load starts and when it finishes.
- var package = _packages[id.package];
+ var assets = _assets[id.package];
var asset;
- if (package != null) asset = package.assets[id];
+ if (assets != null) asset = assets[id];
var hasError = _errors.contains(id);
@@ -455,16 +511,6 @@
String toString() => "Error loading $id.";
}
-/// Used by [MockProvider] to keep track of which assets and transformers exist
-/// for each package.
-class _MockPackage {
- final AssetSet assets;
- final List<List<Transformer>> transformers;
-
- _MockPackage(this.assets, Iterable<Iterable<Transformer>> transformers)
- : transformers = transformers.map((phase) => phase.toList()).toList();
-}
-
/// An implementation of [Asset] that never hits the file system.
class _MockAsset implements Asset {
final AssetId id;
diff --git a/pkg/crypto/lib/crypto.dart b/pkg/crypto/lib/crypto.dart
index f5f737b..ee11c25 100644
--- a/pkg/crypto/lib/crypto.dart
+++ b/pkg/crypto/lib/crypto.dart
@@ -2,6 +2,10 @@
// 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.
+/**
+ * Cryptographic algorithms, with support for hash functions such as
+ * SHA-1, SHA-256, HMAC, and MD5.
+ */
library crypto;
import 'dart:math';
diff --git a/pkg/custom_element/lib/custom-elements.debug.js b/pkg/custom_element/lib/custom-elements.debug.js
new file mode 100644
index 0000000..400730b
--- /dev/null
+++ b/pkg/custom_element/lib/custom-elements.debug.js
@@ -0,0 +1,1458 @@
+// Copyright (c) 2012 The Polymer Authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+(function() {
+
+var scope = window.PolymerLoader = {};
+var flags = {};
+
+// convert url arguments to flags
+
+if (!flags.noOpts) {
+ location.search.slice(1).split('&').forEach(function(o) {
+ o = o.split('=');
+ o[0] && (flags[o[0]] = o[1] || true);
+ });
+}
+
+// process global logFlags
+
+parseLogFlags(flags);
+
+function load(scopeName) {
+ // imports
+
+ var scope = window[scopeName];
+ var entryPointName = scope.entryPointName;
+ var processFlags = scope.processFlags;
+
+ // acquire attributes and base path from entry point
+
+ var entryPoint = findScript(entryPointName);
+ var base = entryPoint.basePath;
+
+ // acquire common flags
+ var flags = scope.flags;
+
+ // convert attributes to flags
+ var flags = PolymerLoader.flags;
+ for (var i=0, a; (a=entryPoint.attributes[i]); i++) {
+ if (a.name !== 'src') {
+ flags[a.name] = a.value || true;
+ }
+ }
+
+ // parse log flags into global
+ parseLogFlags(flags);
+
+ // exports
+
+ scope.basePath = base;
+ scope.flags = flags;
+
+ // process flags for dynamic dependencies
+
+ if (processFlags) {
+ processFlags.call(scope, flags);
+ }
+
+ // post-process imports
+
+ var modules = scope.modules || [];
+ var sheets = scope.sheets || [];
+
+ // write script tags for dependencies
+
+ modules.forEach(function(src) {
+ document.write('<script src="' + base + src + '"></script>');
+ });
+
+ // write link tags for styles
+
+ sheets.forEach(function(src) {
+ document.write('<link rel="stylesheet" href="' + base + src + '">');
+ });
+}
+
+// utility method
+
+function findScript(fileName) {
+ var script = document.querySelector('script[src*="' + fileName + '"]');
+ var src = script.attributes.src.value;
+ script.basePath = src.slice(0, src.indexOf(fileName));
+ return script;
+}
+
+function parseLogFlags(flags) {
+ var logFlags = window.logFlags = window.logFlags || {};
+ if (flags.log) {
+ flags.log.split(',').forEach(function(f) {
+ logFlags[f] = true;
+ });
+ }
+}
+
+scope.flags = flags;
+scope.load = load;
+
+})();
+
+window.CustomElements = {flags:{}};
+// SideTable is a weak map where possible. If WeakMap is not available the
+// association is stored as an expando property.
+var SideTable;
+// TODO(arv): WeakMap does not allow for Node etc to be keys in Firefox
+if (typeof WeakMap !== 'undefined' && navigator.userAgent.indexOf('Firefox/') < 0) {
+ SideTable = WeakMap;
+} else {
+ (function() {
+ var defineProperty = Object.defineProperty;
+ var hasOwnProperty = Object.hasOwnProperty;
+ var counter = new Date().getTime() % 1e9;
+
+ SideTable = function() {
+ this.name = '__st' + (Math.random() * 1e9 >>> 0) + (counter++ + '__');
+ };
+
+ SideTable.prototype = {
+ set: function(key, value) {
+ defineProperty(key, this.name, {value: value, writable: true});
+ },
+ get: function(key) {
+ return hasOwnProperty.call(key, this.name) ? key[this.name] : undefined;
+ },
+ delete: function(key) {
+ this.set(key, undefined);
+ }
+ }
+ })();
+}
+
+(function(global) {
+
+ var registrationsTable = new SideTable();
+
+ // We use setImmediate or postMessage for our future callback.
+ var setImmediate = window.msSetImmediate;
+
+ // Use post message to emulate setImmediate.
+ if (!setImmediate) {
+ var setImmediateQueue = [];
+ var sentinel = String(Math.random());
+ window.addEventListener('message', function(e) {
+ if (e.data === sentinel) {
+ var queue = setImmediateQueue;
+ setImmediateQueue = [];
+ queue.forEach(function(func) {
+ func();
+ });
+ }
+ });
+ setImmediate = function(func) {
+ setImmediateQueue.push(func);
+ window.postMessage(sentinel, '*');
+ };
+ }
+
+ // This is used to ensure that we never schedule 2 callas to setImmediate
+ var isScheduled = false;
+
+ // Keep track of observers that needs to be notified next time.
+ var scheduledObservers = [];
+
+ /**
+ * Schedules |dispatchCallback| to be called in the future.
+ * @param {MutationObserver} observer
+ */
+ function scheduleCallback(observer) {
+ scheduledObservers.push(observer);
+ if (!isScheduled) {
+ isScheduled = true;
+ setImmediate(dispatchCallbacks);
+ }
+ }
+
+ function wrapIfNeeded(node) {
+ return window.ShadowDOMPolyfill &&
+ window.ShadowDOMPolyfill.wrapIfNeeded(node) ||
+ node;
+ }
+
+ function dispatchCallbacks() {
+ // http://dom.spec.whatwg.org/#mutation-observers
+
+ isScheduled = false; // Used to allow a new setImmediate call above.
+
+ var observers = scheduledObservers;
+ scheduledObservers = [];
+ // Sort observers based on their creation UID (incremental).
+ observers.sort(function(o1, o2) {
+ return o1.uid_ - o2.uid_;
+ });
+
+ var anyNonEmpty = false;
+ observers.forEach(function(observer) {
+
+ // 2.1, 2.2
+ var queue = observer.takeRecords();
+ // 2.3. Remove all transient registered observers whose observer is mo.
+ removeTransientObserversFor(observer);
+
+ // 2.4
+ if (queue.length) {
+ observer.callback_(queue, observer);
+ anyNonEmpty = true;
+ }
+ });
+
+ // 3.
+ if (anyNonEmpty)
+ dispatchCallbacks();
+ }
+
+ function removeTransientObserversFor(observer) {
+ observer.nodes_.forEach(function(node) {
+ var registrations = registrationsTable.get(node);
+ if (!registrations)
+ return;
+ registrations.forEach(function(registration) {
+ if (registration.observer === observer)
+ registration.removeTransientObservers();
+ });
+ });
+ }
+
+ /**
+ * This function is used for the "For each registered observer observer (with
+ * observer's options as options) in target's list of registered observers,
+ * run these substeps:" and the "For each ancestor ancestor of target, and for
+ * each registered observer observer (with options options) in ancestor's list
+ * of registered observers, run these substeps:" part of the algorithms. The
+ * |options.subtree| is checked to ensure that the callback is called
+ * correctly.
+ *
+ * @param {Node} target
+ * @param {function(MutationObserverInit):MutationRecord} callback
+ */
+ function forEachAncestorAndObserverEnqueueRecord(target, callback) {
+ for (var node = target; node; node = node.parentNode) {
+ var registrations = registrationsTable.get(node);
+
+ if (registrations) {
+ for (var j = 0; j < registrations.length; j++) {
+ var registration = registrations[j];
+ var options = registration.options;
+
+ // Only target ignores subtree.
+ if (node !== target && !options.subtree)
+ continue;
+
+ var record = callback(options);
+ if (record)
+ registration.enqueue(record);
+ }
+ }
+ }
+ }
+
+ var uidCounter = 0;
+
+ /**
+ * The class that maps to the DOM MutationObserver interface.
+ * @param {Function} callback.
+ * @constructor
+ */
+ function JsMutationObserver(callback) {
+ this.callback_ = callback;
+ this.nodes_ = [];
+ this.records_ = [];
+ this.uid_ = ++uidCounter;
+ }
+
+ JsMutationObserver.prototype = {
+ observe: function(target, options) {
+ target = wrapIfNeeded(target);
+
+ // 1.1
+ if (!options.childList && !options.attributes && !options.characterData ||
+
+ // 1.2
+ options.attributeOldValue && !options.attributes ||
+
+ // 1.3
+ options.attributeFilter && options.attributeFilter.length &&
+ !options.attributes ||
+
+ // 1.4
+ options.characterDataOldValue && !options.characterData) {
+
+ throw new SyntaxError();
+ }
+
+ var registrations = registrationsTable.get(target);
+ if (!registrations)
+ registrationsTable.set(target, registrations = []);
+
+ // 2
+ // If target's list of registered observers already includes a registered
+ // observer associated with the context object, replace that registered
+ // observer's options with options.
+ var registration;
+ for (var i = 0; i < registrations.length; i++) {
+ if (registrations[i].observer === this) {
+ registration = registrations[i];
+ registration.removeListeners();
+ registration.options = options;
+ break;
+ }
+ }
+
+ // 3.
+ // Otherwise, add a new registered observer to target's list of registered
+ // observers with the context object as the observer and options as the
+ // options, and add target to context object's list of nodes on which it
+ // is registered.
+ if (!registration) {
+ registration = new Registration(this, target, options);
+ registrations.push(registration);
+ this.nodes_.push(target);
+ }
+
+ registration.addListeners();
+ },
+
+ disconnect: function() {
+ this.nodes_.forEach(function(node) {
+ var registrations = registrationsTable.get(node);
+ for (var i = 0; i < registrations.length; i++) {
+ var registration = registrations[i];
+ if (registration.observer === this) {
+ registration.removeListeners();
+ registrations.splice(i, 1);
+ // Each node can only have one registered observer associated with
+ // this observer.
+ break;
+ }
+ }
+ }, this);
+ this.records_ = [];
+ },
+
+ takeRecords: function() {
+ var copyOfRecords = this.records_;
+ this.records_ = [];
+ return copyOfRecords;
+ }
+ };
+
+ /**
+ * @param {string} type
+ * @param {Node} target
+ * @constructor
+ */
+ function MutationRecord(type, target) {
+ this.type = type;
+ this.target = target;
+ this.addedNodes = [];
+ this.removedNodes = [];
+ this.previousSibling = null;
+ this.nextSibling = null;
+ this.attributeName = null;
+ this.attributeNamespace = null;
+ this.oldValue = null;
+ }
+
+ function copyMutationRecord(original) {
+ var record = new MutationRecord(original.type, original.target);
+ record.addedNodes = original.addedNodes.slice();
+ record.removedNodes = original.removedNodes.slice();
+ record.previousSibling = original.previousSibling;
+ record.nextSibling = original.nextSibling;
+ record.attributeName = original.attributeName;
+ record.attributeNamespace = original.attributeNamespace;
+ record.oldValue = original.oldValue;
+ return record;
+ };
+
+ // We keep track of the two (possibly one) records used in a single mutation.
+ var currentRecord, recordWithOldValue;
+
+ /**
+ * Creates a record without |oldValue| and caches it as |currentRecord| for
+ * later use.
+ * @param {string} oldValue
+ * @return {MutationRecord}
+ */
+ function getRecord(type, target) {
+ return currentRecord = new MutationRecord(type, target);
+ }
+
+ /**
+ * Gets or creates a record with |oldValue| based in the |currentRecord|
+ * @param {string} oldValue
+ * @return {MutationRecord}
+ */
+ function getRecordWithOldValue(oldValue) {
+ if (recordWithOldValue)
+ return recordWithOldValue;
+ recordWithOldValue = copyMutationRecord(currentRecord);
+ recordWithOldValue.oldValue = oldValue;
+ return recordWithOldValue;
+ }
+
+ function clearRecords() {
+ currentRecord = recordWithOldValue = undefined;
+ }
+
+ /**
+ * @param {MutationRecord} record
+ * @return {boolean} Whether the record represents a record from the current
+ * mutation event.
+ */
+ function recordRepresentsCurrentMutation(record) {
+ return record === recordWithOldValue || record === currentRecord;
+ }
+
+ /**
+ * Selects which record, if any, to replace the last record in the queue.
+ * This returns |null| if no record should be replaced.
+ *
+ * @param {MutationRecord} lastRecord
+ * @param {MutationRecord} newRecord
+ * @param {MutationRecord}
+ */
+ function selectRecord(lastRecord, newRecord) {
+ if (lastRecord === newRecord)
+ return lastRecord;
+
+ // Check if the the record we are adding represents the same record. If
+ // so, we keep the one with the oldValue in it.
+ if (recordWithOldValue && recordRepresentsCurrentMutation(lastRecord))
+ return recordWithOldValue;
+
+ return null;
+ }
+
+ /**
+ * Class used to represent a registered observer.
+ * @param {MutationObserver} observer
+ * @param {Node} target
+ * @param {MutationObserverInit} options
+ * @constructor
+ */
+ function Registration(observer, target, options) {
+ this.observer = observer;
+ this.target = target;
+ this.options = options;
+ this.transientObservedNodes = [];
+ }
+
+ Registration.prototype = {
+ enqueue: function(record) {
+ var records = this.observer.records_;
+ var length = records.length;
+
+ // There are cases where we replace the last record with the new record.
+ // For example if the record represents the same mutation we need to use
+ // the one with the oldValue. If we get same record (this can happen as we
+ // walk up the tree) we ignore the new record.
+ if (records.length > 0) {
+ var lastRecord = records[length - 1];
+ var recordToReplaceLast = selectRecord(lastRecord, record);
+ if (recordToReplaceLast) {
+ records[length - 1] = recordToReplaceLast;
+ return;
+ }
+ } else {
+ scheduleCallback(this.observer);
+ }
+
+ records[length] = record;
+ },
+
+ addListeners: function() {
+ this.addListeners_(this.target);
+ },
+
+ addListeners_: function(node) {
+ var options = this.options;
+ if (options.attributes)
+ node.addEventListener('DOMAttrModified', this, true);
+
+ if (options.characterData)
+ node.addEventListener('DOMCharacterDataModified', this, true);
+
+ if (options.childList)
+ node.addEventListener('DOMNodeInserted', this, true);
+
+ if (options.childList || options.subtree)
+ node.addEventListener('DOMNodeRemoved', this, true);
+ },
+
+ removeListeners: function() {
+ this.removeListeners_(this.target);
+ },
+
+ removeListeners_: function(node) {
+ var options = this.options;
+ if (options.attributes)
+ node.removeEventListener('DOMAttrModified', this, true);
+
+ if (options.characterData)
+ node.removeEventListener('DOMCharacterDataModified', this, true);
+
+ if (options.childList)
+ node.removeEventListener('DOMNodeInserted', this, true);
+
+ if (options.childList || options.subtree)
+ node.removeEventListener('DOMNodeRemoved', this, true);
+ },
+
+ /**
+ * Adds a transient observer on node. The transient observer gets removed
+ * next time we deliver the change records.
+ * @param {Node} node
+ */
+ addTransientObserver: function(node) {
+ // Don't add transient observers on the target itself. We already have all
+ // the required listeners set up on the target.
+ if (node === this.target)
+ return;
+
+ this.addListeners_(node);
+ this.transientObservedNodes.push(node);
+ var registrations = registrationsTable.get(node);
+ if (!registrations)
+ registrationsTable.set(node, registrations = []);
+
+ // We know that registrations does not contain this because we already
+ // checked if node === this.target.
+ registrations.push(this);
+ },
+
+ removeTransientObservers: function() {
+ var transientObservedNodes = this.transientObservedNodes;
+ this.transientObservedNodes = [];
+
+ transientObservedNodes.forEach(function(node) {
+ // Transient observers are never added to the target.
+ this.removeListeners_(node);
+
+ var registrations = registrationsTable.get(node);
+ for (var i = 0; i < registrations.length; i++) {
+ if (registrations[i] === this) {
+ registrations.splice(i, 1);
+ // Each node can only have one registered observer associated with
+ // this observer.
+ break;
+ }
+ }
+ }, this);
+ },
+
+ handleEvent: function(e) {
+ // Stop propagation since we are managing the propagation manually.
+ // This means that other mutation events on the page will not work
+ // correctly but that is by design.
+ e.stopImmediatePropagation();
+
+ switch (e.type) {
+ case 'DOMAttrModified':
+ // http://dom.spec.whatwg.org/#concept-mo-queue-attributes
+
+ var name = e.attrName;
+ var namespace = e.relatedNode.namespaceURI;
+ var target = e.target;
+
+ // 1.
+ var record = new getRecord('attributes', target);
+ record.attributeName = name;
+ record.attributeNamespace = namespace;
+
+ // 2.
+ var oldValue =
+ e.attrChange === MutationEvent.ADDITION ? null : e.prevValue;
+
+ forEachAncestorAndObserverEnqueueRecord(target, function(options) {
+ // 3.1, 4.2
+ if (!options.attributes)
+ return;
+
+ // 3.2, 4.3
+ if (options.attributeFilter && options.attributeFilter.length &&
+ options.attributeFilter.indexOf(name) === -1 &&
+ options.attributeFilter.indexOf(namespace) === -1) {
+ return;
+ }
+ // 3.3, 4.4
+ if (options.attributeOldValue)
+ return getRecordWithOldValue(oldValue);
+
+ // 3.4, 4.5
+ return record;
+ });
+
+ break;
+
+ case 'DOMCharacterDataModified':
+ // http://dom.spec.whatwg.org/#concept-mo-queue-characterdata
+ var target = e.target;
+
+ // 1.
+ var record = getRecord('characterData', target);
+
+ // 2.
+ var oldValue = e.prevValue;
+
+
+ forEachAncestorAndObserverEnqueueRecord(target, function(options) {
+ // 3.1, 4.2
+ if (!options.characterData)
+ return;
+
+ // 3.2, 4.3
+ if (options.characterDataOldValue)
+ return getRecordWithOldValue(oldValue);
+
+ // 3.3, 4.4
+ return record;
+ });
+
+ break;
+
+ case 'DOMNodeRemoved':
+ this.addTransientObserver(e.target);
+ // Fall through.
+ case 'DOMNodeInserted':
+ // http://dom.spec.whatwg.org/#concept-mo-queue-childlist
+ var target = e.relatedNode;
+ var changedNode = e.target;
+ var addedNodes, removedNodes;
+ if (e.type === 'DOMNodeInserted') {
+ addedNodes = [changedNode];
+ removedNodes = [];
+ } else {
+
+ addedNodes = [];
+ removedNodes = [changedNode];
+ }
+ var previousSibling = changedNode.previousSibling;
+ var nextSibling = changedNode.nextSibling;
+
+ // 1.
+ var record = getRecord('childList', target);
+ record.addedNodes = addedNodes;
+ record.removedNodes = removedNodes;
+ record.previousSibling = previousSibling;
+ record.nextSibling = nextSibling;
+
+ forEachAncestorAndObserverEnqueueRecord(target, function(options) {
+ // 2.1, 3.2
+ if (!options.childList)
+ return;
+
+ // 2.2, 3.3
+ return record;
+ });
+
+ }
+
+ clearRecords();
+ }
+ };
+
+ global.JsMutationObserver = JsMutationObserver;
+
+})(this);
+
+if (!window.MutationObserver) {
+ window.MutationObserver =
+ window.WebKitMutationObserver ||
+ window.JsMutationObserver;
+ if (!MutationObserver) {
+ throw new Error("no mutation observer support");
+ }
+}
+
+(function(scope){
+
+/*
+if (HTMLElement.prototype.webkitShadowRoot) {
+ Object.defineProperty(HTMLElement.prototype, 'shadowRoot', {
+ get: function() {
+ return this.webkitShadowRoot;
+ }
+ };
+}
+*/
+
+// walk the subtree rooted at node, applying 'find(element, data)' function
+// to each element
+// if 'find' returns true for 'element', do not search element's subtree
+function findAll(node, find, data) {
+ var e = node.firstElementChild;
+ if (!e) {
+ e = node.firstChild;
+ while (e && e.nodeType !== Node.ELEMENT_NODE) {
+ e = e.nextSibling;
+ }
+ }
+ while (e) {
+ if (find(e, data) !== true) {
+ findAll(e, find, data);
+ }
+ e = e.nextElementSibling;
+ }
+ return null;
+}
+
+// walk all shadowRoots on a given node.
+function forRoots(node, cb) {
+ var root = node.webkitShadowRoot;
+ while(root) {
+ forSubtree(root, cb);
+ root = root.olderShadowRoot;
+ }
+}
+
+// walk the subtree rooted at node, including descent into shadow-roots,
+// applying 'cb' to each element
+function forSubtree(node, cb) {
+ //logFlags.dom && node.childNodes && node.childNodes.length && console.group('subTree: ', node);
+ findAll(node, function(e) {
+ if (cb(e)) {
+ return true;
+ }
+ forRoots(e, cb);
+ });
+ forRoots(node, cb);
+ //logFlags.dom && node.childNodes && node.childNodes.length && console.groupEnd();
+}
+
+// manage lifecycle on added node
+function added(node) {
+ if (upgrade(node)) {
+ insertedNode(node);
+ return true;
+ }
+ inserted(node);
+}
+
+// manage lifecycle on added node's subtree only
+function addedSubtree(node) {
+ forSubtree(node, function(e) {
+ if (added(e)) {
+ return true;
+ }
+ });
+}
+
+// manage lifecycle on added node and it's subtree
+function addedNode(node) {
+ return added(node) || addedSubtree(node);
+}
+
+// upgrade custom elements at node, if applicable
+function upgrade(node) {
+ if (!node.__upgraded__ && node.nodeType === Node.ELEMENT_NODE) {
+ var type = node.getAttribute('is') || node.localName;
+ var definition = scope.registry[type];
+ if (definition) {
+ logFlags.dom && console.group('upgrade:', node.localName);
+ scope.upgrade(node);
+ logFlags.dom && console.groupEnd();
+ return true;
+ }
+ }
+}
+
+function insertedNode(node) {
+ inserted(node);
+ if (inDocument(node)) {
+ forSubtree(node, function(e) {
+ inserted(e);
+ });
+ }
+}
+
+// TODO(sjmiles): if there are descents into trees that can never have inDocument(*) true, fix this
+
+function inserted(element) {
+ // TODO(sjmiles): it's possible we were inserted and removed in the space
+ // of one microtask, in which case we won't be 'inDocument' here
+ // But there are other cases where we are testing for inserted without
+ // specific knowledge of mutations, and must test 'inDocument' to determine
+ // whether to call inserted
+ // If we can factor these cases into separate code paths we can have
+ // better diagnostics.
+ // TODO(sjmiles): when logging, do work on all custom elements so we can
+ // track behavior even when callbacks not defined
+ //console.log('inserted: ', element.localName);
+ if (element.enteredDocumentCallback || (element.__upgraded__ && logFlags.dom)) {
+ logFlags.dom && console.group('inserted:', element.localName);
+ if (inDocument(element)) {
+ element.__inserted = (element.__inserted || 0) + 1;
+ // if we are in a 'removed' state, bluntly adjust to an 'inserted' state
+ if (element.__inserted < 1) {
+ element.__inserted = 1;
+ }
+ // if we are 'over inserted', squelch the callback
+ if (element.__inserted > 1) {
+ logFlags.dom && console.warn('inserted:', element.localName,
+ 'insert/remove count:', element.__inserted)
+ } else if (element.enteredDocumentCallback) {
+ logFlags.dom && console.log('inserted:', element.localName);
+ element.enteredDocumentCallback();
+ }
+ }
+ logFlags.dom && console.groupEnd();
+ }
+}
+
+function removedNode(node) {
+ removed(node);
+ forSubtree(node, function(e) {
+ removed(e);
+ });
+}
+
+function removed(element) {
+ // TODO(sjmiles): temporary: do work on all custom elements so we can track
+ // behavior even when callbacks not defined
+ if (element.leftDocumentCallback || (element.__upgraded__ && logFlags.dom)) {
+ logFlags.dom && console.log('removed:', element.localName);
+ if (!inDocument(element)) {
+ element.__inserted = (element.__inserted || 0) - 1;
+ // if we are in a 'inserted' state, bluntly adjust to an 'removed' state
+ if (element.__inserted > 0) {
+ element.__inserted = 0;
+ }
+ // if we are 'over removed', squelch the callback
+ if (element.__inserted < 0) {
+ logFlags.dom && console.warn('removed:', element.localName,
+ 'insert/remove count:', element.__inserted)
+ } else if (element.leftDocumentCallback) {
+ element.leftDocumentCallback();
+ }
+ }
+ }
+}
+
+function inDocument(element) {
+ var p = element;
+ while (p) {
+ if (p == element.ownerDocument) {
+ return true;
+ }
+ p = p.parentNode || p.host;
+ }
+}
+
+function watchShadow(node) {
+ if (node.webkitShadowRoot && !node.webkitShadowRoot.__watched) {
+ logFlags.dom && console.log('watching shadow-root for: ', node.localName);
+ // watch all unwatched roots...
+ var root = node.webkitShadowRoot;
+ while (root) {
+ watchRoot(root);
+ root = root.olderShadowRoot;
+ }
+ }
+}
+
+function watchRoot(root) {
+ if (!root.__watched) {
+ observe(root);
+ root.__watched = true;
+ }
+}
+
+function watchAllShadows(node) {
+ watchShadow(node);
+ forSubtree(node, function(e) {
+ watchShadow(node);
+ });
+}
+
+function filter(inNode) {
+ switch (inNode.localName) {
+ case 'style':
+ case 'script':
+ case 'template':
+ case undefined:
+ return true;
+ }
+}
+
+function handler(mutations) {
+ //
+ if (logFlags.dom) {
+ var mx = mutations[0];
+ if (mx && mx.type === 'childList' && mx.addedNodes) {
+ if (mx.addedNodes) {
+ var d = mx.addedNodes[0];
+ while (d && d !== document && !d.host) {
+ d = d.parentNode;
+ }
+ var u = d && (d.URL || d._URL || (d.host && d.host.localName)) || '';
+ u = u.split('/?').shift().split('/').pop();
+ }
+ }
+ console.group('mutations (%d) [%s]', mutations.length, u || '');
+ }
+ //
+ mutations.forEach(function(mx) {
+ //logFlags.dom && console.group('mutation');
+ if (mx.type === 'childList') {
+ forEach(mx.addedNodes, function(n) {
+ //logFlags.dom && console.log(n.localName);
+ if (filter(n)) {
+ return;
+ }
+ // watch shadow-roots on nodes that have had them attached manually
+ // TODO(sjmiles): remove if createShadowRoot is overridden
+ // TODO(sjmiles): removed as an optimization, manual shadow roots
+ // must be watched explicitly
+ //watchAllShadows(n);
+ // nodes added may need lifecycle management
+ addedNode(n);
+ });
+ // removed nodes may need lifecycle management
+ forEach(mx.removedNodes, function(n) {
+ //logFlags.dom && console.log(n.localName);
+ if (filter(n)) {
+ return;
+ }
+ removedNode(n);
+ });
+ }
+ //logFlags.dom && console.groupEnd();
+ });
+ logFlags.dom && console.groupEnd();
+};
+
+var observer = new MutationObserver(handler);
+
+function takeRecords() {
+ // TODO(sjmiles): ask Raf why we have to call handler ourselves
+ handler(observer.takeRecords());
+}
+
+var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach);
+
+function observe(inRoot) {
+ observer.observe(inRoot, {childList: true, subtree: true});
+}
+
+function observeDocument(document) {
+ observe(document);
+}
+
+function upgradeDocument(document) {
+ logFlags.dom && console.group('upgradeDocument: ', (document.URL || document._URL || '').split('/').pop());
+ addedNode(document);
+ logFlags.dom && console.groupEnd();
+}
+
+// exports
+
+scope.watchShadow = watchShadow;
+scope.watchAllShadows = watchAllShadows;
+
+scope.upgradeAll = addedNode;
+scope.upgradeSubtree = addedSubtree;
+
+scope.observeDocument = observeDocument;
+scope.upgradeDocument = upgradeDocument;
+
+scope.takeRecords = takeRecords;
+
+})(window.CustomElements);
+
+/**
+ * Implements `document.register`
+ * @module CustomElements
+*/
+
+/**
+ * Polyfilled extensions to the `document` object.
+ * @class Document
+*/
+
+(function(scope) {
+
+// imports
+
+if (!scope) {
+ scope = window.CustomElements = {flags:{}};
+}
+var flags = scope.flags;
+
+// native document.register?
+
+var hasNative = Boolean(document.webkitRegister || document.register);
+var useNative = !flags.register && hasNative;
+
+if (useNative) {
+
+ // normalize
+ document.register = document.register || document.webkitRegister;
+
+ // stub
+ var nop = function() {};
+
+ // exports
+ scope.registry = {};
+ scope.upgradeElement = nop;
+
+ scope.watchShadow = nop;
+ scope.watchAllShadows = nop;
+ scope.upgrade = nop;
+ scope.upgradeAll = nop;
+ scope.upgradeSubtree = nop;
+ scope.observeDocument = nop;
+ scope.upgradeDocument = nop;
+ scope.takeRecords = nop;
+
+} else {
+
+ /**
+ * Registers a custom tag name with the document.
+ *
+ * When a registered element is created, a `readyCallback` method is called
+ * in the scope of the element. The `readyCallback` method can be specified on
+ * either `inOptions.prototype` or `inOptions.lifecycle` with the latter taking
+ * precedence.
+ *
+ * @method register
+ * @param {String} inName The tag name to register. Must include a dash ('-'),
+ * for example 'x-component'.
+ * @param {Object} inOptions
+ * @param {String} [inOptions.extends]
+ * (_off spec_) Tag name of an element to extend (or blank for a new
+ * element). This parameter is not part of the specification, but instead
+ * is a hint for the polyfill because the extendee is difficult to infer.
+ * Remember that the input prototype must chain to the extended element's
+ * prototype (or HTMLElement.prototype) regardless of the value of
+ * `extends`.
+ * @param {Object} inOptions.prototype The prototype to use for the new
+ * element. The prototype must inherit from HTMLElement.
+ * @param {Object} [inOptions.lifecycle]
+ * Callbacks that fire at important phases in the life of the custom
+ * element.
+ *
+ * @example
+ * FancyButton = document.register("fancy-button", {
+ * extends: 'button',
+ * prototype: Object.create(HTMLButtonElement.prototype, {
+ * readyCallback: {
+ * value: function() {
+ * console.log("a fancy-button was created",
+ * }
+ * }
+ * })
+ * });
+ * @return {Function} Constructor for the newly registered type.
+ */
+ function register(inName, inOptions) {
+ //console.warn('document.register("' + inName + '", ', inOptions, ')');
+ // construct a defintion out of options
+ // TODO(sjmiles): probably should clone inOptions instead of mutating it
+ var definition = inOptions || {};
+ if (!inName) {
+ // TODO(sjmiles): replace with more appropriate error (EricB can probably
+ // offer guidance)
+ throw new Error('Name argument must not be empty');
+ }
+ // record name
+ definition.name = inName;
+ // must have a prototype, default to an extension of HTMLElement
+ // TODO(sjmiles): probably should throw if no prototype, check spec
+ if (!definition.prototype) {
+ // TODO(sjmiles): replace with more appropriate error (EricB can probably
+ // offer guidance)
+ throw new Error('Options missing required prototype property');
+ }
+ // ensure a lifecycle object so we don't have to null test it
+ definition.lifecycle = definition.lifecycle || {};
+ // build a list of ancestral custom elements (for native base detection)
+ // TODO(sjmiles): we used to need to store this, but current code only
+ // uses it in 'resolveTagName': it should probably be inlined
+ definition.ancestry = ancestry(definition.extends);
+ // extensions of native specializations of HTMLElement require localName
+ // to remain native, and use secondary 'is' specifier for extension type
+ resolveTagName(definition);
+ // some platforms require modifications to the user-supplied prototype
+ // chain
+ resolvePrototypeChain(definition);
+ // overrides to implement attributeChanged callback
+ overrideAttributeApi(definition.prototype);
+ // 7.1.5: Register the DEFINITION with DOCUMENT
+ registerDefinition(inName, definition);
+ // 7.1.7. Run custom element constructor generation algorithm with PROTOTYPE
+ // 7.1.8. Return the output of the previous step.
+ definition.ctor = generateConstructor(definition);
+ definition.ctor.prototype = definition.prototype;
+ // force our .constructor to be our actual constructor
+ definition.prototype.constructor = definition.ctor;
+ // if initial parsing is complete
+ if (scope.ready) {
+ // upgrade any pre-existing nodes of this type
+ scope.upgradeAll(document);
+ }
+ return definition.ctor;
+ }
+
+ function ancestry(inExtends) {
+ var extendee = registry[inExtends];
+ if (extendee) {
+ return ancestry(extendee.extends).concat([extendee]);
+ }
+ return [];
+ }
+
+ function resolveTagName(inDefinition) {
+ // if we are explicitly extending something, that thing is our
+ // baseTag, unless it represents a custom component
+ var baseTag = inDefinition.extends;
+ // if our ancestry includes custom components, we only have a
+ // baseTag if one of them does
+ for (var i=0, a; (a=inDefinition.ancestry[i]); i++) {
+ baseTag = a.is && a.tag;
+ }
+ // our tag is our baseTag, if it exists, and otherwise just our name
+ inDefinition.tag = baseTag || inDefinition.name;
+ if (baseTag) {
+ // if there is a base tag, use secondary 'is' specifier
+ inDefinition.is = inDefinition.name;
+ }
+ }
+
+ function resolvePrototypeChain(inDefinition) {
+ // if we don't support __proto__ we need to locate the native level
+ // prototype for precise mixing in
+ if (!Object.__proto__) {
+ // default prototype
+ var native = HTMLElement.prototype;
+ // work out prototype when using type-extension
+ if (inDefinition.is) {
+ var inst = document.createElement(inDefinition.tag);
+ native = Object.getPrototypeOf(inst);
+ }
+ // ensure __proto__ reference is installed at each point on the prototype
+ // chain.
+ // NOTE: On platforms without __proto__, a mixin strategy is used instead
+ // of prototype swizzling. In this case, this generated __proto__ provides
+ // limited support for prototype traversal.
+ var proto = inDefinition.prototype, ancestor;
+ while (proto && (proto !== native)) {
+ var ancestor = Object.getPrototypeOf(proto);
+ proto.__proto__ = ancestor;
+ proto = ancestor;
+ }
+ }
+ // cache this in case of mixin
+ inDefinition.native = native;
+ }
+
+ // SECTION 4
+
+ function instantiate(inDefinition) {
+ // 4.a.1. Create a new object that implements PROTOTYPE
+ // 4.a.2. Let ELEMENT by this new object
+ //
+ // the custom element instantiation algorithm must also ensure that the
+ // output is a valid DOM element with the proper wrapper in place.
+ //
+ return upgrade(domCreateElement(inDefinition.tag), inDefinition);
+ }
+
+ function upgrade(inElement, inDefinition) {
+ // some definitions specify an 'is' attribute
+ if (inDefinition.is) {
+ inElement.setAttribute('is', inDefinition.is);
+ }
+ // make 'element' implement inDefinition.prototype
+ implement(inElement, inDefinition);
+ // flag as upgraded
+ inElement.__upgraded__ = true;
+ // there should never be a shadow root on inElement at this point
+ // we require child nodes be upgraded before `created`
+ scope.upgradeSubtree(inElement);
+ // lifecycle management
+ created(inElement);
+ // OUTPUT
+ return inElement;
+ }
+
+ function implement(inElement, inDefinition) {
+ // prototype swizzling is best
+ if (Object.__proto__) {
+ inElement.__proto__ = inDefinition.prototype;
+ } else {
+ // where above we can re-acquire inPrototype via
+ // getPrototypeOf(Element), we cannot do so when
+ // we use mixin, so we install a magic reference
+ customMixin(inElement, inDefinition.prototype, inDefinition.native);
+ inElement.__proto__ = inDefinition.prototype;
+ }
+ }
+
+ function customMixin(inTarget, inSrc, inNative) {
+ // TODO(sjmiles): 'used' allows us to only copy the 'youngest' version of
+ // any property. This set should be precalculated. We also need to
+ // consider this for supporting 'super'.
+ var used = {};
+ // start with inSrc
+ var p = inSrc;
+ // sometimes the default is HTMLUnknownElement.prototype instead of
+ // HTMLElement.prototype, so we add a test
+ // the idea is to avoid mixing in native prototypes, so adding
+ // the second test is WLOG
+ while (p !== inNative && p !== HTMLUnknownElement.prototype) {
+ var keys = Object.getOwnPropertyNames(p);
+ for (var i=0, k; k=keys[i]; i++) {
+ if (!used[k]) {
+ Object.defineProperty(inTarget, k,
+ Object.getOwnPropertyDescriptor(p, k));
+ used[k] = 1;
+ }
+ }
+ p = Object.getPrototypeOf(p);
+ }
+ }
+
+ function created(inElement) {
+ // invoke createdCallback
+ if (inElement.createdCallback) {
+ inElement.createdCallback();
+ }
+ }
+
+ // attribute watching
+
+ function overrideAttributeApi(prototype) {
+ // overrides to implement callbacks
+ // TODO(sjmiles): should support access via .attributes NamedNodeMap
+ // TODO(sjmiles): preserves user defined overrides, if any
+ var setAttribute = prototype.setAttribute;
+ prototype.setAttribute = function(name, value) {
+ changeAttribute.call(this, name, value, setAttribute);
+ }
+ var removeAttribute = prototype.removeAttribute;
+ prototype.removeAttribute = function(name, value) {
+ changeAttribute.call(this, name, value, removeAttribute);
+ }
+ }
+
+ function changeAttribute(name, value, operation) {
+ var oldValue = this.getAttribute(name);
+ operation.apply(this, arguments);
+ if (this.attributeChangedCallback
+ && (this.getAttribute(name) !== oldValue)) {
+ this.attributeChangedCallback(name, oldValue);
+ }
+ }
+
+ // element registry (maps tag names to definitions)
+
+ var registry = {};
+
+ function registerDefinition(inName, inDefinition) {
+ if (registry[inName]) {
+ throw new Error('Cannot register a tag more than once');
+ }
+ registry[inName] = inDefinition;
+ }
+
+ function generateConstructor(inDefinition) {
+ return function() {
+ return instantiate(inDefinition);
+ };
+ }
+
+ function createElement(tag, typeExtension) {
+ // TODO(sjmiles): ignore 'tag' when using 'typeExtension', we could
+ // error check it, or perhaps there should only ever be one argument
+ var definition = registry[typeExtension || tag];
+ if (definition) {
+ return new definition.ctor();
+ }
+ return domCreateElement(tag);
+ }
+
+ function upgradeElement(inElement) {
+ if (!inElement.__upgraded__ && (inElement.nodeType === Node.ELEMENT_NODE)) {
+ var type = inElement.getAttribute('is') || inElement.localName;
+ var definition = registry[type];
+ return definition && upgrade(inElement, definition);
+ }
+ }
+
+ function cloneNode(deep) {
+ // call original clone
+ var n = domCloneNode.call(this, deep);
+ // upgrade the element and subtree
+ scope.upgradeAll(n);
+ // return the clone
+ return n;
+ }
+ // capture native createElement before we override it
+
+ var domCreateElement = document.createElement.bind(document);
+
+ // capture native cloneNode before we override it
+
+ var domCloneNode = Node.prototype.cloneNode;
+
+ // exports
+
+ document.register = register;
+ document.createElement = createElement; // override
+ Node.prototype.cloneNode = cloneNode; // override
+
+ scope.registry = registry;
+
+ /**
+ * Upgrade an element to a custom element. Upgrading an element
+ * causes the custom prototype to be applied, an `is` attribute
+ * to be attached (as needed), and invocation of the `readyCallback`.
+ * `upgrade` does nothing if the element is already upgraded, or
+ * if it matches no registered custom tag name.
+ *
+ * @method ugprade
+ * @param {Element} inElement The element to upgrade.
+ * @return {Element} The upgraded element.
+ */
+ scope.upgrade = upgradeElement;
+}
+
+scope.hasNative = hasNative;
+scope.useNative = useNative;
+
+})(window.CustomElements);
+
+(function() {
+
+// import
+
+var IMPORT_LINK_TYPE = window.HTMLImports ? HTMLImports.IMPORT_LINK_TYPE : 'none';
+
+// highlander object for parsing a document tree
+
+var parser = {
+ selectors: [
+ 'link[rel=' + IMPORT_LINK_TYPE + ']'
+ ],
+ map: {
+ link: 'parseLink'
+ },
+ parse: function(inDocument) {
+ if (!inDocument.__parsed) {
+ // only parse once
+ inDocument.__parsed = true;
+ // all parsable elements in inDocument (depth-first pre-order traversal)
+ var elts = inDocument.querySelectorAll(parser.selectors);
+ // for each parsable node type, call the mapped parsing method
+ forEach(elts, function(e) {
+ parser[parser.map[e.localName]](e);
+ });
+ // upgrade all upgradeable static elements, anything dynamically
+ // created should be caught by observer
+ CustomElements.upgradeDocument(inDocument);
+ // observe document for dom changes
+ CustomElements.observeDocument(inDocument);
+ }
+ },
+ parseLink: function(linkElt) {
+ // imports
+ if (isDocumentLink(linkElt)) {
+ this.parseImport(linkElt);
+ }
+ },
+ parseImport: function(linkElt) {
+ if (linkElt.content) {
+ parser.parse(linkElt.content);
+ }
+ }
+};
+
+function isDocumentLink(inElt) {
+ return (inElt.localName === 'link'
+ && inElt.getAttribute('rel') === IMPORT_LINK_TYPE);
+}
+
+var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach);
+
+// exports
+
+CustomElements.parser = parser;
+
+})();
+(function(){
+
+// bootstrap parsing
+
+function bootstrap() {
+ // go async so call stack can unwind
+ setTimeout(function() {
+ // parse document
+ CustomElements.parser.parse(document);
+ // one more pass before register is 'live'
+ CustomElements.upgradeDocument(document);
+ // set internal 'ready' flag, now document.register will trigger
+ // synchronous upgrades
+ CustomElements.ready = true;
+ // capture blunt profiling data
+ CustomElements.readyTime = Date.now();
+ if (window.HTMLImports) {
+ CustomElements.elapsed = CustomElements.readyTime - HTMLImports.readyTime;
+ }
+ // notify the system that we are bootstrapped
+ document.body.dispatchEvent(
+ new CustomEvent('WebComponentsReady', {bubbles: true})
+ );
+ }, 0);
+}
+
+// CustomEvent shim for IE
+if (typeof window.CustomEvent !== 'function') {
+ window.CustomEvent = function(inType) {
+ var e = document.createEvent('HTMLEvents');
+ e.initEvent(inType, true, true);
+ return e;
+ };
+}
+
+if (document.readyState === 'complete') {
+ bootstrap();
+} else {
+ var loadEvent = window.HTMLImports ? 'HTMLImportsLoaded' : 'DOMContentLoaded';
+ window.addEventListener(loadEvent, bootstrap);
+}
+
+})();
diff --git a/pkg/custom_element/lib/custom-elements.min.js b/pkg/custom_element/lib/custom-elements.min.js
new file mode 100644
index 0000000..f0c3e81
--- /dev/null
+++ b/pkg/custom_element/lib/custom-elements.min.js
@@ -0,0 +1,28 @@
+// Copyright (c) 2012 The Polymer Authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+window.CustomElements={flags:{}};var SideTable;if("undefined"!=typeof WeakMap&&navigator.userAgent.indexOf("Firefox/")<0?SideTable=WeakMap:function(){var a=Object.defineProperty,b=Object.hasOwnProperty,c=(new Date).getTime()%1e9;SideTable=function(){this.name="__st"+(1e9*Math.random()>>>0)+(c++ +"__")},SideTable.prototype={set:function(b,c){a(b,this.name,{value:c,writable:!0})},get:function(a){return b.call(a,this.name)?a[this.name]:void 0},"delete":function(a){this.set(a,void 0)}}}(),function(a){function b(a){u.push(a),t||(t=!0,q(d))}function c(a){return window.ShadowDOMPolyfill&&window.ShadowDOMPolyfill.wrapIfNeeded(a)||a}function d(){t=!1;var a=u;u=[],a.sort(function(a,b){return a.uid_-b.uid_});var b=!1;a.forEach(function(a){var c=a.takeRecords();e(a),c.length&&(a.callback_(c,a),b=!0)}),b&&d()}function e(a){a.nodes_.forEach(function(b){var c=p.get(b);c&&c.forEach(function(b){b.observer===a&&b.removeTransientObservers()})})}function f(a,b){for(var c=a;c;c=c.parentNode){var d=p.get(c);if(d)for(var e=0;e<d.length;e++){var f=d[e],g=f.options;if(c===a||g.subtree){var h=b(g);h&&f.enqueue(h)}}}}function g(a){this.callback_=a,this.nodes_=[],this.records_=[],this.uid_=++v}function h(a,b){this.type=a,this.target=b,this.addedNodes=[],this.removedNodes=[],this.previousSibling=null,this.nextSibling=null,this.attributeName=null,this.attributeNamespace=null,this.oldValue=null}function i(a){var b=new h(a.type,a.target);return b.addedNodes=a.addedNodes.slice(),b.removedNodes=a.removedNodes.slice(),b.previousSibling=a.previousSibling,b.nextSibling=a.nextSibling,b.attributeName=a.attributeName,b.attributeNamespace=a.attributeNamespace,b.oldValue=a.oldValue,b}function j(a,b){return w=new h(a,b)}function k(a){return x?x:(x=i(w),x.oldValue=a,x)}function l(){w=x=void 0}function m(a){return a===x||a===w}function n(a,b){return a===b?a:x&&m(a)?x:null}function o(a,b,c){this.observer=a,this.target=b,this.options=c,this.transientObservedNodes=[]}var p=new SideTable,q=window.msSetImmediate;if(!q){var r=[],s=String(Math.random());window.addEventListener("message",function(a){if(a.data===s){var b=r;r=[],b.forEach(function(a){a()})}}),q=function(a){r.push(a),window.postMessage(s,"*")}}var t=!1,u=[],v=0;g.prototype={observe:function(a,b){if(a=c(a),!b.childList&&!b.attributes&&!b.characterData||b.attributeOldValue&&!b.attributes||b.attributeFilter&&b.attributeFilter.length&&!b.attributes||b.characterDataOldValue&&!b.characterData)throw new SyntaxError;var d=p.get(a);d||p.set(a,d=[]);for(var e,f=0;f<d.length;f++)if(d[f].observer===this){e=d[f],e.removeListeners(),e.options=b;break}e||(e=new o(this,a,b),d.push(e),this.nodes_.push(a)),e.addListeners()},disconnect:function(){this.nodes_.forEach(function(a){for(var b=p.get(a),c=0;c<b.length;c++){var d=b[c];if(d.observer===this){d.removeListeners(),b.splice(c,1);break}}},this),this.records_=[]},takeRecords:function(){var a=this.records_;return this.records_=[],a}};var w,x;o.prototype={enqueue:function(a){var c=this.observer.records_,d=c.length;if(c.length>0){var e=c[d-1],f=n(e,a);if(f)return c[d-1]=f,void 0}else b(this.observer);c[d]=a},addListeners:function(){this.addListeners_(this.target)},addListeners_:function(a){var b=this.options;b.attributes&&a.addEventListener("DOMAttrModified",this,!0),b.characterData&&a.addEventListener("DOMCharacterDataModified",this,!0),b.childList&&a.addEventListener("DOMNodeInserted",this,!0),(b.childList||b.subtree)&&a.addEventListener("DOMNodeRemoved",this,!0)},removeListeners:function(){this.removeListeners_(this.target)},removeListeners_:function(a){var b=this.options;b.attributes&&a.removeEventListener("DOMAttrModified",this,!0),b.characterData&&a.removeEventListener("DOMCharacterDataModified",this,!0),b.childList&&a.removeEventListener("DOMNodeInserted",this,!0),(b.childList||b.subtree)&&a.removeEventListener("DOMNodeRemoved",this,!0)},addTransientObserver:function(a){if(a!==this.target){this.addListeners_(a),this.transientObservedNodes.push(a);var b=p.get(a);b||p.set(a,b=[]),b.push(this)}},removeTransientObservers:function(){var a=this.transientObservedNodes;this.transientObservedNodes=[],a.forEach(function(a){this.removeListeners_(a);for(var b=p.get(a),c=0;c<b.length;c++)if(b[c]===this){b.splice(c,1);break}},this)},handleEvent:function(a){switch(a.stopImmediatePropagation(),a.type){case"DOMAttrModified":var b=a.attrName,c=a.relatedNode.namespaceURI,d=a.target,e=new j("attributes",d);e.attributeName=b,e.attributeNamespace=c;var g=a.attrChange===MutationEvent.ADDITION?null:a.prevValue;f(d,function(a){return!a.attributes||a.attributeFilter&&a.attributeFilter.length&&-1===a.attributeFilter.indexOf(b)&&-1===a.attributeFilter.indexOf(c)?void 0:a.attributeOldValue?k(g):e});break;case"DOMCharacterDataModified":var d=a.target,e=j("characterData",d),g=a.prevValue;f(d,function(a){return a.characterData?a.characterDataOldValue?k(g):e:void 0});break;case"DOMNodeRemoved":this.addTransientObserver(a.target);case"DOMNodeInserted":var h,i,d=a.relatedNode,m=a.target;"DOMNodeInserted"===a.type?(h=[m],i=[]):(h=[],i=[m]);var n=m.previousSibling,o=m.nextSibling,e=j("childList",d);e.addedNodes=h,e.removedNodes=i,e.previousSibling=n,e.nextSibling=o,f(d,function(a){return a.childList?e:void 0})}l()}},a.JsMutationObserver=g}(this),!window.MutationObserver&&(window.MutationObserver=window.WebKitMutationObserver||window.JsMutationObserver,!MutationObserver))throw new Error("no mutation observer support");!function(a){function b(a,c,d){var e=a.firstElementChild;if(!e)for(e=a.firstChild;e&&e.nodeType!==Node.ELEMENT_NODE;)e=e.nextSibling;for(;e;)c(e,d)!==!0&&b(e,c,d),e=e.nextElementSibling;return null}function c(a,b){for(var c=a.webkitShadowRoot;c;)d(c,b),c=c.olderShadowRoot}function d(a,d){b(a,function(a){return d(a)?!0:(c(a,d),void 0)}),c(a,d)}function e(a){return h(a)?(i(a),!0):(j(a),void 0)}function f(a){d(a,function(a){return e(a)?!0:void 0})}function g(a){return e(a)||f(a)}function h(b){if(!b.__upgraded__&&b.nodeType===Node.ELEMENT_NODE){var c=b.getAttribute("is")||b.localName,d=a.registry[c];if(d)return logFlags.dom&&console.group("upgrade:",b.localName),a.upgrade(b),logFlags.dom&&console.groupEnd(),!0}}function i(a){j(a),m(a)&&d(a,function(a){j(a)})}function j(a){(a.enteredDocumentCallback||a.__upgraded__&&logFlags.dom)&&(logFlags.dom&&console.group("inserted:",a.localName),m(a)&&(a.__inserted=(a.__inserted||0)+1,a.__inserted<1&&(a.__inserted=1),a.__inserted>1?logFlags.dom&&console.warn("inserted:",a.localName,"insert/remove count:",a.__inserted):a.enteredDocumentCallback&&(logFlags.dom&&console.log("inserted:",a.localName),a.enteredDocumentCallback())),logFlags.dom&&console.groupEnd())}function k(a){l(a),d(a,function(a){l(a)})}function l(a){(a.leftDocumentCallback||a.__upgraded__&&logFlags.dom)&&(logFlags.dom&&console.log("removed:",a.localName),m(a)||(a.__inserted=(a.__inserted||0)-1,a.__inserted>0&&(a.__inserted=0),a.__inserted<0?logFlags.dom&&console.warn("removed:",a.localName,"insert/remove count:",a.__inserted):a.leftDocumentCallback&&a.leftDocumentCallback()))}function m(a){for(var b=a;b;){if(b==a.ownerDocument)return!0;b=b.parentNode||b.host}}function n(a){if(a.webkitShadowRoot&&!a.webkitShadowRoot.__watched){logFlags.dom&&console.log("watching shadow-root for: ",a.localName);for(var b=a.webkitShadowRoot;b;)o(b),b=b.olderShadowRoot}}function o(a){a.__watched||(t(a),a.__watched=!0)}function p(a){n(a),d(a,function(){n(a)})}function q(a){switch(a.localName){case"style":case"script":case"template":case void 0:return!0}}function r(a){if(logFlags.dom){var b=a[0];if(b&&"childList"===b.type&&b.addedNodes&&b.addedNodes){for(var c=b.addedNodes[0];c&&c!==document&&!c.host;)c=c.parentNode;var d=c&&(c.URL||c._URL||c.host&&c.host.localName)||"";d=d.split("/?").shift().split("/").pop()}console.group("mutations (%d) [%s]",a.length,d||"")}a.forEach(function(a){"childList"===a.type&&(x(a.addedNodes,function(a){q(a)||g(a)}),x(a.removedNodes,function(a){q(a)||k(a)}))}),logFlags.dom&&console.groupEnd()}function s(){r(w.takeRecords())}function t(a){w.observe(a,{childList:!0,subtree:!0})}function u(a){t(a)}function v(a){logFlags.dom&&console.group("upgradeDocument: ",(a.URL||a._URL||"").split("/").pop()),g(a),logFlags.dom&&console.groupEnd()}var w=new MutationObserver(r),x=Array.prototype.forEach.call.bind(Array.prototype.forEach);a.watchShadow=n,a.watchAllShadows=p,a.upgradeAll=g,a.upgradeSubtree=f,a.observeDocument=u,a.upgradeDocument=v,a.takeRecords=s}(window.CustomElements),function(a){function b(b,f){var g=f||{};if(!b)throw new Error("Name argument must not be empty");if(g.name=b,!g.prototype)throw new Error("Options missing required prototype property");return g.lifecycle=g.lifecycle||{},g.ancestry=c(g.extends),d(g),e(g),k(g.prototype),m(b,g),g.ctor=n(g),g.ctor.prototype=g.prototype,g.prototype.constructor=g.ctor,a.ready&&a.upgradeAll(document),g.ctor}function c(a){var b=v[a];return b?c(b.extends).concat([b]):[]}function d(a){for(var b,c=a.extends,d=0;b=a.ancestry[d];d++)c=b.is&&b.tag;a.tag=c||a.name,c&&(a.is=a.name)}function e(a){if(!Object.__proto__){var b=HTMLElement.prototype;if(a.is){var c=document.createElement(a.tag);b=Object.getPrototypeOf(c)}for(var d,e=a.prototype;e&&e!==b;){var d=Object.getPrototypeOf(e);e.__proto__=d,e=d}}a.native=b}function f(a){return g(w(a.tag),a)}function g(b,c){return c.is&&b.setAttribute("is",c.is),h(b,c),b.__upgraded__=!0,a.upgradeSubtree(b),j(b),b}function h(a,b){Object.__proto__?a.__proto__=b.prototype:(i(a,b.prototype,b.native),a.__proto__=b.prototype)}function i(a,b,c){for(var d={},e=b;e!==c&&e!==HTMLUnknownElement.prototype;){for(var f,g=Object.getOwnPropertyNames(e),h=0;f=g[h];h++)d[f]||(Object.defineProperty(a,f,Object.getOwnPropertyDescriptor(e,f)),d[f]=1);e=Object.getPrototypeOf(e)}}function j(a){a.createdCallback&&a.createdCallback()}function k(a){var b=a.setAttribute;a.setAttribute=function(a,c){l.call(this,a,c,b)};var c=a.removeAttribute;a.removeAttribute=function(a,b){l.call(this,a,b,c)}}function l(a,b,c){var d=this.getAttribute(a);c.apply(this,arguments),this.attributeChangedCallback&&this.getAttribute(a)!==d&&this.attributeChangedCallback(a,d)}function m(a,b){if(v[a])throw new Error("Cannot register a tag more than once");v[a]=b}function n(a){return function(){return f(a)}}function o(a,b){var c=v[b||a];return c?new c.ctor:w(a)}function p(a){if(!a.__upgraded__&&a.nodeType===Node.ELEMENT_NODE){var b=a.getAttribute("is")||a.localName,c=v[b];return c&&g(a,c)}}function q(b){var c=x.call(this,b);return a.upgradeAll(c),c}a||(a=window.CustomElements={flags:{}});var r=a.flags,s=Boolean(document.webkitRegister||document.register),t=!r.register&&s;if(t){document.register=document.register||document.webkitRegister;var u=function(){};a.registry={},a.upgradeElement=u,a.watchShadow=u,a.watchAllShadows=u,a.upgrade=u,a.upgradeAll=u,a.upgradeSubtree=u,a.observeDocument=u,a.upgradeDocument=u,a.takeRecords=u}else{var v={},w=document.createElement.bind(document),x=Node.prototype.cloneNode;document.register=b,document.createElement=o,Node.prototype.cloneNode=q,a.registry=v,a.upgrade=p}a.hasNative=s,a.useNative=t}(window.CustomElements),function(){function a(a){return"link"===a.localName&&a.getAttribute("rel")===b}var b=window.HTMLImports?HTMLImports.IMPORT_LINK_TYPE:"none",c={selectors:["link[rel="+b+"]"],map:{link:"parseLink"},parse:function(a){if(!a.__parsed){a.__parsed=!0;var b=a.querySelectorAll(c.selectors);d(b,function(a){c[c.map[a.localName]](a)}),CustomElements.upgradeDocument(a),CustomElements.observeDocument(a)}},parseLink:function(b){a(b)&&this.parseImport(b)},parseImport:function(a){a.content&&c.parse(a.content)}},d=Array.prototype.forEach.call.bind(Array.prototype.forEach);CustomElements.parser=c}(),function(){function a(){setTimeout(function(){CustomElements.parser.parse(document),CustomElements.upgradeDocument(document),CustomElements.ready=!0,CustomElements.readyTime=Date.now(),window.HTMLImports&&(CustomElements.elapsed=CustomElements.readyTime-HTMLImports.readyTime),document.body.dispatchEvent(new CustomEvent("WebComponentsReady",{bubbles:!0}))},0)}if("function"!=typeof window.CustomEvent&&(window.CustomEvent=function(a){var b=document.createEvent("HTMLEvents");return b.initEvent(a,!0,!0),b}),"complete"===document.readyState)a();else{var b=window.HTMLImports?"HTMLImportsLoaded":"DOMContentLoaded";window.addEventListener(b,a)}}();
diff --git a/pkg/custom_element/lib/custom_element.dart b/pkg/custom_element/lib/custom_element.dart
index 16978ae..4121dbf 100644
--- a/pkg/custom_element/lib/custom_element.dart
+++ b/pkg/custom_element/lib/custom_element.dart
@@ -313,6 +313,8 @@
host.innerHtml = v;
}
+ InputMethodContext get inputMethodContext => host.inputMethodContext;
+
bool get isContentEditable => host.isContentEditable;
String get lang => host.lang;
@@ -338,7 +340,8 @@
void click() { host.click(); }
- InputMethodContext getInputContext() => host.getInputContext();
+ List<Node> getDestinationInsertionPoints() =>
+ host.getDestinationInsertionPoints();
Element insertAdjacentElement(String where, Element element) =>
host.insertAdjacentElement(where, element);
diff --git a/pkg/docgen/README.md b/pkg/docgen/README.md
index 24ba58a..66d0a46 100644
--- a/pkg/docgen/README.md
+++ b/pkg/docgen/README.md
@@ -32,19 +32,21 @@
- `-h`, `--help` Prints help and usage information.
- `-v`, `--verbose` Output more logging information.
-- `-j`, `--[no-]json` Outputs to JSON. Files are outputted to YAML by default.
+- `-j`, `--[no-]json` Outputs to JSON. Files are outputted to YAML by default.
+If `--append` is used, it takes the file-format of the previous run stated in
+library_list.json ignoring the flag.
- `--include-private` Flag to include private declarations.
- `--include-sdk` Flag to parse SDK Library files imported.
- `--parse-sdk` Parses the SDK libraries only. (Ignores the path passed in.)
- `--package-root` Sets the package root of the library being analyzed.
-- `--append` Appends to the docs folder, library_list.txt, and index.txt.
+- `--append` Appends to the docs folder, library_list.json, and index.txt.
- `--introduction` Adds the provided markdown text file as the introduction
for the outputted documentation.
###### Output Directory
Documented libraries will be located at bin/docs in either YAML or JSON format
-depending on options specified. There will also be a library_list.txt,
+depending on options specified. There will also be a library_list.json,
containing a list of all the libraries inside the docs folder.
To get more information on how to use the outputted documentation with
diff --git a/pkg/docgen/bin/docgen.dart b/pkg/docgen/bin/docgen.dart
index ca4f780..293f3cf 100644
--- a/pkg/docgen/bin/docgen.dart
+++ b/pkg/docgen/bin/docgen.dart
@@ -49,7 +49,9 @@
if (verbose) Logger.root.level = Level.FINEST;
});
parser.addFlag('json', abbr: 'j',
- help: 'Outputs to JSON. Files are outputted to YAML by default.',
+ help: 'Outputs to JSON. Files are outputted to YAML by default. '
+ 'If --append is used, it takes the file-format of the previous '
+ 'run stated in library_list.json ignoring the flag.',
negatable: true);
parser.addFlag('include-private',
help: 'Flag to include private declarations.', negatable: false);
@@ -61,7 +63,7 @@
parser.addOption('package-root',
help: 'Sets the package root of the library being analyzed.');
parser.addFlag('append',
- help: 'Append to the docs folder, library_list.txt and index.txt',
+ help: 'Append to the docs folder, library_list.json and index.txt',
defaultsTo: false, negatable: false);
parser.addOption('introduction',
help: 'Adds the provided markdown text file as the introduction'
diff --git a/pkg/docgen/lib/dart2yaml.dart b/pkg/docgen/lib/dart2yaml.dart
index 57ca7fe..343b61f 100644
--- a/pkg/docgen/lib/dart2yaml.dart
+++ b/pkg/docgen/lib/dart2yaml.dart
@@ -7,6 +7,8 @@
*/
library dart2yaml;
+import 'dart:collection';
+
/**
* Gets a String representing the input Map in YAML format.
*/
@@ -26,10 +28,11 @@
*/
void _addLevel(StringBuffer yaml, Map documentData, int level,
{bool isList: false}) {
- // Since the ordering of the keys could be non-deterministic, the keys
- // are sorted to ensure consistency in the output.
+ // The order of the keys could be nondeterministic, but it is insufficient
+ // to just sort the keys no matter what, as their order could be significant
+ // (i.e. parameters to a method). The order of the keys should be enforced
+ // by the caller of this function.
var keys = documentData.keys.toList();
- keys.sort();
keys.forEach((key) {
_calcSpaces(level, yaml);
// Only the first entry of the map should be preceeded with a '-' since
diff --git a/pkg/docgen/lib/docgen.dart b/pkg/docgen/lib/docgen.dart
index a51ab86..6faca3f5 100644
--- a/pkg/docgen/lib/docgen.dart
+++ b/pkg/docgen/lib/docgen.dart
@@ -244,26 +244,44 @@
if (parseSdk) entityMap['dart.core.Object'].subclasses.clear();
var filteredEntities = entityMap.values.where(_isVisible);
+
+ // Outputs a JSON file with all libraries and their preview comments.
+ // This will help the viewer know what libraries are available to read in.
+ var libraryMap;
+ if (append) {
+ var docsDir = listDir('docs');
+ if (!docsDir.contains('docs/library_list.json')) {
+ throw new StateError('No library_list.json');
+ }
+ libraryMap = parse(new File('docs/library_list.json').readAsStringSync());
+ libraryMap['libraries'].addAll(filteredEntities
+ .where((e) => e is Library)
+ .map((e) => e.previewMap));
+ if (introduction.isNotEmpty) {
+ var intro = libraryMap['introduction'];
+ if (intro.isNotEmpty) intro += '<br/><br/>';
+ intro += markdown.markdownToHtml(
+ new File(introduction).readAsStringSync(),
+ linkResolver: linkResolver, inlineSyntaxes: markdownSyntaxes);
+ libraryMap['introduction'] = intro;
+ }
+ outputToYaml = libraryMap['filetype'] == 'yaml';
+ } else {
+ libraryMap = {
+ 'libraries' : filteredEntities.where((e) =>
+ e is Library).map((e) => e.previewMap).toList(),
+ 'introduction' : introduction == '' ?
+ '' : markdown.markdownToHtml(new File(introduction)
+ .readAsStringSync(), linkResolver: linkResolver,
+ inlineSyntaxes: markdownSyntaxes),
+ 'filetype' : outputToYaml ? 'yaml' : 'json'
+ };
+ }
+ _writeToFile(stringify(libraryMap), 'library_list.json');
// Output libraries and classes to file after all information is generated.
filteredEntities.where((e) => e is Class || e is Library).forEach((output) {
_writeIndexableToFile(output, outputToYaml);
});
- // Outputs a YAML or JSON file with all libraries and their preview comments
- // after creating all libraries. This will help the viewer know what
- // libraries are available to read in.
- var libraryMap = {
- 'libraries' : filteredEntities.where((e) =>
- e is Library).map((e) => e.previewMap).toList(),
- 'introduction' : introduction == '' ?
- '' : markdown.markdownToHtml(new File(introduction).readAsStringSync(),
- linkResolver: linkResolver, inlineSyntaxes: markdownSyntaxes)
- };
- if (outputToYaml) {
- _writeToFile(getYamlString(libraryMap), 'library_list.yaml',
- append: append);
- } else {
- _writeToFile(stringify(libraryMap), 'library_list.json', append: append);
- }
// Outputs all the qualified names documented with their type.
// This will help generate search results.
_writeToFile(filteredEntities.map((e) =>
diff --git a/pkg/intl/lib/generate_localized.dart b/pkg/intl/lib/generate_localized.dart
index 9516372..6477023 100644
--- a/pkg/intl/lib/generate_localized.dart
+++ b/pkg/intl/lib/generate_localized.dart
@@ -215,7 +215,8 @@
Future initializeMessages(String localeName) {
initializeInternalMessageLookup(() => new CompositeMessageLookup());
messageLookup.addLocale(localeName, _findGeneratedMessagesFor);
- return deferredLibraries[localeName].load();
+ var lib = deferredLibraries[localeName];
+ return lib == null ? new Future.value(false) : lib.load();
}
MessageLookupByLibrary _findGeneratedMessagesFor(locale) {
diff --git a/pkg/intl/test/message_extraction/sample_with_messages.dart b/pkg/intl/test/message_extraction/sample_with_messages.dart
index 292273c..753f39c 100644
--- a/pkg/intl/test/message_extraction/sample_with_messages.dart
+++ b/pkg/intl/test/message_extraction/sample_with_messages.dart
@@ -178,6 +178,8 @@
var fr = new Intl("fr");
var english = new Intl("en_US");
var de = new Intl("de_DE");
+ // Throw in an initialize of a null locale to make sure it doesn't throw.
+ initializeMessages(null);
initializeMessages(fr.locale).then((_) => printStuff(fr));
initializeMessages(de.locale).then((_) => printStuff(de));
printStuff(english);
diff --git a/pkg/meta/lib/meta.dart b/pkg/meta/lib/meta.dart
index c86e377..9960d59 100644
--- a/pkg/meta/lib/meta.dart
+++ b/pkg/meta/lib/meta.dart
@@ -46,3 +46,18 @@
class _Override {
const _Override();
}
+
+/**
+ * An annotation used to mark a class that should be considered to implement
+ * every possible getter, setter and method. Tools can use this annotation to
+ * suppress warnings when there is no explicit implementation of a referenced
+ * member. Tools should provide a hint if this annotation is applied to a class
+ * that does not implement or inherit an implementation of the method
+ * [:noSuchMethod:] (other than the implementation in [Object]). Note that
+ * classes are not affected by the use of this annotation on a supertype.
+ */
+const proxy = const _Proxy();
+
+class _Proxy {
+ const _Proxy();
+}
\ No newline at end of file
diff --git a/pkg/pkg.status b/pkg/pkg.status
index 39486e0..f41776a 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -8,9 +8,12 @@
*/packages/*/*: Skip
*/*/packages/*/*: Skip
*/*/*/packages/*/*: Skip
+*/*/*/*/packages/*/*: Skip
# Skip non-test files ending with "_test".
scheduled_test/lib/*: Skip
+polymer/lib/*: Skip
+polymer/example/*: Skip
scheduled_test/test/scheduled_server_test: Pass, Fail, Slow, Crash # Issue 9231, 9582
scheduled_test/test/scheduled_process_test: Pass, Slow # Issue 9231
@@ -20,7 +23,6 @@
[ $compiler == dart2js && $runtime == d8 ]
unmodifiable_collection/test/unmodifiable_collection_test: Pass, Fail # Issue 12429
-csslib/test/declaration_test: Pass, Crash # V8 issue 2846
[ $compiler == dart2js ]
analyzer_experimental/test/generated/ast_test: Fail #Issue 12341
@@ -28,7 +30,7 @@
[ $compiler == dart2js && $checked && $runtime == ie9 ]
crypto/test/base64_test: Timeout # Issue 12486
-[ $compiler == dart2js && ($runtime == d8 || $runtime == drt) ]
+[ $compiler == dart2js && $runtime == drt ]
crypto/test/hmac_sha256_test: Pass, Fail # v8 bug: Issue 12293
crypto/test/sha1_test: Pass, Fail # v8 bug: Issue 12293
crypto/test/sha256_test: Pass, Fail # v8 bug: Issue 12293
@@ -87,6 +89,8 @@
observe/test/observe_test: Fail # Issue 11970
observe/test/path_observer_test: Fail # Issue 11970
mdv/test/binding_syntax_test: Fail # Issue 11970
+polymer_expressions/test/eval_test: Fail # Issue 12578
+polymer_expressions/test/syntax_test: Fail # Issue 12578
serialization/test/serialization_test: Fail # Issue 6490
serialization/test/no_library_test: Fail # Issue 6490
@@ -109,7 +113,6 @@
csslib/test/var_test: Fail # looking for VM-specific stack traces, issue 12469
[ $compiler == dart2js && $runtime == drt ]
-third_party/html5lib/test/parser_feature_test: Fail # issue 12466
csslib: Pass, Fail # issue 12466
[ $browser ]
@@ -138,6 +141,7 @@
oauth2/test/handle_access_token_response_test: Fail, OK # Uses dart:io.
observe/test/transform_test: Fail, OK # Uses dart:io.
path/test/io_test: Fail, OK # Uses dart:io.
+polymer/test/*: Fail, OK # Uses dart:io.
watcher/test/*: Fail, OK # Uses dart:io.
scheduled_test/test/descriptor/async_test: Fail # http://dartbug.com/8440
@@ -179,9 +183,6 @@
# not minified.
unittest/test/*_minified_test: Skip # DO NOT COPY THIS UNLESS YOU WORK ON DART2JS
-[ $compiler == none && $runtime == drt ]
-dartdoc/test/dartdoc_test: Skip # See dartbug.com/4541.
-
[ $arch == arm ]
*: Skip
diff --git a/pkg/polymer/README.md b/pkg/polymer/README.md
new file mode 100644
index 0000000..d4d177f0b
--- /dev/null
+++ b/pkg/polymer/README.md
@@ -0,0 +1,85 @@
+Polymer.dart
+============
+
+Polymer is a new type of library for the web, built on top of Web Components,
+and designed to leverage the evolving web platform on modern browsers.
+
+Polymer.dart is a Dart port of Polymer created and maintained by the Dart team.
+The Dart team is collaborating with the Polymer team to ensure that polymer.dart
+elements and polyfills are fully compatible with Polymer.
+
+For more information about Polymer, see <http://www.polymer-project.org/>.
+For more information about Dart, see <http://www.dartlang.org/>.
+
+Try It Now
+-----------
+Add the polymer.dart package to your pubspec.yaml file:
+
+```yaml
+dependencies:
+ polymer: any
+```
+
+Instead of using `any`, we recommend using version ranges to avoid getting your
+project broken on each release. Using a version range lets you upgrade your
+package at your own pace. You can find the latest version number at
+<https://pub.dartlang.org/packages/polymer>.
+
+
+Learn More
+----------
+
+**Note**: these documents are currently out of date.
+
+* [Read an overview][overview]
+* [Setup your tools][tools]
+* [Browse the features][features]
+* [Dive into the specification][spec]
+
+See our [TodoMVC][] example by opening up the Dart Editor's Welcome Page and
+selecting "TodoMVC".
+
+Running Tests
+-------------
+
+Dependencies are installed using the [Pub Package Manager][pub].
+```bash
+pub install
+
+# Run command line tests and automated end-to-end tests. It needs two
+# executables on your path: `dart` and `content_shell` (see below
+# for links to download `content_shell`)
+test/run.sh
+```
+Note: to run browser tests you will need to have [content_shell][cs],
+which can be downloaded prebuilt for [Ubuntu Lucid][cs_lucid],
+[Windows][cs_win], or [Mac][cs_mac]. You can also build it from the
+[Dartium and content_shell sources][dartium_src].
+
+For Linux users all the necessary fonts must be installed see
+<https://code.google.com/p/chromium/wiki/LayoutTestsLinux>.
+
+Contacting Us
+-------------
+
+Please file issues in our [Issue Tracker][issues] or contact us on the
+[Dart Web UI mailing list][mailinglist].
+
+We also have the [Web UI development list][devlist] for discussions about
+internals of the code, code reviews, etc.
+
+[wc]: http://dvcs.w3.org/hg/webcomponents/raw-file/tip/explainer/index.html
+[pub]: http://www.dartlang.org/docs/pub-package-manager/
+[cs]: http://www.chromium.org/developers/testing/webkit-layout-tests
+[cs_lucid]: http://gsdview.appspot.com/dartium-archive/continuous/drt-lucid64.zip
+[cs_mac]: http://gsdview.appspot.com/dartium-archive/continuous/drt-mac.zip
+[cs_win]: http://gsdview.appspot.com/dartium-archive/continuous/drt-win.zip
+[dartium_src]: http://code.google.com/p/dart/wiki/BuildingDartium
+[TodoMVC]: http://addyosmani.github.com/todomvc/
+[issues]: http://dartbug.com/new
+[mailinglist]: https://groups.google.com/a/dartlang.org/forum/?fromgroups#!forum/web-ui
+[devlist]: https://groups.google.com/a/dartlang.org/forum/?fromgroups#!forum/web-ui-dev
+[overview]: http://www.dartlang.org/articles/dart-web-components/
+[tools]: https://www.dartlang.org/articles/dart-web-components/tools.html
+[spec]: https://www.dartlang.org/articles/dart-web-components/spec.html
+[features]: https://www.dartlang.org/articles/dart-web-components/summary.html
diff --git a/pkg/polymer/bin/dwc.dart b/pkg/polymer/bin/dwc.dart
new file mode 100755
index 0000000..3d3a0a2
--- /dev/null
+++ b/pkg/polymer/bin/dwc.dart
@@ -0,0 +1,8 @@
+#!/usr/bin/env dart
+// 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.
+
+import 'package:polymer/dwc.dart' as dwc;
+
+void main() => dwc.main();
diff --git a/pkg/polymer/build.dart b/pkg/polymer/build.dart
new file mode 100755
index 0000000..5e863b8
--- /dev/null
+++ b/pkg/polymer/build.dart
@@ -0,0 +1,17 @@
+#!/usr/bin/env dart
+// 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.
+
+/** Build logic that lets the Dart editor build examples in the background. */
+library build;
+import 'package:polymer/component_build.dart';
+import 'dart:io';
+
+void main() {
+ var args = new Options().arguments.toList()..addAll(['--', '--deploy']);
+ build(args, [
+ 'example/component/news/web/index.html',
+ 'example/scoped_style/index.html',
+ '../../samples/third_party/todomvc/web/index.html']);
+}
diff --git a/pkg/polymer/example/component/news/test/expected/news_index_test.html.txt b/pkg/polymer/example/component/news/test/expected/news_index_test.html.txt
new file mode 100644
index 0000000..f5907ed
--- /dev/null
+++ b/pkg/polymer/example/component/news/test/expected/news_index_test.html.txt
@@ -0,0 +1,85 @@
+Content-Type: text/plain
+<html><head><style>template { display: none; }</style>
+ <title>Simple Web Components Example</title>
+
+ <script src="../../packages/polymer/testing/testing.js"></script>
+<style>template,
+thead[template],
+tbody[template],
+tfoot[template],
+th[template],
+tr[template],
+td[template],
+caption[template],
+colgroup[template],
+col[template],
+option[template] {
+ display: none;
+}</style></head>
+<body><polymer-element name="x-news" extends="ul">
+ <template>
+ <style scoped="">
+ div.breaking {
+ color: Red;
+ font-size: 20px;
+ border: 1px dashed Purple;
+ }
+ div.other {
+ padding: 2px 0 0 0;
+ border: 1px solid Cyan;
+ }
+ </style>
+ <div class="breaking">
+ <h2>Breaking Stories</h2>
+ <ul>
+ <content select=".breaking"></content>
+ </ul>
+ </div>
+ <div class="other">
+ <h2>Other News</h2>
+ <ul>
+ <content></content>
+ </ul>
+ </div>
+ </template>
+
+</polymer-element>
+
+<h1>Simple Web Components Example</h1>
+<ul is="x-news"><shadow-root>
+ <style scoped="">
+ div.breaking {
+ color: Red;
+ font-size: 20px;
+ border: 1px dashed Purple;
+ }
+ div.other {
+ padding: 2px 0 0 0;
+ border: 1px solid Cyan;
+ }
+ </style>
+ <div class="breaking">
+ <h2>Breaking Stories</h2>
+ <ul>
+ <content select=".breaking"></content>
+ </ul>
+ </div>
+ <div class="other">
+ <h2>Other News</h2>
+ <ul>
+ <content></content>
+ </ul>
+ </div>
+ </shadow-root>
+ <li><a href="//example.com/stories/1">A story</a></li>
+ <li><a href="//example.com/stories/2">Another story</a></li>
+ <li class="breaking"><a href="//example.com/stories/3">Also a story</a></li>
+ <li><a href="//example.com/stories/4">Yet another story</a></li>
+ <li><a href="//example.com/stories/4">Awesome story</a></li>
+ <li class="breaking"><a href="//example.com/stories/5">Horrible story</a></li>
+</ul>
+
+
+
+<script type="text/javascript" src="packages/shadow_dom/shadow_dom.debug.js"></script>
+<script type="application/dart" src="news_index_test.html_bootstrap.dart"></script></body></html>
diff --git a/pkg/polymer/example/component/news/test/news_index_test.html b/pkg/polymer/example/component/news/test/news_index_test.html
new file mode 100644
index 0000000..95bfadd
--- /dev/null
+++ b/pkg/polymer/example/component/news/test/news_index_test.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<!--
+This example is from
+https://github.com/dglazkov/Web-Components-Polyfill/blob/master/samples/news
+-->
+<html>
+<head>
+ <title>Simple Web Components Example</title>
+ <link rel="import" href="../web/news-component.html">
+ <script src="packages/polymer/testing/testing.js"></script>
+</head>
+<body>
+<h1>Simple Web Components Example</h1>
+<ul is="x-news">
+ <li><a href="//example.com/stories/1">A story</a></li>
+ <li><a href="//example.com/stories/2">Another story</a></li>
+ <li class="breaking"><a href="//example.com/stories/3">Also a story</a></li>
+ <li><a href="//example.com/stories/4">Yet another story</a></li>
+ <li><a href="//example.com/stories/4">Awesome story</a></li>
+ <li class="breaking"><a href="//example.com/stories/5">Horrible story</a></li>
+</ul>
+<script type="application/dart">
+import 'dart:html';
+main() {
+ window.postMessage('done', '*');
+}
+</script>
+</body>
+</html>
diff --git a/pkg/polymer/example/component/news/test/test.dart b/pkg/polymer/example/component/news/test/test.dart
new file mode 100755
index 0000000..a4c98a0
--- /dev/null
+++ b/pkg/polymer/example/component/news/test/test.dart
@@ -0,0 +1,14 @@
+#!/usr/bin/env dart
+// 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 'dart:io';
+import 'package:polymer/testing/content_shell_test.dart';
+import 'package:unittest/compact_vm_config.dart';
+
+void main() {
+ useCompactVMConfiguration();
+ // Base directory, input, expected, output:
+ renderTests('..', '.', 'expected', 'out');
+}
diff --git a/pkg/polymer/example/component/news/web/index.html b/pkg/polymer/example/component/news/web/index.html
new file mode 100644
index 0000000..3354d9b
--- /dev/null
+++ b/pkg/polymer/example/component/news/web/index.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<!--
+This example is from
+https://github.com/dglazkov/Web-Components-Polyfill/blob/master/samples/news
+-->
+<html>
+<head>
+ <title>Simple Web Components Example</title>
+ <link rel="import" href="news-component.html">
+ <script src='packages/polymer/boot.js'></script>
+</head>
+<body>
+<h1>Simple Web Components Example</h1>
+<ul is="x-news">
+ <li><a href="//example.com/stories/1">A story</a></li>
+ <li><a href="//example.com/stories/2">Another story</a></li>
+ <li class="breaking"><a href="//example.com/stories/3">Also a story</a></li>
+ <li><a href="//example.com/stories/4">Yet another story</a></li>
+ <li><a href="//example.com/stories/4">Awesome story</a></li>
+ <li class="breaking"><a href="//example.com/stories/5">Horrible story</a></li>
+</ul>
+ <script type="application/dart">main() {}</script>
+</body>
+</html>
diff --git a/pkg/polymer/example/component/news/web/news-component.html b/pkg/polymer/example/component/news/web/news-component.html
new file mode 100644
index 0000000..8e604d2
--- /dev/null
+++ b/pkg/polymer/example/component/news/web/news-component.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<!--
+This example is from
+https://github.com/dglazkov/Web-Components-Polyfill/blob/master/samples/news
+-->
+<html>
+<head>
+ <title>News Component</title>
+</head>
+<body>
+<polymer-element name="x-news" extends="ul">
+ <template>
+ <style scoped>
+ div.breaking {
+ color: Red;
+ font-size: 20px;
+ border: 1px dashed Purple;
+ }
+ div.other {
+ padding: 2px 0 0 0;
+ border: 1px solid Cyan;
+ }
+ </style>
+ <div class="breaking">
+ <h2>Breaking Stories</h2>
+ <ul>
+ <content select=".breaking"></content>
+ </ul>
+ </div>
+ <div class="other">
+ <h2>Other News</h2>
+ <ul>
+ <content></content>
+ </ul>
+ </div>
+ </template>
+ <script type="application/dart">
+ import 'package:polymer/polymer.dart';
+
+ class XNews extends PolymerElement {}
+
+ @initMethod
+ _init() {
+ registerPolymerElement('x-news', () => new XNews());
+ }
+ </script>
+</polymer-element>
+</body>
+</html>
diff --git a/pkg/polymer/example/scoped_style/index.html b/pkg/polymer/example/scoped_style/index.html
new file mode 100644
index 0000000..bc81e7a
--- /dev/null
+++ b/pkg/polymer/example/scoped_style/index.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Simple CSS Test</title>
+ <link rel="import" href="my_test.html">
+ <script src='packages/polymer/boot.js'></script>
+</head>
+<body>
+<style>
+ p { color: black;}
+</style>
+<p>outside of element, should be black</p>
+
+<my-test></my-test>
+</body>
+</html>
diff --git a/pkg/polymer/example/scoped_style/my_test.html b/pkg/polymer/example/scoped_style/my_test.html
new file mode 100644
index 0000000..2713a3f
--- /dev/null
+++ b/pkg/polymer/example/scoped_style/my_test.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Test Compopnent</title>
+</head>
+<body>
+<polymer-element name="my-test">
+ <template>
+ <style>
+ p { color: red;}
+ </style>
+ <p>Inside element, should be red</p>
+ </template>
+ <script type="application/dart">
+ import 'package:polymer/polymer.dart';
+
+ @CustomTag('my-test')
+ class MyTest extends PolymerElement {}
+ </script>
+</polymer-element>
+</body>
+</html>
diff --git a/pkg/polymer/lib/boot.js b/pkg/polymer/lib/boot.js
new file mode 100644
index 0000000..84bb489
--- /dev/null
+++ b/pkg/polymer/lib/boot.js
@@ -0,0 +1,158 @@
+// 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.
+
+// This script dynamically prepares a set of files to run polymer.dart. It uses
+// the html_import polyfill to search for all imported files, then
+// it inlines all <polymer-element> definitions on the top-level page (needed by
+// registerPolymerElement), and it removes script tags that appear inside
+// those tags. It finally rewrites the main entrypoint to call an initialization
+// function on each of the declared <polymer-elements>.
+//
+// This script is needed only when running polymer.dart in Dartium. It should be
+// removed by the polymer deployment commands.
+
+// As an example, given an input of this form:
+// <polymer-element name="c1">
+// <template></template>
+// <script type="application/dart" src="url0.dart"></script>
+// </polymer-element>
+// <element name="c2">
+// <template></template>
+// <script type="application/dart">main() => { print('body2'); }</script>
+// </element>
+// <c1></c1>
+// <c2></c2>
+// <script type="application/dart" src="url2.dart"></script>
+// <script src="packages/polymer/boot.js"></script>
+//
+// This script will simplifies the page as follows:
+// <polymer-element name="c1">
+// <template></template>
+// </polymer-element>
+// <polymer-element name="c2">
+// <template></template>
+// </polymer-element>
+// <c1></c1>
+// <c2></c2>
+// <script type="application/dart">
+// import 'url0.dart' as i0;
+// import "data:application/dart;base64,CiAgICBtYWluKCkgewogICAgICBwcmludCgnYm9keTInKTsKICAgIH0KICAgIA==" as i1;
+// import 'url2.dart' as i2;
+// ...
+// main() {
+// // code that checks which libraries have a 'main' and invokes them.
+// // practically equivalent to: i0._init(); i1._init(); i2.main();
+// }
+// </script>
+
+
+(function() {
+ // Only run in Dartium.
+ if (!navigator.webkitStartDart) {
+ // TODO(sigmund): rephrase when we split build.dart in two: analysis vs
+ // deploy pieces.
+ console.warn('boot.js only works in Dartium. Run the build.dart' +
+ ' tool to compile a depolyable JavaScript version')
+ return;
+ }
+ document.write(
+ '<script src="packages/html_import/html_import.min.js"></script>');
+
+ // Extract a Dart import URL from a script tag, which is the 'src' attribute
+ // of the script tag, or a data-url with the script contents for inlined code.
+ function getScriptUrl(script) {
+ var url = script.src;
+ if (url) {
+ // Normalize package: urls
+ var index = url.indexOf('packages/');
+ if (index == 0 || (index > 0 && url[index - 1] == '/')) {
+ url = "package:" + url.slice(index + 9);
+ }
+ return url;
+ } else {
+ // TODO(sigmund): investigate how to eliminate the warning in Dartium
+ // (changing to text/javascript hides the warning, but seems wrong).
+ return "data:application/dart;base64," + window.btoa(script.textContent);
+ }
+ }
+
+ // Moves <polymer-elements> from imported documents into the top-level page.
+ function inlinePolymerElements(content, ref, seen) {
+ if (!seen) seen = {};
+ var links = content.querySelectorAll('link[rel="import"]');
+ for (var i = 0; i < links.length; i++) {
+ var link = links[i].import;
+ if (seen[link.href]) continue;
+ seen[link.href] = link;
+ inlinePolymerElements(link.content, ref, seen);
+ }
+
+ if (content != document) { // no need to do anything for the top-level page
+ var elements = content.querySelectorAll('polymer-element');
+ for (var i = 0; i < elements.length; i++) {
+ document.body.insertBefore(elements[i], ref);
+ }
+ }
+ }
+
+ // Creates a Dart program that imports [urls] and passes them to initPolymer
+ // (which in turn will invoke their main function, their methods marked with
+ // @initMethod, and register any custom tag labeled with @CustomTag).
+ function createMain(urls, mainUrl) {
+ var imports = Array(urls.length + 1);
+ for (var i = 0; i < urls.length; ++i) {
+ imports[i] = 'import "' + urls[i] + '" as i' + i + ';';
+ }
+ imports[urls.length] = 'import "package:polymer/polymer.dart" as polymer;';
+ var arg = urls.length == 0 ? '[]' :
+ ('[\n "' + urls.join('",\n "') + '"\n ]');
+ return (imports.join('\n') +
+ '\n\nmain() {\n' +
+ ' polymer.initPolymer(' + arg + ');\n' +
+ '}\n');
+ }
+
+ // Finds all top-level <script> tags, and <script> tags in custom elements
+ // and merges them into a single entrypoint.
+ function mergeScripts() {
+ var scripts = document.getElementsByTagName("script");
+ var length = scripts.length;
+
+ var urls = [];
+ var toRemove = [];
+
+ // Collect the information we need to replace the script tags
+ for (var i = 0; i < length; ++i) {
+ var script = scripts[i];
+ if (script.type == "application/dart") {
+ urls.push(getScriptUrl(script));
+ toRemove.push(script);
+ }
+ }
+
+ toRemove.forEach(function (s) { s.parentNode.removeChild(s); });
+
+ // Append a new script tag that initializes everything.
+ var newScript = document.createElement('script');
+ newScript.type = "application/dart";
+ newScript.textContent = createMain(urls);
+ document.body.appendChild(newScript);
+ }
+
+ var alreadyRan = false;
+ window.addEventListener('HTMLImportsLoaded', function (e) {
+ if (alreadyRan) {
+ console.warn('HTMLImportsLoaded fired again.');
+ return;
+ }
+ alreadyRan = true;
+ var ref = document.body.children[0];
+ inlinePolymerElements(document, ref);
+ mergeScripts();
+ if (!navigator.webkitStartDart()) {
+ document.body.innerHTML = 'This build has expired. Please download a ' +
+ 'new Dartium at http://www.dartlang.org/dartium/index.html';
+ }
+ });
+})();
diff --git a/pkg/polymer/lib/component_build.dart b/pkg/polymer/lib/component_build.dart
new file mode 100644
index 0000000..316124e
--- /dev/null
+++ b/pkg/polymer/lib/component_build.dart
@@ -0,0 +1,166 @@
+// 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.
+
+/**
+ * Common logic to make it easy to create a `build.dart` for your project.
+ *
+ * The `build.dart` script is invoked automatically by the Editor whenever a
+ * file in the project changes. It must be placed in the root of a project
+ * (where pubspec.yaml lives) and should be named exactly 'build.dart'.
+ *
+ * A common `build.dart` would look as follows:
+ *
+ * import 'dart:io';
+ * import 'package:polymer/component_build.dart';
+ *
+ * main() => build(new Options().arguments, ['web/index.html']);
+ */
+library build_utils;
+
+import 'dart:async';
+import 'dart:io';
+import 'dart:json' as json;
+import 'package:args/args.dart';
+
+import 'dwc.dart' as dwc;
+import 'src/utils.dart';
+import 'src/compiler_options.dart';
+
+/**
+ * Set up 'build.dart' to compile with the dart web components compiler every
+ * [entryPoints] listed. On clean commands, the directory where [entryPoints]
+ * live will be scanned for generated files to delete them.
+ */
+// TODO(jmesserly): we need a better way to automatically detect input files
+Future<List<dwc.CompilerResult>> build(List<String> arguments,
+ List<String> entryPoints,
+ {bool printTime: true, bool shouldPrint: true}) {
+ bool useColors = stdioType(stdout) == StdioType.TERMINAL;
+ return asyncTime('Total time', () {
+ var args = _processArgs(arguments);
+ var tasks = new FutureGroup();
+ var lastTask = new Future.value(null);
+ tasks.add(lastTask);
+
+ var changedFiles = args["changed"];
+ var removedFiles = args["removed"];
+ var cleanBuild = args["clean"];
+ var machineFormat = args["machine"];
+ // Also trigger a full build if the script was run from the command line
+ // with no arguments
+ var fullBuild = args["full"] || (!machineFormat && changedFiles.isEmpty &&
+ removedFiles.isEmpty && !cleanBuild);
+
+ var options = CompilerOptions.parse(args.rest, checkUsage: false);
+
+ // [outputOnlyDirs] contains directories known to only have output files.
+ // When outputDir is not specified, we create a new directory which only
+ // contains output files. If options.outputDir is specified, we don't know
+ // if the output directory may also have input files. In which case,
+ // [_handleCleanCommand] and [_isInputFile] are more conservative.
+ //
+ // TODO(sigmund): get rid of this. Instead, use the compiler to understand
+ // which files are input or output files.
+ var outputOnlyDirs = options.outputDir == null ? []
+ : entryPoints.map((e) => _outDir(e)).toList();
+
+ if (cleanBuild) {
+ _handleCleanCommand(outputOnlyDirs);
+ } else if (fullBuild
+ || changedFiles.any((f) => _isInputFile(f, outputOnlyDirs))
+ || removedFiles.any((f) => _isInputFile(f, outputOnlyDirs))) {
+ for (var file in entryPoints) {
+ var dwcArgs = new List.from(args.rest);
+ if (machineFormat) dwcArgs.add('--json_format');
+ if (!useColors) dwcArgs.add('--no-colors');
+ // We'll set 'out/' as the out folder, unless an output directory was
+ // already specified in the command line.
+ if (options.outputDir == null) dwcArgs.addAll(['-o', _outDir(file)]);
+ dwcArgs.add(file);
+ // Chain tasks to that we run one at a time.
+ lastTask = lastTask.then((_) => dwc.run(dwcArgs, printTime: printTime,
+ shouldPrint: shouldPrint));
+ if (machineFormat) {
+ lastTask = lastTask.then((res) {
+ appendMessage(Map jsonMessage) {
+ var message = json.stringify([jsonMessage]);
+ if (shouldPrint) print(message);
+ res.messages.add(message);
+ }
+ // Print for the Editor messages about mappings and generated files
+ res.outputs.forEach((out, input) {
+ if (out.endsWith(".html") && input != null) {
+ appendMessage({
+ "method": "mapping",
+ "params": {"from": input, "to": out},
+ });
+ }
+ appendMessage({"method": "generated", "params": {"file": out}});
+ });
+ return res;
+ });
+ }
+ tasks.add(lastTask);
+ }
+ }
+ return tasks.future.then((r) => r.where((v) => v != null));
+ }, printTime: printTime, useColors: useColors);
+}
+
+String _outDir(String file) => path.join(path.dirname(file), 'out');
+
+/** Tell whether [filePath] is a generated file. */
+bool _isGeneratedFile(String filePath, List<String> outputOnlyDirs) {
+ var dirPrefix = path.dirname(filePath);
+ for (var outDir in outputOnlyDirs) {
+ if (dirPrefix.startsWith(outDir)) return true;
+ }
+ return path.basename(filePath).startsWith('_');
+}
+
+/** Tell whether [filePath] is an input file. */
+bool _isInputFile(String filePath, List<String> outputOnlyDirs) {
+ var ext = path.extension(filePath);
+ return (ext == '.dart' || ext == '.html') &&
+ !_isGeneratedFile(filePath, outputOnlyDirs);
+}
+
+/**
+ * Delete all generated files. Currently we only delete files under directories
+ * that are known to contain only generated code.
+ */
+void _handleCleanCommand(List<String> outputOnlyDirs) {
+ for (var dirPath in outputOnlyDirs) {
+ var dir = new Directory(dirPath);
+ if (!dir.existsSync()) continue;
+ for (var f in dir.listSync(recursive: false)) {
+ if (f is File && _isGeneratedFile(f.path, outputOnlyDirs)) f.deleteSync();
+ }
+ }
+}
+
+/** Process the command-line arguments. */
+ArgResults _processArgs(List<String> arguments) {
+ var parser = new ArgParser()
+ ..addOption("changed", help: "the file has changed since the last build",
+ allowMultiple: true)
+ ..addOption("removed", help: "the file was removed since the last build",
+ allowMultiple: true)
+ ..addFlag("clean", negatable: false, help: "remove any build artifacts")
+ ..addFlag("full", negatable: false, help: "perform a full build")
+ ..addFlag("machine", negatable: false,
+ help: "produce warnings in a machine parseable format")
+ ..addFlag("help", abbr: 'h',
+ negatable: false, help: "displays this help and exit");
+ var args = parser.parse(arguments);
+ if (args["help"]) {
+ print('A build script that invokes the web-ui compiler (dwc).');
+ print('Usage: dart build.dart [options] [-- [dwc-options]]');
+ print('\nThese are valid options expected by build.dart:');
+ print(parser.getUsage());
+ print('\nThese are valid options expected by dwc:');
+ dwc.run(['-h']).then((_) => exit(0));
+ }
+ return args;
+}
diff --git a/pkg/polymer/lib/dwc.dart b/pkg/polymer/lib/dwc.dart
new file mode 100755
index 0000000..b70f29b
--- /dev/null
+++ b/pkg/polymer/lib/dwc.dart
@@ -0,0 +1,198 @@
+// 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.
+
+/** The entry point to the compiler. Used to implement `bin/dwc.dart`. */
+library dwc;
+
+import 'dart:async';
+import 'dart:io';
+import 'package:logging/logging.dart' show Level;
+
+import 'src/compiler.dart';
+import 'src/file_system.dart';
+import 'src/file_system/console.dart';
+import 'src/files.dart';
+import 'src/messages.dart';
+import 'src/compiler_options.dart';
+import 'src/utils.dart';
+
+FileSystem _fileSystem;
+
+void main() {
+ run(new Options().arguments).then((result) {
+ exit(result.success ? 0 : 1);
+ });
+}
+
+/** Contains the result of a compiler run. */
+class CompilerResult {
+ final bool success;
+
+ /** Map of output path to source, if there is one */
+ final Map<String, String> outputs;
+
+ /** List of files read during compilation */
+ final List<String> inputs;
+
+ final List<String> messages;
+ String bootstrapFile;
+
+ CompilerResult([this.success = true,
+ this.outputs,
+ this.inputs,
+ this.messages = const [],
+ this.bootstrapFile]);
+
+ factory CompilerResult._(bool success,
+ List<String> messages, List<OutputFile> outputs, List<SourceFile> files) {
+ var file;
+ var outs = new Map<String, String>();
+ for (var out in outputs) {
+ if (path.basename(out.path).endsWith('_bootstrap.dart')) {
+ file = out.path;
+ }
+ outs[out.path] = out.source;
+ }
+ var inputs = files.map((f) => f.path).toList();
+ return new CompilerResult(success, outs, inputs, messages, file);
+ }
+}
+
+/**
+ * Runs the web components compiler with the command-line options in [args].
+ * See [CompilerOptions] for the definition of valid arguments.
+ */
+// TODO(jmesserly): fix this to return a proper exit code
+// TODO(justinfagnani): return messages in the result
+Future<CompilerResult> run(List<String> args, {bool printTime,
+ bool shouldPrint: true}) {
+ var options = CompilerOptions.parse(args);
+ if (options == null) return new Future.value(new CompilerResult());
+ if (printTime == null) printTime = options.verbose;
+
+ _fileSystem = new ConsoleFileSystem();
+ var messages = new Messages(options: options, shouldPrint: shouldPrint);
+
+ return asyncTime('Total time spent on ${options.inputFile}', () {
+ var compiler = new Compiler(_fileSystem, options, messages);
+ var res;
+ return compiler.run()
+ .then((_) {
+ var success = messages.messages.every((m) => m.level != Level.SEVERE);
+ var msgs = options.jsonFormat
+ ? messages.messages.map((m) => m.toJson())
+ : messages.messages.map((m) => m.toString());
+ res = new CompilerResult._(success, msgs.toList(),
+ compiler.output, compiler.files);
+ })
+ .then((_) => _symlinkPubPackages(res, options, messages))
+ .then((_) => _emitFiles(compiler.output, options.clean))
+ .then((_) => res);
+ }, printTime: printTime, useColors: options.useColors);
+}
+
+Future _emitFiles(List<OutputFile> outputs, bool clean) {
+ outputs.forEach((f) => _writeFile(f.path, f.contents, clean));
+ return _fileSystem.flush();
+}
+
+void _writeFile(String filePath, String contents, bool clean) {
+ if (clean) {
+ File fileOut = new File(filePath);
+ if (fileOut.existsSync()) {
+ fileOut.deleteSync();
+ }
+ } else {
+ _createIfNeeded(path.dirname(filePath));
+ _fileSystem.writeString(filePath, contents);
+ }
+}
+
+void _createIfNeeded(String outdir) {
+ if (outdir.isEmpty) return;
+ var outDirectory = new Directory(outdir);
+ if (!outDirectory.existsSync()) {
+ _createIfNeeded(path.dirname(outdir));
+ outDirectory.createSync();
+ }
+}
+
+/**
+ * Creates a symlink to the pub packages directory in the output location. The
+ * returned future completes when the symlink was created (or immediately if it
+ * already exists).
+ */
+Future _symlinkPubPackages(CompilerResult result, CompilerOptions options,
+ Messages messages) {
+ if (options.outputDir == null || result.bootstrapFile == null
+ || options.packageRoot != null) {
+ // We don't need to copy the packages directory if the output was generated
+ // in-place where the input lives, if the compiler was called without an
+ // entry-point file, or if the compiler was called with a package-root
+ // option.
+ return new Future.value(null);
+ }
+
+ var linkDir = path.dirname(result.bootstrapFile);
+ _createIfNeeded(linkDir);
+ var linkPath = path.join(linkDir, 'packages');
+ // A resolved symlink works like a directory
+ // TODO(sigmund): replace this with something smarter once we have good
+ // symlink support in dart:io
+ if (new Directory(linkPath).existsSync()) {
+ // Packages directory already exists.
+ return new Future.value(null);
+ }
+
+ // A broken symlink works like a file
+ var toFile = new File(linkPath);
+ if (toFile.existsSync()) {
+ toFile.deleteSync();
+ }
+
+ var targetPath = path.join(path.dirname(options.inputFile), 'packages');
+ // [fullPathSync] will canonicalize the path, resolving any symlinks.
+ // TODO(sigmund): once it's possible in dart:io, we just want to use a full
+ // path, but not necessarily resolve symlinks.
+ var target = new File(targetPath).fullPathSync().toString();
+ return createSymlink(target, linkPath, messages: messages);
+}
+
+
+// TODO(jmesserly): this code was taken from Pub's io library.
+// Added error handling and don't return the file result, to match the code
+// we had previously. Also "target" and "link" only accept strings. And inlined
+// the relevant parts of runProcess. Note that it uses "cmd" to get the path
+// on Windows.
+/**
+ * Creates a new symlink that creates an alias of [target] at [link], both of
+ * which can be a [String], [File], or [Directory]. Returns a [Future] which
+ * completes to the symlink file (i.e. [link]).
+ */
+Future createSymlink(String target, String link, {Messages messages: null}) {
+ messages = messages == null? new Messages.silent() : messages;
+ var command = 'ln';
+ var args = ['-s', target, link];
+
+ if (Platform.operatingSystem == 'windows') {
+ // Call mklink on Windows to create an NTFS junction point. Only works on
+ // Vista or later. (Junction points are available earlier, but the "mklink"
+ // command is not.) I'm using a junction point (/j) here instead of a soft
+ // link (/d) because the latter requires some privilege shenanigans that
+ // I'm not sure how to specify from the command line.
+ command = 'cmd';
+ args = ['/c', 'mklink', '/j', link, target];
+ }
+
+ return Process.run(command, args).then((result) {
+ if (result.exitCode != 0) {
+ var details = 'subprocess stdout:\n${result.stdout}\n'
+ 'subprocess stderr:\n${result.stderr}';
+ messages.error(
+ 'unable to create symlink\n target: $target\n link:$link\n$details',
+ null);
+ }
+ return null;
+ });
+}
diff --git a/pkg/polymer/lib/observe.dart b/pkg/polymer/lib/observe.dart
new file mode 100644
index 0000000..0a02a90
--- /dev/null
+++ b/pkg/polymer/lib/observe.dart
@@ -0,0 +1,124 @@
+// 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.
+
+/**
+ * Helpers for observable objects.
+ * Intended for use with `package:observe`.
+ */
+library polymer.observe;
+
+import 'dart:async';
+import 'package:observe/observe.dart';
+
+const _VALUE = const Symbol('value');
+
+/**
+ * Forwards an observable property from one object to another. For example:
+ *
+ * class MyModel extends ObservableBase {
+ * StreamSubscription _sub;
+ * MyOtherModel _otherModel;
+ *
+ * MyModel() {
+ * ...
+ * _sub = bindProperty(_otherModel, const Symbol('value'),
+ * () => notifyProperty(this, const Symbol('prop'));
+ * }
+ *
+ * String get prop => _otherModel.value;
+ * set prop(String value) { _otherModel.value = value; }
+ * }
+ *
+ * See also [notifyProperty].
+ */
+StreamSubscription bindProperty(Observable source, Symbol sourceName,
+ void callback()) {
+ return source.changes.listen((records) {
+ for (var record in records) {
+ if (record.changes(sourceName)) {
+ callback();
+ }
+ }
+ });
+}
+
+/**
+ * Notify the property change. Shorthand for:
+ *
+ * target.notifyChange(new PropertyChangeRecord(targetName));
+ */
+void notifyProperty(Observable target, Symbol targetName) {
+ target.notifyChange(new PropertyChangeRecord(targetName));
+}
+
+
+// Inspired by ArrayReduction at:
+// https://raw.github.com/rafaelw/ChangeSummary/master/util/array_reduction.js
+// The main difference is we support anything on the rich Dart Iterable API.
+
+/**
+ * Observes a path starting from each item in the list.
+ */
+class ListPathObserver<E, P> extends ChangeNotifierBase {
+ final ObservableList<E> list;
+ final String _itemPath;
+ final List<PathObserver> _observers = <PathObserver>[];
+ final List<StreamSubscription> _subs = <StreamSubscription>[];
+ StreamSubscription _sub;
+ bool _scheduled = false;
+ Iterable<P> _value;
+
+ ListPathObserver(this.list, String path)
+ : _itemPath = path {
+
+ _sub = list.changes.listen((records) {
+ for (var record in records) {
+ if (record is ListChangeRecord) {
+ _observeItems(record.addedCount - record.removedCount);
+ }
+ }
+ _scheduleReduce(null);
+ });
+
+ _observeItems(list.length);
+ _reduce();
+ }
+
+ Iterable<P> get value => _value;
+
+ void dispose() {
+ if (_sub != null) _sub.cancel();
+ _subs.forEach((s) => s.cancel());
+ _subs.clear();
+ }
+
+ void _reduce() {
+ _scheduled = false;
+ _value = _observers.map((o) => o.value);
+ notifyChange(new PropertyChangeRecord(_VALUE));
+ }
+
+ void _scheduleReduce(_) {
+ if (_scheduled) return;
+ _scheduled = true;
+ runAsync(_reduce);
+ }
+
+ void _observeItems(int lengthAdjust) {
+ if (lengthAdjust > 0) {
+ for (int i = 0; i < lengthAdjust; i++) {
+ int len = _observers.length;
+ var pathObs = new PathObserver(list, '$len.$_itemPath');
+ _subs.add(pathObs.changes.listen(_scheduleReduce));
+ _observers.add(pathObs);
+ }
+ } else if (lengthAdjust < 0) {
+ for (int i = 0; i < -lengthAdjust; i++) {
+ _subs.removeLast().cancel();
+ }
+ int len = _observers.length;
+ _observers.removeRange(len + lengthAdjust, len);
+ }
+ }
+}
diff --git a/pkg/polymer/lib/observe_html.dart b/pkg/polymer/lib/observe_html.dart
new file mode 100644
index 0000000..7280b0e
--- /dev/null
+++ b/pkg/polymer/lib/observe_html.dart
@@ -0,0 +1,63 @@
+// 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.
+
+// TODO(jmesserly): can we handle this more elegantly?
+// In general, it seems like we want a convenient way to take a Stream plus a
+// getter and convert this into an Observable.
+
+/** Helpers for exposing dart:html as observable data. */
+library polymer.observe_html;
+
+import 'dart:html';
+import 'package:observe/observe.dart';
+
+/** An observable version of [window.location.hash]. */
+final ObservableLocationHash windowLocation = new ObservableLocationHash._();
+
+class ObservableLocationHash extends ChangeNotifierBase {
+ ObservableLocationHash._() {
+ // listen on changes to #hash in the URL
+ // Note: listen on both popState and hashChange, because IE9 doesn't support
+ // history API. See http://dartbug.com/5483
+ // TODO(jmesserly): only listen to these if someone is listening to our
+ // changes.
+ window.onHashChange.listen(_notifyHashChange);
+ window.onPopState.listen(_notifyHashChange);
+ }
+
+ String get hash => window.location.hash;
+
+ /**
+ * Pushes a new URL state, similar to the affect of clicking a link.
+ * Has no effect if the [value] already equals [window.location.hash].
+ */
+ void set hash(String value) {
+ if (value == hash) return;
+
+ window.history.pushState(null, '', value);
+ _notifyHashChange(null);
+ }
+
+ void _notifyHashChange(_) {
+ notifyChange(new PropertyChangeRecord(const Symbol('hash')));
+ }
+}
+
+/** Add or remove CSS class [className] based on the [value]. */
+void updateCssClass(Element element, String className, bool value) {
+ if (value == true) {
+ element.classes.add(className);
+ } else {
+ element.classes.remove(className);
+ }
+}
+
+/** Bind a CSS class to the observable [object] and property [path]. */
+PathObserver bindCssClass(Element element, String className,
+ Observable object, String path) {
+
+ return new PathObserver(object, path)..bindSync((value) {
+ updateCssClass(element, className, value);
+ });
+}
diff --git a/pkg/polymer/lib/polymer.dart b/pkg/polymer/lib/polymer.dart
new file mode 100644
index 0000000..575619b
--- /dev/null
+++ b/pkg/polymer/lib/polymer.dart
@@ -0,0 +1,149 @@
+// 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.
+
+/**
+ * This library exports all of the commonly used functions and types for
+ * building UI's.
+ *
+ * See this article for more information:
+ * <http://www.dartlang.org/articles/dart-web-components/>.
+ */
+library polymer;
+
+import 'dart:async';
+import 'dart:mirrors';
+
+import 'package:mdv/mdv.dart' as mdv;
+import 'package:observe/src/microtask.dart';
+import 'package:path/path.dart' as path;
+import 'polymer_element.dart' show registerPolymerElement;
+
+export 'package:custom_element/custom_element.dart';
+export 'package:observe/observe.dart';
+export 'package:observe/src/microtask.dart';
+
+export 'observe.dart';
+export 'observe_html.dart';
+export 'polymer_element.dart';
+export 'safe_html.dart';
+
+
+/** Annotation used to automatically register polymer elements. */
+class CustomTag {
+ final String tagName;
+ const CustomTag(this.tagName);
+}
+
+/**
+ * Metadata used to label static or top-level methods that are called
+ * automatically when loading the library of a custom element.
+ */
+const initMethod = const _InitMethodAnnotation();
+
+/**
+ * Initializes a polymer application as follows:
+ * * set up up polling for observable changes
+ * * initialize MDV
+ * * for each library in [libraries], register custom elements labeled with
+ * [CustomTag] and invoke the initialization method on it.
+ *
+ * The initialization on each library is either a method named `main` or
+ * a top-level function and annotated with [initMethod].
+ *
+ * The urls in [libraries] can be absolute or relative to [srcUrl].
+ */
+void initPolymer(List<String> libraries, [String srcUrl]) {
+ wrapMicrotask(() {
+ // DOM events don't yet go through microtasks, so we catch those here.
+ new Timer.periodic(new Duration(milliseconds: 125),
+ (_) => performMicrotaskCheckpoint());
+
+ // TODO(jmesserly): mdv should use initMdv instead of mdv.initialize.
+ mdv.initialize();
+ for (var lib in libraries) {
+ _loadLibrary(lib, srcUrl);
+ }
+ })();
+}
+
+/** All libraries in the current isolate. */
+final _libs = currentMirrorSystem().libraries;
+
+/**
+ * Reads the library at [uriString] (which can be an absolute URI or a relative
+ * URI from [srcUrl]), and:
+ *
+ * * If present, invokes `main`.
+ *
+ * * If present, invokes any top-level and static functions marked
+ * with the [initMethod] annotation (in the order they appear).
+ *
+ * * Registers any [PolymerElement] that is marked with the [CustomTag]
+ * annotation.
+ */
+void _loadLibrary(String uriString, [String srcUrl]) {
+ var uri = Uri.parse(uriString);
+ if (uri.scheme == '' && srcUrl != null) {
+ uri = Uri.parse(path.normalize(path.join(path.dirname(srcUrl), uriString)));
+ }
+ var lib = _libs[uri];
+ if (lib == null) {
+ print('warning: $uri library not found');
+ return;
+ }
+
+ // Invoke `main`, if present.
+ if (lib.functions[const Symbol('main')] != null) {
+ lib.invoke(const Symbol('main'), const []);
+ }
+
+ // Search top-level functions marked with @initMethod
+ for (var f in lib.functions.values) {
+ _maybeInvoke(lib, f);
+ }
+
+ for (var c in lib.classes.values) {
+ // Search for @CustomTag on classes
+ for (var m in c.metadata) {
+ var meta = m.reflectee;
+ if (meta is CustomTag) {
+ registerPolymerElement(meta.tagName,
+ () => c.newInstance(const Symbol(''), const []).reflectee);
+ }
+ }
+
+ // TODO(sigmund): check also static methods marked with @initMethod.
+ // This is blocked on two bugs:
+ // - dartbug.com/12133 (static methods are incorrectly listed as top-level
+ // in dart2js, so they end up being called twice)
+ // - dartbug.com/12134 (sometimes "method.metadata" throws an exception,
+ // we could wrap and hide those exceptions, but it's not ideal).
+ }
+}
+
+void _maybeInvoke(ObjectMirror obj, MethodMirror method) {
+ var annotationFound = false;
+ for (var meta in method.metadata) {
+ if (identical(meta.reflectee, initMethod)) {
+ annotationFound = true;
+ break;
+ }
+ }
+ if (!annotationFound) return;
+ if (!method.isStatic) {
+ print("warning: methods marked with @initMethod should be static,"
+ " ${method.simpleName} is not.");
+ return;
+ }
+ if (!method.parameters.where((p) => !p.isOptional).isEmpty) {
+ print("warning: methods marked with @initMethod should take no "
+ "arguments, ${method.simpleName} expects some.");
+ return;
+ }
+ obj.invoke(method.simpleName, const []);
+}
+
+class _InitMethodAnnotation {
+ const _InitMethodAnnotation();
+}
diff --git a/pkg/polymer/lib/polymer_element.dart b/pkg/polymer/lib/polymer_element.dart
new file mode 100644
index 0000000..297625e
--- /dev/null
+++ b/pkg/polymer/lib/polymer_element.dart
@@ -0,0 +1,566 @@
+// 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 polymer.polymer_element;
+
+import 'dart:async';
+import 'dart:html';
+import 'dart:mirrors';
+import 'dart:js' as dartJs;
+
+import 'package:custom_element/custom_element.dart';
+import 'package:js/js.dart' as js;
+import 'package:mdv/mdv.dart' show NodeBinding;
+import 'package:observe/observe.dart';
+import 'package:observe/src/microtask.dart';
+import 'package:polymer_expressions/polymer_expressions.dart';
+
+import 'src/utils_observe.dart' show toCamelCase, toHyphenedName;
+
+/**
+ * Registers a [PolymerElement]. This is similar to [registerCustomElement]
+ * but it is designed to work with the `<element>` element and adds additional
+ * features.
+ */
+void registerPolymerElement(String localName, PolymerElement create()) {
+ registerCustomElement(localName, () => create().._initialize(localName));
+}
+
+/**
+ * *Warning*: many features of this class are not fully implemented.
+ *
+ * The base class for Polymer elements. It provides convience features on top
+ * of the custom elements web standard.
+ *
+ * Currently it supports publishing attributes via:
+ *
+ * <element name="..." attributes="foo, bar, baz">
+ *
+ * Any attribute published this way can be used in a data binding expression,
+ * and it should contain a corresponding DOM field.
+ *
+ * *Warning*: due to dart2js mirror limititations, the mapping from HTML
+ * attribute to element property is a conversion from `dash-separated-words`
+ * to camelCase, rather than searching for a property with the same name.
+ */
+// TODO(jmesserly): fix the dash-separated-words issue. Polymer uses lowercase.
+class PolymerElement extends CustomElement with _EventsMixin {
+ // This is a partial port of:
+ // https://github.com/Polymer/polymer/blob/stable/src/attrs.js
+ // https://github.com/Polymer/polymer/blob/stable/src/bindProperties.js
+ // https://github.com/Polymer/polymer/blob/7936ff8/src/declaration/events.js
+ // https://github.com/Polymer/polymer/blob/7936ff8/src/instance/events.js
+ // TODO(jmesserly): we still need to port more of the functionality
+
+ /// The one syntax to rule them all.
+ static BindingDelegate _polymerSyntax = new PolymerExpressions();
+ // TODO(sigmund): delete. The next line is only added to avoid warnings from
+ // the analyzer (see http://dartbug.com/11672)
+ Element get host => super.host;
+
+ bool get applyAuthorStyles => false;
+ bool get resetStyleInheritance => false;
+
+ /**
+ * The declaration of this polymer-element, used to extract template contents
+ * and other information.
+ */
+ static Map<String, Element> _declarations = {};
+ static Element getDeclaration(String localName) {
+ if (localName == null) return null;
+ var element = _declarations[localName];
+ if (element == null) {
+ element = document.query('polymer-element[name="$localName"]');
+ _declarations[localName] = element;
+ }
+ return element;
+ }
+
+ Map<String, PathObserver> _publishedAttrs;
+ Map<String, StreamSubscription> _bindings;
+ final List<String> _localNames = [];
+
+ void _initialize(String localName) {
+ if (localName == null) return;
+
+ var declaration = getDeclaration(localName);
+ if (declaration == null) return;
+
+ if (declaration.attributes['extends'] != null) {
+ var base = declaration.attributes['extends'];
+ // Skip normal tags, only initialize parent custom elements.
+ if (base.contains('-')) _initialize(base);
+ }
+
+ _parseHostEvents(declaration);
+ _parseLocalEvents(declaration);
+ _publishAttributes(declaration);
+ _localNames.add(localName);
+ }
+
+ void _publishAttributes(elementElement) {
+ _bindings = {};
+ _publishedAttrs = {};
+
+ var attrs = elementElement.attributes['attributes'];
+ if (attrs != null) {
+ // attributes='a b c' or attributes='a,b,c'
+ for (var name in attrs.split(attrs.contains(',') ? ',' : ' ')) {
+ name = name.trim();
+
+ // TODO(jmesserly): PathObserver is overkill here; it helps avoid
+ // "new Symbol" and other mirrors-related warnings.
+ _publishedAttrs[name] = new PathObserver(this, toCamelCase(name));
+ }
+ }
+ }
+
+ void created() {
+ // TODO(jmesserly): this breaks until we get some kind of type conversion.
+ // _publishedAttrs.forEach((name, propObserver) {
+ // var value = attributes[name];
+ // if (value != null) propObserver.value = value;
+ // });
+ _initShadowRoot();
+ _addHostListeners();
+ }
+
+ /**
+ * Creates the document fragment to use for each instance of the custom
+ * element, given the `<template>` node. By default this is equivalent to:
+ *
+ * template.createInstance(this, polymerSyntax);
+ *
+ * Where polymerSyntax is a singleton `PolymerExpressions` instance from the
+ * [polymer_expressions](https://pub.dartlang.org/packages/polymer_expressions)
+ * package.
+ *
+ * You can override this method to change the instantiation behavior of the
+ * template, for example to use a different data-binding syntax.
+ */
+ DocumentFragment instanceTemplate(Element template) =>
+ template.createInstance(this, _polymerSyntax);
+
+ void _initShadowRoot() {
+ for (var localName in _localNames) {
+ var declaration = getDeclaration(localName);
+ var root = createShadowRoot(localName);
+ _addInstanceListeners(root, localName);
+
+ root.applyAuthorStyles = applyAuthorStyles;
+ root.resetStyleInheritance = resetStyleInheritance;
+
+ var templateNode = declaration.children.firstWhere(
+ (n) => n.localName == 'template', orElse: () => null);
+ if (templateNode == null) return;
+
+ // Create the contents of the element's ShadowRoot, and add them.
+ root.nodes.add(instanceTemplate(templateNode));
+
+ var extendsName = declaration.attributes['extends'];
+ _shimCss(root, localName, extendsName);
+ }
+ }
+
+ NodeBinding createBinding(String name, model, String path) {
+ var propObserver = _publishedAttrs[name];
+ if (propObserver != null) {
+ return new _PolymerBinding(this, name, model, path, propObserver);
+ }
+ return super.createBinding(name, model, path);
+ }
+
+ /**
+ * Using Polymer's platform/src/ShadowCSS.js passing the style tag's content.
+ */
+ void _shimCss(ShadowRoot root, String localName, String extendsName) {
+ // TODO(terry): Need to detect if ShadowCSS.js has been loaded. Under
+ // Dartium this wouldn't exist. However, dart:js isn't robust
+ // to use to detect in both Dartium and dart2js if Platform is
+ // defined. Instead in Dartium it throws an exception but in
+ // dart2js it works enough to know if Platform is defined (just
+ // can't be used for further derefs). This bug is described
+ // https://code.google.com/p/dart/issues/detail?id=12548
+ // When fixed only use dart:js. This is necessary under
+ // Dartium (no compile) we want to run w/o the JS polyfill.
+ try {
+ if (dartJs.context["Platform"] == null) { return; }
+ } on NoSuchMethodError catch (e) { return; }
+
+ var platform = js.context["Platform"];
+ if (platform == null) return;
+ var shadowCss = platform.ShadowCSS;
+ if (shadowCss == null) return;
+
+ // TODO(terry): Remove calls to shimShadowDOMStyling2 and replace with
+ // shimShadowDOMStyling when we support unwrapping dart:html
+ // Element to a JS DOM node.
+ var shimShadowDOMStyling2 = shadowCss.shimShadowDOMStyling2;
+ if (shimShadowDOMStyling2 == null) return;
+ var style = root.query('style');
+ if (style == null) return;
+ var scopedCSS = shimShadowDOMStyling2(style.text, localName);
+
+ // TODO(terry): Remove when shimShadowDOMStyling is called we don't need to
+ // replace original CSS with scoped CSS shimShadowDOMStyling
+ // does that.
+ style.text = scopedCSS;
+ }
+}
+
+class _PolymerBinding extends NodeBinding {
+ final PathObserver _publishedAttr;
+
+ _PolymerBinding(node, property, model, path, PathObserver this._publishedAttr)
+ : super(node, property, model, path);
+
+ void boundValueChanged(newValue) {
+ _publishedAttr.value = newValue;
+ }
+}
+
+/**
+ * Polymer features to handle the syntactic sugar on-* to declare to
+ * automatically map event handlers to instance methods of the [PolymerElement].
+ * This mixin is a port of:
+ * https://github.com/Polymer/polymer/blob/7936ff8/src/declaration/events.js
+ * https://github.com/Polymer/polymer/blob/7936ff8/src/instance/events.js
+ */
+abstract class _EventsMixin {
+ // TODO(sigmund): implement the Dart equivalent of 'inheritDelegates'
+ // Notes about differences in the implementation below:
+ // - _templateDelegates: polymer stores the template delegates directly on
+ // the template node (see in parseLocalEvents: 't.delegates = {}'). Here we
+ // simply use a separate map, where keys are the name of the
+ // custom-element.
+ // - _listenLocal we return true/false and propagate that up, JS
+ // implementation does't forward the return value.
+ // - we don't keep the side-table (weak hash map) of unhandled events (see
+ // handleIfNotHandled)
+ // - we don't use event.type to dispatch events, instead we save the event
+ // name with the event listeners. We do so to avoid translating back and
+ // forth between Dom and Dart event names.
+
+ // ---------------------------------------------------------------------------
+ // The following section was ported from:
+ // https://github.com/Polymer/polymer/blob/7936ff8/src/declaration/events.js
+ // ---------------------------------------------------------------------------
+
+ /** Maps event names and their associated method in the element class. */
+ final Map<String, String> _delegates = {};
+
+ /** Expected events per element node. */
+ // TODO(sigmund): investigate whether we need more than 1 set of local events
+ // per element (why does the js implementation stores 1 per template node?)
+ final Map<String, Set<String>> _templateDelegates =
+ new Map<String, Set<String>>();
+
+ /** [host] is needed by this mixin, but not defined here. */
+ Element get host;
+
+ /** Attribute prefix used for declarative event handlers. */
+ static const _eventPrefix = 'on-';
+
+ /** Whether an attribute declares an event. */
+ static bool _isEvent(String attr) => attr.startsWith(_eventPrefix);
+
+ /** Extracts events from the element tag attributes. */
+ void _parseHostEvents(elementElement) {
+ for (var attr in elementElement.attributes.keys.where(_isEvent)) {
+ _delegates[toCamelCase(attr)] = elementElement.attributes[attr];
+ }
+ }
+
+ /** Extracts events under the element's <template>. */
+ void _parseLocalEvents(elementElement) {
+ var name = elementElement.attributes["name"];
+ if (name == null) return;
+ var events = null;
+ for (var template in elementElement.queryAll('template')) {
+ var content = template.content;
+ if (content != null) {
+ for (var child in content.children) {
+ events = _accumulateEvents(child, events);
+ }
+ }
+ }
+ if (events != null) {
+ _templateDelegates[name] = events;
+ }
+ }
+
+ /** Returns all events names listened by [element] and it's children. */
+ static Set<String> _accumulateEvents(Element element, [Set<String> events]) {
+ events = events == null ? new Set<String>() : events;
+
+ // from: accumulateAttributeEvents, accumulateEvent
+ events.addAll(element.attributes.keys.where(_isEvent).map(toCamelCase));
+
+ // from: accumulateChildEvents
+ for (var child in element.children) {
+ _accumulateEvents(child, events);
+ }
+
+ // from: accumulateTemplatedEvents
+ if (element.isTemplate) {
+ var content = element.content;
+ if (content != null) {
+ for (var child in content.children) {
+ _accumulateEvents(child, events);
+ }
+ }
+ }
+ return events;
+ }
+
+ // ---------------------------------------------------------------------------
+ // The following section was ported from:
+ // https://github.com/Polymer/polymer/blob/7936ff8/src/instance/events.js
+ // ---------------------------------------------------------------------------
+
+ /** Attaches event listeners on the [host] element. */
+ void _addHostListeners() {
+ for (var eventName in _delegates.keys) {
+ _addNodeListener(host, eventName,
+ (e) => _hostEventListener(eventName, e));
+ }
+ }
+
+ void _addNodeListener(node, String onEvent, Function listener) {
+ // If [node] is an element (typically when listening for host events) we
+ // use directly the '.onFoo' event stream of the element instance.
+ if (node is Element) {
+ reflect(node).getField(new Symbol(onEvent)).reflectee.listen(listener);
+ return;
+ }
+
+ // When [node] is not an element, most commonly when [node] is the
+ // shadow-root of the polymer-element, we find the appropriate static event
+ // stream providers and attach it to [node].
+ var eventProvider = _eventStreamProviders[onEvent];
+ if (eventProvider != null) {
+ eventProvider.forTarget(node).listen(listener);
+ return;
+ }
+
+ // When no provider is available, mainly because of custom-events, we use
+ // the underlying event listeners from the DOM.
+ var eventName = onEvent.substring(2).toLowerCase(); // onOneTwo => onetwo
+ // Most events names in Dart match those in JS in lowercase except for some
+ // few events listed in this map. We expect these cases to be handled above,
+ // but just in case we include them as a safety net here.
+ var jsNameFixes = const {
+ 'animationend': 'webkitAnimationEnd',
+ 'animationiteration': 'webkitAnimationIteration',
+ 'animationstart': 'webkitAnimationStart',
+ 'doubleclick': 'dblclick',
+ 'fullscreenchange': 'webkitfullscreenchange',
+ 'fullscreenerror': 'webkitfullscreenerror',
+ 'keyadded': 'webkitkeyadded',
+ 'keyerror': 'webkitkeyerror',
+ 'keymessage': 'webkitkeymessage',
+ 'needkey': 'webkitneedkey',
+ 'speechchange': 'webkitSpeechChange',
+ };
+ var fixedName = jsNameFixes[eventName];
+ node.on[fixedName != null ? fixedName : eventName].listen(listener);
+ }
+
+ void _addInstanceListeners(ShadowRoot root, String elementName) {
+ var events = _templateDelegates[elementName];
+ if (events == null) return;
+ for (var eventName in events) {
+ _addNodeListener(root, eventName,
+ (e) => _instanceEventListener(eventName, e));
+ }
+ }
+
+ void _hostEventListener(String eventName, Event event) {
+ var method = _delegates[eventName];
+ if (event.bubbles && method != null) {
+ _dispatchMethod(this, method, event, host);
+ }
+ }
+
+ void _dispatchMethod(Object receiver, String methodName, Event event,
+ Node target) {
+ var detail = event is CustomEvent ? (event as CustomEvent).detail : null;
+ var args = [event, detail, target];
+
+ var method = new Symbol(methodName);
+ // TODO(sigmund): consider making event listeners list all arguments
+ // explicitly. Unless VM mirrors are optimized first, this reflectClass call
+ // will be expensive once custom elements extend directly from Element (see
+ // dartbug.com/11108).
+ var methodDecl = reflectClass(receiver.runtimeType).methods[method];
+ if (methodDecl != null) {
+ // This will either truncate the argument list or extend it with extra
+ // null arguments, so it will match the signature.
+ // TODO(sigmund): consider accepting optional arguments when we can tell
+ // them appart from named arguments (see http://dartbug.com/11334)
+ args.length = methodDecl.parameters.where((p) => !p.isOptional).length;
+ }
+ reflect(receiver).invoke(method, args);
+ performMicrotaskCheckpoint();
+ }
+
+ bool _instanceEventListener(String eventName, Event event) {
+ if (event.bubbles) {
+ if (event.path == null || !ShadowRoot.supported) {
+ return _listenLocalNoEventPath(eventName, event);
+ } else {
+ return _listenLocal(eventName, event);
+ }
+ }
+ return false;
+ }
+
+ bool _listenLocal(String eventName, Event event) {
+ var controller = null;
+ for (var target in event.path) {
+ // if we hit host, stop
+ if (target == host) return true;
+
+ // find a controller for the target, unless we already found `host`
+ // as a controller
+ controller = (controller == host) ? controller : _findController(target);
+
+ // if we have a controller, dispatch the event, and stop if the handler
+ // returns true
+ if (controller != null
+ && handleEvent(controller, eventName, event, target)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // TODO(sorvell): remove when ShadowDOM polyfill supports event path.
+ // Note that _findController will not return the expected controller when the
+ // event target is a distributed node. This is because we cannot traverse
+ // from a composed node to a node in shadowRoot.
+ // This will be addressed via an event path api
+ // https://www.w3.org/Bugs/Public/show_bug.cgi?id=21066
+ bool _listenLocalNoEventPath(String eventName, Event event) {
+ var target = event.target;
+ var controller = null;
+ while (target != null && target != host) {
+ controller = (controller == host) ? controller : _findController(target);
+ if (controller != null
+ && handleEvent(controller, eventName, event, target)) {
+ return true;
+ }
+ target = target.parent;
+ }
+ return false;
+ }
+
+ // TODO(sigmund): investigate if this implementation is correct. Polymer looks
+ // up the shadow-root that contains [node] and uses a weak-hashmap to find the
+ // host associated with that root. This implementation assumes that the
+ // [node] is under [host]'s shadow-root.
+ Element _findController(Node node) => host.xtag;
+
+ bool handleEvent(
+ Element controller, String eventName, Event event, Element element) {
+ // Note: local events are listened only in the shadow root. This dynamic
+ // lookup is used to distinguish determine whether the target actually has a
+ // listener, and if so, to determine lazily what's the target method.
+ var methodName = element.attributes[toHyphenedName(eventName)];
+ if (methodName != null) {
+ _dispatchMethod(controller, methodName, event, element);
+ }
+ return event.bubbles;
+ }
+}
+
+
+/** Event stream providers per event name. */
+// TODO(sigmund): after dartbug.com/11108 is fixed, consider eliminating this
+// table and using reflection instead.
+const Map<String, EventStreamProvider> _eventStreamProviders = const {
+ 'onMouseWheel': Element.mouseWheelEvent,
+ 'onTransitionEnd': Element.transitionEndEvent,
+ 'onAbort': Element.abortEvent,
+ 'onBeforeCopy': Element.beforeCopyEvent,
+ 'onBeforeCut': Element.beforeCutEvent,
+ 'onBeforePaste': Element.beforePasteEvent,
+ 'onBlur': Element.blurEvent,
+ 'onChange': Element.changeEvent,
+ 'onClick': Element.clickEvent,
+ 'onContextMenu': Element.contextMenuEvent,
+ 'onCopy': Element.copyEvent,
+ 'onCut': Element.cutEvent,
+ 'onDoubleClick': Element.doubleClickEvent,
+ 'onDrag': Element.dragEvent,
+ 'onDragEnd': Element.dragEndEvent,
+ 'onDragEnter': Element.dragEnterEvent,
+ 'onDragLeave': Element.dragLeaveEvent,
+ 'onDragOver': Element.dragOverEvent,
+ 'onDragStart': Element.dragStartEvent,
+ 'onDrop': Element.dropEvent,
+ 'onError': Element.errorEvent,
+ 'onFocus': Element.focusEvent,
+ 'onInput': Element.inputEvent,
+ 'onInvalid': Element.invalidEvent,
+ 'onKeyDown': Element.keyDownEvent,
+ 'onKeyPress': Element.keyPressEvent,
+ 'onKeyUp': Element.keyUpEvent,
+ 'onLoad': Element.loadEvent,
+ 'onMouseDown': Element.mouseDownEvent,
+ 'onMouseMove': Element.mouseMoveEvent,
+ 'onMouseOut': Element.mouseOutEvent,
+ 'onMouseOver': Element.mouseOverEvent,
+ 'onMouseUp': Element.mouseUpEvent,
+ 'onPaste': Element.pasteEvent,
+ 'onReset': Element.resetEvent,
+ 'onScroll': Element.scrollEvent,
+ 'onSearch': Element.searchEvent,
+ 'onSelect': Element.selectEvent,
+ 'onSelectStart': Element.selectStartEvent,
+ 'onSubmit': Element.submitEvent,
+ 'onTouchCancel': Element.touchCancelEvent,
+ 'onTouchEnd': Element.touchEndEvent,
+ 'onTouchEnter': Element.touchEnterEvent,
+ 'onTouchLeave': Element.touchLeaveEvent,
+ 'onTouchMove': Element.touchMoveEvent,
+ 'onTouchStart': Element.touchStartEvent,
+ 'onFullscreenChange': Element.fullscreenChangeEvent,
+ 'onFullscreenError': Element.fullscreenErrorEvent,
+ 'onAutocomplete': FormElement.autocompleteEvent,
+ 'onAutocompleteError': FormElement.autocompleteErrorEvent,
+ 'onSpeechChange': InputElement.speechChangeEvent,
+ 'onCanPlay': MediaElement.canPlayEvent,
+ 'onCanPlayThrough': MediaElement.canPlayThroughEvent,
+ 'onDurationChange': MediaElement.durationChangeEvent,
+ 'onEmptied': MediaElement.emptiedEvent,
+ 'onEnded': MediaElement.endedEvent,
+ 'onLoadStart': MediaElement.loadStartEvent,
+ 'onLoadedData': MediaElement.loadedDataEvent,
+ 'onLoadedMetadata': MediaElement.loadedMetadataEvent,
+ 'onPause': MediaElement.pauseEvent,
+ 'onPlay': MediaElement.playEvent,
+ 'onPlaying': MediaElement.playingEvent,
+ 'onProgress': MediaElement.progressEvent,
+ 'onRateChange': MediaElement.rateChangeEvent,
+ 'onSeeked': MediaElement.seekedEvent,
+ 'onSeeking': MediaElement.seekingEvent,
+ 'onShow': MediaElement.showEvent,
+ 'onStalled': MediaElement.stalledEvent,
+ 'onSuspend': MediaElement.suspendEvent,
+ 'onTimeUpdate': MediaElement.timeUpdateEvent,
+ 'onVolumeChange': MediaElement.volumeChangeEvent,
+ 'onWaiting': MediaElement.waitingEvent,
+ 'onKeyAdded': MediaElement.keyAddedEvent,
+ 'onKeyError': MediaElement.keyErrorEvent,
+ 'onKeyMessage': MediaElement.keyMessageEvent,
+ 'onNeedKey': MediaElement.needKeyEvent,
+ 'onWebGlContextLost': CanvasElement.webGlContextLostEvent,
+ 'onWebGlContextRestored': CanvasElement.webGlContextRestoredEvent,
+ 'onPointerLockChange': Document.pointerLockChangeEvent,
+ 'onPointerLockError': Document.pointerLockErrorEvent,
+ 'onReadyStateChange': Document.readyStateChangeEvent,
+ 'onSelectionChange': Document.selectionChangeEvent,
+ 'onSecurityPolicyViolation': Document.securityPolicyViolationEvent,
+};
diff --git a/pkg/polymer/lib/safe_html.dart b/pkg/polymer/lib/safe_html.dart
new file mode 100644
index 0000000..c15dd5c
--- /dev/null
+++ b/pkg/polymer/lib/safe_html.dart
@@ -0,0 +1,39 @@
+// Copyright (c) 2011, 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.
+
+// TODO(sigmund): move this library to a shared package? or make part of
+// dart:html?
+library polymer.safe_html;
+
+/** Declares a string that is a well-formed HTML fragment. */
+class SafeHtml {
+
+ /** Underlying html string. */
+ final String _html;
+
+ // TODO(sigmund): provide a constructor that does html validation
+ SafeHtml.unsafe(this._html);
+
+ String toString() => _html;
+
+ operator ==(other) => other is SafeHtml && _html == other._html;
+ int get hashCode => _html.hashCode;
+}
+
+/**
+ * Declares a string that is safe to use in a Uri attribute, such as `<a href=`,
+ * to avoid cross-site scripting (XSS) attacks.
+ */
+class SafeUri {
+ final String _uri;
+
+ // TODO(sigmund): provide a constructor that takes or creates a Uri and
+ // validates that it is safe (not a javascript: scheme, for example)
+ SafeUri.unsafe(this._uri);
+
+ String toString() => _uri;
+
+ operator ==(other) => other is SafeUri && _uri == other._uri;
+ int get hashCode => _uri.hashCode;
+}
diff --git a/pkg/polymer/lib/src/analyzer.dart b/pkg/polymer/lib/src/analyzer.dart
new file mode 100644
index 0000000..193e139
--- /dev/null
+++ b/pkg/polymer/lib/src/analyzer.dart
@@ -0,0 +1,566 @@
+// 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 the template compilation that concerns with extracting information
+ * from the HTML parse tree.
+ */
+library analyzer;
+
+import 'package:html5lib/dom.dart';
+import 'package:html5lib/dom_parsing.dart';
+import 'package:source_maps/span.dart' hide SourceFile;
+
+import 'custom_tag_name.dart';
+import 'dart_parser.dart' show parseDartCode;
+import 'files.dart';
+import 'info.dart';
+import 'messages.dart';
+import 'summary.dart';
+
+/**
+ * Finds custom elements in this file and the list of referenced files with
+ * component declarations. This is the first pass of analysis on a file.
+ *
+ * Adds emitted error/warning messages to [messages], if [messages] is
+ * supplied.
+ */
+FileInfo analyzeDefinitions(GlobalInfo global, UrlInfo inputUrl,
+ Document document, String packageRoot,
+ Messages messages, {bool isEntryPoint: false}) {
+ var result = new FileInfo(inputUrl, isEntryPoint);
+ var loader = new _ElementLoader(global, result, packageRoot, messages);
+ loader.visit(document);
+ return result;
+}
+
+/**
+ * Extract relevant information from all files found from the root document.
+ *
+ * Adds emitted error/warning messages to [messages], if [messages] is
+ * supplied.
+ */
+void analyzeFile(SourceFile file, Map<String, FileInfo> info,
+ Iterator<int> uniqueIds, GlobalInfo global,
+ Messages messages, emulateScopedCss) {
+ var fileInfo = info[file.path];
+ var analyzer = new _Analyzer(fileInfo, uniqueIds, global, messages,
+ emulateScopedCss);
+ analyzer._normalize(fileInfo, info);
+ analyzer.visit(file.document);
+}
+
+
+/** A visitor that walks the HTML to extract all the relevant information. */
+class _Analyzer extends TreeVisitor {
+ final FileInfo _fileInfo;
+ LibraryInfo _currentInfo;
+ Iterator<int> _uniqueIds;
+ GlobalInfo _global;
+ Messages _messages;
+
+ int _generatedClassNumber = 0;
+
+ /**
+ * Whether to keep indentation spaces. Break lines and indentation spaces
+ * within templates are preserved in HTML. When users specify the attribute
+ * 'indentation="remove"' on a template tag, we'll trim those indentation
+ * spaces that occur within that tag and its decendants. If any decendant
+ * specifies 'indentation="preserve"', then we'll switch back to the normal
+ * behavior.
+ */
+ bool _keepIndentationSpaces = true;
+
+ final bool _emulateScopedCss;
+
+ _Analyzer(this._fileInfo, this._uniqueIds, this._global, this._messages,
+ this._emulateScopedCss) {
+ _currentInfo = _fileInfo;
+ }
+
+ void visitElement(Element node) {
+ if (node.tagName == 'script') {
+ // We already extracted script tags in previous phase.
+ return;
+ }
+
+ if (node.tagName == 'style') {
+ // We've already parsed the CSS.
+ // If this is a component remove the style node.
+ if (_currentInfo is ComponentInfo && _emulateScopedCss) node.remove();
+ return;
+ }
+
+ _bindCustomElement(node);
+
+ var lastInfo = _currentInfo;
+ if (node.tagName == 'polymer-element') {
+ // If element is invalid _ElementLoader already reported an error, but
+ // we skip the body of the element here.
+ var name = node.attributes['name'];
+ if (name == null) return;
+
+ ComponentInfo component = _fileInfo.components[name];
+ if (component == null) return;
+
+ _analyzeComponent(component);
+
+ _currentInfo = component;
+
+ // Remove the <element> tag from the tree
+ node.remove();
+ }
+
+ node.attributes.forEach((name, value) {
+ if (name.startsWith('on')) {
+ _validateEventHandler(node, name, value);
+ } else if (name == 'pseudo' && _currentInfo is ComponentInfo) {
+ // Any component's custom pseudo-element(s) defined?
+ _processPseudoAttribute(node, value.split(' '));
+ }
+ });
+
+ var keepSpaces = _keepIndentationSpaces;
+ if (node.tagName == 'template' &&
+ node.attributes.containsKey('indentation')) {
+ var value = node.attributes['indentation'];
+ if (value != 'remove' && value != 'preserve') {
+ _messages.warning(
+ "Invalid value for 'indentation' ($value). By default we preserve "
+ "the indentation. Valid values are either 'remove' or 'preserve'.",
+ node.sourceSpan);
+ }
+ _keepIndentationSpaces = value != 'remove';
+ }
+
+ // Invoke super to visit children.
+ super.visitElement(node);
+
+ _keepIndentationSpaces = keepSpaces;
+ _currentInfo = lastInfo;
+
+ if (node.tagName == 'body' || node.parent == null) {
+ _fileInfo.body = node;
+ }
+ }
+
+ void _analyzeComponent(ComponentInfo component) {
+ var baseTag = component.extendsTag;
+ component.extendsComponent = baseTag == null ? null
+ : _fileInfo.components[baseTag];
+ if (component.extendsComponent == null && isCustomTag(baseTag)) {
+ _messages.warning(
+ 'custom element with tag name ${component.extendsTag} not found.',
+ component.element.sourceSpan);
+ }
+
+ // Now that the component's code has been loaded, we can validate that the
+ // class exists.
+ component.findClassDeclaration(_messages);
+ }
+
+ void _bindCustomElement(Element node) {
+ // <fancy-button>
+ var component = _fileInfo.components[node.tagName];
+ if (component == null) {
+ // TODO(jmesserly): warn for unknown element tags?
+
+ // <button is="fancy-button">
+ var componentName = node.attributes['is'];
+ if (componentName != null) {
+ component = _fileInfo.components[componentName];
+ } else if (isCustomTag(node.tagName)) {
+ componentName = node.tagName;
+ }
+ if (component == null && componentName != null &&
+ componentName != 'polymer-element') {
+ _messages.warning(
+ 'custom element with tag name $componentName not found.',
+ node.sourceSpan);
+ }
+ }
+
+ if (component != null) {
+ if (!component.hasConflict) {
+ _currentInfo.usedComponents[component] = true;
+ }
+
+ var baseTag = component.baseExtendsTag;
+ var nodeTag = node.tagName;
+ var hasIsAttribute = node.attributes.containsKey('is');
+
+ if (baseTag != null && !hasIsAttribute) {
+ _messages.warning(
+ 'custom element "${component.tagName}" extends from "$baseTag", but'
+ ' this tag will not include the default properties of "$baseTag". '
+ 'To fix this, either write this tag as <$baseTag '
+ 'is="${component.tagName}"> or remove the "extends" attribute from '
+ 'the custom element declaration.', node.sourceSpan);
+ } else if (hasIsAttribute) {
+ if (baseTag == null) {
+ _messages.warning(
+ 'custom element "${component.tagName}" doesn\'t declare any type '
+ 'extensions. To fix this, either rewrite this tag as '
+ '<${component.tagName}> or add \'extends="$nodeTag"\' to '
+ 'the custom element declaration.', node.sourceSpan);
+ } else if (baseTag != nodeTag) {
+ _messages.warning(
+ 'custom element "${component.tagName}" extends from "$baseTag". '
+ 'Did you mean to write <$baseTag is="${component.tagName}">?',
+ node.sourceSpan);
+ }
+ }
+ }
+ }
+
+ void _processPseudoAttribute(Node node, List<String> values) {
+ List mangledValues = [];
+ for (var pseudoElement in values) {
+ if (_global.pseudoElements.containsKey(pseudoElement)) continue;
+
+ _uniqueIds.moveNext();
+ var newValue = "${pseudoElement}_${_uniqueIds.current}";
+ _global.pseudoElements[pseudoElement] = newValue;
+ // Mangled name of pseudo-element.
+ mangledValues.add(newValue);
+
+ if (!pseudoElement.startsWith('x-')) {
+ // TODO(terry): The name must start with x- otherwise it's not a custom
+ // pseudo-element. May want to relax since components no
+ // longer need to start with x-. See isse #509 on
+ // pseudo-element prefix.
+ _messages.warning("Custom pseudo-element must be prefixed with 'x-'.",
+ node.sourceSpan);
+ }
+ }
+
+ // Update the pseudo attribute with the new mangled names.
+ node.attributes['pseudo'] = mangledValues.join(' ');
+ }
+
+ /**
+ * Support for inline event handlers that take expressions.
+ * For example: `on-double-click=myHandler($event, todo)`.
+ */
+ void _validateEventHandler(Element node, String name, String value) {
+ if (!name.startsWith('on-')) {
+ // TODO(jmesserly): do we need an option to suppress this warning?
+ _messages.warning('Event handler $name will be interpreted as an inline '
+ 'JavaScript event handler. Use the form '
+ 'on-event-name="handlerName" if you want a Dart handler '
+ 'that will automatically update the UI based on model changes.',
+ node.sourceSpan);
+ }
+
+ if (value.contains('.') || value.contains('(')) {
+ // TODO(sigmund): should we allow more if we use fancy-syntax?
+ _messages.warning('Invalid event handler body "$value". Declare a method '
+ 'in your custom element "void handlerName(event, detail, target)" '
+ 'and use the form on-event-name="handlerName".',
+ node.sourceSpan);
+ }
+ }
+
+ /**
+ * Normalizes references in [info]. On the [analyzeDefinitions] phase, the
+ * analyzer extracted names of files and components. Here we link those names
+ * to actual info classes. In particular:
+ * * we initialize the [FileInfo.components] map in [info] by importing all
+ * [declaredComponents],
+ * * we scan all [info.componentLinks] and import their
+ * [info.declaredComponents], using [files] to map the href to the file
+ * info. Names in [info] will shadow names from imported files.
+ * * we fill [LibraryInfo.externalCode] on each component declared in
+ * [info].
+ */
+ void _normalize(FileInfo info, Map<String, FileInfo> files) {
+ _attachExtenalScript(info, files);
+
+ for (var component in info.declaredComponents) {
+ _addComponent(info, component);
+ _attachExtenalScript(component, files);
+ }
+
+ for (var link in info.componentLinks) {
+ var file = files[link.resolvedPath];
+ // We already issued an error for missing files.
+ if (file == null) continue;
+ file.declaredComponents.forEach((c) => _addComponent(info, c));
+ }
+ }
+
+ /**
+ * Stores a direct reference in [info] to a dart source file that was loaded
+ * in a script tag with the 'src' attribute.
+ */
+ void _attachExtenalScript(LibraryInfo info, Map<String, FileInfo> files) {
+ var externalFile = info.externalFile;
+ if (externalFile != null) {
+ info.externalCode = files[externalFile.resolvedPath];
+ if (info.externalCode != null) info.externalCode.htmlFile = info;
+ }
+ }
+
+ /** Adds a component's tag name to the names in scope for [fileInfo]. */
+ void _addComponent(FileInfo fileInfo, ComponentSummary component) {
+ var existing = fileInfo.components[component.tagName];
+ if (existing != null) {
+ if (existing == component) {
+ // This is the same exact component as the existing one.
+ return;
+ }
+
+ if (existing is ComponentInfo && component is! ComponentInfo) {
+ // Components declared in [fileInfo] shadow component names declared in
+ // imported files.
+ return;
+ }
+
+ if (existing.hasConflict) {
+ // No need to report a second error for the same name.
+ return;
+ }
+
+ existing.hasConflict = true;
+
+ if (component is ComponentInfo) {
+ _messages.error('duplicate custom element definition for '
+ '"${component.tagName}".', existing.sourceSpan);
+ _messages.error('duplicate custom element definition for '
+ '"${component.tagName}" (second location).', component.sourceSpan);
+ } else {
+ _messages.error('imported duplicate custom element definitions '
+ 'for "${component.tagName}".', existing.sourceSpan);
+ _messages.error('imported duplicate custom element definitions '
+ 'for "${component.tagName}" (second location).',
+ component.sourceSpan);
+ }
+ } else {
+ fileInfo.components[component.tagName] = component;
+ }
+ }
+}
+
+/** A visitor that finds `<link rel="import">` and `<element>` tags. */
+class _ElementLoader extends TreeVisitor {
+ final GlobalInfo _global;
+ final FileInfo _fileInfo;
+ LibraryInfo _currentInfo;
+ String _packageRoot;
+ bool _inHead = false;
+ Messages _messages;
+
+ /**
+ * Adds emitted warning/error messages to [_messages]. [_messages]
+ * must not be null.
+ */
+ _ElementLoader(this._global, this._fileInfo, this._packageRoot,
+ this._messages) {
+ _currentInfo = _fileInfo;
+ }
+
+ void visitElement(Element node) {
+ switch (node.tagName) {
+ case 'link': visitLinkElement(node); break;
+ case 'element':
+ _messages.warning('<element> elements are not supported, use'
+ ' <polymer-element> instead', node.sourceSpan);
+ break;
+ case 'polymer-element':
+ visitElementElement(node);
+ break;
+ case 'script': visitScriptElement(node); break;
+ case 'head':
+ var savedInHead = _inHead;
+ _inHead = true;
+ super.visitElement(node);
+ _inHead = savedInHead;
+ break;
+ default: super.visitElement(node); break;
+ }
+ }
+
+ /**
+ * Process `link rel="import"` as specified in:
+ * <https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/components/index.html#link-type-component>
+ */
+ void visitLinkElement(Element node) {
+ var rel = node.attributes['rel'];
+ if (rel != 'component' && rel != 'components' &&
+ rel != 'import' && rel != 'stylesheet') return;
+
+ if (!_inHead) {
+ _messages.warning('link rel="$rel" only valid in '
+ 'head.', node.sourceSpan);
+ return;
+ }
+
+ if (rel == 'component' || rel == 'components') {
+ _messages.warning('import syntax is changing, use '
+ 'rel="import" instead of rel="$rel".', node.sourceSpan);
+ }
+
+ var href = node.attributes['href'];
+ if (href == null || href == '') {
+ _messages.warning('link rel="$rel" missing href.',
+ node.sourceSpan);
+ return;
+ }
+
+ bool isStyleSheet = rel == 'stylesheet';
+ var urlInfo = UrlInfo.resolve(href, _fileInfo.inputUrl, node.sourceSpan,
+ _packageRoot, _messages, ignoreAbsolute: isStyleSheet);
+ if (urlInfo == null) return;
+ if (isStyleSheet) {
+ _fileInfo.styleSheetHrefs.add(urlInfo);
+ } else {
+ _fileInfo.componentLinks.add(urlInfo);
+ }
+ }
+
+ void visitElementElement(Element node) {
+ // TODO(jmesserly): what do we do in this case? It seems like an <element>
+ // inside a Shadow DOM should be scoped to that <template> tag, and not
+ // visible from the outside.
+ if (_currentInfo is ComponentInfo) {
+ _messages.error('Nested component definitions are not yet supported.',
+ node.sourceSpan);
+ return;
+ }
+
+ var tagName = node.attributes['name'];
+ var extendsTag = node.attributes['extends'];
+
+ if (tagName == null) {
+ _messages.error('Missing tag name of the component. Please include an '
+ 'attribute like \'name="your-tag-name"\'.',
+ node.sourceSpan);
+ return;
+ }
+
+ var component = new ComponentInfo(node, _fileInfo, tagName, extendsTag);
+ _fileInfo.declaredComponents.add(component);
+ _addComponent(component);
+
+ var lastInfo = _currentInfo;
+ _currentInfo = component;
+ super.visitElement(node);
+ _currentInfo = lastInfo;
+ }
+
+ /** Adds a component's tag name to the global list. */
+ void _addComponent(ComponentInfo component) {
+ var existing = _global.components[component.tagName];
+ if (existing != null) {
+ if (existing.hasConflict) {
+ // No need to report a second error for the same name.
+ return;
+ }
+
+ existing.hasConflict = true;
+
+ _messages.error('duplicate custom element definition for '
+ '"${component.tagName}".', existing.sourceSpan);
+ _messages.error('duplicate custom element definition for '
+ '"${component.tagName}" (second location).', component.sourceSpan);
+ } else {
+ _global.components[component.tagName] = component;
+ }
+ }
+
+ void visitScriptElement(Element node) {
+ var scriptType = node.attributes['type'];
+ var src = node.attributes["src"];
+
+ if (scriptType == null) {
+ // Note: in html5 leaving off type= is fine, but it defaults to
+ // text/javascript. Because this might be a common error, we warn about it
+ // in two cases:
+ // * an inline script tag in a web component
+ // * a script src= if the src file ends in .dart (component or not)
+ //
+ // The hope is that neither of these cases should break existing valid
+ // code, but that they'll help component authors avoid having their Dart
+ // code accidentally interpreted as JavaScript by the browser.
+ if (src == null && _currentInfo is ComponentInfo) {
+ _messages.warning('script tag in component with no type will '
+ 'be treated as JavaScript. Did you forget type="application/dart"?',
+ node.sourceSpan);
+ }
+ if (src != null && src.endsWith('.dart')) {
+ _messages.warning('script tag with .dart source file but no type will '
+ 'be treated as JavaScript. Did you forget type="application/dart"?',
+ node.sourceSpan);
+ }
+ return;
+ }
+
+ if (scriptType != 'application/dart') {
+ if (_currentInfo is ComponentInfo) {
+ // TODO(jmesserly): this warning should not be here, but our compiler
+ // does the wrong thing and it could cause surprising behavior, so let
+ // the user know! See issue #340 for more info.
+ // What we should be doing: leave JS component untouched by compiler.
+ _messages.warning('our custom element implementation does not support '
+ 'JavaScript components yet. If this is affecting you please let us '
+ 'know at https://github.com/dart-lang/web-ui/issues/340.',
+ node.sourceSpan);
+ }
+
+ return;
+ }
+
+ if (src != null) {
+ if (!src.endsWith('.dart')) {
+ _messages.warning('"application/dart" scripts should '
+ 'use the .dart file extension.',
+ node.sourceSpan);
+ }
+
+ if (node.innerHtml.trim() != '') {
+ _messages.error('script tag has "src" attribute and also has script '
+ 'text.', node.sourceSpan);
+ }
+
+ if (_currentInfo.codeAttached) {
+ _tooManyScriptsError(node);
+ } else {
+ _currentInfo.externalFile = UrlInfo.resolve(src, _fileInfo.inputUrl,
+ node.sourceSpan, _packageRoot, _messages);
+ }
+ return;
+ }
+
+ if (node.nodes.length == 0) return;
+
+ // I don't think the html5 parser will emit a tree with more than
+ // one child of <script>
+ assert(node.nodes.length == 1);
+ Text text = node.nodes[0];
+
+ if (_currentInfo.codeAttached) {
+ _tooManyScriptsError(node);
+ } else if (_currentInfo == _fileInfo && !_fileInfo.isEntryPoint) {
+ _messages.warning('top-level dart code is ignored on '
+ ' HTML pages that define components, but are not the entry HTML '
+ 'file.', node.sourceSpan);
+ } else {
+ _currentInfo.inlinedCode = parseDartCode(
+ _currentInfo.dartCodeUrl.resolvedPath, text.value,
+ text.sourceSpan.start);
+ if (_currentInfo.userCode.partOf != null) {
+ _messages.error('expected a library, not a part.',
+ node.sourceSpan);
+ }
+ }
+ }
+
+ void _tooManyScriptsError(Node node) {
+ var location = _currentInfo is ComponentInfo ?
+ 'a custom element declaration' : 'the top-level HTML page';
+
+ _messages.error('there should be only one dart script tag in $location.',
+ node.sourceSpan);
+ }
+}
diff --git a/pkg/polymer/lib/src/compiler.dart b/pkg/polymer/lib/src/compiler.dart
new file mode 100644
index 0000000..5e2c98f
--- /dev/null
+++ b/pkg/polymer/lib/src/compiler.dart
@@ -0,0 +1,770 @@
+// 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 compiler;
+
+import 'dart:async';
+import 'dart:collection' show SplayTreeMap;
+import 'dart:json' as json;
+
+import 'package:analyzer_experimental/src/generated/ast.dart' show Directive, UriBasedDirective;
+import 'package:csslib/visitor.dart' show StyleSheet, treeToDebugString;
+import 'package:html5lib/dom.dart';
+import 'package:html5lib/parser.dart';
+import 'package:observe/transform.dart' show transformObservables;
+import 'package:source_maps/span.dart' show Span;
+import 'package:source_maps/refactor.dart' show TextEditTransaction;
+import 'package:source_maps/printer.dart';
+
+import 'analyzer.dart';
+import 'css_analyzer.dart' show analyzeCss, findUrlsImported,
+ findImportsInStyleSheet, parseCss;
+import 'css_emitters.dart' show rewriteCssUris,
+ emitComponentStyleSheet, emitOriginalCss, emitStyleSheet;
+import 'dart_parser.dart';
+import 'emitters.dart';
+import 'file_system.dart';
+import 'files.dart';
+import 'info.dart';
+import 'messages.dart';
+import 'compiler_options.dart';
+import 'paths.dart';
+import 'utils.dart';
+
+/**
+ * Parses an HTML file [contents] and returns a DOM-like tree.
+ * Note that [contents] will be a [String] if coming from a browser-based
+ * [FileSystem], or it will be a [List<int>] if running on the command line.
+ *
+ * Adds emitted error/warning to [messages], if [messages] is supplied.
+ */
+Document parseHtml(contents, String sourcePath, Messages messages) {
+ var parser = new HtmlParser(contents, generateSpans: true,
+ sourceUrl: sourcePath);
+ var document = parser.parse();
+
+ // Note: errors aren't fatal in HTML (unless strict mode is on).
+ // So just print them as warnings.
+ for (var e in parser.errors) {
+ messages.warning(e.message, e.span);
+ }
+ return document;
+}
+
+/** Compiles an application written with Dart web components. */
+class Compiler {
+ final FileSystem fileSystem;
+ final CompilerOptions options;
+ final List<SourceFile> files = <SourceFile>[];
+ final List<OutputFile> output = <OutputFile>[];
+
+ String _mainPath;
+ String _resetCssFile;
+ StyleSheet _cssResetStyleSheet;
+ PathMapper _pathMapper;
+ Messages _messages;
+
+ FutureGroup _tasks;
+ Set _processed;
+
+ /** Information about source [files] given their href. */
+ final Map<String, FileInfo> info = new SplayTreeMap<String, FileInfo>();
+ final _edits = new Map<DartCodeInfo, TextEditTransaction>();
+
+ final GlobalInfo global = new GlobalInfo();
+
+ /** Creates a compiler with [options] using [fileSystem]. */
+ Compiler(this.fileSystem, this.options, this._messages) {
+ _mainPath = options.inputFile;
+ var mainDir = path.dirname(_mainPath);
+ var baseDir = options.baseDir != null ? options.baseDir : mainDir;
+ var outputDir = options.outputDir != null ? options.outputDir : mainDir;
+ var packageRoot = options.packageRoot != null ? options.packageRoot
+ : path.join(path.dirname(_mainPath), 'packages');
+
+ if (options.resetCssFile != null) {
+ _resetCssFile = options.resetCssFile;
+ if (path.isRelative(_resetCssFile)) {
+ // If CSS reset file path is relative from our current path.
+ _resetCssFile = path.resolve(_resetCssFile);
+ }
+ }
+
+ // Normalize paths - all should be relative or absolute paths.
+ if (path.isAbsolute(_mainPath) || path.isAbsolute(baseDir) ||
+ path.isAbsolute(outputDir) || path.isAbsolute(packageRoot)) {
+ if (path.isRelative(_mainPath)) _mainPath = path.resolve(_mainPath);
+ if (path.isRelative(baseDir)) baseDir = path.resolve(baseDir);
+ if (path.isRelative(outputDir)) outputDir = path.resolve(outputDir);
+ if (path.isRelative(packageRoot)) {
+ packageRoot = path.resolve(packageRoot);
+ }
+ }
+ _pathMapper = new PathMapper(
+ baseDir, outputDir, packageRoot, options.forceMangle,
+ options.rewriteUrls);
+ }
+
+ /** Compile the application starting from the given input file. */
+ Future run() {
+ if (path.basename(_mainPath).endsWith('.dart')) {
+ _messages.error("Please provide an HTML file as your entry point.",
+ null);
+ return new Future.value(null);
+ }
+ return _parseAndDiscover(_mainPath).then((_) {
+ _analyze();
+
+ // Analyze all CSS files.
+ _time('Analyzed Style Sheets', '', () =>
+ analyzeCss(_pathMapper.packageRoot, files, info,
+ global.pseudoElements, _messages,
+ warningsAsErrors: options.warningsAsErrors));
+
+ // TODO(jmesserly): need to go through our errors, and figure out if some
+ // of them should be warnings instead.
+ if (_messages.hasErrors || options.analysisOnly) return;
+ _transformDart();
+ _emit();
+ });
+ }
+
+ /**
+ * Asynchronously parse [inputFile] and transitively discover web components
+ * to load and parse. Returns a future that completes when all files are
+ * processed.
+ */
+ Future _parseAndDiscover(String inputFile) {
+ _tasks = new FutureGroup();
+ _processed = new Set();
+ _processed.add(inputFile);
+ _tasks.add(_parseHtmlFile(new UrlInfo(inputFile, inputFile, null)));
+ return _tasks.future;
+ }
+
+ void _processHtmlFile(UrlInfo inputUrl, SourceFile file) {
+ if (file == null) return;
+
+ bool isEntryPoint = _processed.length == 1;
+
+ files.add(file);
+
+ var fileInfo = _time('Analyzed definitions', inputUrl.url, () {
+ return analyzeDefinitions(global, inputUrl, file.document,
+ _pathMapper.packageRoot, _messages, isEntryPoint: isEntryPoint);
+ });
+ info[inputUrl.resolvedPath] = fileInfo;
+
+ if (isEntryPoint && _resetCssFile != null) {
+ _processed.add(_resetCssFile);
+ _tasks.add(_parseCssFile(new UrlInfo(_resetCssFile, _resetCssFile,
+ null)));
+ }
+
+ _setOutputFilenames(fileInfo);
+ _processImports(fileInfo);
+
+ // Load component files referenced by [file].
+ for (var link in fileInfo.componentLinks) {
+ _loadFile(link, _parseHtmlFile);
+ }
+
+ // Load stylesheet files referenced by [file].
+ for (var link in fileInfo.styleSheetHrefs) {
+ _loadFile(link, _parseCssFile);
+ }
+
+ // Load .dart files being referenced in the page.
+ _loadFile(fileInfo.externalFile, _parseDartFile);
+
+ // Process any @imports inside of a <style> tag.
+ var urlInfos = findUrlsImported(fileInfo, fileInfo.inputUrl,
+ _pathMapper.packageRoot, file.document, _messages, options);
+ for (var urlInfo in urlInfos) {
+ _loadFile(urlInfo, _parseCssFile);
+ }
+
+ // Load .dart files being referenced in components.
+ for (var component in fileInfo.declaredComponents) {
+ if (component.externalFile != null) {
+ _loadFile(component.externalFile, _parseDartFile);
+ } else if (component.userCode != null) {
+ _processImports(component);
+ }
+
+ // Process any @imports inside of the <style> tag in a component.
+ var urlInfos = findUrlsImported(component,
+ component.declaringFile.inputUrl, _pathMapper.packageRoot,
+ component.element, _messages, options);
+ for (var urlInfo in urlInfos) {
+ _loadFile(urlInfo, _parseCssFile);
+ }
+ }
+ }
+
+ /**
+ * Helper function to load [urlInfo] and parse it using [loadAndParse] if it
+ * hasn't been loaded before.
+ */
+ void _loadFile(UrlInfo urlInfo, Future loadAndParse(UrlInfo inputUrl)) {
+ if (urlInfo == null) return;
+ var resolvedPath = urlInfo.resolvedPath;
+ if (!_processed.contains(resolvedPath)) {
+ _processed.add(resolvedPath);
+ _tasks.add(loadAndParse(urlInfo));
+ }
+ }
+
+ void _setOutputFilenames(FileInfo fileInfo) {
+ var filePath = fileInfo.dartCodeUrl.resolvedPath;
+ fileInfo.outputFilename = _pathMapper.mangle(path.basename(filePath),
+ '.dart', path.extension(filePath) == '.html');
+ for (var component in fileInfo.declaredComponents) {
+ var externalFile = component.externalFile;
+ var name = null;
+ if (externalFile != null) {
+ name = _pathMapper.mangle(
+ path.basename(externalFile.resolvedPath), '.dart');
+ } else {
+ var declaringFile = component.declaringFile;
+ var prefix = path.basename(declaringFile.inputUrl.resolvedPath);
+ if (declaringFile.declaredComponents.length == 1
+ && !declaringFile.codeAttached && !declaringFile.isEntryPoint) {
+ name = _pathMapper.mangle(prefix, '.dart', true);
+ } else {
+ var componentName = component.tagName.replaceAll('-', '_');
+ name = _pathMapper.mangle('${prefix}_$componentName', '.dart', true);
+ }
+ }
+ component.outputFilename = name;
+ }
+ }
+
+ /** Parse an HTML file. */
+ Future _parseHtmlFile(UrlInfo inputUrl) {
+ if (!_pathMapper.checkInputPath(inputUrl, _messages)) {
+ return new Future<SourceFile>.value(null);
+ }
+ var filePath = inputUrl.resolvedPath;
+ return fileSystem.readTextOrBytes(filePath)
+ .catchError((e) => _readError(e, inputUrl))
+ .then((source) {
+ if (source == null) return;
+ var file = new SourceFile(filePath);
+ file.document = _time('Parsed', filePath,
+ () => parseHtml(source, filePath, _messages));
+ _processHtmlFile(inputUrl, file);
+ });
+ }
+
+ /** Parse a Dart file. */
+ Future _parseDartFile(UrlInfo inputUrl) {
+ if (!_pathMapper.checkInputPath(inputUrl, _messages)) {
+ return new Future<SourceFile>.value(null);
+ }
+ var filePath = inputUrl.resolvedPath;
+ return fileSystem.readText(filePath)
+ .catchError((e) => _readError(e, inputUrl))
+ .then((code) {
+ if (code == null) return;
+ var file = new SourceFile(filePath, type: SourceFile.DART);
+ file.code = code;
+ _processDartFile(inputUrl, file);
+ });
+ }
+
+ /** Parse a stylesheet file. */
+ Future _parseCssFile(UrlInfo inputUrl) {
+ if (!options.emulateScopedCss ||
+ !_pathMapper.checkInputPath(inputUrl, _messages)) {
+ return new Future<SourceFile>.value(null);
+ }
+ var filePath = inputUrl.resolvedPath;
+ return fileSystem.readText(filePath)
+ .catchError((e) => _readError(e, inputUrl, isWarning: true))
+ .then((code) {
+ if (code == null) return;
+ var file = new SourceFile(filePath, type: SourceFile.STYLESHEET);
+ file.code = code;
+ _processCssFile(inputUrl, file);
+ });
+ }
+
+
+ SourceFile _readError(error, UrlInfo inputUrl, {isWarning: false}) {
+ var message = 'unable to open file "${inputUrl.resolvedPath}"';
+ if (options.verbose) {
+ message = '$message. original message:\n $error';
+ }
+ if (isWarning) {
+ _messages.warning(message, inputUrl.sourceSpan);
+ } else {
+ _messages.error(message, inputUrl.sourceSpan);
+ }
+ return null;
+ }
+
+ void _processDartFile(UrlInfo inputUrl, SourceFile dartFile) {
+ if (dartFile == null) return;
+
+ files.add(dartFile);
+
+ var resolvedPath = inputUrl.resolvedPath;
+ var fileInfo = new FileInfo(inputUrl);
+ info[resolvedPath] = fileInfo;
+ fileInfo.inlinedCode = parseDartCode(resolvedPath, dartFile.code);
+ fileInfo.outputFilename =
+ _pathMapper.mangle(path.basename(resolvedPath), '.dart', false);
+
+ _processImports(fileInfo);
+ }
+
+ void _processImports(LibraryInfo library) {
+ if (library.userCode == null) return;
+
+ for (var directive in library.userCode.directives) {
+ _loadFile(_getDirectiveUrlInfo(library, directive), _parseDartFile);
+ }
+ }
+
+ void _processCssFile(UrlInfo inputUrl, SourceFile cssFile) {
+ if (cssFile == null) return;
+
+ files.add(cssFile);
+
+ var fileInfo = new FileInfo(inputUrl);
+ info[inputUrl.resolvedPath] = fileInfo;
+
+ var styleSheet = parseCss(cssFile.code, _messages, options);
+ if (inputUrl.url == _resetCssFile) {
+ _cssResetStyleSheet = styleSheet;
+ } else if (styleSheet != null) {
+ _resolveStyleSheetImports(inputUrl, cssFile.path, styleSheet);
+ fileInfo.styleSheets.add(styleSheet);
+ }
+ }
+
+ /** Load and parse all style sheets referenced with an @imports. */
+ void _resolveStyleSheetImports(UrlInfo inputUrl, String processingFile,
+ StyleSheet styleSheet) {
+ var urlInfos = _time('CSS imports', processingFile, () =>
+ findImportsInStyleSheet(styleSheet, _pathMapper.packageRoot, inputUrl,
+ _messages));
+
+ for (var urlInfo in urlInfos) {
+ if (urlInfo == null) break;
+ // Load any @imported stylesheet files referenced in this style sheet.
+ _loadFile(urlInfo, _parseCssFile);
+ }
+ }
+
+ String _directiveUri(Directive directive) {
+ var uriDirective = (directive as UriBasedDirective).uri;
+ return (uriDirective as dynamic).value;
+ }
+
+ UrlInfo _getDirectiveUrlInfo(LibraryInfo library, Directive directive) {
+ var uri = _directiveUri(directive);
+ if (uri.startsWith('dart:')) return null;
+ if (uri.startsWith('package:') && uri.startsWith('package:polymer/')) {
+ // Don't process our own package -- we'll implement @observable manually.
+ return null;
+ }
+
+ var span = library.userCode.sourceFile.span(
+ directive.offset, directive.end);
+ return UrlInfo.resolve(uri, library.dartCodeUrl, span,
+ _pathMapper.packageRoot, _messages);
+ }
+
+ /**
+ * Transform Dart source code.
+ * Currently, the only transformation is [transformObservables].
+ * Calls _emitModifiedDartFiles to write the transformed files.
+ */
+ void _transformDart() {
+ var libraries = _findAllDartLibraries();
+
+ var transformed = [];
+ for (var lib in libraries) {
+ var userCode = lib.userCode;
+ var transaction = transformObservables(userCode.compilationUnit,
+ userCode.sourceFile, userCode.code, _messages);
+ if (transaction != null) {
+ _edits[lib.userCode] = transaction;
+ if (transaction.hasEdits) {
+ transformed.add(lib);
+ } else if (lib.htmlFile != null) {
+ // All web components will be transformed too. Track that.
+ transformed.add(lib);
+ }
+ }
+ }
+
+ _findModifiedDartFiles(libraries, transformed);
+
+ libraries.forEach(_fixImports);
+
+ _emitModifiedDartFiles(libraries);
+ }
+
+ /**
+ * Finds all Dart code libraries.
+ * Each library will have [LibraryInfo.inlinedCode] that is non-null.
+ * Also each inlinedCode will be unique.
+ */
+ List<LibraryInfo> _findAllDartLibraries() {
+ var libs = <LibraryInfo>[];
+ void _addLibrary(LibraryInfo lib) {
+ if (lib.inlinedCode != null) libs.add(lib);
+ }
+
+ for (var sourceFile in files) {
+ var file = info[sourceFile.path];
+ _addLibrary(file);
+ file.declaredComponents.forEach(_addLibrary);
+ }
+
+ // Assert that each file path is unique.
+ assert(_uniquePaths(libs));
+ return libs;
+ }
+
+ bool _uniquePaths(List<LibraryInfo> libs) {
+ var seen = new Set();
+ for (var lib in libs) {
+ if (seen.contains(lib.inlinedCode)) {
+ throw new StateError('internal error: '
+ 'duplicate user code for ${lib.dartCodeUrl.resolvedPath}.'
+ ' Files were: $files');
+ }
+ seen.add(lib.inlinedCode);
+ }
+ return true;
+ }
+
+ /**
+ * Queue modified Dart files to be written.
+ * This will not write files that are handled by [WebComponentEmitter] and
+ * [EntryPointEmitter].
+ */
+ void _emitModifiedDartFiles(List<LibraryInfo> libraries) {
+ for (var lib in libraries) {
+ // Components will get emitted by WebComponentEmitter, and the
+ // entry point will get emitted by MainPageEmitter.
+ // So we only need to worry about other .dart files.
+ if (lib.modified && lib is FileInfo &&
+ lib.htmlFile == null && !lib.isEntryPoint) {
+ var transaction = _edits[lib.userCode];
+
+ // Save imports that were modified by _fixImports.
+ for (var d in lib.userCode.directives) {
+ transaction.edit(d.offset, d.end, d.toString());
+ }
+
+ if (!lib.userCode.isPart) {
+ var pos = lib.userCode.firstPartOffset;
+ // Note: we use a different prefix than "autogenerated" to make
+ // ChangeRecord unambiguous. Otherwise it would be imported by this
+ // and polymer, resulting in a collision.
+ // TODO(jmesserly): only generate this for libraries that need it.
+ transaction.edit(pos, pos, "\nimport "
+ "'package:observe/observe.dart' as __observe;\n");
+ }
+ _emitFileAndSourceMaps(lib, transaction.commit(), lib.dartCodeUrl);
+ }
+ }
+ }
+
+ /**
+ * This method computes which Dart files have been modified, starting
+ * from [transformed] and marking recursively through all files that import
+ * the modified files.
+ */
+ void _findModifiedDartFiles(List<LibraryInfo> libraries,
+ List<FileInfo> transformed) {
+
+ if (transformed.length == 0) return;
+
+ // Compute files that reference each file, then use this information to
+ // flip the modified bit transitively. This is a lot simpler than trying
+ // to compute it the other way because of circular references.
+ for (var lib in libraries) {
+ for (var directive in lib.userCode.directives) {
+ var importPath = _getDirectiveUrlInfo(lib, directive);
+ if (importPath == null) continue;
+
+ var importInfo = info[importPath.resolvedPath];
+ if (importInfo != null) {
+ importInfo.referencedBy.add(lib);
+ }
+ }
+ }
+
+ // Propegate the modified bit to anything that references a modified file.
+ void setModified(LibraryInfo library) {
+ if (library.modified) return;
+ library.modified = true;
+ library.referencedBy.forEach(setModified);
+ }
+ transformed.forEach(setModified);
+
+ for (var lib in libraries) {
+ // We don't need this anymore, so free it.
+ lib.referencedBy = null;
+ }
+ }
+
+ void _fixImports(LibraryInfo library) {
+ // Fix imports. Modified files must use the generated path, otherwise
+ // we need to make the path relative to the input.
+ for (var directive in library.userCode.directives) {
+ var importPath = _getDirectiveUrlInfo(library, directive);
+ if (importPath == null) continue;
+ var importInfo = info[importPath.resolvedPath];
+ if (importInfo == null) continue;
+
+ String newUri = null;
+ if (importInfo.modified) {
+ // Use the generated URI for this file.
+ newUri = _pathMapper.importUrlFor(library, importInfo);
+ } else if (options.rewriteUrls) {
+ // Get the relative path to the input file.
+ newUri = _pathMapper.transformUrl(
+ library.dartCodeUrl.resolvedPath, directive.uri.value);
+ }
+ if (newUri != null) {
+ directive.uri = createStringLiteral(newUri);
+ }
+ }
+ }
+
+ /** Run the analyzer on every input html file. */
+ void _analyze() {
+ var uniqueIds = new IntIterator();
+ for (var file in files) {
+ if (file.isHtml) {
+ _time('Analyzed contents', file.path, () =>
+ analyzeFile(file, info, uniqueIds, global, _messages,
+ options.emulateScopedCss));
+ }
+ }
+ }
+
+ /** Emit the generated code corresponding to each input file. */
+ void _emit() {
+ for (var file in files) {
+ if (file.isDart || file.isStyleSheet) continue;
+ _time('Codegen', file.path, () {
+ var fileInfo = info[file.path];
+ _emitComponents(fileInfo);
+ });
+ }
+
+ var entryPoint = files[0];
+ assert(info[entryPoint.path].isEntryPoint);
+ _emitMainDart(entryPoint);
+ _emitMainHtml(entryPoint);
+
+ assert(_unqiueOutputs());
+ }
+
+ bool _unqiueOutputs() {
+ var seen = new Set();
+ for (var file in output) {
+ if (seen.contains(file.path)) {
+ throw new StateError('internal error: '
+ 'duplicate output file ${file.path}. Files were: $output');
+ }
+ seen.add(file.path);
+ }
+ return true;
+ }
+
+ /** Emit the main .dart file. */
+ void _emitMainDart(SourceFile file) {
+ var fileInfo = info[file.path];
+
+ var codeInfo = fileInfo.userCode;
+ if (codeInfo != null) {
+ var printer = new NestedPrinter(0);
+ if (codeInfo.libraryName == null) {
+ printer.addLine('library ${fileInfo.libraryName};');
+ }
+ printer.add(codeInfo.code);
+ _emitFileAndSourceMaps(fileInfo, printer, fileInfo.dartCodeUrl);
+ }
+ }
+
+ // TODO(jmesserly): refactor this out of Compiler.
+ /** Generate an html file with the (trimmed down) main html page. */
+ void _emitMainHtml(SourceFile file) {
+ var fileInfo = info[file.path];
+
+ var bootstrapName = '${path.basename(file.path)}_bootstrap.dart';
+ var bootstrapPath = path.join(path.dirname(file.path), bootstrapName);
+ var bootstrapOutPath = _pathMapper.outputPath(bootstrapPath, '');
+ var bootstrapOutName = path.basename(bootstrapOutPath);
+ var bootstrapInfo = new FileInfo(new UrlInfo('', bootstrapPath, null));
+ var printer = generateBootstrapCode(bootstrapInfo, fileInfo, global,
+ _pathMapper, options);
+ printer.build(bootstrapOutPath);
+ output.add(new OutputFile(
+ bootstrapOutPath, printer.text, source: file.path));
+
+ var document = file.document;
+ var hasCss = _emitAllCss();
+ transformMainHtml(document, fileInfo, _pathMapper, hasCss,
+ options.rewriteUrls, _messages, global, bootstrapOutName);
+ output.add(new OutputFile(_pathMapper.outputPath(file.path, '.html'),
+ document.outerHtml, source: file.path));
+ }
+
+ // TODO(jmesserly): refactor this and other CSS related transforms out of
+ // Compiler.
+ /**
+ * Generate an CSS file for all style sheets (main and components).
+ * Returns true if a file was generated, otherwise false.
+ */
+ bool _emitAllCss() {
+ if (!options.emulateScopedCss) return false;
+
+ var buff = new StringBuffer();
+
+ // Emit all linked style sheet files first.
+ for (var file in files) {
+ var css = new StringBuffer();
+ var fileInfo = info[file.path];
+ if (file.isStyleSheet) {
+ for (var styleSheet in fileInfo.styleSheets) {
+ // Translate any URIs in CSS.
+ rewriteCssUris(_pathMapper, fileInfo.inputUrl.resolvedPath,
+ options.rewriteUrls, styleSheet);
+ css.write(
+ '/* Auto-generated from style sheet href = ${file.path} */\n'
+ '/* DO NOT EDIT. */\n\n');
+ css.write(emitStyleSheet(styleSheet, fileInfo));
+ css.write('\n\n');
+ }
+
+ // Emit the linked style sheet in the output directory.
+ if (fileInfo.inputUrl.url != _resetCssFile) {
+ var outCss = _pathMapper.outputPath(fileInfo.inputUrl.resolvedPath,
+ '');
+ output.add(new OutputFile(outCss, css.toString()));
+ }
+ }
+ }
+
+ // Emit all CSS for each component (style scoped).
+ for (var file in files) {
+ if (file.isHtml) {
+ var fileInfo = info[file.path];
+ for (var component in fileInfo.declaredComponents) {
+ for (var styleSheet in component.styleSheets) {
+ // Translate any URIs in CSS.
+ rewriteCssUris(_pathMapper, fileInfo.inputUrl.resolvedPath,
+ options.rewriteUrls, styleSheet);
+
+ if (buff.isEmpty) {
+ buff.write(
+ '/* Auto-generated from components style tags. */\n'
+ '/* DO NOT EDIT. */\n\n');
+ }
+ buff.write(
+ '/* ==================================================== \n'
+ ' Component ${component.tagName} stylesheet \n'
+ ' ==================================================== */\n');
+
+ var tagName = component.tagName;
+ if (!component.hasAuthorStyles) {
+ if (_cssResetStyleSheet != null) {
+ // If component doesn't have apply-author-styles then we need to
+ // reset the CSS the styles for the component (if css-reset file
+ // option was passed).
+ buff.write('\n/* Start CSS Reset */\n');
+ var style;
+ if (options.emulateScopedCss) {
+ style = emitComponentStyleSheet(_cssResetStyleSheet, tagName);
+ } else {
+ style = emitOriginalCss(_cssResetStyleSheet);
+ }
+ buff.write(style);
+ buff.write('/* End CSS Reset */\n\n');
+ }
+ }
+ if (options.emulateScopedCss) {
+ buff.write(emitComponentStyleSheet(styleSheet, tagName));
+ } else {
+ buff.write(emitOriginalCss(styleSheet));
+ }
+ buff.write('\n\n');
+ }
+ }
+ }
+ }
+
+ if (buff.isEmpty) return false;
+
+ var cssPath = _pathMapper.outputPath(_mainPath, '.css', true);
+ output.add(new OutputFile(cssPath, buff.toString()));
+ return true;
+ }
+
+ /** Emits the Dart code for all components in [fileInfo]. */
+ void _emitComponents(FileInfo fileInfo) {
+ for (var component in fileInfo.declaredComponents) {
+ // TODO(terry): Handle more than one stylesheet per component
+ if (component.styleSheets.length > 1 && options.emulateScopedCss) {
+ var span = component.externalFile != null
+ ? component.externalFile.sourceSpan : null;
+ _messages.warning(
+ 'Component has more than one stylesheet - first stylesheet used.',
+ span);
+ }
+ var printer = emitPolymerElement(
+ component, _pathMapper, _edits[component.userCode], options);
+ _emitFileAndSourceMaps(component, printer, component.externalFile);
+ }
+ }
+
+ /**
+ * Emits a file that was created using [NestedPrinter] and it's corresponding
+ * source map file.
+ */
+ void _emitFileAndSourceMaps(
+ LibraryInfo lib, NestedPrinter printer, UrlInfo dartCodeUrl) {
+ // Bail if we had an error generating the code for the file.
+ if (printer == null) return;
+
+ var libPath = _pathMapper.outputLibraryPath(lib);
+ var dir = path.dirname(libPath);
+ var filename = path.basename(libPath);
+ printer.add('\n//# sourceMappingURL=$filename.map');
+ printer.build(libPath);
+ var sourcePath = dartCodeUrl != null ? dartCodeUrl.resolvedPath : null;
+ output.add(new OutputFile(libPath, printer.text, source: sourcePath));
+ // Fix-up the paths in the source map file
+ var sourceMap = json.parse(printer.map);
+ var urls = sourceMap['sources'];
+ for (int i = 0; i < urls.length; i++) {
+ urls[i] = path.relative(urls[i], from: dir);
+ }
+ output.add(new OutputFile(path.join(dir, '$filename.map'),
+ json.stringify(sourceMap)));
+ }
+
+ _time(String logMessage, String filePath, callback(),
+ {bool printTime: false}) {
+ var message = new StringBuffer();
+ message.write(logMessage);
+ var filename = path.basename(filePath);
+ for (int i = (60 - logMessage.length - filename.length); i > 0 ; i--) {
+ message.write(' ');
+ }
+ message.write(filename);
+ return time(message.toString(), callback,
+ printTime: options.verbose || printTime);
+ }
+}
diff --git a/pkg/polymer/lib/src/compiler_options.dart b/pkg/polymer/lib/src/compiler_options.dart
new file mode 100644
index 0000000..4c1d317
--- /dev/null
+++ b/pkg/polymer/lib/src/compiler_options.dart
@@ -0,0 +1,148 @@
+// 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 polymer.src.compiler_options;
+
+import 'package:args/args.dart';
+
+class CompilerOptions {
+ /** Report warnings as errors. */
+ final bool warningsAsErrors;
+
+ /** True to show informational messages. The `--verbose` flag. */
+ final bool verbose;
+
+ /** Remove any generated files. */
+ final bool clean;
+
+ /** Whether to use colors to print messages on the terminal. */
+ final bool useColors;
+
+ /** Force mangling any generated name (even when --out is provided). */
+ final bool forceMangle;
+
+ /** Generate component's dart code, but not the main entry point file. */
+ final bool componentsOnly;
+
+ /** File to process by the compiler. */
+ String inputFile;
+
+ /** Directory where all sources are found. */
+ final String baseDir;
+
+ /** Directory where all output will be generated. */
+ final String outputDir;
+
+ /** Directory where to look for 'package:' imports. */
+ final String packageRoot;
+
+ /**
+ * Adjust resource URLs in the output HTML to point back to the original
+ * location in the file system. Commonly this is enabled during development,
+ * but disabled for deployment.
+ */
+ final bool rewriteUrls;
+
+ /**
+ * Whether to print error messages using the json format understood by the
+ * Dart editor.
+ */
+ final bool jsonFormat;
+
+ /** Emulate scoped styles using a CSS polyfill. */
+ final bool emulateScopedCss;
+
+ /** Use CSS file for CSS Reset. */
+ final String resetCssFile;
+
+ /** Whether to analyze the input for warnings without generating any code. */
+ final bool analysisOnly;
+
+ // We could make this faster, if it ever matters.
+ factory CompilerOptions() => parse(['']);
+
+ CompilerOptions.fromArgs(ArgResults args)
+ : warningsAsErrors = args['warnings_as_errors'],
+ verbose = args['verbose'],
+ clean = args['clean'],
+ useColors = args['colors'],
+ baseDir = args['basedir'],
+ outputDir = args['out'],
+ packageRoot = args['package-root'],
+ rewriteUrls = args['rewrite-urls'],
+ forceMangle = args['unique_output_filenames'],
+ jsonFormat = args['json_format'],
+ componentsOnly = args['components_only'],
+ emulateScopedCss = args['scoped-css'],
+ resetCssFile = args['css-reset'],
+ analysisOnly = !args['deploy'],
+ inputFile = args.rest.length > 0 ? args.rest[0] : null;
+
+ /**
+ * Returns the compiler options parsed from [arguments]. Set [checkUsage] to
+ * false to suppress checking of correct usage or printing help messages.
+ */
+ // TODO(sigmund): convert all flags to use dashes instead of underscores
+ static CompilerOptions parse(List<String> arguments,
+ {bool checkUsage: true}) {
+ var parser = new ArgParser()
+ ..addFlag('verbose', abbr: 'v')
+ ..addFlag('clean', help: 'Remove all generated files',
+ defaultsTo: false, negatable: false)
+ ..addFlag('warnings_as_errors', abbr: 'e',
+ help: 'Warnings handled as errors',
+ defaultsTo: false, negatable: false)
+ ..addFlag('colors', help: 'Display errors/warnings in colored text',
+ defaultsTo: true)
+ ..addFlag('rewrite-urls',
+ help: 'Adjust every resource url to point to the original location in'
+ ' the filesystem.\nThis on by default during development and can be'
+ ' disabled to make the generated code easier to deploy.',
+ defaultsTo: true)
+ ..addFlag('unique_output_filenames', abbr: 'u',
+ help: 'Use unique names for all generated files, so they will not '
+ 'have the\nsame name as your input files, even if they are in a'
+ ' different directory',
+ defaultsTo: false, negatable: false)
+ ..addFlag('json_format',
+ help: 'Print error messsages in a json format easy to parse by tools,'
+ ' such as the Dart editor',
+ defaultsTo: false, negatable: false)
+ ..addFlag('components_only',
+ help: 'Generate only the code for component classes, do not generate '
+ 'HTML files or the main bootstrap code.',
+ defaultsTo: false, negatable: false)
+ ..addFlag('scoped-css', help: 'Emulate scoped styles with CSS polyfill',
+ defaultsTo: false)
+ ..addOption('css-reset', abbr: 'r', help: 'CSS file used to reset CSS')
+ ..addFlag('deploy', help: 'Emit code used for deploying a polymer app,'
+ ' if false just show warnings and errors (default)',
+ defaultsTo: false, negatable: false)
+ ..addOption('out', abbr: 'o', help: 'Directory where to generate files'
+ ' (defaults to the same directory as the source file)')
+ ..addOption('basedir', help: 'Base directory where to find all source '
+ 'files (defaults to the source file\'s directory)')
+ ..addOption('package-root', help: 'Where to find "package:" imports'
+ '(defaults to the "packages/" subdirectory next to the source file)')
+ ..addFlag('help', abbr: 'h', help: 'Displays this help message',
+ defaultsTo: false, negatable: false);
+ try {
+ var results = parser.parse(arguments);
+ if (checkUsage && (results['help'] || results.rest.length == 0)) {
+ showUsage(parser);
+ return null;
+ }
+ return new CompilerOptions.fromArgs(results);
+ } on FormatException catch (e) {
+ print(e.message);
+ showUsage(parser);
+ return null;
+ }
+ }
+
+ static showUsage(parser) {
+ print('Usage: dwc [options...] input.html');
+ print(parser.getUsage());
+ }
+}
diff --git a/pkg/polymer/lib/src/css_analyzer.dart b/pkg/polymer/lib/src/css_analyzer.dart
new file mode 100644
index 0000000..270af5d
--- /dev/null
+++ b/pkg/polymer/lib/src/css_analyzer.dart
@@ -0,0 +1,507 @@
+// 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.
+
+/** Portion of the analyzer dealing with CSS sources. */
+library polymer.src.css_analyzer;
+
+import 'package:csslib/parser.dart' as css;
+import 'package:csslib/visitor.dart';
+import 'package:html5lib/dom.dart';
+import 'package:html5lib/dom_parsing.dart';
+
+import 'info.dart';
+import 'files.dart' show SourceFile;
+import 'messages.dart';
+import 'compiler_options.dart';
+
+void analyzeCss(String packageRoot, List<SourceFile> files,
+ Map<String, FileInfo> info, Map<String, String> pseudoElements,
+ Messages messages, {warningsAsErrors: false}) {
+ var analyzer = new _AnalyzerCss(packageRoot, info, pseudoElements, messages,
+ warningsAsErrors);
+ for (var file in files) analyzer.process(file);
+ analyzer.normalize();
+}
+
+class _AnalyzerCss {
+ final String packageRoot;
+ final Map<String, FileInfo> info;
+ final Map<String, String> _pseudoElements;
+ final Messages _messages;
+ final bool _warningsAsErrors;
+
+ Set<StyleSheet> allStyleSheets = new Set<StyleSheet>();
+
+ /**
+ * [_pseudoElements] list of known pseudo attributes found in HTML, any
+ * CSS pseudo-elements 'name::custom-element' is mapped to the manged name
+ * associated with the pseudo-element key.
+ */
+ _AnalyzerCss(this.packageRoot, this.info, this._pseudoElements,
+ this._messages, this._warningsAsErrors);
+
+ /**
+ * Run the analyzer on every file that is a style sheet or any component that
+ * has a style tag.
+ */
+ void process(SourceFile file) {
+ var fileInfo = info[file.path];
+ if (file.isStyleSheet || fileInfo.styleSheets.length > 0) {
+ var styleSheets = processVars(fileInfo);
+
+ // Add to list of all style sheets analyzed.
+ allStyleSheets.addAll(styleSheets);
+ }
+
+ // Process any components.
+ for (var component in fileInfo.declaredComponents) {
+ var all = processVars(component);
+
+ // Add to list of all style sheets analyzed.
+ allStyleSheets.addAll(all);
+ }
+
+ processCustomPseudoElements();
+ }
+
+ void normalize() {
+ // Remove all var definitions for all style sheets analyzed.
+ for (var tree in allStyleSheets) new _RemoveVarDefinitions().visitTree(tree);
+ }
+
+ List<StyleSheet> processVars(var libraryInfo) {
+ // Get list of all stylesheet(s) dependencies referenced from this file.
+ var styleSheets = _dependencies(libraryInfo).toList();
+
+ var errors = [];
+ css.analyze(styleSheets, errors: errors, options:
+ [_warningsAsErrors ? '--warnings_as_errors' : '', 'memory']);
+
+ // Print errors as warnings.
+ for (var e in errors) {
+ _messages.warning(e.message, e.span);
+ }
+
+ // Build list of all var definitions.
+ Map varDefs = new Map();
+ for (var tree in styleSheets) {
+ var allDefs = (new _VarDefinitions()..visitTree(tree)).found;
+ allDefs.forEach((key, value) {
+ varDefs[key] = value;
+ });
+ }
+
+ // Resolve all definitions to a non-VarUsage (terminal expression).
+ varDefs.forEach((key, value) {
+ for (var expr in (value.expression as Expressions).expressions) {
+ var def = _findTerminalVarDefinition(varDefs, value);
+ varDefs[key] = def;
+ }
+ });
+
+ // Resolve all var usages.
+ for (var tree in styleSheets) new _ResolveVarUsages(varDefs).visitTree(tree);
+
+ return styleSheets;
+ }
+
+ processCustomPseudoElements() {
+ var polyFiller = new _PseudoElementExpander(_pseudoElements);
+ for (var tree in allStyleSheets) {
+ polyFiller.visitTree(tree);
+ }
+ }
+
+ /**
+ * Given a component or file check if any stylesheets referenced. If so then
+ * return a list of all referenced stylesheet dependencies (@imports or <link
+ * rel="stylesheet" ..>).
+ */
+ Set<StyleSheet> _dependencies(var libraryInfo, {Set<StyleSheet> seen}) {
+ if (seen == null) seen = new Set();
+
+ // Used to resolve all pathing information.
+ var inputUrl = libraryInfo is FileInfo
+ ? libraryInfo.inputUrl
+ : (libraryInfo as ComponentInfo).declaringFile.inputUrl;
+
+ for (var styleSheet in libraryInfo.styleSheets) {
+ if (!seen.contains(styleSheet)) {
+ // TODO(terry): VM uses expandos to implement hashes. Currently, it's a
+ // linear (not constant) time cost (see dartbug.com/5746).
+ // If this bug isn't fixed and performance show's this a
+ // a problem we'll need to implement our own hashCode or
+ // use a different key for better perf.
+ // Add the stylesheet.
+ seen.add(styleSheet);
+
+ // Any other imports in this stylesheet?
+ var urlInfos = findImportsInStyleSheet(styleSheet, packageRoot,
+ inputUrl, _messages);
+
+ // Process other imports in this stylesheets.
+ for (var importSS in urlInfos) {
+ var importInfo = info[importSS.resolvedPath];
+ if (importInfo != null) {
+ // Add all known stylesheets processed.
+ seen.addAll(importInfo.styleSheets);
+ // Find dependencies for stylesheet referenced with a
+ // @import
+ for (var ss in importInfo.styleSheets) {
+ var urls = findImportsInStyleSheet(ss, packageRoot, inputUrl,
+ _messages);
+ for (var url in urls) {
+ _dependencies(info[url.resolvedPath], seen: seen);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return seen;
+ }
+}
+
+/**
+ * Find var- definitions in a style sheet.
+ * [found] list of known definitions.
+ */
+class _VarDefinitions extends Visitor {
+ final Map<String, VarDefinition> found = new Map();
+
+ void visitTree(StyleSheet tree) {
+ visitStyleSheet(tree);
+ }
+
+ visitVarDefinition(VarDefinition node) {
+ // Replace with latest variable definition.
+ found[node.definedName] = node;
+ super.visitVarDefinition(node);
+ }
+
+ void visitVarDefinitionDirective(VarDefinitionDirective node) {
+ visitVarDefinition(node.def);
+ }
+}
+
+/**
+ * Resolve any CSS expression which contains a var() usage to the ultimate real
+ * CSS expression value e.g.,
+ *
+ * var-one: var(two);
+ * var-two: #ff00ff;
+ *
+ * .test {
+ * color: var(one);
+ * }
+ *
+ * then .test's color would be #ff00ff
+ */
+class _ResolveVarUsages extends Visitor {
+ final Map<String, VarDefinition> varDefs;
+ bool inVarDefinition = false;
+ bool inUsage = false;
+ Expressions currentExpressions;
+
+ _ResolveVarUsages(this.varDefs);
+
+ void visitTree(StyleSheet tree) {
+ visitStyleSheet(tree);
+ }
+
+ void visitVarDefinition(VarDefinition varDef) {
+ inVarDefinition = true;
+ super.visitVarDefinition(varDef);
+ inVarDefinition = false;
+ }
+
+ void visitExpressions(Expressions node) {
+ currentExpressions = node;
+ super.visitExpressions(node);
+ currentExpressions = null;
+ }
+
+ void visitVarUsage(VarUsage node) {
+ // Don't process other var() inside of a varUsage. That implies that the
+ // default is a var() too. Also, don't process any var() inside of a
+ // varDefinition (they're just place holders until we've resolved all real
+ // usages.
+ if (!inUsage && !inVarDefinition && currentExpressions != null) {
+ var expressions = currentExpressions.expressions;
+ var index = expressions.indexOf(node);
+ assert(index >= 0);
+ var def = varDefs[node.name];
+ if (def != null) {
+ // Found a VarDefinition use it.
+ _resolveVarUsage(currentExpressions.expressions, index, def);
+ } else if (node.defaultValues.any((e) => e is VarUsage)) {
+ // Don't have a VarDefinition need to use default values resolve all
+ // default values.
+ var terminalDefaults = [];
+ for (var defaultValue in node.defaultValues) {
+ terminalDefaults.addAll(resolveUsageTerminal(defaultValue));
+ }
+ expressions.replaceRange(index, index + 1, terminalDefaults);
+ } else {
+ // No VarDefinition but default value is a terminal expression; use it.
+ expressions.replaceRange(index, index + 1, node.defaultValues);
+ }
+ }
+
+ inUsage = true;
+ super.visitVarUsage(node);
+ inUsage = false;
+ }
+
+ List<Expression> resolveUsageTerminal(VarUsage usage) {
+ var result = [];
+
+ var varDef = varDefs[usage.name];
+ var expressions;
+ if (varDef == null) {
+ // VarDefinition not found try the defaultValues.
+ expressions = usage.defaultValues;
+ } else {
+ // Use the VarDefinition found.
+ expressions = (varDef.expression as Expressions).expressions;
+ }
+
+ for (var expr in expressions) {
+ if (expr is VarUsage) {
+ // Get terminal value.
+ result.addAll(resolveUsageTerminal(expr));
+ }
+ }
+
+ // We're at a terminal just return the VarDefinition expression.
+ if (result.isEmpty && varDef != null) {
+ result = (varDef.expression as Expressions).expressions;
+ }
+
+ return result;
+ }
+
+ _resolveVarUsage(List<Expressions> expressions, int index,
+ VarDefinition def) {
+ var defExpressions = (def.expression as Expressions).expressions;
+ expressions.replaceRange(index, index + 1, defExpressions);
+ }
+}
+
+/** Remove all var definitions. */
+class _RemoveVarDefinitions extends Visitor {
+ void visitTree(StyleSheet tree) {
+ visitStyleSheet(tree);
+ }
+
+ void visitStyleSheet(StyleSheet ss) {
+ ss.topLevels.removeWhere((e) => e is VarDefinitionDirective);
+ super.visitStyleSheet(ss);
+ }
+
+ void visitDeclarationGroup(DeclarationGroup node) {
+ node.declarations.removeWhere((e) => e is VarDefinition);
+ super.visitDeclarationGroup(node);
+ }
+}
+
+/**
+ * Process all selectors looking for a pseudo-element in a selector. If the
+ * name is found in our list of known pseudo-elements. Known pseudo-elements
+ * are built when parsing a component looking for an attribute named "pseudo".
+ * The value of the pseudo attribute is the name of the custom pseudo-element.
+ * The name is mangled so Dart/JS can't directly access the pseudo-element only
+ * CSS can access a custom pseudo-element (and see issue #510, querying needs
+ * access to custom pseudo-elements).
+ *
+ * Change the custom pseudo-element to be a child of the pseudo attribute's
+ * mangled custom pseudo element name. e.g,
+ *
+ * .test::x-box
+ *
+ * would become:
+ *
+ * .test > *[pseudo="x-box_2"]
+ */
+class _PseudoElementExpander extends Visitor {
+ final Map<String, String> _pseudoElements;
+
+ _PseudoElementExpander(this._pseudoElements);
+
+ void visitTree(StyleSheet tree) => visitStyleSheet(tree);
+
+ visitSelector(Selector node) {
+ var selectors = node.simpleSelectorSequences;
+ for (var index = 0; index < selectors.length; index++) {
+ var selector = selectors[index].simpleSelector;
+ if (selector is PseudoElementSelector) {
+ if (_pseudoElements.containsKey(selector.name)) {
+ // Pseudo Element is a custom element.
+ var mangledName = _pseudoElements[selector.name];
+
+ var span = selectors[index].span;
+
+ var attrSelector = new AttributeSelector(
+ new Identifier('pseudo', span), css.TokenKind.EQUALS,
+ mangledName, span);
+ // The wildcard * namespace selector.
+ var wildCard = new ElementSelector(new Wildcard(span), span);
+ selectors[index] = new SimpleSelectorSequence(wildCard, span,
+ css.TokenKind.COMBINATOR_GREATER);
+ selectors.insert(++index,
+ new SimpleSelectorSequence(attrSelector, span));
+ }
+ }
+ }
+ }
+}
+
+List<UrlInfo> findImportsInStyleSheet(StyleSheet styleSheet,
+ String packageRoot, UrlInfo inputUrl, Messages messages) {
+ var visitor = new _CssImports(packageRoot, inputUrl, messages);
+ visitor.visitTree(styleSheet);
+ return visitor.urlInfos;
+}
+
+/**
+ * Find any imports in the style sheet; normalize the style sheet href and
+ * return a list of all fully qualified CSS files.
+ */
+class _CssImports extends Visitor {
+ final String packageRoot;
+
+ /** Input url of the css file, used to normalize relative import urls. */
+ final UrlInfo inputUrl;
+
+ /** List of all imported style sheets. */
+ final List<UrlInfo> urlInfos = [];
+
+ final Messages _messages;
+
+ _CssImports(this.packageRoot, this.inputUrl, this._messages);
+
+ void visitTree(StyleSheet tree) {
+ visitStyleSheet(tree);
+ }
+
+ void visitImportDirective(ImportDirective node) {
+ var urlInfo = UrlInfo.resolve(node.import, inputUrl,
+ node.span, packageRoot, _messages, ignoreAbsolute: true);
+ if (urlInfo == null) return;
+ urlInfos.add(urlInfo);
+ }
+}
+
+StyleSheet parseCss(String content, Messages messages,
+ CompilerOptions options) {
+ if (content.trim().isEmpty) return null;
+
+ var errors = [];
+
+ // TODO(terry): Add --checked when fully implemented and error handling.
+ var stylesheet = css.parse(content, errors: errors, options:
+ [options.warningsAsErrors ? '--warnings_as_errors' : '', 'memory']);
+
+ // Note: errors aren't fatal in HTML (unless strict mode is on).
+ // So just print them as warnings.
+ for (var e in errors) {
+ messages.warning(e.message, e.span);
+ }
+
+ return stylesheet;
+}
+
+/** Find terminal definition (non VarUsage implies real CSS value). */
+VarDefinition _findTerminalVarDefinition(Map<String, VarDefinition> varDefs,
+ VarDefinition varDef) {
+ var expressions = varDef.expression as Expressions;
+ for (var expr in expressions.expressions) {
+ if (expr is VarUsage) {
+ var usageName = (expr as VarUsage).name;
+ var foundDef = varDefs[usageName];
+
+ // If foundDef is unknown check if defaultValues; if it exist then resolve
+ // to terminal value.
+ if (foundDef == null) {
+ // We're either a VarUsage or terminal definition if in varDefs;
+ // either way replace VarUsage with it's default value because the
+ // VarDefinition isn't found.
+ var defaultValues = (expr as VarUsage).defaultValues;
+ var replaceExprs = expressions.expressions;
+ assert(replaceExprs.length == 1);
+ replaceExprs.replaceRange(0, 1, defaultValues);
+ return varDef;
+ }
+ if (foundDef is VarDefinition) {
+ return _findTerminalVarDefinition(varDefs, foundDef);
+ }
+ } else {
+ // Return real CSS property.
+ return varDef;
+ }
+ }
+
+ // Didn't point to a var definition that existed.
+ return varDef;
+}
+
+/**
+ * Find urls imported inside style tags under [info]. If [info] is a FileInfo
+ * then process only style tags in the body (don't process any style tags in a
+ * component). If [info] is a ComponentInfo only process style tags inside of
+ * the element are processed. For an [info] of type FileInfo [node] is the
+ * file's document and for an [info] of type ComponentInfo then [node] is the
+ * component's element tag.
+ */
+List<UrlInfo> findUrlsImported(LibraryInfo info, UrlInfo inputUrl,
+ String packageRoot, Node node, Messages messages, CompilerOptions options) {
+ // Process any @imports inside of the <style> tag.
+ var styleProcessor =
+ new _CssStyleTag(packageRoot, info, inputUrl, messages, options);
+ styleProcessor.visit(node);
+ return styleProcessor.imports;
+}
+
+/* Process CSS inside of a style tag. */
+class _CssStyleTag extends TreeVisitor {
+ final String _packageRoot;
+
+ /** Either a FileInfo or ComponentInfo. */
+ final LibraryInfo _info;
+ final Messages _messages;
+ final CompilerOptions _options;
+
+ /**
+ * Path of the declaring file, for a [_info] of type FileInfo it's the file's
+ * path for a type ComponentInfo it's the declaring file path.
+ */
+ final UrlInfo _inputUrl;
+
+ /** List of @imports found. */
+ List<UrlInfo> imports = [];
+
+ _CssStyleTag(this._packageRoot, this._info, this._inputUrl, this._messages,
+ this._options);
+
+ void visitElement(Element node) {
+ // Don't process any style tags inside of element if we're processing a
+ // FileInfo. The style tags inside of a component defintion will be
+ // processed when _info is a ComponentInfo.
+ if (node.tagName == 'polymer-element' && _info is FileInfo) return;
+ if (node.tagName == 'style') {
+ // Parse the contents of the scoped style tag.
+ var styleSheet = parseCss(node.nodes.single.value, _messages, _options);
+ if (styleSheet != null) {
+ _info.styleSheets.add(styleSheet);
+
+ // Find all imports return list of @imports in this style tag.
+ var urlInfos = findImportsInStyleSheet(styleSheet, _packageRoot,
+ _inputUrl, _messages);
+ imports.addAll(urlInfos);
+ }
+ }
+ super.visitElement(node);
+ }
+}
diff --git a/pkg/polymer/lib/src/css_emitters.dart b/pkg/polymer/lib/src/css_emitters.dart
new file mode 100644
index 0000000..d1863f5
--- /dev/null
+++ b/pkg/polymer/lib/src/css_emitters.dart
@@ -0,0 +1,155 @@
+// 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 polymer.src.css_emitters;
+
+import 'package:csslib/visitor.dart' show Visitor, CssPrinter, ElementSelector,
+ UriTerm, Selector, HostDirective, SimpleSelectorSequence, StyleSheet;
+
+import 'info.dart';
+import 'paths.dart' show PathMapper;
+import 'utils.dart';
+
+void rewriteCssUris(PathMapper pathMapper, String cssPath, bool rewriteUrls,
+ StyleSheet styleSheet) {
+ new _UriVisitor(pathMapper, cssPath, rewriteUrls).visitTree(styleSheet);
+}
+
+/** Compute each CSS URI resource relative from the generated CSS file. */
+class _UriVisitor extends Visitor {
+ /**
+ * Relative path from the output css file to the location of the original
+ * css file that contained the URI to each resource.
+ */
+ final String _pathToOriginalCss;
+
+ factory _UriVisitor(PathMapper pathMapper, String cssPath, bool rewriteUrl) {
+ var cssDir = path.dirname(cssPath);
+ var outCssDir = rewriteUrl ? pathMapper.outputDirPath(cssPath)
+ : path.dirname(cssPath);
+ return new _UriVisitor._internal(path.relative(cssDir, from: outCssDir));
+ }
+
+ _UriVisitor._internal(this._pathToOriginalCss);
+
+ void visitUriTerm(UriTerm node) {
+ // Don't touch URIs that have any scheme (http, etc.).
+ var uri = Uri.parse(node.text);
+ if (uri.host != '') return;
+ if (uri.scheme != '' && uri.scheme != 'package') return;
+
+ node.text = pathToUrl(
+ path.normalize(path.join(_pathToOriginalCss, node.text)));
+ }
+}
+
+
+/** Emit the contents of the style tag outside of a component. */
+String emitStyleSheet(StyleSheet ss, FileInfo file) =>
+ (new _CssEmitter(file.components.keys.toSet())
+ ..visitTree(ss, pretty: true)).toString();
+
+/** Emit a component's style tag content emulating scoped css. */
+String emitComponentStyleSheet(StyleSheet ss, String tagName) =>
+ (new _ComponentCssEmitter(tagName)..visitTree(ss, pretty: true)).toString();
+
+String emitOriginalCss(StyleSheet css) =>
+ (new CssPrinter()..visitTree(css)).toString();
+
+/** Only x-tag name element selectors are emitted as [is="x-"]. */
+class _CssEmitter extends CssPrinter {
+ final Set _componentsTag;
+ _CssEmitter(this._componentsTag);
+
+ void visitElementSelector(ElementSelector node) {
+ // If element selector is a component's tag name, then change selector to
+ // find element who's is attribute's the component's name.
+ if (_componentsTag.contains(node.name)) {
+ emit('[is="${node.name}"]');
+ return;
+ }
+ super.visitElementSelector(node);
+ }
+}
+
+/**
+ * Emits a css stylesheet applying rules to emulate scoped css. The rules adjust
+ * element selectors to include the component's tag name.
+ */
+class _ComponentCssEmitter extends CssPrinter {
+ final String _componentTagName;
+ bool _inHostDirective = false;
+ bool _selectorStartInHostDirective = false;
+
+ _ComponentCssEmitter(this._componentTagName);
+
+ /** Is the element selector an x-tag name. */
+ bool _isSelectorElementXTag(Selector node) {
+ if (node.simpleSelectorSequences.length > 0) {
+ var selector = node.simpleSelectorSequences[0].simpleSelector;
+ return selector is ElementSelector && selector.name == _componentTagName;
+ }
+ return false;
+ }
+
+ void visitSelector(Selector node) {
+ // If the selector starts with an x-tag name don't emit it twice.
+ if (!_isSelectorElementXTag(node)) {
+ if (_inHostDirective) {
+ // Style the element that's hosting the component, therefore don't emit
+ // the descendent combinator (first space after the [is="x-..."]).
+ emit('[is="$_componentTagName"]');
+ // Signal that first simpleSelector must be checked.
+ _selectorStartInHostDirective = true;
+ } else {
+ // Emit its scoped as a descendent (space at end).
+ emit('[is="$_componentTagName"] ');
+ }
+ }
+ super.visitSelector(node);
+ }
+
+ /**
+ * If first simple selector of a ruleset in a @host directive is a wildcard
+ * then don't emit the wildcard.
+ */
+ void visitSimpleSelectorSequence(SimpleSelectorSequence node) {
+ if (_selectorStartInHostDirective) {
+ _selectorStartInHostDirective = false;
+ if (node.simpleSelector.isWildcard) {
+ // Skip the wildcard if first item in the sequence.
+ return;
+ }
+ assert(node.isCombinatorNone);
+ }
+
+ super.visitSimpleSelectorSequence(node);
+ }
+
+ void visitElementSelector(ElementSelector node) {
+ // If element selector is the component's tag name, then change selector to
+ // find element who's is attribute is the component's name.
+ if (_componentTagName == node.name) {
+ emit('[is="$_componentTagName"]');
+ return;
+ }
+ super.visitElementSelector(node);
+ }
+
+ /**
+ * If we're polyfilling scoped styles the @host directive is stripped. Any
+ * ruleset(s) processed in an @host will fixup the first selector. See
+ * visitSelector and visitSimpleSelectorSequence in this class, they adjust
+ * the selectors so it styles the element hosting the compopnent.
+ */
+ void visitHostDirective(HostDirective node) {
+ _inHostDirective = true;
+ emit('/* @host */');
+ for (var ruleset in node.rulesets) {
+ ruleset.visit(this);
+ }
+ _inHostDirective = false;
+ emit('/* end of @host */\n');
+ }
+}
diff --git a/pkg/polymer/lib/src/custom_tag_name.dart b/pkg/polymer/lib/src/custom_tag_name.dart
new file mode 100644
index 0000000..637b937
--- /dev/null
+++ b/pkg/polymer/lib/src/custom_tag_name.dart
@@ -0,0 +1,27 @@
+// 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 polymer.src.custom_tag_name;
+
+/**
+ * Returns true if this is a valid custom element name. See:
+ * <https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/index.html#dfn-custom-element-name>
+ */
+bool isCustomTag(String name) {
+ if (name == null || !name.contains('-')) return false;
+
+ // These names have meaning in SVG or MathML, so they aren't allowed as custom
+ // tags.
+ var invalidNames = const {
+ 'annotation-xml': '',
+ 'color-profile': '',
+ 'font-face': '',
+ 'font-face-src': '',
+ 'font-face-uri': '',
+ 'font-face-format': '',
+ 'font-face-name': '',
+ 'missing-glyph': '',
+ };
+ return !invalidNames.containsKey(name);
+}
diff --git a/pkg/polymer/lib/src/dart_parser.dart b/pkg/polymer/lib/src/dart_parser.dart
new file mode 100644
index 0000000..a2f44c3
--- /dev/null
+++ b/pkg/polymer/lib/src/dart_parser.dart
@@ -0,0 +1,132 @@
+// 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.
+
+/**
+ * Parser for Dart code based on the experimental analyzer.
+ */
+library dart_parser;
+
+import 'package:analyzer_experimental/src/generated/ast.dart';
+import 'package:analyzer_experimental/src/generated/error.dart';
+import 'package:analyzer_experimental/src/generated/parser.dart';
+import 'package:analyzer_experimental/src/generated/scanner.dart';
+import 'package:source_maps/span.dart' show SourceFile, SourceFileSegment, Location;
+import 'utils.dart' show escapeDartString;
+
+/** Information extracted from a source Dart file. */
+class DartCodeInfo {
+
+ /** Library qualified identifier, if any. */
+ final String libraryName;
+
+ /** Library which the code is part-of, if any. */
+ final String partOf;
+
+ /** Declared imports, exports, and parts. */
+ final List<Directive> directives;
+
+ /** Source file representation used to compute source map information. */
+ final SourceFile sourceFile;
+
+ /** The parsed code. */
+ final CompilationUnit compilationUnit;
+
+ /** The full source code. */
+ final String code;
+
+ DartCodeInfo(this.libraryName, this.partOf, this.directives, code,
+ this.sourceFile, [compilationUnit])
+ : this.code = code,
+ this.compilationUnit = compilationUnit == null
+ ? _parseCompilationUnit(code) : compilationUnit;
+
+ bool get isPart =>
+ compilationUnit.directives.any((d) => d is PartOfDirective);
+
+ int get directivesEnd {
+ if (compilationUnit.directives.length == 0) return 0;
+ return compilationUnit.directives.last.end;
+ }
+
+ /**
+ * The position of the first "part" directive. If none is found,
+ * this behaves like [directivesEnd].
+ */
+ int get firstPartOffset {
+ for (var directive in compilationUnit.directives) {
+ if (directive is PartDirective) return directive.offset;
+ }
+ // No part directives, just return directives end.
+ return directivesEnd;
+ }
+
+ /** Gets the code after the [directives]. */
+ String codeAfterDirectives() => code.substring(directivesEnd);
+
+ ClassDeclaration findClass(String name) {
+ for (var decl in compilationUnit.declarations) {
+ if (decl is ClassDeclaration) {
+ if (decl.name.name == name) return decl;
+ }
+ }
+ return null;
+ }
+}
+
+SimpleStringLiteral createStringLiteral(String contents) {
+ var lexeme = "'${escapeDartString(contents)}'";
+ var token = new StringToken(TokenType.STRING, lexeme, null);
+ return new SimpleStringLiteral.full(token, contents);
+}
+
+
+/**
+ * Parse and extract top-level directives from [code].
+ *
+ */
+// TODO(sigmund): log emitted error/warning messages
+DartCodeInfo parseDartCode(String path, String code, [Location offset]) {
+ var unit = _parseCompilationUnit(code);
+
+ // Extract some information from the compilation unit.
+ String libraryName, partName;
+ var directives = [];
+ int directiveEnd = 0;
+ for (var directive in unit.directives) {
+ if (directive is LibraryDirective) {
+ libraryName = directive.name.name;
+ } else if (directive is PartOfDirective) {
+ partName = directive.libraryName.name;
+ } else {
+ assert(directive is UriBasedDirective);
+ // Normalize the library URI.
+ var uriNode = directive.uri;
+ if (uriNode is! SimpleStringLiteral) {
+ String uri = uriNode.accept(new ConstantEvaluator());
+ directive.uri = createStringLiteral(uri);
+ }
+ directives.add(directive);
+ }
+ }
+
+ var sourceFile = offset == null
+ ? new SourceFile.text(path, code)
+ : new SourceFileSegment(path, code, offset);
+
+ return new DartCodeInfo(libraryName, partName, directives, code,
+ sourceFile, unit);
+}
+
+CompilationUnit _parseCompilationUnit(String code) {
+ var errorListener = new _ErrorCollector();
+ var scanner = new StringScanner(null, code, errorListener);
+ var token = scanner.tokenize();
+ var parser = new Parser(null, errorListener);
+ return parser.parseCompilationUnit(token);
+}
+
+class _ErrorCollector extends AnalysisErrorListener {
+ final errors = new List<AnalysisError>();
+ onError(error) => errors.add(error);
+}
diff --git a/pkg/polymer/lib/src/emitters.dart b/pkg/polymer/lib/src/emitters.dart
new file mode 100644
index 0000000..dbd6816
--- /dev/null
+++ b/pkg/polymer/lib/src/emitters.dart
@@ -0,0 +1,249 @@
+// 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.
+
+/** Collects several code emitters for the template tool. */
+library emitters;
+
+import 'package:html5lib/dom.dart';
+import 'package:html5lib/dom_parsing.dart' show TreeVisitor;
+import 'package:html5lib/parser.dart' show parseFragment;
+import 'package:source_maps/printer.dart';
+import 'package:source_maps/refactor.dart';
+
+import 'compiler_options.dart';
+import 'css_emitters.dart' show emitStyleSheet, emitOriginalCss;
+import 'html5_utils.dart';
+import 'info.dart' show ComponentInfo, FileInfo, GlobalInfo;
+import 'messages.dart';
+import 'paths.dart' show PathMapper;
+import 'utils.dart' show escapeDartString, path;
+
+/** Generates the class corresponding to a single web component. */
+NestedPrinter emitPolymerElement(ComponentInfo info, PathMapper pathMapper,
+ TextEditTransaction transaction, CompilerOptions options) {
+ if (info.classDeclaration == null) return null;
+
+ var codeInfo = info.userCode;
+ if (transaction == null) {
+ // TODO(sigmund): avoid emitting this file if we don't need to do any
+ // modifications (e.g. no @observable and not adding the libraryName).
+ transaction = new TextEditTransaction(codeInfo.code, codeInfo.sourceFile);
+ }
+ if (codeInfo.libraryName == null) {
+ // For deploy, we need to import the library associated with the component,
+ // so we need to ensure there is a library directive.
+ var libraryName = info.tagName.replaceAll(new RegExp('[-./]'), '_');
+ transaction.edit(0, 0, 'library $libraryName;');
+ }
+ return transaction.commit();
+}
+
+/** The code that will be used to bootstrap the application. */
+NestedPrinter generateBootstrapCode(
+ FileInfo info, FileInfo userMainInfo, GlobalInfo global,
+ PathMapper pathMapper, CompilerOptions options) {
+
+ var printer = new NestedPrinter(0)
+ ..addLine('library app_bootstrap;')
+ ..addLine('')
+ ..addLine("import 'package:polymer/polymer.dart';")
+ ..addLine("import 'dart:mirrors' show currentMirrorSystem;");
+
+ int i = 0;
+ for (var c in global.components.values) {
+ if (c.hasConflict) continue;
+ printer.addLine("import '${pathMapper.importUrlFor(info, c)}' as i$i;");
+ i++;
+ }
+ if (userMainInfo.userCode != null) {
+ printer..addLine("import '${pathMapper.importUrlFor(info, userMainInfo)}' "
+ "as i$i;\n");
+ }
+
+ printer..addLine('')
+ ..addLine('void main() {')
+ ..indent += 1
+ ..addLine("initPolymer([")
+ ..indent += 2;
+
+ for (var c in global.components.values) {
+ if (c.hasConflict) continue;
+ printer.addLine("'${pathMapper.importUrlFor(info, c)}',");
+ }
+
+ if (userMainInfo.userCode != null) {
+ printer.addLine("'${pathMapper.importUrlFor(info, userMainInfo)}',");
+ }
+
+ return printer
+ ..indent -= 1
+ ..addLine('],')
+ ..addLine(
+ "currentMirrorSystem().findLibrary(const Symbol('app_bootstrap'))")
+ ..indent += 2
+ ..addLine(".first.uri.toString());")
+ ..indent -= 4
+ ..addLine('}');
+}
+
+
+/**
+ * Rewrites attributes that contain relative URL (excluding src urls in script
+ * and link tags which are already rewritten by other parts of the compiler).
+*/
+class _AttributeUrlTransform extends TreeVisitor {
+ final String filePath;
+ final PathMapper pathMapper;
+
+ _AttributeUrlTransform(this.filePath, this.pathMapper);
+
+ visitElement(Element node) {
+ if (node.tagName == 'script') return;
+ if (node.tagName == 'link') return;
+
+ for (var key in node.attributes.keys) {
+ if (urlAttributes.contains(key)) {
+ node.attributes[key] =
+ pathMapper.transformUrl(filePath, node.attributes[key]);
+ }
+ }
+ super.visitElement(node);
+ }
+}
+
+final _shadowDomJS = new RegExp(r'shadowdom\..*\.js', caseSensitive: false);
+final _bootJS = new RegExp(r'.*/polymer/boot.js', caseSensitive: false);
+
+/** Trim down the html for the main html page. */
+void transformMainHtml(Document document, FileInfo fileInfo,
+ PathMapper pathMapper, bool hasCss, bool rewriteUrls,
+ Messages messages, GlobalInfo global, String bootstrapOutName) {
+ var filePath = fileInfo.inputUrl.resolvedPath;
+
+ var dartLoaderTag = null;
+ bool shadowDomFound = false;
+ for (var tag in document.queryAll('script')) {
+ var src = tag.attributes['src'];
+ if (src != null) {
+ var last = src.split('/').last;
+ if (last == 'dart.js' || last == 'testing.js') {
+ dartLoaderTag = tag;
+ } else if (_shadowDomJS.hasMatch(last)) {
+ shadowDomFound = true;
+ }
+ }
+ if (tag.attributes['type'] == 'application/dart') {
+ tag.remove();
+ } else if (src != null) {
+ if (_bootJS.hasMatch(src)) {
+ tag.remove();
+ } else if (rewriteUrls) {
+ tag.attributes["src"] = pathMapper.transformUrl(filePath, src);
+ }
+ }
+ }
+
+ for (var tag in document.queryAll('link')) {
+ var href = tag.attributes['href'];
+ var rel = tag.attributes['rel'];
+ if (rel == 'component' || rel == 'components' || rel == 'import') {
+ tag.remove();
+ } else if (href != null && rewriteUrls && !hasCss) {
+ // Only rewrite URL if rewrite on and we're not CSS polyfilling.
+ tag.attributes['href'] = pathMapper.transformUrl(filePath, href);
+ }
+ }
+
+ if (rewriteUrls) {
+ // Transform any element's attribute which is a relative URL.
+ new _AttributeUrlTransform(filePath, pathMapper).visit(document);
+ }
+
+ if (hasCss) {
+ var newCss = pathMapper.mangle(path.basename(filePath), '.css', true);
+ var linkElem = new Element.html(
+ '<link rel="stylesheet" type="text/css" href="$newCss">');
+ document.head.insertBefore(linkElem, null);
+ }
+
+ var styles = document.queryAll('style');
+ if (styles.length > 0) {
+ var allCss = new StringBuffer();
+ fileInfo.styleSheets.forEach((styleSheet) =>
+ allCss.write(emitStyleSheet(styleSheet, fileInfo)));
+ styles[0].nodes.clear();
+ styles[0].nodes.add(new Text(allCss.toString()));
+ for (var i = styles.length - 1; i > 0 ; i--) {
+ styles[i].remove();
+ }
+ }
+
+ // TODO(jmesserly): put this in the global CSS file?
+ // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html#css-additions
+ document.head.nodes.insert(0, parseFragment(
+ '<style>template { display: none; }</style>'));
+
+ // Move all <element> declarations to the main HTML file
+ // TODO(sigmund): remove this once we have HTMLImports implemented.
+ for (var c in global.components.values) {
+ document.body.nodes.insert(0, new Text('\n'));
+ var fragment = c.element;
+ for (var tag in fragment.queryAll('script')) {
+ // TODO(sigmund): leave script tags around when we start using "boot.js"
+ if (tag.attributes['type'] == 'application/dart') {
+ tag.remove();
+ }
+ }
+ document.body.nodes.insert(0, fragment);
+ }
+
+ if (!shadowDomFound) {
+ // TODO(jmesserly): we probably shouldn't add this automatically.
+ document.body.nodes.add(parseFragment('<script type="text/javascript" '
+ 'src="packages/shadow_dom/shadow_dom.debug.js"></script>\n'));
+
+ // JS interop code required for Polymer CSS shimming.
+ document.body.nodes.add(parseFragment('<script type="text/javascript" '
+ 'src="packages/browser/interop.js"></script>\n'));
+ }
+
+ var bootstrapScript = parseFragment(
+ '<script type="application/dart" src="$bootstrapOutName"></script>');
+ if (dartLoaderTag == null) {
+ document.body.nodes.add(bootstrapScript);
+ // TODO(jmesserly): turn this warning on.
+ //messages.warning('Missing script to load Dart. '
+ // 'Please add this line to your HTML file: $dartLoader',
+ // document.body.sourceSpan);
+ // TODO(sigmund): switch to 'boot.js'
+ document.body.nodes.add(parseFragment('<script type="text/javascript" '
+ 'src="packages/browser/dart.js"></script>\n'));
+ } else if (dartLoaderTag.parent != document.body) {
+ document.body.nodes.add(bootstrapScript);
+ } else {
+ document.body.insertBefore(bootstrapScript, dartLoaderTag);
+ }
+
+ // Insert the "auto-generated" comment after the doctype, otherwise IE will
+ // go into quirks mode.
+ int commentIndex = 0;
+ DocumentType doctype =
+ document.nodes.firstWhere((n) => n is DocumentType, orElse: () => null);
+ if (doctype != null) {
+ commentIndex = document.nodes.indexOf(doctype) + 1;
+ // TODO(jmesserly): the html5lib parser emits a warning for missing
+ // doctype, but it allows you to put it after comments. Presumably they do
+ // this because some comments won't force IE into quirks mode (sigh). See
+ // this link for more info:
+ // http://bugzilla.validator.nu/show_bug.cgi?id=836
+ // For simplicity we emit the warning always, like validator.nu does.
+ if (doctype.tagName != 'html' || commentIndex != 1) {
+ messages.warning('file should start with <!DOCTYPE html> '
+ 'to avoid the possibility of it being parsed in quirks mode in IE. '
+ 'See http://www.w3.org/TR/html5-diff/#doctype', doctype.sourceSpan);
+ }
+ }
+ document.nodes.insert(commentIndex, parseFragment(
+ '\n<!-- This file was auto-generated from $filePath. -->\n'));
+}
diff --git a/pkg/polymer/lib/src/file_system.dart b/pkg/polymer/lib/src/file_system.dart
new file mode 100644
index 0000000..c6af55c
--- /dev/null
+++ b/pkg/polymer/lib/src/file_system.dart
@@ -0,0 +1,35 @@
+// 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.
+
+/** Abstraction for file systems and utility functions to manipulate paths. */
+library file_system;
+
+import 'dart:async';
+
+/**
+ * Abstraction around file system access to work in a variety of different
+ * environments.
+ */
+abstract class FileSystem {
+ /**
+ * Apply all pending writes. Until this method is called, writeString is not
+ * guaranteed to have any observable impact.
+ */
+ Future flush();
+
+ /**
+ * Reads bytes if possible, but falls back to text if running in a browser.
+ * Return type is either [Future<List<int>>] or [Future<String>].
+ */
+ Future readTextOrBytes(String path);
+
+ /* Like [readTextOrBytes], but decodes bytes as UTF-8. Used for Dart code. */
+ Future<String> readText(String path);
+
+ /**
+ * Writes [text] to file at [path]. Call flush to insure that changes are
+ * visible.
+ */
+ void writeString(String path, String text);
+}
diff --git a/pkg/polymer/lib/src/file_system/console.dart b/pkg/polymer/lib/src/file_system/console.dart
new file mode 100644
index 0000000..6776745
--- /dev/null
+++ b/pkg/polymer/lib/src/file_system/console.dart
@@ -0,0 +1,47 @@
+// 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 console;
+
+import 'dart:async';
+import 'dart:io';
+import 'dart:utf';
+import 'package:polymer/src/file_system.dart';
+
+/** File system implementation for console VM (i.e. no browser). */
+class ConsoleFileSystem implements FileSystem {
+
+ /** Pending futures for file write requests. */
+ final _pending = <String, Future>{};
+
+ Future flush() => Future.wait(_pending.values.toList());
+
+ void writeString(String path, String text) {
+ if(!_pending.containsKey(path)) {
+ _pending[path] = new File(path).open(mode: FileMode.WRITE)
+ .then((file) => file.writeString(text))
+ .then((file) => file.close())
+ .whenComplete(() { _pending.remove(path); });
+ }
+ }
+
+ // TODO(jmesserly): even better would be to pass the RandomAccessFile directly
+ // to html5lib. This will require a further restructuring of FileSystem.
+ // Probably it just needs "readHtml" and "readText" methods.
+ Future<List<int>> readTextOrBytes(String path) {
+ return new File(path).open().then(
+ (file) => file.length().then((length) {
+ // TODO(jmesserly): is this guaranteed to read all of the bytes?
+ var buffer = new List<int>(length);
+ return file.readInto(buffer, 0, length)
+ .then((_) => file.close())
+ .then((_) => buffer);
+ }));
+ }
+
+ // TODO(jmesserly): do we support any encoding other than UTF-8 for Dart?
+ Future<String> readText(String path) {
+ return readTextOrBytes(path).then(decodeUtf8);
+ }
+}
diff --git a/pkg/polymer/lib/src/files.dart b/pkg/polymer/lib/src/files.dart
new file mode 100644
index 0000000..9fea763
--- /dev/null
+++ b/pkg/polymer/lib/src/files.dart
@@ -0,0 +1,47 @@
+// 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 files;
+
+import 'package:html5lib/dom.dart';
+
+/** An input file to process by the template compiler. */
+class SourceFile {
+ static const int HTML = 1;
+ static const int DART = 2;
+ static const int STYLESHEET = 3;
+
+ final String path;
+ final int type;
+
+ Document document;
+
+ /** Dart code or contents of a linked style sheet. */
+ String code;
+
+ SourceFile(this.path, {this.type: HTML});
+
+ bool get isDart => type == DART;
+ bool get isHtml => type == HTML;
+ bool get isStyleSheet => type == STYLESHEET;
+
+ String toString() => "#<SourceFile $path>";
+}
+
+/** An output file to generated by the template compiler. */
+class OutputFile {
+ final String path;
+ final String contents;
+
+ /**
+ * Path to the source file that was transformed into this OutputFile, `null`
+ * for files that are generated and do not correspond to an input
+ * [SourceFile].
+ */
+ final String source;
+
+ OutputFile(this.path, this.contents, {this.source});
+
+ String toString() => "#<OutputFile $path>";
+}
diff --git a/pkg/polymer/lib/src/html5_utils.dart b/pkg/polymer/lib/src/html5_utils.dart
new file mode 100644
index 0000000..391c12b
--- /dev/null
+++ b/pkg/polymer/lib/src/html5_utils.dart
@@ -0,0 +1,29 @@
+// 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.
+
+// TODO(jmesserly): html5lib might be a better home for this.
+// But at the moment we only need it here.
+
+library html5_utils;
+
+/**
+ * HTML attributes that expect a URL value.
+ * <http://dev.w3.org/html5/spec/section-index.html#attributes-1>
+ *
+ * Every one of these attributes is a URL in every context where it is used in
+ * the DOM. The comments show every DOM element where an attribute can be used.
+ */
+const urlAttributes = const [
+ 'action', // in form
+ 'background', // in body
+ 'cite', // in blockquote, del, ins, q
+ 'data', // in object
+ 'formaction', // in button, input
+ 'href', // in a, area, link, base, command
+ 'icon', // in command
+ 'manifest', // in html
+ 'poster', // in video
+ 'src', // in audio, embed, iframe, img, input, script, source, track,
+ // video
+];
diff --git a/pkg/polymer/lib/src/info.dart b/pkg/polymer/lib/src/info.dart
new file mode 100644
index 0000000..9a7b530
--- /dev/null
+++ b/pkg/polymer/lib/src/info.dart
@@ -0,0 +1,330 @@
+// 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.
+
+/**
+ * Datatypes holding information extracted by the analyzer and used by later
+ * phases of the compiler.
+ */
+library polymer.src.info;
+
+import 'dart:collection' show SplayTreeMap, LinkedHashMap;
+
+import 'package:analyzer_experimental/src/generated/ast.dart';
+import 'package:csslib/visitor.dart';
+import 'package:html5lib/dom.dart';
+import 'package:source_maps/span.dart' show Span;
+
+import 'dart_parser.dart' show DartCodeInfo;
+import 'messages.dart';
+import 'summary.dart';
+import 'utils.dart';
+
+/**
+ * Information that is global. Roughly corresponds to `window` and `document`.
+ */
+class GlobalInfo {
+ /**
+ * Pseudo-element names exposed in a component via a pseudo attribute.
+ * The name is only available from CSS (not Dart code) so they're mangled.
+ * The same pseudo-element in different components maps to the same
+ * mangled name (as the pseudo-element is scoped inside of the component).
+ */
+ final Map<String, String> pseudoElements = <String, String>{};
+
+ /** All components declared in the application. */
+ final Map<String, ComponentInfo> components = new SplayTreeMap();
+}
+
+/**
+ * Information for any library-like input. We consider each HTML file a library,
+ * and each component declaration a library as well. Hence we use this as a base
+ * class for both [FileInfo] and [ComponentInfo]. Both HTML files and components
+ * can have .dart code provided by the user for top-level user scripts and
+ * component-level behavior code. This code can either be inlined in the HTML
+ * file or included in a script tag with the "src" attribute.
+ */
+abstract class LibraryInfo implements LibrarySummary {
+
+ /** Whether there is any code associated with the page/component. */
+ bool get codeAttached => inlinedCode != null || externalFile != null;
+
+ /**
+ * The actual inlined code. Use [userCode] if you want the code from this file
+ * or from an external file.
+ */
+ DartCodeInfo inlinedCode;
+
+ /**
+ * If this library's code was loaded using a script tag (e.g. in a component),
+ * [externalFile] has the path to such Dart file relative from the compiler's
+ * base directory.
+ */
+ UrlInfo externalFile;
+
+ /** Info asscociated with [externalFile], if any. */
+ FileInfo externalCode;
+
+ /**
+ * The inverse of [externalCode]. If this .dart file was imported via a script
+ * tag, this refers to the HTML file that imported it.
+ */
+ LibraryInfo htmlFile;
+
+ /** File where the top-level code was defined. */
+ UrlInfo get dartCodeUrl;
+
+ /**
+ * Name of the file that will hold any generated Dart code for this library
+ * unit. Note this is initialized after parsing.
+ */
+ String outputFilename;
+
+ /** Parsed cssSource. */
+ List<StyleSheet> styleSheets = [];
+
+ /** This is used in transforming Dart code to track modified files. */
+ bool modified = false;
+
+ /**
+ * This is used in transforming Dart code to compute files that reference
+ * [modified] files.
+ */
+ List<FileInfo> referencedBy = [];
+
+ /**
+ * Components used within this library unit. For [FileInfo] these are
+ * components used directly in the page. For [ComponentInfo] these are
+ * components used within their shadowed template.
+ */
+ final Map<ComponentSummary, bool> usedComponents =
+ new LinkedHashMap<ComponentSummary, bool>();
+
+ /**
+ * The actual code, either inlined or from an external file, or `null` if none
+ * was defined.
+ */
+ DartCodeInfo get userCode =>
+ externalCode != null ? externalCode.inlinedCode : inlinedCode;
+}
+
+/** Information extracted at the file-level. */
+class FileInfo extends LibraryInfo implements HtmlFileSummary {
+ /** Relative path to this file from the compiler's base directory. */
+ final UrlInfo inputUrl;
+
+ /**
+ * Whether this file should be treated as the entry point of the web app, i.e.
+ * the file users navigate to in their browser. This will be true if this file
+ * was passed in the command line to the dwc compiler, and the
+ * `--components_only` flag was omitted.
+ */
+ final bool isEntryPoint;
+
+ // TODO(terry): Ensure that that the libraryName is a valid identifier:
+ // a..z || A..Z || _ [a..z || A..Z || 0..9 || _]*
+ String get libraryName =>
+ path.basename(inputUrl.resolvedPath).replaceAll('.', '_');
+
+ /** File where the top-level code was defined. */
+ UrlInfo get dartCodeUrl => externalFile != null ? externalFile : inputUrl;
+
+ /**
+ * All custom element definitions in this file. This may contain duplicates.
+ * Normally you should use [components] for lookup.
+ */
+ final List<ComponentInfo> declaredComponents = new List<ComponentInfo>();
+
+ /**
+ * All custom element definitions defined in this file or imported via
+ *`<link rel='components'>` tag. Maps from the tag name to the component
+ * information. This map is sorted by the tag name.
+ */
+ final Map<String, ComponentSummary> components =
+ new SplayTreeMap<String, ComponentSummary>();
+
+ /** Files imported with `<link rel="import">` */
+ final List<UrlInfo> componentLinks = <UrlInfo>[];
+
+ /** Files imported with `<link rel="stylesheet">` */
+ final List<UrlInfo> styleSheetHrefs = <UrlInfo>[];
+
+ /** Root is associated with the body node. */
+ Element body;
+
+ FileInfo(this.inputUrl, [this.isEntryPoint = false]);
+
+ /**
+ * Query for an [Element] matching the provided [tag], starting from the
+ * [body].
+ */
+ Element query(String tag) => body.query(tag);
+}
+
+
+/** Information about a web component definition declared locally. */
+// TODO(sigmund): use a mixin to pull in ComponentSummary.
+class ComponentInfo extends LibraryInfo implements ComponentSummary {
+ /** The file that declares this component. */
+ final FileInfo declaringFile;
+
+ /** The component tag name, defined with the `name` attribute on `element`. */
+ final String tagName;
+
+ /**
+ * The tag name that this component extends, defined with the `extends`
+ * attribute on `element`.
+ */
+ final String extendsTag;
+
+ /**
+ * The component info associated with the [extendsTag] name, if any.
+ * This will be `null` if the component extends a built-in HTML tag, or
+ * if the analyzer has not run yet.
+ */
+ ComponentSummary extendsComponent;
+
+ /** The Dart class containing the component's behavior. */
+ String className;
+
+ /** The Dart class declaration. */
+ ClassDeclaration get classDeclaration => _classDeclaration;
+ ClassDeclaration _classDeclaration;
+
+ /** The declaring `<element>` tag. */
+ final Node element;
+
+ /** File where this component was defined. */
+ UrlInfo get dartCodeUrl => externalFile != null
+ ? externalFile : declaringFile.inputUrl;
+
+ /**
+ * True if [tagName] was defined by more than one component. If this happened
+ * we will skip over the component.
+ */
+ bool hasConflict = false;
+
+ ComponentInfo(this.element, this.declaringFile, this.tagName,
+ this.extendsTag);
+
+ /**
+ * Gets the HTML tag extended by the base of the component hierarchy.
+ * Equivalent to [extendsTag] if this inherits directly from an HTML element,
+ * in other words, if [extendsComponent] is null.
+ */
+ String get baseExtendsTag =>
+ extendsComponent == null ? extendsTag : extendsComponent.baseExtendsTag;
+
+ Span get sourceSpan => element.sourceSpan;
+
+ /** Is apply-author-styles enabled. */
+ bool get hasAuthorStyles =>
+ element.attributes.containsKey('apply-author-styles');
+
+ /**
+ * Finds the declaring class, and initializes [className] and
+ * [classDeclaration]. Also [userCode] is generated if there was no script.
+ */
+ void findClassDeclaration(Messages messages) {
+ var constructor = element.attributes['constructor'];
+ className = constructor != null ? constructor :
+ toCamelCase(tagName, startUppercase: true);
+
+ // If we don't have any code, generate a small class definition, and
+ // pretend the user wrote it as inlined code.
+ if (userCode == null) {
+ var superclass = extendsComponent != null ? extendsComponent.className
+ : 'autogenerated.PolymerElement';
+ inlinedCode = new DartCodeInfo(null, null, [],
+ 'class $className extends $superclass {\n}', null);
+ }
+
+ var code = userCode.code;
+ _classDeclaration = userCode.findClass(className);
+ if (_classDeclaration == null) {
+ // Check for deprecated x-tags implied constructor.
+ if (tagName.startsWith('x-') && constructor == null) {
+ var oldCtor = toCamelCase(tagName.substring(2), startUppercase: true);
+ _classDeclaration = userCode.findClass(oldCtor);
+ if (_classDeclaration != null) {
+ messages.warning('Implied constructor name for x-tags has changed to '
+ '"$className". You should rename your class or add a '
+ 'constructor="$oldCtor" attribute to the element declaration. '
+ 'Also custom tags are not required to start with "x-" if their '
+ 'name has at least one dash.',
+ element.sourceSpan);
+ className = oldCtor;
+ }
+ }
+
+ if (_classDeclaration == null) {
+ messages.error('please provide a class definition '
+ 'for $className:\n $code', element.sourceSpan);
+ return;
+ }
+ }
+ }
+
+ String toString() => '#<ComponentInfo $tagName '
+ '${inlinedCode != null ? "inline" : "from ${dartCodeUrl.resolvedPath}"}>';
+}
+
+
+/**
+ * Information extracted about a URL that refers to another file. This is
+ * mainly introduced to be able to trace back where URLs come from when
+ * reporting errors.
+ */
+class UrlInfo {
+ /** Original url. */
+ final String url;
+
+ /** Path that the URL points to. */
+ final String resolvedPath;
+
+ /** Original source location where the URL was extracted from. */
+ final Span sourceSpan;
+
+ UrlInfo(this.url, this.resolvedPath, this.sourceSpan);
+
+ /**
+ * Resolve a path from an [url] found in a file located at [inputUrl].
+ * Returns null for absolute [url]. Unless [ignoreAbsolute] is true, reports
+ * an error message if the url is an absolute url.
+ */
+ static UrlInfo resolve(String url, UrlInfo inputUrl, Span span,
+ String packageRoot, Messages messages, {bool ignoreAbsolute: false}) {
+
+ var uri = Uri.parse(url);
+ if (uri.host != '' || (uri.scheme != '' && uri.scheme != 'package')) {
+ if (!ignoreAbsolute) {
+ messages.error('absolute paths not allowed here: "$url"', span);
+ }
+ return null;
+ }
+
+ var target;
+ if (url.startsWith('package:')) {
+ target = path.join(packageRoot, url.substring(8));
+ } else if (path.isAbsolute(url)) {
+ if (!ignoreAbsolute) {
+ messages.error('absolute paths not allowed here: "$url"', span);
+ }
+ return null;
+ } else {
+ target = path.join(path.dirname(inputUrl.resolvedPath), url);
+ url = pathToUrl(path.normalize(path.join(
+ path.dirname(inputUrl.url), url)));
+ }
+ target = path.normalize(target);
+
+ return new UrlInfo(url, target, span);
+ }
+
+ bool operator ==(UrlInfo other) =>
+ url == other.url && resolvedPath == other.resolvedPath;
+
+ int get hashCode => resolvedPath.hashCode;
+
+ String toString() => "#<UrlInfo url: $url, resolvedPath: $resolvedPath>";
+}
diff --git a/pkg/polymer/lib/src/messages.dart b/pkg/polymer/lib/src/messages.dart
new file mode 100644
index 0000000..5dc6247
--- /dev/null
+++ b/pkg/polymer/lib/src/messages.dart
@@ -0,0 +1,149 @@
+// 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 messages;
+
+import 'dart:json' as json;
+
+import 'package:barback/barback.dart' show TransformLogger;
+import 'package:source_maps/span.dart' show Span;
+import 'package:logging/logging.dart' show Level;
+
+import 'compiler_options.dart';
+import 'utils.dart';
+
+/** Map between error levels and their display color. */
+final Map<Level, String> _ERROR_COLORS = (() {
+ var colorsMap = new Map<Level, String>();
+ colorsMap[Level.SEVERE] = RED_COLOR;
+ colorsMap[Level.WARNING] = MAGENTA_COLOR;
+ colorsMap[Level.INFO] = GREEN_COLOR;
+ return colorsMap;
+})();
+
+/** A single message from the compiler. */
+class Message {
+ final Level level;
+ final String message;
+ final Span span;
+ final bool useColors;
+
+ Message(this.level, this.message, {this.span, this.useColors: false});
+
+ String get kind => level == Level.SEVERE ? 'error' :
+ (level == Level.WARNING ? 'warning' : 'info');
+
+ String toString() {
+ var output = new StringBuffer();
+ bool colors = useColors && _ERROR_COLORS.containsKey(level);
+ var levelColor = _ERROR_COLORS[level];
+ if (colors) output.write(levelColor);
+ output..write(kind)..write(' ');
+ if (colors) output.write(NO_COLOR);
+
+ if (span == null) {
+ output.write(message);
+ } else {
+ output.write(span.getLocationMessage(message, useColors: colors,
+ color: levelColor));
+ }
+
+ return output.toString();
+ }
+
+ String toJson() {
+ if (span == null) return toString();
+ return json.stringify([{
+ 'method': kind,
+ 'params': {
+ 'file': span.sourceUrl,
+ 'message': message,
+ 'line': span.start.line + 1,
+ 'charStart': span.start.offset,
+ 'charEnd': span.end.offset,
+ }
+ }]);
+ }
+}
+
+/**
+ * This class tracks and prints information, warnings, and errors emitted by the
+ * compiler.
+ */
+class Messages implements TransformLogger {
+ final CompilerOptions options;
+ final bool shouldPrint;
+
+ final List<Message> messages = <Message>[];
+
+ Messages({CompilerOptions options, this.shouldPrint: true})
+ : options = options != null ? options : new CompilerOptions();
+
+ /**
+ * Creates a new instance of [Messages] which doesn't write messages to
+ * the console.
+ */
+ Messages.silent(): this(shouldPrint: false);
+
+ /**
+ * True if we have an error that prevents correct codegen.
+ * For example, if we failed to read an input file.
+ */
+ bool get hasErrors => messages.any((m) => m.level == Level.SEVERE);
+
+ // Convenience methods for testing
+ int get length => messages.length;
+
+ Message operator[](int index) => messages[index];
+
+ void clear() {
+ messages.clear();
+ }
+
+ /** [message] is considered a static compile-time error by the Dart lang. */
+ void error(String message, [Span span]) {
+ var msg = new Message(Level.SEVERE, message, span: span,
+ useColors: options.useColors);
+
+ messages.add(msg);
+ printMessage(msg);
+ }
+
+ /** [message] is considered a type warning by the Dart lang. */
+ void warning(String message, [Span span]) {
+ if (options.warningsAsErrors) {
+ error(message, span);
+ } else {
+ var msg = new Message(Level.WARNING, message,
+ span: span, useColors: options.useColors);
+
+ messages.add(msg);
+ printMessage(msg);
+ }
+ }
+
+ /// the list of error messages. Empty list, if there are no error messages.
+ List<Message> get errors =>
+ messages.where((m) => m.level == Level.SEVERE).toList();
+
+ /// the list of warning messages. Empty list if there are no warning messages.
+ List<Message> get warnings =>
+ messages.where((m) => m.level == Level.WARNING).toList();
+
+ /**
+ * [message] at [span] will tell the user about what the compiler
+ * is doing.
+ */
+ void info(String message, [Span span]) {
+ var msg = new Message(Level.INFO, message, span: span,
+ useColors: options.useColors);
+
+ messages.add(msg);
+ if (options.verbose) printMessage(msg);
+ }
+
+ void printMessage(msg) {
+ if (shouldPrint) print(options.jsonFormat ? msg.toJson() : msg);
+ }
+}
diff --git a/pkg/polymer/lib/src/paths.dart b/pkg/polymer/lib/src/paths.dart
new file mode 100644
index 0000000..34037d9
--- /dev/null
+++ b/pkg/polymer/lib/src/paths.dart
@@ -0,0 +1,170 @@
+// 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.
+
+/**
+ * Holds path information that is used by the WebUI compiler to find files,
+ * compute their output location and relative paths between them.
+ */
+library polymer.src.paths;
+
+import 'info.dart' show UrlInfo;
+import 'messages.dart';
+import 'summary.dart';
+import 'utils.dart' show path, pathToUrl;
+
+/**
+ * Stores information about paths and computes mappings between input and output
+ * path locations.
+ */
+class PathMapper {
+ /**
+ * Common prefix to all input paths that are read from the file system. The
+ * output generated by the compiler will reflect the directory structure
+ * starting from [_baseDir]. For instance, if [_baseDir] is `a/b/c` and
+ * [_outputDir] is `g/h/`, then the corresponding output file for
+ * `a/b/c/e/f.html` will be under `g/h/e/f.html.dart`.
+ */
+ final String _baseDir;
+
+ /** Base path where all output is generated. */
+ final String _outputDir;
+
+ /** The package root directory. */
+ final String packageRoot;
+
+ /** Whether to add prefixes and to output file names. */
+ final bool _mangleFilenames;
+
+ final bool _rewriteUrls;
+
+ bool get _rewritePackageImports => _rewriteUrls || !_mangleFilenames;
+
+ /** Default prefix added to all filenames. */
+ static const String _DEFAULT_PREFIX = '_';
+
+ PathMapper(String baseDir, String outputDir, this.packageRoot,
+ bool forceMangle, this._rewriteUrls)
+ : _baseDir = baseDir,
+ _outputDir = outputDir,
+ _mangleFilenames = forceMangle || (baseDir == outputDir);
+
+ /** Add a prefix and [suffix] if [_mangleFilenames] is true */
+ String mangle(String name, String suffix, [bool forceSuffix = false]) =>
+ _mangleFilenames ? "$_DEFAULT_PREFIX$name$suffix"
+ : (forceSuffix ? "$name$suffix" : name);
+
+ /**
+ * Checks that `input.resolvedPath` is a valid input path. It must be in
+ * [_baseDir] and must not be in the [_outputDir]. If not, an error message
+ * is added to [messages].
+ */
+ bool checkInputPath(UrlInfo input, Messages messages) {
+ if (_mangleFilenames) return true;
+ var canonicalized = path.normalize(input.resolvedPath);
+ var parentDir = '..${path.separator}';
+ if (!path.relative(canonicalized, from: _outputDir).startsWith(parentDir)) {
+ messages.error(
+ 'The file ${input.resolvedPath} cannot be processed. '
+ 'Files cannot be under the output folder (${_outputDir}).',
+ input.sourceSpan);
+ return false;
+ }
+ if (path.relative(canonicalized, from: _baseDir).startsWith(parentDir)) {
+ messages.error(
+ 'The file ${input.resolvedPath} cannot be processed. '
+ 'All processed files must be under the base folder (${_baseDir}), you'
+ ' can specify the base folder using the --basedir flag.',
+ input.sourceSpan);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * The path to the output file corresponding to [input], by adding
+ * [_DEFAULT_PREFIX] and a [suffix] to its file name.
+ */
+ String outputPath(String input, String suffix, [bool forceSuffix = false]) =>
+ path.join(outputDirPath(input),
+ mangle(path.basename(input), suffix, forceSuffix));
+
+ /** The path to the output file corresponding to [info]. */
+ String outputLibraryPath(LibrarySummary lib) =>
+ path.join(outputDirPath(lib.dartCodeUrl.resolvedPath),
+ lib.outputFilename);
+
+ /** The corresponding output directory for [input]'s directory. */
+ String outputDirPath(String input) {
+ return _rewritePackages(path.normalize(
+ path.join(_outputDir, path.relative(
+ path.dirname(input), from: _baseDir))));
+ }
+
+ /**
+ * We deal with `packages/` directories in a very special way. We assume it
+ * points to resources loaded from other pub packages. If an output directory
+ * is specified, the compiler will create a packages symlink so that
+ * `package:` imports work.
+ *
+ * To make it possible to share components through pub, we allow using tags of
+ * the form `<link rel="import" href="packages/...">`, so that you can
+ * refer to components within the packages symlink. Regardless of whether an
+ * --out option was given to the compiler, we don't want to generate files
+ * inside `packages/` for those components. Instead we will generate such
+ * code in a special directory called `_from_packages/`.
+ */
+ String _rewritePackages(String outputPath) {
+ // TODO(jmesserly): this should match against packageRoot instead.
+ if (!outputPath.contains('packages')) return outputPath;
+ if (!_rewritePackageImports) return outputPath;
+ var segments = path.split(outputPath);
+ return path.joinAll(
+ segments.map((s) => s == 'packages' ? '_from_packages' : s));
+ }
+
+ /**
+ * Returns a url to import/export the output library represented by [target]
+ * from the output library of [src]. In other words, a url to import or export
+ * `target.outputFilename` from `src.outputFilename`.
+ */
+ String importUrlFor(LibrarySummary src, LibrarySummary target) {
+ if (!_rewritePackageImports &&
+ target.dartCodeUrl.url.startsWith('package:')) {
+ return pathToUrl(path.join(path.dirname(target.dartCodeUrl.url),
+ target.outputFilename));
+ }
+ var srcDir = path.dirname(src.dartCodeUrl.resolvedPath);
+ var relDir = path.relative(
+ path.dirname(target.dartCodeUrl.resolvedPath), from: srcDir);
+ return pathToUrl(_rewritePackages(path.normalize(
+ path.join(relDir, target.outputFilename))));
+ }
+
+ /**
+ * Transforms a [target] url seen in [src] (e.g. a Dart import, a .css href in
+ * an HTML file, etc) into a corresponding url from the output file associated
+ * with [src]. This will keep 'package:', 'dart:', path-absolute, and absolute
+ * urls intact, but it will fix relative paths to walk from the output
+ * directory back to the input directory. An exception will be thrown if
+ * [target] is not under [_baseDir].
+ */
+ String transformUrl(String src, String target) {
+ var uri = Uri.parse(target);
+ if (uri.isAbsolute) return target;
+ if (!uri.scheme.isEmpty) return target;
+ if (!uri.host.isEmpty) return target;
+ if (uri.path.isEmpty) return target; // Implies standalone ? or # in URI.
+ if (path.isAbsolute(target)) return target;
+
+ return pathToUrl(path.normalize(path.relative(
+ path.join(path.dirname(src), target), from: outputDirPath(src))));
+ }
+}
+
+/**
+ * Returns a "mangled" name, with a prefix and [suffix] depending on the
+ * compiler's settings. [forceSuffix] causes [suffix] to be appended even if
+ * the compiler is not mangling names.
+ */
+typedef String NameMangler(String name, String suffix, [bool forceSuffix]);
diff --git a/pkg/polymer/lib/src/summary.dart b/pkg/polymer/lib/src/summary.dart
new file mode 100644
index 0000000..841870a
--- /dev/null
+++ b/pkg/polymer/lib/src/summary.dart
@@ -0,0 +1,88 @@
+// 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.
+
+/**
+ * Summary information for components and libraries.
+ *
+ * These classes are used for modular compilation. Summaries are a subset of the
+ * information collected by Info objects (see `info.dart`). When we are
+ * compiling a single file, the information extracted from that file is stored
+ * as info objects, but any information that is needed from other files (like
+ * imported components) is stored as a summary.
+ */
+library polymer.src.summary;
+
+import 'package:source_maps/span.dart' show Span;
+
+// TODO(sigmund): consider moving UrlInfo out of info.dart
+import 'info.dart' show UrlInfo;
+
+/**
+ * Summary information from other library-like objects, which includes HTML
+ * components and dart libraries).
+ */
+class LibrarySummary {
+ /** Path to the sources represented by this summary. */
+ final UrlInfo dartCodeUrl;
+
+ /** Name given to this source after it was compiled. */
+ final String outputFilename;
+
+ LibrarySummary(this.dartCodeUrl, this.outputFilename);
+}
+
+/** Summary information for an HTML file that defines custom elements. */
+class HtmlFileSummary extends LibrarySummary {
+ /**
+ * Summary of each component defined either explicitly the HTML file or
+ * included transitively from `<link rel="import">` tags.
+ */
+ final Map<String, ComponentSummary> components;
+
+ HtmlFileSummary(UrlInfo dartCodeUrl, String outputFilename, this.components)
+ : super(dartCodeUrl, outputFilename);
+}
+
+/** Information about a web component definition. */
+class ComponentSummary extends LibrarySummary {
+ /** The component tag name, defined with the `name` attribute on `element`. */
+ final String tagName;
+
+ /**
+ * The tag name that this component extends, defined with the `extends`
+ * attribute on `element`.
+ */
+ final String extendsTag;
+
+ /**
+ * The Dart class containing the component's behavior, derived from tagName or
+ * defined in the `constructor` attribute on `element`.
+ */
+ final String className;
+
+ /** Summary of the base component, if any. */
+ final ComponentSummary extendsComponent;
+
+ /**
+ * True if [tagName] was defined by more than one component. Used internally
+ * by the analyzer. Conflicting component will be skipped by the compiler.
+ */
+ bool hasConflict;
+
+ /** Original span where this component is declared. */
+ final Span sourceSpan;
+
+ ComponentSummary(UrlInfo dartCodeUrl, String outputFilename,
+ this.tagName, this.extendsTag, this.className, this.extendsComponent,
+ this.sourceSpan, [this.hasConflict = false])
+ : super(dartCodeUrl, outputFilename);
+
+ /**
+ * Gets the HTML tag extended by the base of the component hierarchy.
+ * Equivalent to [extendsTag] if this inherits directly from an HTML element,
+ * in other words, if [extendsComponent] is null.
+ */
+ String get baseExtendsTag =>
+ extendsComponent == null ? extendsTag : extendsComponent.baseExtendsTag;
+}
diff --git a/pkg/polymer/lib/src/utils.dart b/pkg/polymer/lib/src/utils.dart
new file mode 100644
index 0000000..da79dc2
--- /dev/null
+++ b/pkg/polymer/lib/src/utils.dart
@@ -0,0 +1,177 @@
+// 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 polymer.src.utils;
+
+import 'dart:async';
+import 'package:path/path.dart' show Builder;
+export 'utils_observe.dart' show toCamelCase, toHyphenedName;
+
+/**
+ * An instance of the pathos library builder. We could just use the default
+ * builder in pathos, but we add this indirection to make it possible to run
+ * unittest for windows paths.
+ */
+Builder path = new Builder();
+
+/** Convert a OS specific path into a url. */
+String pathToUrl(String relPath) =>
+ (path.separator == '/') ? relPath : path.split(relPath).join('/');
+
+/**
+ * Invokes [callback], logs how long it took to execute in ms, and returns
+ * whatever [callback] returns. The log message will be printed if [printTime]
+ * is true.
+ */
+time(String logMessage, callback(),
+ {bool printTime: false, bool useColors: false}) {
+ final watch = new Stopwatch();
+ watch.start();
+ var result = callback();
+ watch.stop();
+ final duration = watch.elapsedMilliseconds;
+ if (printTime) {
+ _printMessage(logMessage, duration, useColors);
+ }
+ return result;
+}
+
+/**
+ * Invokes [callback], logs how long it takes from the moment [callback] is
+ * executed until the future it returns is completed. Returns the future
+ * returned by [callback]. The log message will be printed if [printTime]
+ * is true.
+ */
+Future asyncTime(String logMessage, Future callback(),
+ {bool printTime: false, bool useColors: false}) {
+ final watch = new Stopwatch();
+ watch.start();
+ return callback()..then((_) {
+ watch.stop();
+ final duration = watch.elapsedMilliseconds;
+ if (printTime) {
+ _printMessage(logMessage, duration, useColors);
+ }
+ });
+}
+
+void _printMessage(String logMessage, int duration, bool useColors) {
+ var buf = new StringBuffer();
+ buf.write(logMessage);
+ for (int i = logMessage.length; i < 60; i++) buf.write(' ');
+ buf.write(' -- ');
+ if (useColors) {
+ buf.write(GREEN_COLOR);
+ }
+ if (duration < 10) buf.write(' ');
+ if (duration < 100) buf.write(' ');
+ buf..write(duration)..write(' ms');
+ if (useColors) {
+ buf.write(NO_COLOR);
+ }
+ print(buf.toString());
+}
+
+// Color constants used for generating messages.
+final String GREEN_COLOR = '\u001b[32m';
+final String RED_COLOR = '\u001b[31m';
+final String MAGENTA_COLOR = '\u001b[35m';
+final String NO_COLOR = '\u001b[0m';
+
+/** A future that waits until all added [Future]s complete. */
+// TODO(sigmund): this should be part of the futures/core libraries.
+class FutureGroup {
+ static const _FINISHED = -1;
+
+ int _pending = 0;
+ Future _failedTask;
+ final Completer<List> _completer = new Completer<List>();
+ final List results = [];
+
+ /** Gets the task that failed, if any. */
+ Future get failedTask => _failedTask;
+
+ /**
+ * Wait for [task] to complete.
+ *
+ * If this group has already been marked as completed, you'll get a
+ * [StateError].
+ *
+ * If this group has a [failedTask], new tasks will be ignored, because the
+ * error has already been signaled.
+ */
+ void add(Future task) {
+ if (_failedTask != null) return;
+ if (_pending == _FINISHED) throw new StateError("Future already completed");
+
+ _pending++;
+ var i = results.length;
+ results.add(null);
+ task.then((res) {
+ results[i] = res;
+ if (_failedTask != null) return;
+ _pending--;
+ if (_pending == 0) {
+ _pending = _FINISHED;
+ _completer.complete(results);
+ }
+ }, onError: (e) {
+ if (_failedTask != null) return;
+ _failedTask = task;
+ _completer.completeError(e, getAttachedStackTrace(e));
+ });
+ }
+
+ Future<List> get future => _completer.future;
+}
+
+
+/**
+ * Escapes [text] for use in a Dart string.
+ * [single] specifies single quote `'` vs double quote `"`.
+ * [triple] indicates that a triple-quoted string, such as `'''` or `"""`.
+ */
+String escapeDartString(String text, {bool single: true, bool triple: false}) {
+ // Note: don't allocate anything until we know we need it.
+ StringBuffer result = null;
+
+ for (int i = 0; i < text.length; i++) {
+ int code = text.codeUnitAt(i);
+ var replace = null;
+ switch (code) {
+ case 92/*'\\'*/: replace = r'\\'; break;
+ case 36/*r'$'*/: replace = r'\$'; break;
+ case 34/*'"'*/: if (!single) replace = r'\"'; break;
+ case 39/*"'"*/: if (single) replace = r"\'"; break;
+ case 10/*'\n'*/: if (!triple) replace = r'\n'; break;
+ case 13/*'\r'*/: if (!triple) replace = r'\r'; break;
+
+ // Note: we don't escape unicode characters, under the assumption that
+ // writing the file in UTF-8 will take care of this.
+
+ // TODO(jmesserly): do we want to replace any other non-printable
+ // characters (such as \f) for readability?
+ }
+
+ if (replace != null && result == null) {
+ result = new StringBuffer(text.substring(0, i));
+ }
+
+ if (result != null) result.write(replace != null ? replace : text[i]);
+ }
+
+ return result == null ? text : result.toString();
+}
+
+/** Iterates through an infinite sequence, starting from zero. */
+class IntIterator implements Iterator<int> {
+ int _next = -1;
+
+ int get current => _next < 0 ? null : _next;
+
+ bool moveNext() {
+ _next++;
+ return true;
+ }
+}
diff --git a/pkg/polymer/lib/src/utils_observe.dart b/pkg/polymer/lib/src/utils_observe.dart
new file mode 100644
index 0000000..b568d0c
--- /dev/null
+++ b/pkg/polymer/lib/src/utils_observe.dart
@@ -0,0 +1,33 @@
+// 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 polymer.src.utils_observe;
+
+/**
+ * Converts a string name with hyphens into an identifier, by removing hyphens
+ * and capitalizing the following letter. Optionally [startUppercase] to
+ * captialize the first letter.
+ */
+String toCamelCase(String hyphenedName, {bool startUppercase: false}) {
+ var segments = hyphenedName.split('-');
+ int start = startUppercase ? 0 : 1;
+ for (int i = start; i < segments.length; i++) {
+ var segment = segments[i];
+ if (segment.length > 0) {
+ // Character between 'a'..'z' mapped to 'A'..'Z'
+ segments[i] = '${segment[0].toUpperCase()}${segment.substring(1)}';
+ }
+ }
+ return segments.join('');
+}
+
+String toHyphenedName(String word) {
+ var sb = new StringBuffer();
+ for (int i = 0; i < word.length; i++) {
+ var lower = word[i].toLowerCase();
+ if (word[i] != lower && i > 0) sb.write('-');
+ sb.write(lower);
+ }
+ return sb.toString();
+}
diff --git a/pkg/polymer/lib/testing/content_shell_test.dart b/pkg/polymer/lib/testing/content_shell_test.dart
new file mode 100644
index 0000000..97398be
--- /dev/null
+++ b/pkg/polymer/lib/testing/content_shell_test.dart
@@ -0,0 +1,229 @@
+// 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.
+
+/**
+ * Helper library to run tests in content_shell
+ */
+library polymer.testing.end2end;
+
+import 'dart:io';
+import 'package:args/args.dart';
+import 'package:path/path.dart' as path;
+import 'package:unittest/unittest.dart';
+import 'package:polymer/dwc.dart' as dwc;
+
+
+/**
+ * Compiles [testFile] with the web-ui compiler, and then runs the output as a
+ * unit test in content_shell.
+ */
+void endToEndTests(String inputDir, String outDir, {List<String> arguments}) {
+ _testHelper(new _TestOptions(inputDir, inputDir, null, outDir,
+ arguments: arguments));
+}
+
+/**
+ * Compiles [testFile] with the web-ui compiler, and then runs the output as a
+ * render test in content_shell.
+ */
+void renderTests(String baseDir, String inputDir, String expectedDir,
+ String outDir, {List<String> arguments, String script, String pattern,
+ bool deleteDir: true}) {
+ _testHelper(new _TestOptions(baseDir, inputDir, expectedDir, outDir,
+ arguments: arguments, script: script, pattern: pattern,
+ deleteDir: deleteDir));
+}
+
+void _testHelper(_TestOptions options) {
+ expect(options, isNotNull);
+
+ var paths = new Directory(options.inputDir).listSync()
+ .where((f) => f is File).map((f) => f.path)
+ .where((p) => p.endsWith('_test.html') && options.pattern.hasMatch(p));
+
+ if (paths.isEmpty) return;
+
+ // First clear the output folder. Otherwise we can miss bugs when we fail to
+ // generate a file.
+ var dir = new Directory(options.outDir);
+ if (dir.existsSync() && options.deleteDir) {
+ print('Cleaning old output for ${path.normalize(options.outDir)}');
+ dir.deleteSync(recursive: true);
+ }
+ dir.createSync();
+
+ for (var filePath in paths) {
+ var filename = path.basename(filePath);
+ test('compile $filename', () {
+ var testArgs = ['-o', options.outDir, '--basedir', options.baseDir,
+ '--deploy']
+ ..addAll(options.compilerArgs)
+ ..add(filePath);
+ expect(dwc.run(testArgs, printTime: false).then((res) {
+ expect(res.messages.length, 0, reason: res.messages.join('\n'));
+ }), completes);
+ });
+ }
+
+ var filenames = paths.map(path.basename).toList();
+ // Sort files to match the order in which run.sh runs diff.
+ filenames.sort();
+
+ // Get the path from "input" relative to "baseDir"
+ var relativeToBase = path.relative(options.inputDir, from: options.baseDir);
+ var finalOutDir = path.join(options.outDir, relativeToBase);
+
+ runTests(String search) {
+ var output;
+
+ for (var filename in filenames) {
+ test('content_shell run $filename$search', () {
+ var args = ['--dump-render-tree',
+ 'file://$finalOutDir/$filename$search'];
+ var env = {'DART_FLAGS': '--checked'};
+ expect(Process.run('content_shell', args, environment: env).then((res) {
+ expect(res.exitCode, 0, reason: 'content_shell exit code: '
+ '${res.exitCode}. Contents of stderr: \n${res.stderr}');
+ var outs = res.stdout.split('#EOF\n')
+ .where((s) => !s.trim().isEmpty).toList();
+ expect(outs.length, 1);
+ output = outs.first;
+ }), completes);
+ });
+
+ test('verify $filename $search', () {
+ expect(output, isNotNull, reason:
+ 'Output not available, maybe content_shell failed to run.');
+ var outPath = path.join(options.outDir, '$filename.txt');
+ new File(outPath).writeAsStringSync(output);
+ if (options.isRenderTest) {
+ var expectedPath = path.join(options.expectedDir, '$filename.txt');
+ var expected = new File(expectedPath).readAsStringSync();
+ expect(output, expected, reason: 'unexpected output for <$filename>');
+ } else {
+ bool passes = matches(
+ new RegExp('All .* tests passed')).matches(output, {});
+ expect(passes, true, reason: 'unit test failed:\n$output');
+ }
+ });
+ }
+ }
+
+ bool compiled = false;
+ ensureCompileToJs() {
+ if (compiled) return;
+ compiled = true;
+
+ for (var filename in filenames) {
+ test('dart2js $filename', () {
+ // TODO(jmesserly): this depends on DWC's output scheme.
+ // Alternatively we could use html5lib to find the script tag.
+ var inPath = '${filename}_bootstrap.dart';
+ var outPath = '${inPath}.js';
+
+ inPath = path.join(finalOutDir, inPath);
+ outPath = path.join(finalOutDir, outPath);
+
+ expect(Process.run('dart2js', ['-o$outPath', inPath]).then((res) {
+ expect(res.exitCode, 0, reason: 'dart2js exit code: '
+ '${res.exitCode}. Contents of stderr: \n${res.stderr}. '
+ 'Contents of stdout: \n${res.stdout}.');
+ expect(new File(outPath).existsSync(), true, reason: 'input file '
+ '$inPath should have been compiled to $outPath.');
+ }), completes);
+ });
+ }
+ }
+
+ if (options.runAsDart) {
+ runTests('');
+ }
+ if (options.runAsJs) {
+ ensureCompileToJs();
+ runTests('?js=1');
+ }
+ if (options.forcePolyfillShadowDom) {
+ ensureCompileToJs();
+ runTests('?js=1&shadowdomjs=1');
+ }
+}
+
+class _TestOptions {
+ final String baseDir;
+ final String inputDir;
+
+ final String expectedDir;
+ bool get isRenderTest => expectedDir != null;
+
+ final String outDir;
+ final bool deleteDir;
+
+ final bool runAsDart;
+ final bool runAsJs;
+ final bool forcePolyfillShadowDom;
+
+ final List<String> compilerArgs;
+ final RegExp pattern;
+
+ factory _TestOptions(String baseDir, String inputDir, String expectedDir,
+ String outDir, {List<String> arguments, String script, String pattern,
+ bool deleteDir: true}) {
+ if (arguments == null) arguments = new Options().arguments;
+ if (script == null) script = new Options().script;
+
+ var args = _parseArgs(arguments, script);
+ if (args == null) return null;
+ var compilerArgs = args.rest;
+ var filePattern;
+ if (pattern != null) {
+ filePattern = new RegExp(pattern);
+ } else if (compilerArgs.length > 0) {
+ filePattern = new RegExp(compilerArgs[0]);
+ compilerArgs = compilerArgs.sublist(1);
+ } else {
+ filePattern = new RegExp('.');
+ }
+
+ var scriptDir = path.absolute(path.dirname(script));
+ baseDir = path.join(scriptDir, baseDir);
+ inputDir = path.join(scriptDir, inputDir);
+ outDir = path.join(scriptDir, outDir);
+ if (expectedDir != null) {
+ expectedDir = path.join(scriptDir, expectedDir);
+ }
+
+ return new _TestOptions._(baseDir, inputDir, expectedDir, outDir, deleteDir,
+ args['dart'] == true, args['js'] == true, args['shadowdom'] == true,
+ compilerArgs, filePattern);
+ }
+
+ _TestOptions._(this.baseDir, this.inputDir, this.expectedDir, this.outDir,
+ this.deleteDir, this.runAsDart, this.runAsJs,
+ this.forcePolyfillShadowDom, this.compilerArgs, this.pattern);
+}
+
+ArgResults _parseArgs(List<String> arguments, String script) {
+ var parser = new ArgParser()
+ ..addFlag('dart', abbr: 'd', help: 'run on Dart VM', defaultsTo: true)
+ ..addFlag('js', abbr: 'j', help: 'run compiled dart2js', defaultsTo: true)
+ ..addFlag('shadowdom', abbr: 's',
+ help: 'run dart2js and polyfilled ShadowDOM', defaultsTo: true)
+ ..addFlag('help', abbr: 'h', help: 'Displays this help message',
+ defaultsTo: false, negatable: false);
+
+ showUsage() {
+ print('Usage: $script [options...] [test_name_regexp]');
+ print(parser.getUsage());
+ return null;
+ }
+
+ try {
+ var results = parser.parse(arguments);
+ if (results['help']) return showUsage();
+ return results;
+ } on FormatException catch (e) {
+ print(e.message);
+ return showUsage();
+ }
+}
diff --git a/pkg/polymer/lib/testing/testing.js b/pkg/polymer/lib/testing/testing.js
new file mode 100644
index 0000000..de27047
--- /dev/null
+++ b/pkg/polymer/lib/testing/testing.js
@@ -0,0 +1,147 @@
+// 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.
+
+(function() {
+ var undoReplaceScripts = [];
+
+ var flags = {};
+ // populate flags from location
+ location.search.slice(1).split('&').forEach(function(o) {
+ o = o.split('=');
+ o[0] && (flags[o[0]] = o[1] || true);
+ });
+
+ // Webkit is migrating from layoutTestController to testRunner, we use
+ // layoutTestController as a fallback until that settles in.
+ var runner = window.testRunner || window.layoutTestController;
+
+ if (runner) {
+ runner.dumpAsText();
+ runner.waitUntilDone();
+ }
+
+ function dumpDOM() {
+ // Undo any scripts that were modified.
+ undoReplaceScripts.forEach(function(undo) { undo(); });
+
+ function expandShadowRoot(node) {
+ for (var n = node.firstChild; n; n = n.nextSibling) {
+ expandShadowRoot(n);
+ }
+ var shadow = node.shadowRoot || node.webkitShadowRoot ||
+ node.olderShadowRoot;
+
+ if (shadow) {
+ expandShadowRoot(shadow);
+
+ var name = 'shadow-root';
+ if (shadow == node.olderShadowRoot) name = 'older-' + name;
+
+ var fakeShadow = document.createElement(name);
+ while (shadow.firstChild) fakeShadow.appendChild(shadow.firstChild);
+ node.insertBefore(fakeShadow, node.firstChild);
+ }
+ }
+
+ // TODO(jmesserly): use querySelector to workaround unwrapped "document".
+ expandShadowRoot(document.querySelector('body'));
+
+ // Clean up all of the junk added to the DOM by js-interop and shadow CSS
+ // TODO(jmesserly): it seems like we're leaking lots of dart-port attributes
+ // for the document elemenet
+ function cleanTree(node) {
+ for (var n = node.firstChild; n; n = n.nextSibling) {
+ cleanTree(n);
+ }
+
+ // Remove dart-port attributes
+ if (node.attributes) {
+ for (var i = 0; i < node.attributes.length; i++) {
+ if (node.attributes[i].value.indexOf('dart-port') == 0) {
+ node.removeAttribute(i);
+ }
+ }
+ }
+
+ if (node.tagName == 'script' &&
+ node.textContent.indexOf('_DART_TEMPORARY_ATTACHED') >= 0) {
+ node.parentNode.removeChild(node);
+ }
+ }
+
+ // TODO(jmesserly): use querySelector to workaround unwrapped "document".
+ cleanTree(document.querySelector('html'));
+
+ var out = document.createElement('pre');
+ out.textContent = document.documentElement.outerHTML;
+ document.body.innerHTML = '';
+ document.body.appendChild(out);
+ }
+
+ function messageHandler(e) {
+ if (e.data == 'done' && runner) {
+ // On success, dump the DOM. Convert shadowRoot contents into
+ // <shadow-root>
+ dumpDOM();
+ runner.notifyDone();
+ }
+ }
+
+ window.addEventListener('message', messageHandler, false);
+
+ function errorHandler(e) {
+ if (runner) {
+ window.setTimeout(function() { runner.notifyDone(); }, 0);
+ }
+ window.console.log('FAIL');
+ }
+
+ window.addEventListener('error', errorHandler, false);
+
+ if (navigator.webkitStartDart && !flags.js) {
+ // TODO(jmesserly): fix this so we don't need to copy from browser/dart.js
+ if (!navigator.webkitStartDart()) {
+ document.body.innerHTML = 'This build has expired. Please download a new Dartium at http://www.dartlang.org/dartium/index.html';
+ }
+ } else {
+ if (flags.shadowdomjs) {
+ // Allow flags to force polyfill of ShadowDOM so we can test it.
+ window.__forceShadowDomPolyfill = true;
+ }
+
+ // TODO:
+ // - Support in-browser compilation.
+ // - Handle inline Dart scripts.
+ window.addEventListener("DOMContentLoaded", function (e) {
+ // Fall back to compiled JS. Run through all the scripts and
+ // replace them if they have a type that indicate that they source
+ // in Dart code.
+ //
+ // <script type="application/dart" src="..."></script>
+ //
+ var scripts = document.getElementsByTagName("script");
+ var length = scripts.length;
+ for (var i = 0; i < length; ++i) {
+ var script = scripts[i];
+ if (script.type == "application/dart") {
+ // Remap foo.dart to foo.dart.js.
+ if (script.src && script.src != '') {
+ var jsScript = document.createElement('script');
+ jsScript.src = script.src.replace(/\.dart(?=\?|$)/, '.dart.js');
+ var parent = script.parentNode;
+ // TODO(vsm): Find a solution for issue 8455 that works with more
+ // than one script.
+ document.currentScript = jsScript;
+
+ undoReplaceScripts.push(function() {
+ parent.replaceChild(script, jsScript);
+ });
+ parent.replaceChild(jsScript, script);
+ }
+ }
+ }
+ }, false);
+ }
+
+})();
diff --git a/pkg/polymer/pubspec.yaml b/pkg/polymer/pubspec.yaml
new file mode 100644
index 0000000..78b2b66
--- /dev/null
+++ b/pkg/polymer/pubspec.yaml
@@ -0,0 +1,26 @@
+name: polymer
+author: Web UI Authors <web-ui-dev@dartlang.org>
+description: >
+ Polymer.dart is a new type of library for the web, built on top of Web
+ Components, and designed to leverage the evolving web platform on modern
+ browsers.
+homepage: https://www.dartlang.org
+dependencies:
+ analyzer_experimental: any
+ args: any
+ barback: any
+ browser: any
+ csslib: any
+ custom_element: any
+ html_import: any
+ html5lib: any
+ js: any
+ logging: any
+ mdv: any
+ observe: any
+ path: any
+ polymer_expressions: any
+ shadow_dom: any
+ source_maps: any
+ # TODO(jmesserly): make this a dev_dependency
+ unittest: any
diff --git a/pkg/polymer/test/compiler_test.dart b/pkg/polymer/test/compiler_test.dart
new file mode 100644
index 0000000..d5d47ba
--- /dev/null
+++ b/pkg/polymer/test/compiler_test.dart
@@ -0,0 +1,141 @@
+// 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.
+
+/** End-to-end tests for the [Compiler] API. */
+library compiler_test;
+
+import 'package:logging/logging.dart' show Level;
+import 'package:path/path.dart' as path;
+import 'package:polymer/src/messages.dart';
+import 'package:unittest/compact_vm_config.dart';
+import 'package:unittest/unittest.dart';
+
+import 'testing.dart';
+
+main() {
+ useCompactVMConfiguration();
+
+ test('recursive dependencies', () {
+ var messages = new Messages.silent();
+ var compiler = createCompiler({
+ 'index.html': '<head>'
+ '<link rel="import" href="foo.html">'
+ '<link rel="import" href="bar.html">'
+ '<body><x-foo></x-foo><x-bar></x-bar>'
+ '<script type="application/dart">main() {}</script>',
+ 'foo.html': '<head><link rel="import" href="bar.html">'
+ '<body><polymer-element name="x-foo" constructor="Foo">'
+ '<template><x-bar>',
+ 'bar.html': '<head><link rel="import" href="foo.html">'
+ '<body><polymer-element name="x-bar" constructor="Boo">'
+ '<template><x-foo>',
+ }, messages);
+
+ compiler.run().then(expectAsync1((e) {
+ MockFileSystem fs = compiler.fileSystem;
+ expect(fs.readCount, equals({
+ 'index.html': 1,
+ 'foo.html': 1,
+ 'bar.html': 1
+ }), reason: 'Actual:\n ${fs.readCount}');
+
+ var outputs = compiler.output.map((o) => o.path);
+ expect(outputs, equals([
+ 'foo.html.dart',
+ 'foo.html.dart.map',
+ 'bar.html.dart',
+ 'bar.html.dart.map',
+ 'index.html.dart',
+ 'index.html.dart.map',
+ 'index.html_bootstrap.dart',
+ 'index.html',
+ ].map((p) => path.join('out', p))));
+ }));
+ });
+
+ group('missing files', () {
+ test('main script', () {
+ var messages = new Messages.silent();
+ var compiler = createCompiler({
+ 'index.html': '<head></head><body>'
+ '<script type="application/dart" src="notfound.dart"></script>'
+ '</body>',
+ }, messages);
+
+ compiler.run().then(expectAsync1((e) {
+ var msgs = messages.messages.where((m) =>
+ m.message.contains('unable')).toList();
+
+ expect(msgs.length, 1);
+ expect(msgs[0].level, Level.SEVERE);
+ expect(msgs[0].message, contains('unable to open file'));
+ expect(msgs[0].span, isNotNull);
+ expect(msgs[0].span.sourceUrl, 'index.html');
+
+ MockFileSystem fs = compiler.fileSystem;
+ expect(fs.readCount, { 'index.html': 1, 'notfound.dart': 1 });
+
+ var outputs = compiler.output.map((o) => o.path.toString());
+ expect(outputs, []);
+ }));
+ });
+
+ test('component html', () {
+ var messages = new Messages.silent();
+ var compiler = createCompiler({
+ 'index.html': '<head>'
+ '<link rel="import" href="notfound.html">'
+ '<body><x-foo>'
+ '<script type="application/dart">main() {}</script>',
+ }, messages);
+
+ compiler.run().then(expectAsync1((e) {
+ var msgs = messages.messages.where((m) =>
+ m.message.contains('unable')).toList();
+
+ expect(msgs.length, 1);
+ expect(msgs[0].level, Level.SEVERE);
+ expect(msgs[0].message, contains('unable to open file'));
+ expect(msgs[0].span, isNotNull);
+ expect(msgs[0].span.sourceUrl, 'index.html');
+
+ MockFileSystem fs = compiler.fileSystem;
+ expect(fs.readCount, { 'index.html': 1, 'notfound.html': 1 });
+
+ var outputs = compiler.output.map((o) => o.path.toString());
+ expect(outputs, []);
+ }));
+ });
+
+ test('component script', () {
+ var messages = new Messages.silent();
+ var compiler = createCompiler({
+ 'index.html': '<head>'
+ '<link rel="import" href="foo.html">'
+ '<body><x-foo></x-foo>'
+ '<script type="application/dart">main() {}</script>'
+ '</body>',
+ 'foo.html': '<body><polymer-element name="x-foo" constructor="Foo">'
+ '<template></template>'
+ '<script type="application/dart" src="notfound.dart"></script>',
+ }, messages);
+
+ compiler.run().then(expectAsync1((e) {
+ var msgs = messages.messages.where((m) =>
+ m.message.contains('unable')).toList();
+
+ expect(msgs.length, 1);
+ expect(msgs[0].level, Level.SEVERE);
+ expect(msgs[0].message, contains('unable to open file'));
+
+ MockFileSystem fs = compiler.fileSystem;
+ expect(fs.readCount,
+ { 'index.html': 1, 'foo.html': 1, 'notfound.dart': 1 });
+
+ var outputs = compiler.output.map((o) => o.path.toString());
+ expect(outputs, []);
+ }));
+ });
+ });
+}
diff --git a/pkg/polymer/test/css_test.dart b/pkg/polymer/test/css_test.dart
new file mode 100644
index 0000000..1702312
--- /dev/null
+++ b/pkg/polymer/test/css_test.dart
@@ -0,0 +1,559 @@
+// 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 css_test;
+
+import 'package:path/path.dart' as path;
+import 'package:polymer/src/messages.dart';
+import 'package:polymer/src/utils.dart' as utils;
+import 'package:unittest/compact_vm_config.dart';
+import 'package:unittest/unittest.dart';
+
+import 'testing.dart';
+
+test_simple_var() {
+ Map createFiles() {
+ return {
+ 'index.html':
+ '<!DOCTYPE html>'
+ '<html lang="en">'
+ '<head>'
+ '<meta charset="utf-8">'
+ '</head>'
+ '<body>'
+ '<style>'
+ '@main_color: var(b);'
+ '@b: var(c);'
+ '@c: red;'
+ '</style>'
+ '<style>'
+ '.test { color: var(main_color); }'
+ '</style>'
+ '<script type="application/dart">main() {}</script>'
+ '</body>'
+ '</html>',
+ };
+ }
+
+ var messages = new Messages.silent();
+ var compiler = createCompiler(createFiles(), messages, errors: true,
+ scopedCss: true);
+
+ compiler.run().then(expectAsync1((e) {
+ MockFileSystem fs = compiler.fileSystem;
+ expect(fs.readCount, equals({
+ 'index.html': 1,
+ }), reason: 'Actual:\n ${fs.readCount}');
+
+ var htmlInfo = compiler.info['index.html'];
+ expect(htmlInfo.styleSheets.length, 2);
+ expect(prettyPrintCss(htmlInfo.styleSheets[0]), '');
+ expect(prettyPrintCss(htmlInfo.styleSheets[1]), '.test { color: red; }');
+
+ var outputs = compiler.output.map((o) => o.path);
+ expect(outputs, equals([
+ 'out/index.html.dart',
+ 'out/index.html.dart.map',
+ 'out/index.html_bootstrap.dart',
+ 'out/index.html',
+ ]));
+ }));
+}
+
+test_var() {
+ Map createFiles() {
+ return {
+ 'index.html':
+ '<!DOCTYPE html>'
+ '<html lang="en">'
+ '<head>'
+ '<meta charset="utf-8">'
+ '</head>'
+ '<body>'
+ '<style>'
+ '@main-color: var(b);'
+ '@b: var(c);'
+ '@c: red;'
+ '@d: var(main-color-1, green);'
+ '@border-pen: solid;'
+ '@inset: 5px;'
+ '@frame-color: solid orange;'
+ '@big-border: 2px 2px 2px;'
+ '@border-stuff: 3px dashed var(main-color);'
+ '@border-2: 3px var(big-border) dashed var(main-color-1, green);'
+ '@blue-border: bold var(not-found, 1px 10px blue)'
+ '</style>'
+ '<style>'
+ '.test-1 { color: var(main-color-1, blue); }'
+ '.test-2 { color: var(main-color-1, var(main-color)); }'
+ '.test-3 { color: var(d, yellow); }'
+ '.test-4 { color: var(d-1, yellow); }'
+ '.test-5 { color: var(d-1, var(d)); }'
+ '.test-6 { border: var(inset) var(border-pen) var(d); }'
+ '.test-7 { border: 10px var(border-pen) var(d); }'
+ '.test-8 { border: 20px var(border-pen) yellow; }'
+ '.test-9 { border: 30px dashed var(d); }'
+ '.test-10 { border: 40px var(frame-color);}'
+ '.test-11 { border: 40px var(frame-color-1, blue);}'
+ '.test-12 { border: 40px var(frame-color-1, solid blue);}'
+ '.test-13 {'
+ 'border: 40px var(x1, var(x2, var(x3, var(frame-color)));'
+ '}'
+ '.test-14 { border: 40px var(x1, var(frame-color); }'
+ '.test-15 { border: 40px var(x1, solid blue);}'
+ '.test-16 { border: 1px 1px 2px 3px var(frame-color);}'
+ '.test-17 { border: 1px 1px 2px 3px var(x1, solid blue);}'
+ '.test-18 { border: 1px 1px 2px var(border-stuff);}'
+ '.test-19 { border: var(big-border) var(border-stuff);}'
+ '.test-20 { border: var(border-2);}'
+ '.test-21 { border: var(blue-border);}'
+ '</style>'
+ '<script type="application/dart">main() {}</script>'
+ '</body>'
+ '</html>',
+ };
+ }
+
+ var messages = new Messages.silent();
+ var compiler = createCompiler(createFiles(), messages, errors: true,
+ scopedCss: true);
+
+ compiler.run().then(expectAsync1((e) {
+ MockFileSystem fs = compiler.fileSystem;
+ expect(fs.readCount, equals({
+ 'index.html': 1,
+ }), reason: 'Actual:\n ${fs.readCount}');
+
+ var htmlInfo = compiler.info['index.html'];
+ expect(htmlInfo.styleSheets.length, 2);
+ expect(prettyPrintCss(htmlInfo.styleSheets[0]), '');
+ expect(prettyPrintCss(htmlInfo.styleSheets[1]),
+ '.test-1 { color: blue; } '
+ '.test-2 { color: red; } '
+ '.test-3 { color: green; } '
+ '.test-4 { color: yellow; } '
+ '.test-5 { color: green; } '
+ '.test-6 { border: 5px solid green; } '
+ '.test-7 { border: 10px solid green; } '
+ '.test-8 { border: 20px solid yellow; } '
+ '.test-9 { border: 30px dashed green; } '
+ '.test-10 { border: 40px solid orange; } '
+ '.test-11 { border: 40px blue; } '
+ '.test-12 { border: 40px solid blue; } '
+ '.test-13 { border: 40px solid orange; } '
+ '.test-14 { border: 40px solid orange; } '
+ '.test-15 { border: 40px solid blue; } '
+ '.test-16 { border: 1px 1px 2px 3px solid orange; } '
+ '.test-17 { border: 1px 1px 2px 3px solid blue; } '
+ '.test-18 { border: 1px 1px 2px 3px dashed red; } '
+ '.test-19 { border: 2px 2px 2px 3px dashed red; } '
+ '.test-20 { border: 3px 2px 2px 2px dashed green; } '
+ '.test-21 { border: bold 1px 10px blue; }');
+ var outputs = compiler.output.map((o) => o.path);
+ expect(outputs, equals([
+ 'out/index.html.dart',
+ 'out/index.html.dart.map',
+ 'out/index.html_bootstrap.dart',
+ 'out/index.html',
+ ]));
+ }));
+}
+
+test_simple_import() {
+ Map createFiles() {
+ return {
+ 'foo.css': r'''@main_color: var(b);
+ @b: var(c);
+ @c: red;''',
+ 'index.html':
+ '<!DOCTYPE html>'
+ '<html lang="en">'
+ '<head>'
+ '<meta charset="utf-8">'
+ '</head>'
+ '<body>'
+ '<style>'
+ '@import "foo.css";'
+ '.test { color: var(main_color); }'
+ '</style>'
+ '<script type="application/dart">main() {}</script>'
+ '</body>'
+ '</html>',
+ };
+ }
+
+ var messages = new Messages.silent();
+ var compiler = createCompiler(createFiles(), messages, errors: true,
+ scopedCss: true);
+
+ compiler.run().then(expectAsync1((e) {
+ MockFileSystem fs = compiler.fileSystem;
+ expect(fs.readCount, equals({
+ 'foo.css': 1,
+ 'index.html': 1,
+ }), reason: 'Actual:\n ${fs.readCount}');
+
+ var cssInfo = compiler.info['foo.css'];
+ expect(cssInfo.styleSheets.length, 1);
+ expect(prettyPrintCss(cssInfo.styleSheets[0]), '');
+
+ var htmlInfo = compiler.info['index.html'];
+ expect(htmlInfo.styleSheets.length, 1);
+ expect(prettyPrintCss(htmlInfo.styleSheets[0]),
+ '@import url(foo.css); .test { color: red; }');
+
+ var outputs = compiler.output.map((o) => o.path);
+ expect(outputs, equals([
+ 'out/index.html.dart',
+ 'out/index.html.dart.map',
+ 'out/index.html_bootstrap.dart',
+ 'out/foo.css',
+ 'out/index.html',
+ ]));
+ }));
+}
+
+test_imports() {
+ Map createFiles() {
+ return {
+ 'first.css':
+ '@import "third.css";'
+ '@main-width: var(main-width-b);'
+ '@main-width-b: var(main-width-c);'
+ '@main-width-c: var(wide-width);',
+ 'second.css':
+ '@import "fourth.css";'
+ '@main-color: var(main-color-b);'
+ '@main-color-b: var(main-color-c);'
+ '@main-color-c: var(color-value);',
+ 'third.css':
+ '@wide-width: var(wide-width-b);'
+ '@wide-width-b: var(wide-width-c);'
+ '@wide-width-c: 100px;',
+ 'fourth.css':
+ '@color-value: var(color-value-b);'
+ '@color-value-b: var(color-value-c);'
+ '@color-value-c: red;',
+ 'index.html':
+ '<!DOCTYPE html>'
+ '<html lang="en">'
+ '<head>'
+ '<meta charset="utf-8">'
+ '<link rel="stylesheet" href="first.css">'
+ '</head>'
+ '<body>'
+ '<style>'
+ '@import "first.css";'
+ '@import "second.css";'
+ '.test-1 { color: var(main-color); }'
+ '.test-2 { width: var(main-width); }'
+ '</style>'
+ '<script type="application/dart">main() {}</script>'
+ '</body>'
+ '</html>',
+ };
+ }
+
+ var messages = new Messages.silent();
+ var compiler = createCompiler(createFiles(), messages, errors: true,
+ scopedCss: true);
+
+ compiler.run().then(expectAsync1((e) {
+ MockFileSystem fs = compiler.fileSystem;
+ expect(fs.readCount, equals({
+ 'first.css': 1,
+ 'second.css': 1,
+ 'third.css': 1,
+ 'fourth.css': 1,
+ 'index.html': 1,
+ }), reason: 'Actual:\n ${fs.readCount}');
+
+ var firstInfo = compiler.info['first.css'];
+ expect(firstInfo.styleSheets.length, 1);
+ expect(prettyPrintCss(firstInfo.styleSheets[0]), '@import url(third.css);');
+
+ var secondInfo = compiler.info['second.css'];
+ expect(secondInfo.styleSheets.length, 1);
+ expect(prettyPrintCss(secondInfo.styleSheets[0]),
+ '@import url(fourth.css);');
+
+ var thirdInfo = compiler.info['third.css'];
+ expect(thirdInfo.styleSheets.length, 1);
+ expect(prettyPrintCss(thirdInfo.styleSheets[0]), '');
+
+ var fourthInfo = compiler.info['fourth.css'];
+ expect(fourthInfo.styleSheets.length, 1);
+ expect(prettyPrintCss(fourthInfo.styleSheets[0]), '');
+
+ var htmlInfo = compiler.info['index.html'];
+ expect(htmlInfo.styleSheets.length, 1);
+ expect(prettyPrintCss(htmlInfo.styleSheets[0]),
+ '@import url(first.css); '
+ '@import url(second.css); '
+ '.test-1 { color: red; } '
+ '.test-2 { width: 100px; }');
+
+ var outputs = compiler.output.map((o) => o.path);
+ expect(outputs, equals([
+ 'out/index.html.dart',
+ 'out/index.html.dart.map',
+ 'out/index.html_bootstrap.dart',
+ 'out/first.css',
+ 'out/second.css',
+ 'out/third.css',
+ 'out/fourth.css',
+ 'out/index.html',
+ ]));
+ }));
+}
+
+test_component_var() {
+ Map createFiles() {
+ return {
+ 'index.html': '<!DOCTYPE html>'
+ '<html lang="en">'
+ '<head>'
+ '<meta charset="utf-8">'
+ '<link rel="import" href="foo.html">'
+ '</head>'
+ '<body>'
+ '<x-foo></x-foo>'
+ '<script type="application/dart">main() {}</script>'
+ '</body>'
+ '</html>',
+ 'foo.html': '<!DOCTYPE html>'
+ '<html lang="en">'
+ '<head>'
+ '<meta charset="utf-8">'
+ '</head>'
+ '<body>'
+ '<polymer-element name="x-foo" constructor="Foo">'
+ '<template>'
+ '<style scoped>'
+ '@import "foo.css";'
+ '.main { color: var(main_color); }'
+ '.test-background { '
+ 'background: url(http://www.foo.com/bar.png);'
+ '}'
+ '</style>'
+ '</template>'
+ '</polymer-element>'
+ '</body>'
+ '</html>',
+ 'foo.css': r'''@main_color: var(b);
+ @b: var(c);
+ @c: red;
+
+ @one: var(two);
+ @two: var(one);
+
+ @four: var(five);
+ @five: var(six);
+ @six: var(four);
+
+ @def-1: var(def-2);
+ @def-2: var(def-3);
+ @def-3: var(def-2);''',
+ };
+ }
+
+ test('var- and Less @define', () {
+ var messages = new Messages.silent();
+ var compiler = createCompiler(createFiles(), messages, errors: true,
+ scopedCss: true);
+
+ compiler.run().then(expectAsync1((e) {
+ MockFileSystem fs = compiler.fileSystem;
+ expect(fs.readCount, equals({
+ 'index.html': 1,
+ 'foo.html': 1,
+ 'foo.css': 1
+ }), reason: 'Actual:\n ${fs.readCount}');
+
+ var cssInfo = compiler.info['foo.css'];
+ expect(cssInfo.styleSheets.length, 1);
+ var htmlInfo = compiler.info['foo.html'];
+ expect(htmlInfo.styleSheets.length, 0);
+ expect(htmlInfo.declaredComponents.length, 1);
+ expect(htmlInfo.declaredComponents[0].styleSheets.length, 1);
+
+ var outputs = compiler.output.map((o) => o.path);
+ expect(outputs, equals([
+ 'out/foo.html.dart',
+ 'out/foo.html.dart.map',
+ 'out/index.html.dart',
+ 'out/index.html.dart.map',
+ 'out/index.html_bootstrap.dart',
+ 'out/foo.css',
+ 'out/index.html.css',
+ 'out/index.html',
+ ]));
+
+ for (var file in compiler.output) {
+ if (file.path == 'out/index.html.css') {
+ expect(file.contents,
+ '/* Auto-generated from components style tags. */\n'
+ '/* DO NOT EDIT. */\n\n'
+ '/* ==================================================== \n'
+ ' Component x-foo stylesheet \n'
+ ' ==================================================== */\n'
+ '@import "foo.css";\n'
+ '[is="x-foo"] .main {\n'
+ ' color: #f00;\n'
+ '}\n'
+ '[is="x-foo"] .test-background {\n'
+ ' background: url("http://www.foo.com/bar.png");\n'
+ '}\n\n');
+ } else if (file.path == 'out/foo.css') {
+ expect(file.contents,
+ '/* Auto-generated from style sheet href = foo.css */\n'
+ '/* DO NOT EDIT. */\n\n\n\n');
+ }
+ }
+
+ // Check for warning messages about var- cycles.
+ expect(messages.messages.length, 8);
+
+ var errorMessage = messages.messages[0];
+ expect(errorMessage.message, contains('var cycle detected var-def-1'));
+ expect(errorMessage.span, isNotNull);
+ expect(errorMessage.span.start.line, 11);
+ expect(errorMessage.span.start.column, 22);
+ expect(errorMessage.span.text, '@def-1: var(def-2)');
+
+ errorMessage = messages.messages[1];
+ expect(errorMessage.message, contains('var cycle detected var-five'));
+ expect(errorMessage.span, isNotNull);
+ expect(errorMessage.span.start.line, 8);
+ expect(errorMessage.span.start.column, 22);
+ expect(errorMessage.span.text, '@five: var(six)');
+
+ errorMessage = messages.messages[2];
+ expect(errorMessage.message, contains('var cycle detected var-six'));
+ expect(errorMessage.span, isNotNull);
+ expect(errorMessage.span.start.line, 9);
+ expect(errorMessage.span.start.column, 22);
+ expect(errorMessage.span.text, '@six: var(four)');
+
+ errorMessage = messages.messages[3];
+ expect(errorMessage.message, contains('var cycle detected var-def-3'));
+ expect(errorMessage.span, isNotNull);
+ expect(errorMessage.span.start.line, 13);
+ expect(errorMessage.span.start.column, 22);
+ expect(errorMessage.span.text, '@def-3: var(def-2)');
+
+ errorMessage = messages.messages[4];
+ expect(errorMessage.message, contains('var cycle detected var-two'));
+ expect(errorMessage.span, isNotNull);
+ expect(errorMessage.span.start.line, 5);
+ expect(errorMessage.span.start.column, 22);
+ expect(errorMessage.span.text, '@two: var(one)');
+
+ errorMessage = messages.messages[5];
+ expect(errorMessage.message, contains('var cycle detected var-def-2'));
+ expect(errorMessage.span, isNotNull);
+ expect(errorMessage.span.start.line, 12);
+ expect(errorMessage.span.start.column, 22);
+ expect(errorMessage.span.text, '@def-2: var(def-3)');
+
+ errorMessage = messages.messages[6];
+ expect(errorMessage.message, contains('var cycle detected var-one'));
+ expect(errorMessage.span, isNotNull);
+ expect(errorMessage.span.start.line, 4);
+ expect(errorMessage.span.start.column, 22);
+ expect(errorMessage.span.text, '@one: var(two)');
+
+ errorMessage = messages.messages[7];
+ expect(errorMessage.message, contains('var cycle detected var-four'));
+ expect(errorMessage.span, isNotNull);
+ expect(errorMessage.span.start.line, 7);
+ expect(errorMessage.span.start.column, 22);
+ expect(errorMessage.span.text, '@four: var(five)');
+ }));
+ });
+}
+
+test_pseudo_element() {
+ var messages = new Messages.silent();
+ var compiler = createCompiler({
+ 'index.html': '<head>'
+ '<link rel="import" href="foo.html">'
+ '<style>'
+ '.test::x-foo { background-color: red; }'
+ '.test::x-foo1 { color: blue; }'
+ '.test::x-foo2 { color: green; }'
+ '</style>'
+ '<body>'
+ '<x-foo class=test></x-foo>'
+ '<x-foo></x-foo>'
+ '<script type="application/dart">main() {}</script>',
+ 'foo.html': '<head>'
+ '<body><polymer-element name="x-foo" constructor="Foo">'
+ '<template>'
+ '<div pseudo="x-foo">'
+ '<div>Test</div>'
+ '</div>'
+ '<div pseudo="x-foo1 x-foo2">'
+ '<div>Test</div>'
+ '</div>'
+ '</template>',
+ }, messages, scopedCss: true);
+
+ compiler.run().then(expectAsync1((e) {
+ MockFileSystem fs = compiler.fileSystem;
+ expect(fs.readCount, equals({
+ 'index.html': 1,
+ 'foo.html': 1,
+ }), reason: 'Actual:\n ${fs.readCount}');
+
+ var outputs = compiler.output.map((o) => o.path);
+ expect(outputs, equals([
+ 'out/foo.html.dart',
+ 'out/foo.html.dart.map',
+ 'out/index.html.dart',
+ 'out/index.html.dart.map',
+ 'out/index.html_bootstrap.dart',
+ 'out/index.html',
+ ]));
+ expect(compiler.output.last.contents, contains(
+ '<div pseudo="x-foo_0">'
+ '<div>Test</div>'
+ '</div>'
+ '<div pseudo="x-foo1_1 x-foo2_2">'
+ '<div>Test</div>'
+ '</div>'));
+ expect(compiler.output.last.contents, contains(
+ '<style>.test > *[pseudo="x-foo_0"] {\n'
+ ' background-color: #f00;\n'
+ '}\n'
+ '.test > *[pseudo="x-foo1_1"] {\n'
+ ' color: #00f;\n'
+ '}\n'
+ '.test > *[pseudo="x-foo2_2"] {\n'
+ ' color: #008000;\n'
+ '}'
+ '</style>'));
+ }));
+}
+
+main() {
+ useCompactVMConfiguration();
+
+ group('css', () {
+ setUp(() {
+ utils.path = new path.Builder(style: path.Style.posix);
+ });
+
+ tearDown(() {
+ utils.path = new path.Builder();
+ });
+
+ test('test_simple_var', test_simple_var);
+ test('test_var', test_var);
+ test('test_simple_import', test_simple_import);
+ test('test_imports', test_imports);
+ group('test_component_var', test_component_var);
+ test('test_pseudo_element', test_pseudo_element);
+ });
+}
diff --git a/pkg/polymer/test/data/unit/event_path_test.html b/pkg/polymer/test/data/unit/event_path_test.html
new file mode 100644
index 0000000..811479d
--- /dev/null
+++ b/pkg/polymer/test/data/unit/event_path_test.html
@@ -0,0 +1,142 @@
+<!doctype html>
+<!--
+ 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.
+-->
+<html>
+ <head>
+ <title>event path</title>
+ <script src="packages/polymer/testing/testing.js"></script>
+ <script src="packages/unittest/test_controller.js"></script>
+ <!--
+ Test ported from:
+ https://github.com/Polymer/polymer/blob/7936ff8/test/html/event-path.html
+
+ This test actually doesn't test the polymer's event layer. It just ensures
+ that tests are propagated in the right order when using Shadow DOM.
+ -->
+ </head>
+ <body>
+
+ <polymer-element name="x-selector">
+ <template>
+ <div id="selectorDiv">
+ <content id="selectorContent"></content>
+ </div>
+ </template>
+ <script type="application/dart">
+ import 'package:polymer/polymer.dart';
+ @CustomTag("x-selector")
+ class XSelector extends PolymerElement {}
+ </script>
+ </polymer-element>
+
+ <polymer-element name="x-overlay">
+ <template>
+ <content id="overlayContent"></content>
+ </template>
+ <script type="application/dart">
+ import 'package:polymer/polymer.dart';
+ @CustomTag("x-overlay")
+ class XOverlay extends PolymerElement {}
+ </script>
+ </polymer-element>
+
+ <polymer-element name="x-menu" extends="x-selector">
+ <template>
+ <div id="menuDiv">
+ <shadow id="menuShadow"></shadow>
+ </div>
+ </template>
+ <script type="application/dart">
+ import 'package:polymer/polymer.dart';
+ @CustomTag("x-menu")
+ class XMenu extends PolymerElement {}
+ </script>
+ </polymer-element>
+
+ <polymer-element name="x-menu-button">
+ <template>
+ <div>
+ <x-overlay id="overlay">
+ <div id="menuButtonDiv">
+ <x-menu id="menu">
+ <content id="menuButtonContent"></content>
+ </x-menu>
+ </div>
+ </x-overlay>
+ </div>
+ </template>
+ <script type="application/dart">
+ import 'package:polymer/polymer.dart';
+ @CustomTag("x-menu-button")
+ class XMenuButton extends PolymerElement {}
+ </script>
+ </polymer-element>
+
+ <x-menu-button id="menuButton">
+ <div id="item1"><div id="source"></div>Item1</div>
+ <div id="item2">Item2</div>
+ </x-menu-button>
+
+
+ <script type="application/dart">
+ import 'dart:html';
+ import 'dart:async';
+ import 'package:unittest/unittest.dart';
+ import 'package:unittest/html_config.dart';
+
+ main() {
+ useHtmlConfiguration();
+ test('bubbling in the right order', () {
+ // TODO(sigmund): this should change once we port over the
+ // 'WebComponentsReady' event.
+ runAsync(expectAsync0(() {
+ var item1 = query('#item1');
+ var menuButton = query('#menuButton');
+ // Note: polymer uses automatic node finding (menuButton.$.menu)
+ // also note that their node finding code also reachs into the ids
+ // from the parent shadow (menu.$.selectorContent instead of
+ // menu.$.menuShadow.$.selectorContent)
+ var menu = menuButton.shadowRoot.query('#menu');
+ var selector = menu.shadowRoot.query("#menuShadow");
+ var overlay = menuButton.shadowRoot.query('#overlay');
+ var expectedPath = <Node>[
+ item1,
+ menuButton.shadowRoot.query('#menuButtonContent'),
+ selector.olderShadowRoot.query('#selectorContent'),
+ selector.olderShadowRoot.query('#selectorDiv'),
+ menu.shadowRoot.query('#menuShadow').olderShadowRoot,
+ menu.shadowRoot.query('#menuShadow'),
+ menu.shadowRoot.query('#menuDiv'),
+ menu.shadowRoot,
+ menu,
+ menuButton.shadowRoot.query('#menuButtonDiv'),
+ // TODO(sigmund): this test is currently broken because currently
+ // registerElement is sensitive to the order in which each custom
+ // element is registered. When fixed, we should be able to add the
+ // following three targets:
+ // overlay.shadowRoot.query('#overlayContent'),
+ // overlay.shadowRoot,
+ // overlay,
+ menuButton.shadowRoot,
+ menuButton
+ ];
+ var x = 0;
+ for (int i = 0; i < expectedPath.length; i++) {
+ var node = expectedPath[i];
+ expect(node, isNotNull, reason: "Should not be null at $i");
+ node.on['x'].listen(expectAsync1((e) {
+ expect(e.currentTarget, node);
+ expect(x++, i);
+ }));
+ }
+
+ item1.dispatchEvent(new Event('x', canBubble: true));
+ }));
+ });
+ }
+ </script>
+ </body>
+</html>
diff --git a/pkg/polymer/test/data/unit/events_test.html b/pkg/polymer/test/data/unit/events_test.html
new file mode 100644
index 0000000..cbf33d1
--- /dev/null
+++ b/pkg/polymer/test/data/unit/events_test.html
@@ -0,0 +1,97 @@
+<!doctype html>
+<!--
+ 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.
+-->
+<html>
+ <head>
+ <title>event path</title>
+ <script src="packages/polymer/testing/testing.js"></script>
+ <script src="packages/unittest/test_controller.js"></script>
+ <!--
+ Test ported from:
+ https://github.com/Polymer/polymer/blob/7936ff8/test/js/events.js
+
+ TODO(sigmund): when we have support for mutation observers, render all of
+ the test in Dart (like events.js does in JS)
+ -->
+ </head>
+ <body>
+
+ <polymer-element name="test-a" on-click="clickHandler">
+ <template></template>
+ <script type="application/dart">
+ import 'package:polymer/polymer.dart';
+
+ @CustomTag("test-a")
+ class TestA extends PolymerElement {
+ List clicks = [];
+ void clickHandler() {
+ clicks.add('host click on: $localName (id $id)');
+ }
+ }
+ </script>
+ </polymer-element>
+
+ <polymer-element name="test-b">
+ <template>
+ <div>
+ <span id="b-1">1</span>
+ <span id="b-2" on-click="clickHandler">2</span>
+ </div>
+ </template>
+ <script type="application/dart">
+ import 'package:polymer/polymer.dart';
+
+ @CustomTag("test-b")
+ class TestB extends PolymerElement {
+ List clicks = [];
+ void clickHandler(event, detail, target) {
+ clicks.add('local click under $localName (id $id) on ${target.id}');
+ }
+ }
+ </script>
+ </polymer-element>
+
+ <test-a id="a"></test-a>
+ <test-b id="b"></test-b>
+
+ <script type="application/dart">
+ import 'dart:html';
+ import 'dart:async';
+ import 'package:unittest/unittest.dart';
+ import 'package:unittest/html_config.dart';
+
+ main() {
+ useHtmlConfiguration();
+
+ test('host event', () {
+ // Note: this test is currently the only event in
+ // polymer/test/js/events.js at commit #7936ff8
+ Timer.run(expectAsync0(() {
+ var testA = query('#a');
+ expect(testA.xtag.clicks, isEmpty);
+ testA.click();
+ expect(testA.xtag.clicks, ['host click on: test-a (id a)']);
+ }));
+ });
+
+ test('local event', () {
+ Timer.run(expectAsync0(() {
+ var testB = query('#b');
+ expect(testB.xtag.clicks, isEmpty);
+ testB.click();
+ expect(testB.xtag.clicks, []);
+ var b1 = testB.shadowRoot.query('#b-1');
+ b1.click();
+ expect(testB.xtag.clicks, []);
+ var b2 = testB.shadowRoot.query('#b-2');
+ b2.click();
+ expect(testB.xtag.clicks, ['local click under test-b (id b) on b-2']);
+ }));
+ });
+ }
+ </script>
+ </body>
+</html>
diff --git a/pkg/polymer/test/paths_test.dart b/pkg/polymer/test/paths_test.dart
new file mode 100644
index 0000000..4a54a9d
--- /dev/null
+++ b/pkg/polymer/test/paths_test.dart
@@ -0,0 +1,339 @@
+// 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 for [PathMapper]. */
+library path_info_test;
+
+import 'package:path/path.dart' as path;
+import 'package:polymer/src/info.dart';
+import 'package:polymer/src/paths.dart';
+import 'package:polymer/src/utils.dart' as utils;
+import 'package:unittest/compact_vm_config.dart';
+import 'package:unittest/unittest.dart';
+
+main() {
+ useCompactVMConfiguration();
+ group('paths', () {
+ setUp(() {
+ utils.path = new path.Builder(style: path.Style.posix);
+ });
+
+ tearDown(() {
+ utils.path = new path.Builder();
+ });
+
+ testPaths();
+ });
+}
+
+testPaths() {
+ group('outdir == basedir:', () {
+ group('outputPath', () {
+ test('mangle automatic', () {
+ var pathMapper = _newPathMapper('a', 'a', false);
+ var file = _mockFile('a/b.dart', pathMapper);
+ expect(file.dartCodeUrl.resolvedPath, 'a/b.dart');
+ expect(pathMapper.outputPath(file.dartCodeUrl.resolvedPath, '.dart'),
+ 'a/_b.dart.dart');
+ });
+
+ test('within packages/', () {
+ var pathMapper = _newPathMapper('a', 'a', false);
+ var file = _mockFile('a/packages/b.dart', pathMapper);
+ expect(file.dartCodeUrl.resolvedPath, 'a/packages/b.dart');
+ expect(pathMapper.outputPath(file.dartCodeUrl.resolvedPath, '.dart'),
+ 'a/_from_packages/_b.dart.dart');
+ });
+ });
+
+ group('importUrlFor', () {
+ test('simple pathMapper', () {
+ var pathMapper = _newPathMapper('a', 'a', false);
+ var file1 = _mockFile('a/b.dart', pathMapper);
+ var file2 = _mockFile('a/c/d.dart', pathMapper);
+ var file3 = _mockFile('a/e/f.dart', pathMapper);
+ expect(pathMapper.importUrlFor(file1, file2), 'c/_d.dart.dart');
+ expect(pathMapper.importUrlFor(file1, file3), 'e/_f.dart.dart');
+ expect(pathMapper.importUrlFor(file2, file1), '../_b.dart.dart');
+ expect(pathMapper.importUrlFor(file2, file3), '../e/_f.dart.dart');
+ expect(pathMapper.importUrlFor(file3, file2), '../c/_d.dart.dart');
+ expect(pathMapper.importUrlFor(file3, file1), '../_b.dart.dart');
+ });
+
+ test('include packages/', () {
+ var pathMapper = _newPathMapper('a', 'a', false);
+ var file1 = _mockFile('a/b.dart', pathMapper);
+ var file2 = _mockFile('a/c/d.dart', pathMapper);
+ var file3 = _mockFile('a/packages/f.dart', pathMapper);
+ expect(pathMapper.importUrlFor(file1, file2), 'c/_d.dart.dart');
+ expect(pathMapper.importUrlFor(file1, file3),
+ '_from_packages/_f.dart.dart');
+ expect(pathMapper.importUrlFor(file2, file1), '../_b.dart.dart');
+ expect(pathMapper.importUrlFor(file2, file3),
+ '../_from_packages/_f.dart.dart');
+ expect(pathMapper.importUrlFor(file3, file2), '../c/_d.dart.dart');
+ expect(pathMapper.importUrlFor(file3, file1), '../_b.dart.dart');
+ });
+
+ test('packages, but no rewrite', () {
+ var pathMapper = _newPathMapper('a', 'a', false, rewriteUrls: false);
+ var file1 = _mockFile('a/b.dart', pathMapper);
+ var file2 = _mockFile('a/c/d.dart', pathMapper);
+ var file3 = _mockFile('a/packages/c/f.dart', pathMapper,
+ url: 'package:e/f.dart');
+ expect(pathMapper.importUrlFor(file1, file2), 'c/_d.dart.dart');
+ expect(pathMapper.importUrlFor(file1, file3),
+ 'package:e/_f.dart.dart');
+ expect(pathMapper.importUrlFor(file2, file1), '../_b.dart.dart');
+ expect(pathMapper.importUrlFor(file2, file3),
+ 'package:e/_f.dart.dart');
+ });
+
+ test('windows paths', () {
+ try {
+ utils.path = new path.Builder(style: path.Style.windows);
+ var pathMapper = _newPathMapper('a', 'a', false);
+ var file1 = _mockFile('a\\b.dart', pathMapper);
+ var file2 = _mockFile('a\\c\\d.dart', pathMapper);
+ var file3 = _mockFile('a\\packages\\f.dart', pathMapper);
+ expect(pathMapper.importUrlFor(file1, file2), 'c/_d.dart.dart');
+ expect(pathMapper.importUrlFor(file1, file3),
+ '_from_packages/_f.dart.dart');
+ expect(pathMapper.importUrlFor(file2, file1), '../_b.dart.dart');
+ expect(pathMapper.importUrlFor(file2, file3),
+ '../_from_packages/_f.dart.dart');
+ expect(pathMapper.importUrlFor(file3, file2), '../c/_d.dart.dart');
+ expect(pathMapper.importUrlFor(file3, file1), '../_b.dart.dart');
+ } finally {
+ utils.path = new path.Builder();
+ }
+ });
+ });
+
+ test('transformUrl simple paths', () {
+ var pathMapper = _newPathMapper('a', 'a', false);
+ var file1 = 'a/b.dart';
+ var file2 = 'a/c/d.html';
+ // when the output == input directory, no paths should be rewritten
+ expect(pathMapper.transformUrl(file1, '/a.dart'), '/a.dart');
+ expect(pathMapper.transformUrl(file1, 'c.dart'), 'c.dart');
+ expect(pathMapper.transformUrl(file1, '../c/d.dart'), '../c/d.dart');
+ expect(pathMapper.transformUrl(file1, 'packages/c.dart'),
+ 'packages/c.dart');
+ expect(pathMapper.transformUrl(file2, 'e.css'), 'e.css');
+ expect(pathMapper.transformUrl(file2, '../c/e.css'), 'e.css');
+ expect(pathMapper.transformUrl(file2, '../q/e.css'), '../q/e.css');
+ expect(pathMapper.transformUrl(file2, 'packages/c.css'),
+ 'packages/c.css');
+ expect(pathMapper.transformUrl(file2, '../packages/c.css'),
+ '../packages/c.css');
+ });
+
+ test('transformUrl with source in packages/', () {
+ var pathMapper = _newPathMapper('a', 'a', false);
+ var file = 'a/packages/e.html';
+ // Even when output == base, files under packages/ are moved to
+ // _from_packages, so all imports are affected:
+ expect(pathMapper.transformUrl(file, 'e.css'), '../packages/e.css');
+ expect(pathMapper.transformUrl(file, '../packages/e.css'),
+ '../packages/e.css');
+ expect(pathMapper.transformUrl(file, '../q/e.css'), '../q/e.css');
+ expect(pathMapper.transformUrl(file, 'packages/c.css'),
+ '../packages/packages/c.css');
+ });
+ });
+
+ group('outdir != basedir:', () {
+ group('outputPath', (){
+ test('no force mangle', () {
+ var pathMapper = _newPathMapper('a', 'out', false);
+ var file = _mockFile('a/b.dart', pathMapper);
+ expect(file.dartCodeUrl.resolvedPath, 'a/b.dart');
+ expect(pathMapper.outputPath(file.dartCodeUrl.resolvedPath, '.dart'),
+ 'out/b.dart');
+ });
+
+ test('force mangling', () {
+ var pathMapper = _newPathMapper('a', 'out', true);
+ var file = _mockFile('a/b.dart', pathMapper);
+ expect(file.dartCodeUrl.resolvedPath, 'a/b.dart');
+ expect(pathMapper.outputPath(file.dartCodeUrl.resolvedPath, '.dart'),
+ 'out/_b.dart.dart');
+ });
+
+ test('within packages/, no mangle', () {
+ var pathMapper = _newPathMapper('a', 'out', false);
+ var file = _mockFile('a/packages/b.dart', pathMapper);
+ expect(file.dartCodeUrl.resolvedPath, 'a/packages/b.dart');
+ expect(pathMapper.outputPath(file.dartCodeUrl.resolvedPath, '.dart'),
+ 'out/_from_packages/b.dart');
+ });
+
+ test('within packages/, mangle', () {
+ var pathMapper = _newPathMapper('a', 'out', true);
+ var file = _mockFile('a/packages/b.dart', pathMapper);
+ expect(file.dartCodeUrl.resolvedPath, 'a/packages/b.dart');
+ expect(pathMapper.outputPath(file.dartCodeUrl.resolvedPath, '.dart'),
+ 'out/_from_packages/_b.dart.dart');
+ });
+ });
+
+ group('importUrlFor', (){
+ test('simple paths, no mangle', () {
+ var pathMapper = _newPathMapper('a', 'out', false);
+ var file1 = _mockFile('a/b.dart', pathMapper);
+ var file2 = _mockFile('a/c/d.dart', pathMapper);
+ var file3 = _mockFile('a/e/f.dart', pathMapper);
+ expect(pathMapper.importUrlFor(file1, file2), 'c/d.dart');
+ expect(pathMapper.importUrlFor(file1, file3), 'e/f.dart');
+ expect(pathMapper.importUrlFor(file2, file1), '../b.dart');
+ expect(pathMapper.importUrlFor(file2, file3), '../e/f.dart');
+ expect(pathMapper.importUrlFor(file3, file2), '../c/d.dart');
+ expect(pathMapper.importUrlFor(file3, file1), '../b.dart');
+ });
+
+ test('simple paths, mangle', () {
+ var pathMapper = _newPathMapper('a', 'out', true);
+ var file1 = _mockFile('a/b.dart', pathMapper);
+ var file2 = _mockFile('a/c/d.dart', pathMapper);
+ var file3 = _mockFile('a/e/f.dart', pathMapper);
+ expect(pathMapper.importUrlFor(file1, file2), 'c/_d.dart.dart');
+ expect(pathMapper.importUrlFor(file1, file3), 'e/_f.dart.dart');
+ expect(pathMapper.importUrlFor(file2, file1), '../_b.dart.dart');
+ expect(pathMapper.importUrlFor(file2, file3), '../e/_f.dart.dart');
+ expect(pathMapper.importUrlFor(file3, file2), '../c/_d.dart.dart');
+ expect(pathMapper.importUrlFor(file3, file1), '../_b.dart.dart');
+ });
+
+ test('include packages/, no mangle', () {
+ var pathMapper = _newPathMapper('a', 'out', false);
+ var file1 = _mockFile('a/b.dart', pathMapper);
+ var file2 = _mockFile('a/c/d.dart', pathMapper);
+ var file3 = _mockFile('a/packages/e/f.dart', pathMapper,
+ url: 'package:e/f.dart');
+ expect(pathMapper.importUrlFor(file1, file2), 'c/d.dart');
+ expect(pathMapper.importUrlFor(file1, file3),
+ '_from_packages/e/f.dart');
+ expect(pathMapper.importUrlFor(file2, file1), '../b.dart');
+ expect(pathMapper.importUrlFor(file2, file3),
+ '../_from_packages/e/f.dart');
+ expect(pathMapper.importUrlFor(file3, file2), '../../c/d.dart');
+ expect(pathMapper.importUrlFor(file3, file1), '../../b.dart');
+ });
+
+ test('include packages/, mangle', () {
+ var pathMapper = _newPathMapper('a', 'out', true);
+ var file1 = _mockFile('a/b.dart', pathMapper);
+ var file2 = _mockFile('a/c/d.dart', pathMapper);
+ var file3 = _mockFile('a/packages/e/f.dart', pathMapper,
+ url: 'package:e/f.dart');
+ expect(pathMapper.importUrlFor(file1, file2), 'c/_d.dart.dart');
+ expect(pathMapper.importUrlFor(file1, file3),
+ '_from_packages/e/_f.dart.dart');
+ expect(pathMapper.importUrlFor(file2, file1), '../_b.dart.dart');
+ expect(pathMapper.importUrlFor(file2, file3),
+ '../_from_packages/e/_f.dart.dart');
+ expect(pathMapper.importUrlFor(file3, file2), '../../c/_d.dart.dart');
+ expect(pathMapper.importUrlFor(file3, file1), '../../_b.dart.dart');
+ });
+
+ test('windows paths', () {
+ try {
+ utils.path = new path.Builder(style: path.Style.windows);
+ var pathMapper = _newPathMapper('a', 'out', true);
+ var file1 = _mockFile('a\\b.dart', pathMapper);
+ var file2 = _mockFile('a\\c\\d.dart', pathMapper);
+ var file3 = _mockFile('a\\packages\\f.dart', pathMapper);
+ expect(pathMapper.importUrlFor(file1, file2), 'c/_d.dart.dart');
+ expect(pathMapper.importUrlFor(file1, file3),
+ '_from_packages/_f.dart.dart');
+ expect(pathMapper.importUrlFor(file2, file1), '../_b.dart.dart');
+ expect(pathMapper.importUrlFor(file2, file3),
+ '../_from_packages/_f.dart.dart');
+ expect(pathMapper.importUrlFor(file3, file2), '../c/_d.dart.dart');
+ expect(pathMapper.importUrlFor(file3, file1), '../_b.dart.dart');
+ } finally {
+ utils.path = new path.Builder();
+ }
+ });
+ });
+
+ group('transformUrl', () {
+ test('simple source, not in packages/', () {
+ var pathMapper = _newPathMapper('a', 'out', false);
+ var file1 = 'a/b.dart';
+ var file2 = 'a/c/d.html';
+ // when the output == input directory, no paths should be rewritten
+ expect(pathMapper.transformUrl(file1, '/a.dart'), '/a.dart');
+ expect(pathMapper.transformUrl(file1, 'c.dart'), '../a/c.dart');
+
+ // reach out from basedir:
+ expect(pathMapper.transformUrl(file1, '../c/d.dart'), '../c/d.dart');
+
+ // reach into packages dir:
+ expect(pathMapper.transformUrl(file1, 'packages/c.dart'),
+ '../a/packages/c.dart');
+
+ expect(pathMapper.transformUrl(file2, 'e.css'), '../../a/c/e.css');
+
+ _checkPath('../../a/c/../c/e.css', '../../a/c/e.css');
+ expect(pathMapper.transformUrl(file2, '../c/e.css'), '../../a/c/e.css');
+
+ _checkPath('../../a/c/../q/e.css', '../../a/q/e.css');
+ expect(pathMapper.transformUrl(file2, '../q/e.css'), '../../a/q/e.css');
+
+ expect(pathMapper.transformUrl(file2, 'packages/c.css'),
+ '../../a/c/packages/c.css');
+ _checkPath('../../a/c/../packages/c.css', '../../a/packages/c.css');
+ expect(pathMapper.transformUrl(file2, '../packages/c.css'),
+ '../../a/packages/c.css');
+ });
+
+ test('input in packages/', () {
+ var pathMapper = _newPathMapper('a', 'out', true);
+ var file = 'a/packages/e.html';
+ expect(pathMapper.transformUrl(file, 'e.css'),
+ '../../a/packages/e.css');
+ expect(pathMapper.transformUrl(file, '../packages/e.css'),
+ '../../a/packages/e.css');
+ expect(pathMapper.transformUrl(file, '../q/e.css'), '../../a/q/e.css');
+ expect(pathMapper.transformUrl(file, 'packages/c.css'),
+ '../../a/packages/packages/c.css');
+ });
+
+ test('src fragments', () {
+ var pathMapper = _newPathMapper('a', 'out', false);
+ var file1 = 'a/b.dart';
+ var file2 = 'a/c/html.html';
+ // when the output == input directory, no paths should be rewritten
+ expect(pathMapper.transformUrl(file1, '#tips'), '#tips');
+ expect(pathMapper.transformUrl(file1,
+ 'http://www.w3schools.com/html_links.htm#tips'),
+ 'http://www.w3schools.com/html_links.htm#tips');
+ expect(pathMapper.transformUrl(file2,
+ 'html_links.html'),
+ '../../a/c/html_links.html');
+ expect(pathMapper.transformUrl(file2,
+ 'html_links.html#tips'),
+ '../../a/c/html_links.html#tips');
+ });
+ });
+ });
+}
+
+_newPathMapper(String baseDir, String outDir, bool forceMangle,
+ {bool rewriteUrls: true}) =>
+ new PathMapper(baseDir, outDir, 'packages', forceMangle, rewriteUrls);
+
+_mockFile(String filePath, PathMapper pathMapper, {String url}) {
+ var file = new FileInfo(new UrlInfo(
+ url == null ? filePath : url, filePath, null));
+ file.outputFilename = pathMapper.mangle(
+ utils.path.basename(filePath), '.dart', false);
+ return file;
+}
+
+_checkPath(String filePath, String expected) {
+ expect(utils.path.normalize(filePath), expected);
+}
diff --git a/pkg/polymer/test/run.sh b/pkg/polymer/test/run.sh
new file mode 100755
index 0000000..0d2b569
--- /dev/null
+++ b/pkg/polymer/test/run.sh
@@ -0,0 +1,134 @@
+#!/bin/bash
+# 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.
+
+# Usage: call directly in the commandline as test/run.sh ensuring that you have
+# both 'dart' and 'content_shell' in your path. Filter tests by passing a
+# pattern as an argument to this script.
+
+# TODO(sigmund): replace with a real test runner
+
+# bail on error
+set -e
+
+# print commands executed by this script
+# set -x
+
+DIR=$( cd $( dirname "${BASH_SOURCE[0]}" ) && pwd )
+export DART_FLAGS="--checked"
+TEST_PATTERN=$1
+
+function fail {
+ return 1
+}
+
+function show_diff {
+ diff -u -N $1 $2 | \
+ sed -e "s/^\(+.*\)/[32m\1[0m/" |\
+ sed -e "s/^\(-.*\)/[31m\1[0m/"
+ return 1
+}
+
+function update {
+ read -p "Would you like to update the expectations? [y/N]: " answer
+ if [[ $answer == 'y' || $answer == 'Y' ]]; then
+ cp $2 $1
+ return 0
+ fi
+ return 1
+}
+
+function pass {
+ echo -e "[32mOK[0m"
+}
+
+function compare {
+ # use a standard diff, if they are not identical, format the diff nicely to
+ # see what's the error and prompt to see if they wish to update it. If they
+ # do, continue running more tests.
+ diff -q $1 $2 && pass || show_diff $1 $2 || update $1 $2
+}
+
+if [[ ($TEST_PATTERN == "") ]]; then
+ # Note: dartanalyzer needs to be run from the root directory for proper path
+ # canonicalization.
+ pushd $DIR/.. > /dev/null
+
+ echo Analyzing compiler for warnings or type errors
+ dartanalyzer --hints --fatal-warnings --fatal-type-errors bin/dwc.dart
+
+ echo -e "\nAnalyzing runtime for warnings or type errors"
+ dartanalyzer --hints --fatal-warnings --fatal-type-errors lib/polymer.dart
+
+ popd > /dev/null
+fi
+
+function compare_all {
+# TODO(jmesserly): bash and dart regexp might not be 100% the same. Ideally we
+# could do all the heavy lifting in Dart code, and keep this script as a thin
+# wrapper that sets `--enable-type-checks --enable-asserts`
+ for input in $DIR/../example/component/news/test/*_test.html \
+ $DIR/../../../samples/third_party/todomvc/test/*_test.html; do
+ if [[ ($TEST_PATTERN == "") || ($input =~ $TEST_PATTERN) ]]; then
+ FILENAME=`basename $input`
+ DIRNAME=`dirname $input`
+ if [[ `basename $DIRNAME` == 'input' ]]; then
+ DIRNAME=`dirname $DIRNAME`
+ fi
+ echo -e -n "Checking diff for $FILENAME "
+ DUMP="$DIRNAME/out/$FILENAME.txt"
+ EXPECTATION="$DIRNAME/expected/$FILENAME.txt"
+
+ compare $EXPECTATION $DUMP
+ fi
+ done
+ echo -e "[31mSome tests failed[0m"
+ fail
+}
+
+if [[ -e $DIR/data/input/example ]]; then
+ echo "WARNING: detected old data/input/example symlink."
+ echo "Removing it and rerunning pub install to fix broken example symlinks."
+ echo "See http://dartbug.com/9418 for more information."
+ echo "You should only see this message once."
+ if [[ -e $DIR/packages ]]; then
+ find . -name packages -type l | xargs rm
+ fi
+ rm $DIR/data/input/example
+ pushd $DIR/..
+ pub install
+ popd
+fi
+
+# TODO(jmesserly): dart:io fails if we run the Dart scripts with an absolute
+# path. So use pushd/popd to change the working directory.
+if [[ ($TEST_PATTERN == "") ]]; then
+ pushd $DIR/.. > /dev/null
+ echo -e "\nTesting build.dart... "
+ dart $DART_FLAGS build.dart
+ # Run it the way the editor does. Hide stdout because it is in noisy machine
+ # format. Show stderr in case something breaks.
+ # NOTE: not using --checked because the editor doesn't use it, and to workaround
+ # http://dartbug.com/9637
+ dart build.dart --machine --clean > /dev/null
+ dart build.dart --machine --full > /dev/null
+ dart build.dart --machine --changed ../../samples/third_party/todomvc/web/index.html > /dev/null
+ popd > /dev/null
+fi
+
+pushd $DIR > /dev/null
+echo -e "\nRunning unit tests... "
+dart $DART_FLAGS run_all.dart $@ || compare_all
+popd > /dev/null
+
+# Run Dart analyzer to check that we're generating warning clean code.
+# It's a bit slow, so only do this for TodoMVC and html5_utils tests.
+OUT_PATTERN="$DIR/../../../third_party/samples/todomvc/test/out/test/*$TEST_PATTERN*_bootstrap.dart"
+if [[ `ls $OUT_PATTERN 2>/dev/null` != "" ]]; then
+ echo -e "\nAnalyzing generated code for warnings or type errors."
+ ls $OUT_PATTERN 2>/dev/null | dartanalyzer --package-root=packages \
+ --fatal-warnings --fatal-type-errors -batch
+fi
+
+echo -e "[32mAll tests pass[0m"
diff --git a/pkg/polymer/test/run_all.dart b/pkg/polymer/test/run_all.dart
new file mode 100644
index 0000000..b149502
--- /dev/null
+++ b/pkg/polymer/test/run_all.dart
@@ -0,0 +1,78 @@
+// 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.
+
+/**
+ * This is a helper for run.sh. We try to run all of the Dart code in one
+ * instance of the Dart VM to reduce warm-up time.
+ */
+library run_impl;
+
+import 'dart:io';
+import 'package:unittest/compact_vm_config.dart';
+import 'package:unittest/unittest.dart';
+import 'package:polymer/testing/content_shell_test.dart';
+
+import 'css_test.dart' as css_test;
+import 'compiler_test.dart' as compiler_test;
+import 'paths_test.dart' as paths_test;
+import 'utils_test.dart' as utils_test;
+
+main() {
+ var args = new Options().arguments;
+ var pattern = new RegExp(args.length > 0 ? args[0] : '.');
+
+ useCompactVMConfiguration();
+
+ void addGroup(testFile, testMain) {
+ if (pattern.hasMatch(testFile)) {
+ group(testFile.replaceAll('_test.dart', ':'), testMain);
+ }
+ }
+
+ addGroup('compiler_test.dart', compiler_test.main);
+ addGroup('css_test.dart', css_test.main);
+ addGroup('paths_test.dart', paths_test.main);
+ addGroup('utils_test.dart', utils_test.main);
+
+ endToEndTests('data/unit/', 'data/out');
+
+ // Note: if you're adding more render test suites, make sure to update run.sh
+ // as well for convenient baseline diff/updating.
+
+ // TODO(jmesserly): figure out why this fails in content_shell but works in
+ // Dartium and Firefox when using the ShadowDOM polyfill.
+ exampleTest('../example/component/news', ['--no-shadowdom']..addAll(args));
+
+ exampleTest('../../../samples/third_party/todomvc');
+}
+
+void exampleTest(String path, [List<String> args]) {
+ renderTests(path, '$path/test', '$path/test/expected', '$path/test/out',
+ arguments: args);
+}
+
+void cssCompileMangleTest(String path, String pattern,
+ [bool deleteDirectory = true]) {
+ renderTests(path, path, '$path/expected', '$path/out',
+ arguments: ['--css-mangle'], pattern: pattern,
+ deleteDir: deleteDirectory);
+}
+
+void cssCompilePolyFillTest(String path, String pattern, String cssReset,
+ [bool deleteDirectory = true]) {
+ var args = ['--no-css-mangle'];
+ if (cssReset != null) {
+ args.addAll(['--css-reset', '${path}/${cssReset}']);
+ }
+ renderTests(path, path, '$path/expected', '$path/out',
+ arguments: args, pattern: pattern, deleteDir: deleteDirectory);
+}
+
+void cssCompileShadowDOMTest(String path, String pattern,
+ [bool deleteDirectory = true]) {
+ var args = ['--no-css'];
+ renderTests(path, path, '$path/expected', '$path/out',
+ arguments: args, pattern: pattern,
+ deleteDir: deleteDirectory);
+}
diff --git a/pkg/polymer/test/testing.dart b/pkg/polymer/test/testing.dart
new file mode 100644
index 0000000..c89b416
--- /dev/null
+++ b/pkg/polymer/test/testing.dart
@@ -0,0 +1,111 @@
+// 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.
+
+/** Common definitions used for setting up the test environment. */
+library testing;
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:csslib/visitor.dart';
+import 'package:html5lib/dom.dart';
+import 'package:html5lib/parser.dart';
+import 'package:polymer/src/analyzer.dart';
+import 'package:polymer/src/compiler.dart';
+import 'package:polymer/src/file_system.dart';
+import 'package:polymer/src/info.dart';
+import 'package:polymer/src/messages.dart';
+import 'package:polymer/src/compiler_options.dart';
+import 'package:polymer/src/files.dart';
+import 'package:polymer/src/utils.dart';
+
+
+Document parseDocument(String html) => parse(html);
+
+Element parseSubtree(String html) => parseFragment(html).nodes[0];
+
+FileInfo analyzeDefinitionsInTree(Document doc, Messages messages,
+ {String packageRoot: 'packages'}) {
+
+ return analyzeDefinitions(new GlobalInfo(), new UrlInfo('', '', null),
+ doc, packageRoot, messages);
+}
+
+/** Parses files in [fileContents], with [mainHtmlFile] being the main file. */
+List<SourceFile> parseFiles(Map<String, String> fileContents,
+ [String mainHtmlFile = 'index.html']) {
+
+ var result = <SourceFile>[];
+ fileContents.forEach((filename, contents) {
+ var src = new SourceFile(filename);
+ src.document = parse(contents);
+ result.add(src);
+ });
+
+ return result;
+}
+
+/** Analyze all files. */
+Map<String, FileInfo> analyzeFiles(List<SourceFile> files,
+ {Messages messages, String packageRoot: 'packages'}) {
+ messages = messages == null ? new Messages.silent() : messages;
+ var result = new Map<String, FileInfo>();
+
+ // analyze definitions
+ var global = new GlobalInfo();
+ for (var file in files) {
+ var path = file.path;
+ result[path] = analyzeDefinitions(global, new UrlInfo(path, path, null),
+ file.document, packageRoot, messages);
+ }
+
+ // analyze file contents
+ var uniqueIds = new IntIterator();
+ var pseudoElements = new Map();
+ for (var file in files) {
+ analyzeFile(file, result, uniqueIds, pseudoElements, messages, true);
+ }
+ return result;
+}
+
+Compiler createCompiler(Map files, Messages messages, {bool errors: false,
+ bool scopedCss: false}) {
+ List baseOptions = ['--no-colors', '-o', 'out', '--deploy', 'index.html'];
+ if (errors) baseOptions.insert(0, '--warnings_as_errors');
+ if (scopedCss) baseOptions.insert(0, '--scoped-css');
+ var options = CompilerOptions.parse(baseOptions);
+ var fs = new MockFileSystem(files);
+ return new Compiler(fs, options, messages);
+}
+
+String prettyPrintCss(StyleSheet styleSheet) =>
+ ((new CssPrinter())..visitTree(styleSheet)).toString();
+
+/**
+ * Abstraction around file system access to work in a variety of different
+ * environments.
+ */
+class MockFileSystem extends FileSystem {
+ final Map _files;
+ final Map readCount = {};
+
+ MockFileSystem(this._files);
+
+ Future readTextOrBytes(String filename) => readText(filename);
+
+ Future<String> readText(String path) {
+ readCount[path] = readCount.putIfAbsent(path, () => 0) + 1;
+ var file = _files[path];
+ if (file != null) {
+ return new Future.value(file);
+ } else {
+ return new Future.error(
+ new FileException('MockFileSystem: $path not found'));
+ }
+ }
+
+ // Compiler doesn't call these
+ void writeString(String outfile, String text) {}
+ Future flush() {}
+}
diff --git a/pkg/polymer/test/utils_test.dart b/pkg/polymer/test/utils_test.dart
new file mode 100644
index 0000000..393d215
--- /dev/null
+++ b/pkg/polymer/test/utils_test.dart
@@ -0,0 +1,86 @@
+// 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 for some of the utility helper functions used by the compiler. */
+library utils_test;
+
+import 'package:unittest/compact_vm_config.dart';
+import 'package:unittest/unittest.dart';
+import 'package:polymer/src/utils.dart';
+
+main() {
+ useCompactVMConfiguration();
+
+ for (bool startUppercase in [false, true]) {
+ Matcher caseEquals(String str) {
+ if (startUppercase) str = str[0].toUpperCase() + str.substring(1);
+ return equals(str);
+ }
+
+ camelCase(str) => toCamelCase(str, startUppercase: startUppercase);
+
+ group('toCamelCase startUppercase=$startUppercase', () {
+ test('empty', () {
+ expect(camelCase(''), equals(''));
+ });
+
+ test('single token', () {
+ expect(camelCase('a'), caseEquals('a'));
+ expect(camelCase('ab'), caseEquals('ab'));
+ expect(camelCase('Ab'), caseEquals('Ab'));
+ expect(camelCase('AB'), caseEquals('AB'));
+ expect(camelCase('long_word'), caseEquals('long_word'));
+ });
+
+ test('dashes in the middle', () {
+ expect(camelCase('a-b'), caseEquals('aB'));
+ expect(camelCase('a-B'), caseEquals('aB'));
+ expect(camelCase('A-b'), caseEquals('AB'));
+ expect(camelCase('long-word'), caseEquals('longWord'));
+ });
+
+ test('leading/trailing dashes', () {
+ expect(camelCase('-hi'), caseEquals('Hi'));
+ expect(camelCase('hi-'), caseEquals('hi'));
+ expect(camelCase('hi-friend-'), caseEquals('hiFriend'));
+ });
+
+ test('consecutive dashes', () {
+ expect(camelCase('--hi-friend'), caseEquals('HiFriend'));
+ expect(camelCase('hi--friend'), caseEquals('hiFriend'));
+ expect(camelCase('hi-friend--'), caseEquals('hiFriend'));
+ });
+ });
+ }
+
+ group('toHyphenedName', () {
+ test('empty', () {
+ expect(toHyphenedName(''), '');
+ });
+
+ test('all lower case', () {
+ expect(toHyphenedName('a'), 'a');
+ expect(toHyphenedName('a-b'), 'a-b');
+ expect(toHyphenedName('aBc'), 'a-bc');
+ expect(toHyphenedName('abC'), 'ab-c');
+ expect(toHyphenedName('abc-d'), 'abc-d');
+ expect(toHyphenedName('long_word'), 'long_word');
+ });
+
+ test('capitalized letters in the middle/end', () {
+ expect(toHyphenedName('aB'), 'a-b');
+ expect(toHyphenedName('longWord'), 'long-word');
+ });
+
+ test('leading capital letters', () {
+ expect(toHyphenedName('Hi'), 'hi');
+ expect(toHyphenedName('Hi-'), 'hi-');
+ expect(toHyphenedName('HiFriend'), 'hi-friend');
+ });
+
+ test('consecutive capital letters', () {
+ expect(toHyphenedName('aBC'), 'a-b-c');
+ });
+ });
+}
diff --git a/pkg/scheduled_test/lib/scheduled_process.dart b/pkg/scheduled_test/lib/scheduled_process.dart
index 3ff903c..27ebc17 100644
--- a/pkg/scheduled_test/lib/scheduled_process.dart
+++ b/pkg/scheduled_test/lib/scheduled_process.dart
@@ -5,6 +5,7 @@
library scheduled_test.scheduled_process;
import 'dart:async';
+import 'dart:convert';
import 'dart:io';
import 'scheduled_test.dart';
@@ -203,7 +204,7 @@
return chunk;
})
.transform(new StringDecoder(_encoding))
- .transform(new LineTransformer()));
+ .transform(new LineSplitter()));
}
/// Schedule an exception handler that will clean up the process and provide
diff --git a/pkg/scheduled_test/test/metatest.dart b/pkg/scheduled_test/test/metatest.dart
index 4834b6e..9e94d07 100644
--- a/pkg/scheduled_test/test/metatest.dart
+++ b/pkg/scheduled_test/test/metatest.dart
@@ -200,10 +200,9 @@
/// Special test configuration for use within the child isolates. This hides all
/// output and reports data back to the parent isolate.
-class _MetaConfiguration extends SimpleConfiguration {
- final name = "MetaConfiguration";
+class _MetaConfiguration extends Configuration {
- void logTestCaseMesssage(TestCase testCase, String message) {}
+ _MetaConfiguration() : super.blank();
void onSummary(int passed, int failed, int errors, List<TestCase> results,
String uncaughtError) {
@@ -220,7 +219,4 @@
}).toList()
});
}
-
- void onInit() {}
- void onDone(bool success) {}
}
diff --git a/pkg/scheduled_test/test/scheduled_process_test.dart b/pkg/scheduled_test/test/scheduled_process_test.dart
index b855e02..33cfa7c 100644
--- a/pkg/scheduled_test/test/scheduled_process_test.dart
+++ b/pkg/scheduled_test/test/scheduled_process_test.dart
@@ -5,6 +5,7 @@
library scheduled_process_test;
import 'dart:async';
+import 'dart:convert';
import 'dart:io';
import 'package:path/path.dart' as path;
@@ -367,11 +368,12 @@
var utilsPath = path.absolute(path.join(Platform.script, 'utils.dart'));
return new File(path.join(dir, 'test.dart')).writeAsString('''
import 'dart:async';
+ import 'dart:convert';
import 'dart:io';
var stdinLines = stdin
.transform(new StringDecoder())
- .transform(new LineTransformer());
+ .transform(new LineSplitter());
void main() {
$script
diff --git a/pkg/stack_trace/lib/src/frame.dart b/pkg/stack_trace/lib/src/frame.dart
index 3db4ab5..b222737 100644
--- a/pkg/stack_trace/lib/src/frame.dart
+++ b/pkg/stack_trace/lib/src/frame.dart
@@ -134,6 +134,12 @@
}
}
+ /// Parses a string representation of an IE stack frame.
+ ///
+ /// IE10+ frames look just like V8 frames. Prior to IE10, stack traces can't
+ /// be retrieved.
+ factory Frame.parseIE(String frame) => new Frame.parseV8(frame);
+
/// Parses a string representation of a Firefox stack frame.
factory Frame.parseFirefox(String frame) {
var match = _firefoxFrame.firstMatch(frame);
@@ -155,6 +161,12 @@
return new Frame(uri, int.parse(match[4]), null, member);
}
+ /// Parses a string representation of a Safari stack frame.
+ ///
+ /// Safari 6+ frames look just like Firefox frames. Prior to Safari 6, stack
+ /// traces can't be retrieved.
+ factory Frame.parseSafari(String frame) => new Frame.parseFirefox(frame);
+
/// Parses this package's string representation of a stack frame.
factory Frame.parseFriendly(String frame) {
var match = _friendlyFrame.firstMatch(frame);
diff --git a/pkg/stack_trace/lib/src/trace.dart b/pkg/stack_trace/lib/src/trace.dart
index 863d64e..19f0a12 100644
--- a/pkg/stack_trace/lib/src/trace.dart
+++ b/pkg/stack_trace/lib/src/trace.dart
@@ -14,6 +14,14 @@
final _terseRegExp = new RegExp(r"(-patch)?(/.*)?$");
+/// A RegExp to match V8's stack traces.
+///
+/// V8's traces start with a line that's either just "Error" or else is a
+/// description of the exception that occurred. That description can be multiple
+/// lines, so we just look for any line other than the first that begins with
+/// four spaces and "at".
+final _v8Trace = new RegExp(r"\n at ");
+
/// A RegExp to match Firefox's stack traces.
///
/// Firefox's trace frames start with the name of the function in which the
@@ -74,8 +82,9 @@
factory Trace.parse(String trace) {
try {
if (trace.isEmpty) return new Trace(<Frame>[]);
- if (trace.startsWith("Error\n")) return new Trace.parseV8(trace);
- if (trace.contains(_firefoxTrace)) return new Trace.parseFirefox(trace);
+ if (trace.contains(_v8Trace)) return new Trace.parseV8(trace);
+ // Valid Safari traces are a superset of valid Firefox traces.
+ if (trace.contains(_firefoxTrace)) return new Trace.parseSafari(trace);
if (trace.contains(_friendlyTrace)) return new Trace.parseFriendly(trace);
// Default to parsing the stack trace as a VM trace. This is also hit on
@@ -93,13 +102,36 @@
/// Parses a string representation of a Chrome/V8 stack trace.
Trace.parseV8(String trace)
- : this(trace.split("\n").skip(1).map((line) => new Frame.parseV8(line)));
+ : this(trace.split("\n").skip(1)
+ // It's possible that an Exception's description contains a line that
+ // looks like a V8 trace line, which will screw this up.
+ // Unfortunately, that's impossible to detect.
+ .skipWhile((line) => !line.startsWith(" at "))
+ .map((line) => new Frame.parseV8(line)));
+
+ /// Parses a string representation of an Internet Explorer stack trace.
+ ///
+ /// IE10+ traces look just like V8 traces. Prior to IE10, stack traces can't
+ /// be retrieved.
+ Trace.parseIE(String trace)
+ : this.parseV8(trace);
/// Parses a string representation of a Firefox stack trace.
Trace.parseFirefox(String trace)
: this(trace.trim().split("\n")
.map((line) => new Frame.parseFirefox(line)));
+ /// Parses a string representation of a Safari stack trace.
+ ///
+ /// Safari 6+ stack traces look just like Firefox traces, except that they
+ /// sometimes (e.g. in isolates) have a "[native code]" frame. We just ignore
+ /// this frame to make the stack format more consistent between browsers.
+ /// Prior to Safari 6, stack traces can't be retrieved.
+ Trace.parseSafari(String trace)
+ : this(trace.trim().split("\n")
+ .where((line) => line != '[native code]')
+ .map((line) => new Frame.parseFirefox(line)));
+
/// Parses this package's a string representation of a stack trace.
Trace.parseFriendly(String trace)
: this(trace.trim().split("\n")
diff --git a/pkg/stack_trace/test/trace_test.dart b/pkg/stack_trace/test/trace_test.dart
index 92b2b20..c3ce039 100644
--- a/pkg/stack_trace/test/trace_test.dart
+++ b/pkg/stack_trace/test/trace_test.dart
@@ -61,6 +61,35 @@
equals(Uri.parse("http://pub.dartlang.org/stuff.js")));
expect(trace.frames[2].uri,
equals(Uri.parse("http://pub.dartlang.org/thing.js")));
+
+ trace = new Trace.parse(
+ "Exception: foo\n"
+ ' at Foo._bar (http://pub.dartlang.org/stuff.js:42:21)\n'
+ ' at http://pub.dartlang.org/stuff.js:0:2\n'
+ ' at zip.<anonymous>.zap '
+ '(http://pub.dartlang.org/thing.js:1:100)');
+
+ expect(trace.frames[0].uri,
+ equals(Uri.parse("http://pub.dartlang.org/stuff.js")));
+ expect(trace.frames[1].uri,
+ equals(Uri.parse("http://pub.dartlang.org/stuff.js")));
+ expect(trace.frames[2].uri,
+ equals(Uri.parse("http://pub.dartlang.org/thing.js")));
+
+ trace = new Trace.parse(
+ 'Exception: foo\n'
+ ' bar\n'
+ ' at Foo._bar (http://pub.dartlang.org/stuff.js:42:21)\n'
+ ' at http://pub.dartlang.org/stuff.js:0:2\n'
+ ' at zip.<anonymous>.zap '
+ '(http://pub.dartlang.org/thing.js:1:100)');
+
+ expect(trace.frames[0].uri,
+ equals(Uri.parse("http://pub.dartlang.org/stuff.js")));
+ expect(trace.frames[1].uri,
+ equals(Uri.parse("http://pub.dartlang.org/stuff.js")));
+ expect(trace.frames[2].uri,
+ equals(Uri.parse("http://pub.dartlang.org/thing.js")));
});
test('parses a Firefox stack trace correctly', () {
@@ -101,6 +130,22 @@
equals(Uri.parse("http://pub.dartlang.org/stuff.js")));
});
+ test('.parseSafari', () {
+ var trace = new Trace.parse(
+ 'Foo._bar@http://pub.dartlang.org/stuff.js:42\n'
+ 'zip/<@http://pub.dartlang.org/stuff.js:0\n'
+ 'zip.zap(12, "@)()/<")@http://pub.dartlang.org/thing.js:1\n'
+ '[native code]');
+
+ expect(trace.frames[0].uri,
+ equals(Uri.parse("http://pub.dartlang.org/stuff.js")));
+ expect(trace.frames[1].uri,
+ equals(Uri.parse("http://pub.dartlang.org/stuff.js")));
+ expect(trace.frames[2].uri,
+ equals(Uri.parse("http://pub.dartlang.org/thing.js")));
+ expect(trace.frames.length, equals(3));
+ });
+
test('parses a package:stack_trace stack trace correctly', () {
var trace = new Trace.parse(
'http://dartlang.org/foo/bar.dart 10:11 Foo.<fn>.bar\n'
diff --git a/pkg/unittest/lib/src/configuration.dart b/pkg/unittest/lib/src/configuration.dart
index 4571b90..c9ec1c0 100644
--- a/pkg/unittest/lib/src/configuration.dart
+++ b/pkg/unittest/lib/src/configuration.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// 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.
@@ -16,10 +16,17 @@
factory Configuration() => new SimpleConfiguration();
/**
+ * Creates an [Configuration] instances that does nothing.
+ *
+ * For use by subclasses which wish to implement only a subset of features.
+ */
+ Configuration.blank();
+
+ /**
* If [true], tests are started automatically. Otherwise [runTests]
* must be called explicitly after tests are set up.
*/
- bool get autoStart;
+ bool get autoStart => true;
/**
* Called as soon as the unittest framework becomes initialized. This is done
@@ -28,7 +35,7 @@
* It is also used to tell the vm or browser that tests are going to be run
* asynchronously and that the process should wait until they are done.
*/
- void onInit();
+ void onInit() {}
/** Called as soon as the unittest framework starts running. */
void onStart() {}
@@ -37,31 +44,31 @@
* Called when each test starts. Useful to show intermediate progress on
* a test suite.
*/
- void onTestStart(TestCase testCase);
+ void onTestStart(TestCase testCase) {}
/**
* Called when each test is first completed. Useful to show intermediate
* progress on a test suite.
*/
- void onTestResult(TestCase testCase);
+ void onTestResult(TestCase testCase) {}
/**
* Called when an already completed test changes state. For example: a test
* that was marked as passing may later be marked as being in error because
* it still had callbacks being invoked.
*/
- void onTestResultChanged(TestCase testCase);
+ void onTestResultChanged(TestCase testCase) {}
/**
* Handles the logging of messages by a test case.
*/
- void onLogMessage(TestCase testCase, String message);
+ void onLogMessage(TestCase testCase, String message) {}
/**
* Called when the unittest framework is done running. [success] indicates
* whether all tests passed successfully.
*/
- void onDone(bool success);
+ void onDone(bool success) {}
/**
* Called with the result of all test cases. Browser tests commonly override
@@ -71,6 +78,6 @@
* of tests (e.g. setting up the test).
*/
void onSummary(int passed, int failed, int errors, List<TestCase> results,
- String uncaughtError);
+ String uncaughtError) {}
}
diff --git a/pkg/unittest/lib/src/simple_configuration.dart b/pkg/unittest/lib/src/simple_configuration.dart
index b9d3a02..d4a0f6e 100644
--- a/pkg/unittest/lib/src/simple_configuration.dart
+++ b/pkg/unittest/lib/src/simple_configuration.dart
@@ -22,7 +22,7 @@
* advantage of the platform can create a subclass and override methods from
* this class.
*/
-class SimpleConfiguration implements Configuration {
+class SimpleConfiguration extends Configuration {
// The VM won't shut down if a receive port is open. Use this to make sure
// we correctly wait for asynchronous tests.
ReceivePort _receivePort;
@@ -32,7 +32,7 @@
* Particularly useful in cases where we have parent/child configurations
* such as layout tests.
*/
- final String name = 'Configuration';
+ String get name => 'Configuration';
bool get autoStart => true;
@@ -56,7 +56,7 @@
* The constructor sets up a failure handler for [expect] that redirects
* [expect] failures to [onExpectFailure].
*/
- SimpleConfiguration() {
+ SimpleConfiguration() : super.blank() {
configureExpectFailureHandler(new _ExpectFailureHandler(this));
}
@@ -65,8 +65,6 @@
_postMessage('unittest-suite-wait-for-done');
}
- void onStart() {}
-
/**
* Called when each test starts. Useful to show intermediate progress on
* a test suite. Derived classes should call this first before their own
diff --git a/pkg/unittest/test/unittest_test_utils.dart b/pkg/unittest/test/unittest_test_utils.dart
index 03fc8d6..7d9a922 100644
--- a/pkg/unittest/test/unittest_test_utils.dart
+++ b/pkg/unittest/test/unittest_test_utils.dart
@@ -33,7 +33,7 @@
'$setup:$teardown:$uncaughtError$testDetails';
}
-class TestConfiguration extends SimpleConfiguration {
+class TestConfiguration extends Configuration {
// Some test state that is captured.
int count = 0; // A count of callbacks.
@@ -44,9 +44,7 @@
final SendPort _port;
String _result;
- TestConfiguration(this._port);
-
- void onInit() {}
+ TestConfiguration(this._port) : super.blank();
void onSummary(int passed, int failed, int errors, List<TestCase> results,
String uncaughtError) {
diff --git a/runtime/bin/dbg_connection.cc b/runtime/bin/dbg_connection.cc
index e5d4f6b..e5abc5e 100644
--- a/runtime/bin/dbg_connection.cc
+++ b/runtime/bin/dbg_connection.cc
@@ -260,7 +260,9 @@
int msg_id,
const char* err_msg) {
dart::TextBuffer msg(64);
- msg.Printf("{\"id\": %d, \"error\": \"Error: %s\"}", msg_id, err_msg);
+ msg.Printf("{\"id\": %d, \"error\": \"Error: ", msg_id);
+ msg.AddEscapedString(err_msg);
+ msg.Printf("\"}");
SendMsg(debug_fd, &msg);
}
diff --git a/runtime/bin/dbg_message.cc b/runtime/bin/dbg_message.cc
index caec295..36cfeba 100644
--- a/runtime/bin/dbg_message.cc
+++ b/runtime/bin/dbg_message.cc
@@ -50,6 +50,14 @@
}
+bool MessageParser::HasParam(const char* name) const {
+ const char* params = Params();
+ ASSERT(params != NULL);
+ dart::JSONReader r(params);
+ return r.Seek(name);
+}
+
+
intptr_t MessageParser::GetIntParam(const char* name) const {
const char* params = Params();
ASSERT(params != NULL);
@@ -224,13 +232,13 @@
intptr_t len = 0;
Dart_Handle res = Dart_ListLength(object, &len);
ASSERT_NOT_ERROR(res);
- buf->Printf("\"kind\":\"list\",\"length\":%"Pd",", len);
+ buf->Printf("\"kind\":\"list\",\"length\":%" Pd ",", len);
} else {
buf->Printf("\"kind\":\"object\",");
intptr_t class_id = 0;
Dart_Handle res = Dart_GetObjClassId(object, &class_id);
if (!Dart_IsError(res)) {
- buf->Printf("\"classId\":%"Pd",", class_id);
+ buf->Printf("\"classId\":%" Pd ",", class_id);
}
}
buf->Printf("\"text\":\"");
@@ -250,7 +258,7 @@
static void FormatRemoteObj(dart::TextBuffer* buf, Dart_Handle object) {
intptr_t obj_id = Dart_CacheObject(object);
ASSERT(obj_id >= 0);
- buf->Printf("{\"objectId\":%"Pd",", obj_id);
+ buf->Printf("{\"objectId\":%" Pd ",", obj_id);
FormatValue(buf, object);
buf->Printf("}");
}
@@ -300,9 +308,9 @@
RETURN_IF_ERROR(name);
buf->Printf("{\"name\":\"%s\",", GetStringChars(name));
if (super_id > 0) {
- buf->Printf("\"superclassId\":%"Pd",", super_id);
+ buf->Printf("\"superclassId\":%" Pd ",", super_id);
}
- buf->Printf("\"libraryId\":%"Pd",", library_id);
+ buf->Printf("\"libraryId\":%" Pd ",", library_id);
RETURN_IF_ERROR(static_fields);
buf->Printf("\"fields\":");
FormatNamedValueList(buf, static_fields);
@@ -366,7 +374,7 @@
}
Dart_Handle res = Dart_GetObjClassId(object, &class_id);
RETURN_IF_ERROR(res);
- buf->Printf("{\"classId\": %"Pd",", class_id);
+ buf->Printf("{\"classId\": %" Pd ",", class_id);
buf->Printf("\"kind\":\"object\",\"fields\":");
Dart_Handle fields = Dart_GetInstanceFields(object);
RETURN_IF_ERROR(fields);
@@ -383,8 +391,8 @@
intptr_t slice_length) {
intptr_t end_index = index + slice_length;
ASSERT(end_index <= list_length);
- buf->Printf("{\"index\":%"Pd",", index);
- buf->Printf("\"length\":%"Pd",", slice_length);
+ buf->Printf("{\"index\":%" Pd ",", index);
+ buf->Printf("\"length\":%" Pd ",", slice_length);
buf->Printf("\"elements\":[");
for (intptr_t i = index; i < end_index; i++) {
Dart_Handle value = Dart_ListGetAt(list, i);
@@ -470,6 +478,7 @@
{ "getClassProperties", DbgMessage::HandleGetClassPropsCmd },
{ "getLibraryProperties", DbgMessage::HandleGetLibPropsCmd },
{ "setLibraryProperties", DbgMessage::HandleSetLibPropsCmd },
+ { "evaluateExpr", DbgMessage::HandleEvaluateExprCmd },
{ "getObjectProperties", DbgMessage::HandleGetObjPropsCmd },
{ "getListElements", DbgMessage::HandleGetListCmd },
{ "getGlobalVariables", DbgMessage::HandleGetGlobalsCmd },
@@ -633,6 +642,54 @@
}
+bool DbgMessage::HandleEvaluateExprCmd(DbgMessage* in_msg) {
+ ASSERT(in_msg != NULL);
+ MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
+ int msg_id = msg_parser.MessageId();
+ Dart_Handle target;
+
+ if (msg_parser.HasParam("libraryId")) {
+ in_msg->SendErrorReply(msg_id,
+ "libararyId evaluation target not supported");
+ return false;
+ } else if (msg_parser.HasParam("classId")) {
+ in_msg->SendErrorReply(msg_id,
+ "classId evaluation target not supported");
+ return false;
+ } else if (msg_parser.HasParam("objectId")) {
+ intptr_t obj_id = msg_parser.GetIntParam("objectId");
+ target = Dart_GetCachedObject(obj_id);
+ } else {
+ in_msg->SendErrorReply(msg_id, "illegal evaluation target");
+ return false;
+ }
+
+ if (Dart_IsError(target)) {
+ in_msg->SendErrorReply(msg_id, Dart_GetError(target));
+ return false;
+ }
+ char* expr_chars = msg_parser.GetStringParam("expression");
+ Dart_Handle expr = Dart_NewStringFromCString(expr_chars);
+ if (Dart_IsError(expr)) {
+ in_msg->SendErrorReply(msg_id, Dart_GetError(expr));
+ return false;
+ }
+
+ Dart_Handle value = Dart_EvaluateExpr(target, expr);
+ if (Dart_IsError(value)) {
+ in_msg->SendErrorReply(msg_id, Dart_GetError(value));
+ return false;
+ }
+
+ dart::TextBuffer msg(64);
+ msg.Printf("{\"id\":%d, \"result\":", msg_id);
+ FormatRemoteObj(&msg, value);
+ msg.Printf("}");
+ in_msg->SendReply(&msg);
+ return false;
+}
+
+
bool DbgMessage::HandleGetObjPropsCmd(DbgMessage* in_msg) {
ASSERT(in_msg != NULL);
MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
@@ -869,7 +926,7 @@
Dart_Handle res = Dart_IntegerToUint64(bp_id, &bp_id_value);
ASSERT_NOT_ERROR(res);
dart::TextBuffer msg(64);
- msg.Printf("{ \"id\": %d, \"result\": { \"breakpointId\": %"Pu64" }}",
+ msg.Printf("{ \"id\": %d, \"result\": { \"breakpointId\": %" Pu64 " }}",
msg_id, bp_id_value);
in_msg->SendReply(&msg);
return false;
@@ -992,7 +1049,7 @@
dart::TextBuffer msg(128);
msg.Printf("{ \"event\": \"paused\", \"params\": { ");
msg.Printf("\"reason\": \"breakpoint\", ");
- msg.Printf("\"isolateId\": %"Pd64"", isolate_id_);
+ msg.Printf("\"isolateId\": %" Pd64 "", isolate_id_);
if (!Dart_IsNull(location.script_url)) {
ASSERT(Dart_IsString(location.script_url));
msg.Printf(",\"location\": { \"url\":");
@@ -1014,7 +1071,7 @@
dart::TextBuffer msg(128);
msg.Printf("{ \"event\": \"paused\", \"params\": {");
msg.Printf("\"reason\": \"exception\", ");
- msg.Printf("\"isolateId\": %"Pd64", ", isolate_id_);
+ msg.Printf("\"isolateId\": %" Pd64 ", ", isolate_id_);
msg.Printf("\"exception\":");
FormatRemoteObj(&msg, exception);
FormatLocationFromTrace(&msg, stack_trace, ", ");
@@ -1034,7 +1091,7 @@
ASSERT_NOT_ERROR(res);
msg.Printf("{ \"event\": \"paused\", \"params\": { ");
msg.Printf("\"reason\": \"interrupted\", ");
- msg.Printf("\"isolateId\": %"Pd64"", isolate_id);
+ msg.Printf("\"isolateId\": %" Pd64 "", isolate_id);
FormatLocationFromTrace(&msg, trace, ", ");
msg.Printf("}}");
} else {
@@ -1045,7 +1102,7 @@
ASSERT(kind == kShutdown);
msg.Printf("\"reason\": \"shutdown\", ");
}
- msg.Printf("\"id\": %"Pd64" ", isolate_id);
+ msg.Printf("\"id\": %" Pd64 " ", isolate_id);
msg.Printf("}}");
}
DebuggerConnectionHandler::BroadcastMsg(&msg);
@@ -1170,10 +1227,10 @@
return; // No items in the list.
}
DbgMsgQueue* queue = list_;
- msg->Printf("%"Pd64"", queue->isolate_id());
+ msg->Printf("%" Pd64 "", queue->isolate_id());
queue = queue->next();
while (queue != NULL) {
- msg->Printf(",%"Pd64"", queue->isolate_id());
+ msg->Printf(",%" Pd64 "", queue->isolate_id());
queue = queue->next();
}
}
@@ -1185,9 +1242,9 @@
Dart_EnterScope();
dart::TextBuffer msg(128);
msg.Printf("{ \"event\": \"breakpointResolved\", \"params\": {");
- msg.Printf("\"breakpointId\": %"Pd"", bp_id);
+ msg.Printf("\"breakpointId\": %" Pd "", bp_id);
- msg.Printf(", \"isolateId\":%"Pd64"", isolate_id);
+ msg.Printf(", \"isolateId\":%" Pd64 "", isolate_id);
ASSERT(!Dart_IsNull(location.script_url));
ASSERT(Dart_IsString(location.script_url));
msg.Printf(", \"location\":{\"url\":");
diff --git a/runtime/bin/dbg_message.h b/runtime/bin/dbg_message.h
index ca05255..5386318 100644
--- a/runtime/bin/dbg_message.h
+++ b/runtime/bin/dbg_message.h
@@ -43,6 +43,7 @@
int MessageId() const;
const char* Params() const;
+ bool HasParam(const char* name) const;
intptr_t GetIntParam(const char* name) const;
intptr_t GetOptIntParam(const char* name, intptr_t default_val) const;
@@ -103,6 +104,7 @@
static bool HandleGetLibPropsCmd(DbgMessage* msg);
static bool HandleSetLibPropsCmd(DbgMessage* msg);
static bool HandleGetGlobalsCmd(DbgMessage* msg);
+ static bool HandleEvaluateExprCmd(DbgMessage* msg);
static bool HandleGetObjPropsCmd(DbgMessage* msg);
static bool HandleGetListCmd(DbgMessage* msg);
static bool HandleGetScriptURLsCmd(DbgMessage* msg);
diff --git a/runtime/bin/eventhandler_linux.cc b/runtime/bin/eventhandler_linux.cc
index 111e7e6..6d15c9e 100644
--- a/runtime/bin/eventhandler_linux.cc
+++ b/runtime/bin/eventhandler_linux.cc
@@ -171,7 +171,7 @@
if (result == -1) {
perror("Interrupt message failure:");
}
- FATAL1("Interrupt message failure. Wrote %"Pd" bytes.", result);
+ FATAL1("Interrupt message failure. Wrote %" Pd " bytes.", result);
}
}
diff --git a/runtime/bin/eventhandler_macos.cc b/runtime/bin/eventhandler_macos.cc
index 971ef1b..419c93e 100644
--- a/runtime/bin/eventhandler_macos.cc
+++ b/runtime/bin/eventhandler_macos.cc
@@ -190,7 +190,7 @@
if (result == -1) {
perror("Interrupt message failure:");
}
- FATAL1("Interrupt message failure. Wrote %"Pd" bytes.", result);
+ FATAL1("Interrupt message failure. Wrote %" Pd " bytes.", result);
}
}
diff --git a/runtime/bin/io_natives.cc b/runtime/bin/io_natives.cc
index ff790d6..2948ce8 100644
--- a/runtime/bin/io_natives.cc
+++ b/runtime/bin/io_natives.cc
@@ -35,6 +35,8 @@
V(Platform_LocalHostname, 0) \
V(Platform_ExecutableName, 0) \
V(Platform_Environment, 0) \
+ V(Platform_ExecutableArguments, 0) \
+ V(Platform_PackageRoot, 0) \
V(Platform_GetVersion, 0) \
V(Process_Start, 10) \
V(Process_Wait, 5) \
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index 57c5168..7e5138e 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -339,6 +339,8 @@
}
}
+ // The arguments to the VM are at positions 1 through i-1 in argv.
+ Platform::SetExecutableArguments(i, argv);
// Get the script name.
if (i < argc) {
@@ -461,6 +463,7 @@
return NULL;
}
+ Platform::SetPackageRoot(package_root);
Dart_Handle io_lib_url = DartUtils::NewString("dart:io");
CHECK_RESULT(io_lib_url);
Dart_Handle io_lib = Dart_LookupLibrary(io_lib_url);
diff --git a/runtime/bin/platform.cc b/runtime/bin/platform.cc
index 4d1bbed..f7a2920 100644
--- a/runtime/bin/platform.cc
+++ b/runtime/bin/platform.cc
@@ -13,6 +13,9 @@
namespace bin {
const char* Platform::executable_name_ = NULL;
+const char* Platform::package_root_ = NULL;
+int Platform::script_index_ = 1;
+char** Platform::argv_ = NULL;
void FUNCTION_NAME(Platform_NumberOfProcessors)(Dart_NativeArguments args) {
Dart_SetReturnValue(args, Dart_NewInteger(Platform::NumberOfProcessors()));
@@ -46,6 +49,31 @@
args, Dart_NewStringFromCString(Platform::GetExecutableName()));
}
+
+void FUNCTION_NAME(Platform_ExecutableArguments)(Dart_NativeArguments args) {
+ int end = Platform::GetScriptIndex();
+ char** argv = Platform::GetArgv();
+ Dart_Handle result = Dart_NewList(end - 1);
+ for (intptr_t i = 1; i < end; i++) {
+ Dart_Handle str = DartUtils::NewString(argv[i]);
+ Dart_Handle error = Dart_ListSetAt(result, i - 1, str);
+ if (Dart_IsError(error)) {
+ Dart_PropagateError(error);
+ }
+ }
+ Dart_SetReturnValue(args, result);
+}
+
+
+void FUNCTION_NAME(Platform_PackageRoot)(Dart_NativeArguments args) {
+ const char* package_root = Platform::GetPackageRoot();
+ if (package_root == NULL) {
+ package_root = "";
+ }
+ Dart_SetReturnValue(args, Dart_NewStringFromCString(package_root));
+}
+
+
void FUNCTION_NAME(Platform_Environment)(Dart_NativeArguments args) {
intptr_t count = 0;
char** env = Platform::Environment(&count);
diff --git a/runtime/bin/platform.h b/runtime/bin/platform.h
index dd195c3..ca723ae3 100644
--- a/runtime/bin/platform.h
+++ b/runtime/bin/platform.h
@@ -42,8 +42,31 @@
return executable_name_;
}
+ // Stores and gets the package root.
+ static void SetPackageRoot(const char* package_root) {
+ package_root_ = package_root;
+ }
+ static const char* GetPackageRoot() {
+ return package_root_;
+ }
+
+ // Stores and gets the flags passed to the executable.
+ static void SetExecutableArguments(int script_index, char** argv) {
+ script_index_ = script_index;
+ argv_ = argv;
+ }
+ static int GetScriptIndex() {
+ return script_index_;
+ }
+ static char** GetArgv() {
+ return argv_;
+ }
+
private:
static const char* executable_name_;
+ static const char* package_root_;
+ static int script_index_;
+ static char** argv_; // VM flags are argv_[1 ... script_index_ - 1]
DISALLOW_ALLOCATION();
DISALLOW_IMPLICIT_CONSTRUCTORS(Platform);
diff --git a/runtime/bin/platform_patch.dart b/runtime/bin/platform_patch.dart
index cfe7a80..fe1e90c 100644
--- a/runtime/bin/platform_patch.dart
+++ b/runtime/bin/platform_patch.dart
@@ -11,5 +11,8 @@
/* patch */ static _localHostname() native "Platform_LocalHostname";
/* patch */ static _executable() native "Platform_ExecutableName";
/* patch */ static _environment() native "Platform_Environment";
+ /* patch */ static List<String> _executableArguments()
+ native "Platform_ExecutableArguments";
+ /* patch */ static String _packageRoot() native "Platform_PackageRoot";
/* patch */ static String _version() native "Platform_GetVersion";
}
diff --git a/runtime/bin/run_vm_tests.cc b/runtime/bin/run_vm_tests.cc
index 9daac7d..7ff4198 100644
--- a/runtime/bin/run_vm_tests.cc
+++ b/runtime/bin/run_vm_tests.cc
@@ -52,7 +52,7 @@
(run_filter == kAllBenchmarks) ||
(strcmp(run_filter, this->name()) == 0)) {
this->Run();
- OS::Print("%s(RunTime): %"Pd"\n", this->name(), this->score());
+ OS::Print("%s(RunTime): %" Pd "\n", this->name(), this->score());
run_matches++;
} else if (run_filter == kList) {
fprintf(stdout, "%s\n", this->name());
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index aa3963a..4f35fab 100755
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -2010,6 +2010,39 @@
void** peer);
/**
+ * Gets an integer native argument at some index.
+ * \param args Native arguments structure.
+ * \param arg_index Index of the desired argument in the structure above.
+ * \param value Returns the integer value if the argument is an Integer.
+ * \return Success if no error occurs. Otherwise returns an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_GetNativeIntegerArgument(Dart_NativeArguments args,
+ int index,
+ int64_t* value);
+
+/**
+ * Gets a boolean native argument at some index.
+ * \param args Native arguments structure.
+ * \param arg_index Index of the desired argument in the structure above.
+ * \param value Returns the boolean value if the argument is a Boolean.
+ * \return Success if no error occurs. Otherwise returns an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_GetNativeBooleanArgument(Dart_NativeArguments args,
+ int index,
+ bool* value);
+
+/**
+ * Gets a double native argument at some index.
+ * \param args Native arguments structure.
+ * \param arg_index Index of the desired argument in the structure above.
+ * \param value Returns the double value if the argument is a double.
+ * \return Success if no error occurs. Otherwise returns an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_GetNativeDoubleArgument(Dart_NativeArguments args,
+ int index,
+ double* value);
+
+/**
* Sets the return value for a native function.
*/
DART_EXPORT void Dart_SetReturnValue(Dart_NativeArguments args,
@@ -2022,7 +2055,7 @@
bool retval);
DART_EXPORT void Dart_SetIntegerReturnValue(Dart_NativeArguments args,
- intptr_t retval);
+ int64_t retval);
DART_EXPORT void Dart_SetDoubleReturnValue(Dart_NativeArguments args,
double retval);
diff --git a/runtime/include/dart_debugger_api.h b/runtime/include/dart_debugger_api.h
index 36249ff..b847a91 100755
--- a/runtime/include/dart_debugger_api.h
+++ b/runtime/include/dart_debugger_api.h
@@ -472,6 +472,25 @@
/**
+ * Execute the expression given in string \expr in the context
+ * of \target.
+ *
+ * Requires there to be a current isolate.
+ *
+ * The expression is evaluated in the context of \target.
+ * If \target is a Dart object, the expression is evaluated as if
+ * it were an instance method of the class of the object.
+ * TODO(hausner): add other execution contexts, e.g. library and class.
+ *
+ * \return A handle to the computed value, or an error object if
+ * the compilation of the expression fails, or if the evaluation throws
+ * an error.
+ */
+DART_EXPORT Dart_Handle Dart_EvaluateExpr(Dart_Handle target,
+ Dart_Handle expr);
+
+
+/**
* Returns the class of the given \object.
*
* Requires there to be a current isolate.
diff --git a/runtime/lib/array.cc b/runtime/lib/array.cc
index da55de9..7116f5b 100644
--- a/runtime/lib/array.cc
+++ b/runtime/lib/array.cc
@@ -19,7 +19,7 @@
isolate, arguments->NativeArgAt(1));
if (!length.IsSmi()) {
const String& error = String::Handle(String::NewFormatted(
- "Length must be an integer in the range [0..%"Pd"].",
+ "Length must be an integer in the range [0..%" Pd "].",
Array::kMaxElements));
const Array& args = Array::Handle(Array::New(1));
args.SetAt(0, error);
@@ -28,7 +28,7 @@
intptr_t len = Smi::Cast(length).Value();
if (len < 0 || len > Array::kMaxElements) {
const String& error = String::Handle(String::NewFormatted(
- "Length (%"Pd") must be an integer in the range [0..%"Pd"].",
+ "Length (%" Pd ") must be an integer in the range [0..%" Pd "].",
len, Array::kMaxElements));
const Array& args = Array::Handle(Array::New(1));
args.SetAt(0, error);
diff --git a/runtime/lib/double.cc b/runtime/lib/double.cc
index 04006e5..f69e963 100644
--- a/runtime/lib/double.cc
+++ b/runtime/lib/double.cc
@@ -172,16 +172,6 @@
}
-DEFINE_NATIVE_ENTRY(Double_pow, 2) {
- const double operand =
- Double::CheckedHandle(arguments->NativeArgAt(0)).value();
- GET_NON_NULL_NATIVE_ARGUMENT(
- Double, exponent_object, arguments->NativeArgAt(1));
- const double exponent = exponent_object.value();
- return Double::New(pow(operand, exponent));
-}
-
-
#if defined(TARGET_OS_MACOS)
// MAC OSX math library produces old style cast warning.
#pragma GCC diagnostic ignored "-Wold-style-cast"
diff --git a/runtime/lib/double.dart b/runtime/lib/double.dart
index 29247ad..166d731 100644
--- a/runtime/lib/double.dart
+++ b/runtime/lib/double.dart
@@ -126,21 +126,6 @@
int toInt() native "Double_toInt";
double toDouble() { return this; }
- double pow(num exponent) {
- if (exponent == 0) {
- return 1.0; // ECMA-262 15.8.2.13
- }
- if (exponent is! num) {
- throw new ArgumentError(null);
- }
- double doubleExponent = exponent.toDouble();
- if (isNaN || exponent.isNaN) {
- return double.NAN;
- }
- return _pow(doubleExponent);
- }
- double _pow(double exponent) native "Double_pow";
-
String toStringAsFixed(int fractionDigits) {
// See ECMAScript-262, 15.7.4.5 for details.
diff --git a/runtime/lib/integers.dart b/runtime/lib/integers.dart
index aaf5712..dca7ef8 100644
--- a/runtime/lib/integers.dart
+++ b/runtime/lib/integers.dart
@@ -163,23 +163,6 @@
int toInt() { return this; }
double toDouble() { return new _Double.fromInteger(this); }
- int pow(int exponent) {
- // Exponentiation by squaring.
- int base = this;
- int result = 1;
- while (exponent != 0) {
- if ((exponent & 1) == 1) {
- result *= base;
- }
- exponent >>= 1;
- // Skip unnecessary operation (can overflow to Mint or Bigint).
- if (exponent != 0) {
- base *= base;
- }
- }
- return result;
- }
-
String toStringAsFixed(int fractionDigits) {
return this.toDouble().toStringAsFixed(fractionDigits);
}
diff --git a/runtime/lib/math.cc b/runtime/lib/math.cc
index 317045d..ca7c7e6 100644
--- a/runtime/lib/math.cc
+++ b/runtime/lib/math.cc
@@ -66,6 +66,15 @@
return Double::New(log(operand.value()));
}
+DEFINE_NATIVE_ENTRY(Math_doublePow, 2) {
+ const double operand =
+ Double::CheckedHandle(arguments->NativeArgAt(0)).value();
+ GET_NON_NULL_NATIVE_ARGUMENT(
+ Double, exponent_object, arguments->NativeArgAt(1));
+ const double exponent = exponent_object.value();
+ return Double::New(pow(operand, exponent));
+}
+
// Returns the typed-data array store in '_Random._state' field.
static RawTypedData* GetRandomStateArray(const Instance& receiver) {
diff --git a/runtime/lib/math_patch.dart b/runtime/lib/math_patch.dart
index 1bf701d..00cacdf 100644
--- a/runtime/lib/math_patch.dart
+++ b/runtime/lib/math_patch.dart
@@ -10,10 +10,38 @@
// an [int], otherwise the result is a [double].
patch num pow(num x, num exponent) {
if ((x is int) && (exponent is int) && (exponent >= 0)) {
- return x.pow(exponent);
+ return _intPow(x, exponent);
}
- // Double.pow will call exponent.toDouble().
- return x.toDouble().pow(exponent);
+ return _doublePow(x.toDouble(), exponent.toDouble());
+}
+
+double _doublePow(double base, double exponent) {
+ if (exponent == 0.0) {
+ return 1.0; // ECMA-262 15.8.2.13
+ }
+ if (base == 1.0) return 1.0;
+ if (base.isNaN || exponent.isNaN) {
+ return double.NAN;
+ }
+ return _pow(base, exponent);
+}
+
+double _pow(double base, double exponent) native "Math_doublePow";
+
+int _intPow(int base, int exponent) {
+ // Exponentiation by squaring.
+ int result = 1;
+ while (exponent != 0) {
+ if ((exponent & 1) == 1) {
+ result *= base;
+ }
+ exponent >>= 1;
+ // Skip unnecessary operation (can overflow to Mint or Bigint).
+ if (exponent != 0) {
+ base *= base;
+ }
+ }
+ return result;
}
patch double atan2(num a, num b) => _atan2(a.toDouble(), b.toDouble());
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc
index 7ab68b6..e0c8b23 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -305,9 +305,16 @@
GET_NON_NULL_NATIVE_ARGUMENT(Type, type, arguments->NativeArgAt(0));
const Class& cls = Class::Handle(type.type_class());
ASSERT(!cls.IsNull());
- return CreateClassMirror(cls,
- AbstractType::Handle(),
- Instance::null_instance());
+ // Strip the type for generics only.
+ if (cls.NumTypeParameters() == 0) {
+ return CreateClassMirror(cls,
+ type,
+ Object::null_instance());
+ } else {
+ return CreateClassMirror(cls,
+ AbstractType::Handle(),
+ Object::null_instance());
+ }
}
diff --git a/runtime/lib/mirrors_impl.dart b/runtime/lib/mirrors_impl.dart
index 88a89cc..ea63f90 100644
--- a/runtime/lib/mirrors_impl.dart
+++ b/runtime/lib/mirrors_impl.dart
@@ -369,6 +369,15 @@
final Type _reflectedType;
final bool _isGeneric;
+ bool get hasReflectedType => _reflectedType != null;
+ Type get reflectedType {
+ if (!hasReflectedType) {
+ throw new UnsupportedError(
+ "Declarations of generics have no reflected type");
+ }
+ return _reflectedType;
+ }
+
Symbol _simpleName;
Symbol get simpleName {
// dynamic, void and the function types have their names set eagerly in the
@@ -417,7 +426,7 @@
// Object has no superclass.
return null;
}
- _superclass = reflectClass(supertype);
+ _superclass = _Mirrors._reflectType(supertype);
}
return _superclass;
}
@@ -924,7 +933,22 @@
this.isGenerativeConstructor,
this.isRedirectingConstructor,
this.isFactoryConstructor)
- : super(reflectee, _s(simpleName));
+ : this.isOperator = _operators.contains(simpleName),
+ super(reflectee, _s(simpleName));
+
+ static const _operators = const ["%", "&", "*", "+", "-", "/", "<", "<<",
+ "<=", "==", ">", ">=", ">>", "[]", "[]=", "^", "|", "~", "unary-", "~/"];
+
+ final bool isStatic;
+ final bool isAbstract;
+ final bool isGetter;
+ final bool isSetter;
+ final bool isConstructor;
+ final bool isConstConstructor;
+ final bool isGenerativeConstructor;
+ final bool isRedirectingConstructor;
+ final bool isFactoryConstructor;
+ final bool isOperator;
DeclarationMirror _owner;
DeclarationMirror get owner {
@@ -969,20 +993,8 @@
return _parameters;
}
- final bool isStatic;
- final bool isAbstract;
-
bool get isRegularMethod => !isGetter && !isSetter && !isConstructor;
- TypeMirror get isOperator {
- throw new UnimplementedError(
- 'MethodMirror.isOperator is not implemented');
- }
-
- final bool isGetter;
- final bool isSetter;
- final bool isConstructor;
-
Symbol _constructorName = null;
Symbol get constructorName {
if (_constructorName == null) {
@@ -1004,11 +1016,6 @@
return _constructorName;
}
- final bool isConstConstructor;
- final bool isGenerativeConstructor;
- final bool isRedirectingConstructor;
- final bool isFactoryConstructor;
-
String toString() => "MethodMirror on '${_n(simpleName)}'";
static dynamic _MethodMirror_owner(reflectee)
diff --git a/runtime/lib/simd128.cc b/runtime/lib/simd128.cc
index 9b79412..1d4d551 100644
--- a/runtime/lib/simd128.cc
+++ b/runtime/lib/simd128.cc
@@ -229,13 +229,36 @@
}
+DEFINE_NATIVE_ENTRY(Float32x4_getSignMask, 1) {
+ GET_NON_NULL_NATIVE_ARGUMENT(Float32x4, self, arguments->NativeArgAt(0));
+ uint32_t mx = (bit_cast<uint32_t>(self.x()) & 0x80000000) >> 31;
+ uint32_t my = (bit_cast<uint32_t>(self.y()) & 0x80000000) >> 31;
+ uint32_t mz = (bit_cast<uint32_t>(self.z()) & 0x80000000) >> 31;
+ uint32_t mw = (bit_cast<uint32_t>(self.w()) & 0x80000000) >> 31;
+ uint32_t value = mx | (my << 1) | (mz << 2) | (mw << 3);
+ return Integer::New(value);
+}
+
+
+DEFINE_NATIVE_ENTRY(Uint32x4_getSignMask, 1) {
+ GET_NON_NULL_NATIVE_ARGUMENT(Uint32x4, self, arguments->NativeArgAt(0));
+ uint32_t mx = (self.x() & 0x80000000) >> 31;
+ uint32_t my = (self.y() & 0x80000000) >> 31;
+ uint32_t mz = (self.z() & 0x80000000) >> 31;
+ uint32_t mw = (self.w() & 0x80000000) >> 31;
+ uint32_t value = mx | (my << 1) | (mz << 2) | (mw << 3);
+ return Integer::New(value);
+}
+
+
DEFINE_NATIVE_ENTRY(Float32x4_shuffle, 2) {
GET_NON_NULL_NATIVE_ARGUMENT(Float32x4, self, arguments->NativeArgAt(0));
GET_NON_NULL_NATIVE_ARGUMENT(Integer, mask, arguments->NativeArgAt(1));
int64_t m = mask.AsInt64Value();
if (m < 0 || m > 255) {
const String& error = String::Handle(
- String::NewFormatted("mask (%"Pd64") must be in the range [0..256)", m));
+ String::NewFormatted("mask (%" Pd64 ") must be in the range [0..256)",
+ m));
const Array& args = Array::Handle(Array::New(1));
args.SetAt(0, error);
Exceptions::ThrowByType(Exceptions::kRange, args);
@@ -471,6 +494,28 @@
}
+DEFINE_NATIVE_ENTRY(Uint32x4_add, 2) {
+ GET_NON_NULL_NATIVE_ARGUMENT(Uint32x4, self, arguments->NativeArgAt(0));
+ GET_NON_NULL_NATIVE_ARGUMENT(Uint32x4, other, arguments->NativeArgAt(1));
+ uint32_t _x = self.x() + other.x();
+ uint32_t _y = self.y() + other.y();
+ uint32_t _z = self.z() + other.z();
+ uint32_t _w = self.w() + other.w();
+ return Uint32x4::New(_x, _y, _z, _w);
+}
+
+
+DEFINE_NATIVE_ENTRY(Uint32x4_sub, 2) {
+ GET_NON_NULL_NATIVE_ARGUMENT(Uint32x4, self, arguments->NativeArgAt(0));
+ GET_NON_NULL_NATIVE_ARGUMENT(Uint32x4, other, arguments->NativeArgAt(1));
+ uint32_t _x = self.x() - other.x();
+ uint32_t _y = self.y() - other.y();
+ uint32_t _z = self.z() - other.z();
+ uint32_t _w = self.w() - other.w();
+ return Uint32x4::New(_x, _y, _z, _w);
+}
+
+
DEFINE_NATIVE_ENTRY(Uint32x4_getX, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(Uint32x4, self, arguments->NativeArgAt(0));
uint32_t value = self.x();
diff --git a/runtime/lib/typed_data.cc b/runtime/lib/typed_data.cc
index 23f0b83..bd7a266 100644
--- a/runtime/lib/typed_data.cc
+++ b/runtime/lib/typed_data.cc
@@ -30,7 +30,7 @@
intptr_t element_size_in_bytes) {
if (!Utils::RangeCheck(offset_in_bytes, num_bytes, length_in_bytes)) {
const String& error = String::Handle(String::NewFormatted(
- "index (%"Pd") must be in the range [0..%"Pd")",
+ "index (%" Pd ") must be in the range [0..%" Pd ")",
(offset_in_bytes / element_size_in_bytes),
(length_in_bytes / element_size_in_bytes)));
const Array& args = Array::Handle(Array::New(1));
@@ -44,7 +44,7 @@
static void LengthCheck(intptr_t len, intptr_t max) {
if (len < 0 || len > max) {
const String& error = String::Handle(String::NewFormatted(
- "Length (%"Pd") of object must be in range [0..%"Pd"]",
+ "Length (%" Pd ") of object must be in range [0..%" Pd "]",
len, max));
const Array& args = Array::Handle(Array::New(1));
args.SetAt(0, error);
@@ -114,7 +114,7 @@
if (length.Value() < 0) {
const String& error = String::Handle(String::NewFormatted(
- "length (%"Pd") must be non-negative", length.Value()));
+ "length (%" Pd ") must be non-negative", length.Value()));
const Array& args = Array::Handle(Array::New(1));
args.SetAt(0, error);
Exceptions::ThrowByType(Exceptions::kArgument, args);
diff --git a/runtime/lib/typed_data.dart b/runtime/lib/typed_data.dart
index 4e76c27..e60c145 100644
--- a/runtime/lib/typed_data.dart
+++ b/runtime/lib/typed_data.dart
@@ -2022,6 +2022,7 @@
double get y native "Float32x4_getY";
double get z native "Float32x4_getZ";
double get w native "Float32x4_getW";
+ int get signMask native "Float32x4_getSignMask";
Float32x4 shuffle(int mask) native "Float32x4_shuffle";
@@ -2081,10 +2082,19 @@
return _xor(other);
}
Uint32x4 _xor(Uint32x4 other) native "Uint32x4_xor";
+ Uint32x4 operator +(Uint32x4 other) {
+ return _add(other);
+ }
+ Uint32x4 _add(Uint32x4 other) native "Uint32x4_add";
+ Uint32x4 operator -(Uint32x4 other) {
+ return _sub(other);
+ }
+ Uint32x4 _sub(Uint32x4 other) native "Uint32x4_sub";
int get x native "Uint32x4_getX";
int get y native "Uint32x4_getY";
int get z native "Uint32x4_getZ";
int get w native "Uint32x4_getW";
+ int get signMask native "Uint32x4_getSignMask";
Uint32x4 withX(int x) native "Uint32x4_setX";
Uint32x4 withY(int y) native "Uint32x4_setY";
Uint32x4 withZ(int z) native "Uint32x4_setZ";
diff --git a/runtime/platform/thread_win.cc b/runtime/platform/thread_win.cc
index 7b3ca56..e8be678 100644
--- a/runtime/platform/thread_win.cc
+++ b/runtime/platform/thread_win.cc
@@ -140,7 +140,7 @@
void Mutex::Unlock() {
BOOL result = ReleaseSemaphore(data_.semaphore_, 1, NULL);
if (result == 0) {
- FATAL1("Mutex unlock failed", GetLastError());
+ FATAL1("Mutex unlock failed %d", GetLastError());
}
}
@@ -244,7 +244,7 @@
// Signal event.
BOOL result = SetEvent(first->event_);
if (result == 0) {
- FATAL1("Monitor::Notify failed to signal event", GetLastError());
+ FATAL1("Monitor::Notify failed to signal event %d", GetLastError());
}
}
LeaveCriticalSection(&waiters_cs_);
@@ -261,7 +261,7 @@
while (current != NULL) {
BOOL result = SetEvent(current->event_);
if (result == 0) {
- FATAL1("Failed to set event for NotifyAll", GetLastError());
+ FATAL1("Failed to set event for NotifyAll %d", GetLastError());
}
current = current->next_;
}
@@ -315,14 +315,14 @@
// Wait forever for a Notify or a NotifyAll event.
result = WaitForSingleObject(wait_data->event_, INFINITE);
if (result == WAIT_FAILED) {
- FATAL1("Monitor::Wait failed", GetLastError());
+ FATAL1("Monitor::Wait failed %d", GetLastError());
}
} else {
// Wait for the given period of time for a Notify or a NotifyAll
// event.
result = WaitForSingleObject(wait_data->event_, millis);
if (result == WAIT_FAILED) {
- FATAL1("Monitor::Wait with timeout failed", GetLastError());
+ FATAL1("Monitor::Wait with timeout failed %d", GetLastError());
}
if (result == WAIT_TIMEOUT) {
// No longer waiting. Remove from the list of waiters.
diff --git a/runtime/vm/allocation.cc b/runtime/vm/allocation.cc
index 0e97ed0..1c88436 100644
--- a/runtime/vm/allocation.cc
+++ b/runtime/vm/allocation.cc
@@ -19,7 +19,7 @@
ASSERT(isolate != NULL);
ASSERT(isolate->current_zone() != NULL);
if (size > static_cast<uword>(kIntptrMax)) {
- FATAL1("ZoneAllocated object has unexpectedly large size %"Pu"", size);
+ FATAL1("ZoneAllocated object has unexpectedly large size %" Pu "", size);
}
return reinterpret_cast<void*>(isolate->current_zone()->AllocUnsafe(size));
}
diff --git a/runtime/vm/assembler_ia32.cc b/runtime/vm/assembler_ia32.cc
index c04347c..a1dfc13 100644
--- a/runtime/vm/assembler_ia32.cc
+++ b/runtime/vm/assembler_ia32.cc
@@ -571,6 +571,24 @@
}
+void Assembler::addpl(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitUint8(0x0F);
+ EmitUint8(0xFE);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void Assembler::subpl(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitUint8(0x0F);
+ EmitUint8(0xFA);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
void Assembler::addps(XmmRegister dst, XmmRegister src) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0x0F);
diff --git a/runtime/vm/assembler_ia32.h b/runtime/vm/assembler_ia32.h
index 83b1c49..d0972ea 100644
--- a/runtime/vm/assembler_ia32.h
+++ b/runtime/vm/assembler_ia32.h
@@ -411,7 +411,8 @@
void divsd(XmmRegister dst, XmmRegister src);
void divsd(XmmRegister dst, const Address& src);
-
+ void addpl(XmmRegister dst, XmmRegister src);
+ void subpl(XmmRegister dst, XmmRegister src);
void addps(XmmRegister dst, XmmRegister src);
void subps(XmmRegister dst, XmmRegister src);
void divps(XmmRegister dst, XmmRegister src);
diff --git a/runtime/vm/assembler_ia32_test.cc b/runtime/vm/assembler_ia32_test.cc
index 3a7d4a5..2f3087f 100644
--- a/runtime/vm/assembler_ia32_test.cc
+++ b/runtime/vm/assembler_ia32_test.cc
@@ -874,6 +874,31 @@
}
+ASSEMBLER_TEST_GENERATE(PackedIntOperations, assembler) {
+ __ movl(EAX, Immediate(0x2));
+ __ movd(XMM0, EAX);
+ __ shufps(XMM0, XMM0, Immediate(0x0));
+ __ movl(EAX, Immediate(0x1));
+ __ movd(XMM1, EAX);
+ __ shufps(XMM1, XMM1, Immediate(0x0));
+ __ addpl(XMM0, XMM1); // 0x3
+ __ addpl(XMM0, XMM0); // 0x6
+ __ subpl(XMM0, XMM1); // 0x5
+ // Copy the low lane at ESP.
+ __ pushl(EAX);
+ __ movss(Address(ESP, 0), XMM0);
+ __ popl(EAX);
+ __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedIntOperations, test) {
+ typedef uint32_t (*PackedIntOperationsCode)();
+ uint32_t res = reinterpret_cast<PackedIntOperationsCode>(test->entry())();
+ EXPECT_EQ(static_cast<uword>(0x5), res);
+}
+
+
ASSEMBLER_TEST_GENERATE(PackedFPOperations2, assembler) {
__ movl(EAX, Immediate(bit_cast<int32_t, float>(4.0f)));
__ movd(XMM0, EAX);
diff --git a/runtime/vm/assembler_x64.cc b/runtime/vm/assembler_x64.cc
index 488cd55..38fad31 100644
--- a/runtime/vm/assembler_x64.cc
+++ b/runtime/vm/assembler_x64.cc
@@ -641,6 +641,27 @@
EmitXmmRegisterOperand(dst & 7, src);
}
+
+void Assembler::addpl(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitREX_RB(dst, src);
+ EmitUint8(0x66);
+ EmitUint8(0x0F);
+ EmitUint8(0xFE);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void Assembler::subpl(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitREX_RB(dst, src);
+ EmitUint8(0x66);
+ EmitUint8(0x0F);
+ EmitUint8(0xFA);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
void Assembler::addps(XmmRegister dst, XmmRegister src) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitREX_RB(dst, src);
diff --git a/runtime/vm/assembler_x64.h b/runtime/vm/assembler_x64.h
index 17324c0..fd0d70b 100644
--- a/runtime/vm/assembler_x64.h
+++ b/runtime/vm/assembler_x64.h
@@ -415,6 +415,8 @@
void mulsd(XmmRegister dst, XmmRegister src);
void divsd(XmmRegister dst, XmmRegister src);
+ void addpl(XmmRegister dst, XmmRegister src);
+ void subpl(XmmRegister dst, XmmRegister src);
void addps(XmmRegister dst, XmmRegister src);
void subps(XmmRegister dst, XmmRegister src);
void divps(XmmRegister dst, XmmRegister src);
diff --git a/runtime/vm/assembler_x64_test.cc b/runtime/vm/assembler_x64_test.cc
index 7fe6a08..a735324 100644
--- a/runtime/vm/assembler_x64_test.cc
+++ b/runtime/vm/assembler_x64_test.cc
@@ -1449,6 +1449,30 @@
}
+ASSEMBLER_TEST_GENERATE(PackedIntOperations, assembler) {
+ __ movl(RAX, Immediate(0x2));
+ __ movd(XMM0, RAX);
+ __ shufps(XMM0, XMM0, Immediate(0x0));
+ __ movl(RAX, Immediate(0x1));
+ __ movd(XMM1, RAX);
+ __ shufps(XMM1, XMM1, Immediate(0x0));
+ __ addpl(XMM0, XMM1); // 0x3
+ __ addpl(XMM0, XMM0); // 0x6
+ __ subpl(XMM0, XMM1); // 0x5
+ __ pushq(RAX);
+ __ movss(Address(RSP, 0), XMM0);
+ __ popq(RAX);
+ __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedIntOperations, test) {
+ typedef uint32_t (*PackedIntOperationsCode)();
+ uint32_t res = reinterpret_cast<PackedIntOperationsCode>(test->entry())();
+ EXPECT_EQ(static_cast<uword>(0x5), res);
+}
+
+
ASSEMBLER_TEST_GENERATE(PackedFPOperations2, assembler) {
__ movq(RAX, Immediate(bit_cast<int32_t, float>(4.0f)));
__ movd(XMM0, RAX);
diff --git a/runtime/vm/ast.cc b/runtime/vm/ast.cc
index 063470e..467de8c 100644
--- a/runtime/vm/ast.cc
+++ b/runtime/vm/ast.cc
@@ -83,7 +83,7 @@
LocalVariable* LetNode::AddInitializer(AstNode* node) {
initializers_.Add(node);
char name[64];
- OS::SNPrint(name, sizeof(name), ":lt%"Pd"_%d", token_pos(), vars_.length());
+ OS::SNPrint(name, sizeof(name), ":lt%" Pd "_%d", token_pos(), vars_.length());
LocalVariable* temp_var =
new LocalVariable(token_pos(),
String::ZoneHandle(Symbols::New(name)),
diff --git a/runtime/vm/ast.h b/runtime/vm/ast.h
index 57e11b0..a4a773d 100644
--- a/runtime/vm/ast.h
+++ b/runtime/vm/ast.h
@@ -1556,11 +1556,13 @@
const Function& function,
const String& native_c_function_name,
NativeFunction native_c_function,
+ LocalScope* scope,
bool is_bootstrap_native)
: AstNode(token_pos),
function_(function),
native_c_function_name_(native_c_function_name),
native_c_function_(native_c_function),
+ scope_(scope),
is_bootstrap_native_(is_bootstrap_native) {
ASSERT(function_.IsZoneHandle());
ASSERT(native_c_function_ != NULL);
@@ -1573,6 +1575,7 @@
return native_c_function_name_;
}
NativeFunction native_c_function() const { return native_c_function_; }
+ LocalScope* scope() const { return scope_; }
bool is_bootstrap_native() const { return is_bootstrap_native_; }
virtual void VisitChildren(AstNodeVisitor* visitor) const { }
@@ -1583,6 +1586,7 @@
const Function& function_; // Native Dart function.
const String& native_c_function_name_;
NativeFunction native_c_function_; // Actual non-Dart implementation.
+ LocalScope* scope_;
const bool is_bootstrap_native_; // Is a bootstrap native method.
DISALLOW_IMPLICIT_CONSTRUCTORS(NativeBodyNode);
diff --git a/runtime/vm/ast_printer.cc b/runtime/vm/ast_printer.cc
index 79006b5..21ff734 100644
--- a/runtime/vm/ast_printer.cc
+++ b/runtime/vm/ast_printer.cc
@@ -171,7 +171,7 @@
void AstPrinter::VisitBinaryOpWithMask32Node(BinaryOpWithMask32Node* node) {
OS::Print("(%s ", node->Name());
node->VisitChildren(this);
- OS::Print(" & 0x%"Px64"", node->mask32());
+ OS::Print(" & 0x%" Px64 "", node->mask32());
OS::Print(")");
}
@@ -419,7 +419,7 @@
} else if (var->owner()->function_level() != 0) {
OS::Print(" lev %d", var->owner()->function_level());
}
- OS::Print(" valid %"Pd"-%"Pd")",
+ OS::Print(" valid %" Pd "-%" Pd ")",
var->token_pos(),
scope->end_token_pos());
}
@@ -480,7 +480,7 @@
OS::Print(" ctx %d", param->owner()->context_level());
}
}
- OS::Print(" valid %"Pd"-%"Pd")",
+ OS::Print(" valid %" Pd "-%" Pd ")",
param->token_pos(),
scope->end_token_pos());
pos++;
diff --git a/runtime/vm/bitmap.cc b/runtime/vm/bitmap.cc
index e2d5fe6e..70619d4 100644
--- a/runtime/vm/bitmap.cc
+++ b/runtime/vm/bitmap.cc
@@ -88,7 +88,7 @@
void BitmapBuilder::SetBit(intptr_t bit_offset, bool value) {
if (!InRange(bit_offset)) {
FATAL1("Fatal error in BitmapBuilder::SetBit :"
- " invalid bit_offset, %"Pd"\n", bit_offset);
+ " invalid bit_offset, %" Pd "\n", bit_offset);
}
int byte_offset = bit_offset >> kBitsPerByteLog2;
ASSERT(byte_offset < data_size_in_bytes_);
diff --git a/runtime/vm/bitmap.h b/runtime/vm/bitmap.h
index bf8e437..fc2c685 100644
--- a/runtime/vm/bitmap.h
+++ b/runtime/vm/bitmap.h
@@ -54,7 +54,7 @@
bool InRange(intptr_t offset) const {
if (offset < 0) {
FATAL1("Fatal error in BitmapBuilder::InRange :"
- " invalid bit_offset, %"Pd"\n", offset);
+ " invalid bit_offset, %" Pd "\n", offset);
}
return (offset < length_);
}
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 60c4f54..e4e2127 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -73,7 +73,6 @@
V(Double_toStringAsFixed, 2) \
V(Double_toStringAsExponential, 2) \
V(Double_toStringAsPrecision, 2) \
- V(Double_pow, 2) \
V(JSSyntaxRegExp_factory, 4) \
V(JSSyntaxRegExp_getPattern, 1) \
V(JSSyntaxRegExp_getIsMultiLine, 1) \
@@ -110,6 +109,7 @@
V(Math_atan2, 2) \
V(Math_exp, 1) \
V(Math_log, 1) \
+ V(Math_doublePow, 2) \
V(Random_nextState, 1) \
V(Random_setupSeed, 2) \
V(DateNatives_currentTimeMillis, 0) \
@@ -202,6 +202,7 @@
V(Float32x4_getY, 1) \
V(Float32x4_getZ, 1) \
V(Float32x4_getW, 1) \
+ V(Float32x4_getSignMask, 1) \
V(Float32x4_shuffle, 2) \
V(Float32x4_withZWInXY, 2) \
V(Float32x4_interleaveXY, 2) \
@@ -223,6 +224,8 @@
V(Uint32x4_or, 2) \
V(Uint32x4_and, 2) \
V(Uint32x4_xor, 2) \
+ V(Uint32x4_add, 2) \
+ V(Uint32x4_sub, 2) \
V(Uint32x4_getX, 1) \
V(Uint32x4_getY, 1) \
V(Uint32x4_getZ, 1) \
@@ -231,6 +234,7 @@
V(Uint32x4_setY, 2) \
V(Uint32x4_setZ, 2) \
V(Uint32x4_setW, 2) \
+ V(Uint32x4_getSignMask, 1) \
V(Uint32x4_getFlagX, 1) \
V(Uint32x4_getFlagY, 1) \
V(Uint32x4_getFlagZ, 1) \
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index 5b4a370..84a3e37 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -648,10 +648,14 @@
ASSERT(type_param.IsFinalized());
declared_bound = type_param.bound();
if (!declared_bound.IsObjectType() && !declared_bound.IsDynamicType()) {
+ if (!declared_bound.IsFinalized() && !declared_bound.IsBeingFinalized()) {
+ declared_bound = FinalizeType(cls, declared_bound, kCanonicalize);
+ type_param.set_bound(declared_bound);
+ }
+ ASSERT(declared_bound.IsFinalized() || declared_bound.IsBeingFinalized());
Error& malformed_error = Error::Handle();
// Note that the bound may be malformed, in which case the bound check
// will return an error and the bound check will be postponed to run time.
- // Note also that the bound may still be unfinalized.
if (declared_bound.IsInstantiated()) {
instantiated_bound = declared_bound.raw();
} else {
@@ -821,15 +825,26 @@
// argument vector.
const intptr_t offset = num_type_arguments - num_type_parameters;
AbstractType& type_arg = AbstractType::Handle(Type::DynamicType());
+ for (intptr_t i = 0; i < offset; i++) {
+ // Temporarily set the type arguments of the super classes to dynamic.
+ full_arguments.SetTypeAt(i, type_arg);
+ }
for (intptr_t i = 0; i < num_type_parameters; i++) {
// If no type parameters were provided, a raw type is desired, so we
- // create a vector of DynamicType.
+ // create a vector of dynamic.
if (!arguments.IsNull()) {
type_arg = arguments.TypeAt(i);
}
ASSERT(type_arg.IsFinalized()); // Index of type parameter is adjusted.
full_arguments.SetTypeAt(offset + i, type_arg);
}
+ // Replace the compile-time argument vector (of length zero or
+ // num_type_parameters) of this type being finalized with the still
+ // unfinalized run-time argument vector (of length num_type_arguments).
+ // This type being finalized may be recursively reached via bounds
+ // checking, in which case type arguments of super classes will be seen
+ // as dynamic.
+ parameterized_type.set_arguments(full_arguments);
// If the type class is a signature class, the full argument vector
// must include the argument vector of the super type.
// If the signature class is a function type alias, it is also the owner
@@ -932,10 +947,11 @@
}
-// Check if an instance field or method of same name exists
+// Check if an instance field, getter, or method of same name exists
// in any super class.
static RawClass* FindSuperOwnerOfInstanceMember(const Class& cls,
- const String& name) {
+ const String& name,
+ const String& getter_name) {
Class& super_class = Class::Handle();
Function& function = Function::Handle();
Field& field = Field::Handle();
@@ -945,6 +961,10 @@
if (!function.IsNull() && !function.is_static()) {
return super_class.raw();
}
+ function = super_class.LookupFunction(getter_name);
+ if (!function.IsNull() && !function.is_static()) {
+ return super_class.raw();
+ }
field = super_class.LookupField(name);
if (!field.IsNull() && !field.is_static()) {
return super_class.raw();
@@ -1019,17 +1039,30 @@
// Note that getters and setters are explicitly listed as such in the list of
// functions of a class, so we do not need to consider fields as implicitly
// generating getters and setters.
- // The only compile errors we report are therefore:
- // - a getter having the same name as a method (but not a getter) in a super
- // class or in a subclass.
- // - a static field, instance field, or static method (but not an instance
- // method) having the same name as an instance member in a super class.
+ // Most overriding conflicts are only static warnings, i.e. they are not
+ // reported as compile-time errors by the vm. However, signature conflicts in
+ // overrides can be reported if the flag --error_on_bad_override is specified.
+ // Static warning examples are:
+ // - a static getter 'v' conflicting with an inherited instance setter 'v='.
+ // - a static setter 'v=' conflicting with an inherited instance member 'v'.
+ // - an instance member 'v' conflicting with an accessible static member 'v'
+ // or 'v=' of a super class (except that an instance method 'v' does not
+ // conflict with an accessible static setter 'v=' of a super class).
+ // The compile-time errors we report are:
+ // - a static member 'v' conflicting with an inherited instance member 'v'.
+ // - a static setter 'v=' conflicting with an inherited instance setter 'v='.
+ // - an instance method conflicting with an inherited instance field or
+ // instance getter.
+ // - an instance field or instance getter conflicting with an inherited
+ // instance method.
// Resolve type of fields and check for conflicts in super classes.
Array& array = Array::Handle(cls.fields());
Field& field = Field::Handle();
AbstractType& type = AbstractType::Handle();
String& name = String::Handle();
+ String& getter_name = String::Handle();
+ String& setter_name = String::Handle();
Class& super_class = Class::Handle();
const intptr_t num_fields = array.Length();
for (intptr_t i = 0; i < num_fields; i++) {
@@ -1040,7 +1073,8 @@
field.set_type(type);
name = field.name();
if (field.is_static()) {
- super_class = FindSuperOwnerOfInstanceMember(cls, name);
+ getter_name = Field::GetterSymbol(name);
+ super_class = FindSuperOwnerOfInstanceMember(cls, name, getter_name);
if (!super_class.IsNull()) {
const String& class_name = String::Handle(cls.Name());
const String& super_class_name = String::Handle(super_class.Name());
@@ -1054,6 +1088,25 @@
name.ToCString(),
super_class_name.ToCString());
}
+ // An implicit setter is not generated for a static field, therefore, we
+ // cannot rely on the code below handling the static setter case to report
+ // a conflict with an instance setter. So we check explicitly here.
+ setter_name = Field::SetterSymbol(name);
+ super_class = FindSuperOwnerOfFunction(cls, setter_name);
+ if (!super_class.IsNull()) {
+ const String& class_name = String::Handle(cls.Name());
+ const String& super_class_name = String::Handle(super_class.Name());
+ const Script& script = Script::Handle(cls.script());
+ ReportError(Error::Handle(), // No previous error.
+ script, field.token_pos(),
+ "static field '%s' of class '%s' conflicts with "
+ "instance setter '%s=' of super class '%s'",
+ name.ToCString(),
+ class_name.ToCString(),
+ name.ToCString(),
+ super_class_name.ToCString());
+ }
+
} else {
// Instance field. Check whether the field overrides a method
// (but not getter).
@@ -1112,7 +1165,6 @@
// Therefore, we undo the optimization performed by the parser, i.e.
// we create an implicit static final getter and reset the field value
// to the sentinel value.
- const String& getter_name = String::Handle(Field::GetterSymbol(name));
const Function& getter = Function::Handle(
Function::New(getter_name,
RawFunction::kImplicitStaticFinalGetter,
@@ -1146,52 +1198,78 @@
Function& function = Function::Handle();
Function& overridden_function = Function::Handle();
const intptr_t num_functions = array.Length();
- String& function_name = String::Handle();
Error& error = Error::Handle();
for (intptr_t i = 0; i < num_functions; i++) {
function ^= array.At(i);
ResolveAndFinalizeSignature(cls, function);
- function_name = function.name();
+ name = function.name();
+ if (FLAG_error_on_bad_override && // Report signature conflicts only.
+ !function.is_static() && !function.IsConstructor()) {
+ // A constructor cannot override anything.
+ for (int i = 0; i < interfaces.Length(); i++) {
+ super_class ^= interfaces.At(i);
+ overridden_function = super_class.LookupDynamicFunction(name);
+ if (!overridden_function.IsNull() &&
+ !function.HasCompatibleParametersWith(overridden_function,
+ &error)) {
+ const String& class_name = String::Handle(cls.Name());
+ const String& super_class_name = String::Handle(super_class.Name());
+ const Script& script = Script::Handle(cls.script());
+ ReportError(error, script, function.token_pos(),
+ "class '%s' overrides method '%s' of super class '%s' "
+ "with incompatible parameters",
+ class_name.ToCString(),
+ name.ToCString(),
+ super_class_name.ToCString());
+ }
+ }
+ }
+ if (function.IsSetterFunction() || function.IsImplicitSetterFunction()) {
+ if (function.is_static()) {
+ super_class = FindSuperOwnerOfFunction(cls, name);
+ if (!super_class.IsNull()) {
+ const String& class_name = String::Handle(cls.Name());
+ const String& super_class_name = String::Handle(super_class.Name());
+ const Script& script = Script::Handle(cls.script());
+ ReportError(Error::Handle(), // No previous error.
+ script, function.token_pos(),
+ "static setter '%s=' of class '%s' conflicts with "
+ "instance setter '%s=' of super class '%s'",
+ name.ToCString(),
+ class_name.ToCString(),
+ name.ToCString(),
+ super_class_name.ToCString());
+ }
+ }
+ continue;
+ }
+ if (function.IsGetterFunction() || function.IsImplicitGetterFunction()) {
+ getter_name = name.raw();
+ name = Field::NameFromGetter(getter_name);
+ } else {
+ getter_name = Field::GetterSymbol(name);
+ }
if (function.is_static()) {
- super_class = FindSuperOwnerOfInstanceMember(cls, function_name);
+ super_class = FindSuperOwnerOfInstanceMember(cls, name, getter_name);
if (!super_class.IsNull()) {
const String& class_name = String::Handle(cls.Name());
const String& super_class_name = String::Handle(super_class.Name());
const Script& script = Script::Handle(cls.script());
ReportError(Error::Handle(), // No previous error.
script, function.token_pos(),
- "static function '%s' of class '%s' conflicts with "
+ "static %s '%s' of class '%s' conflicts with "
"instance member '%s' of super class '%s'",
- function_name.ToCString(),
+ (function.IsGetterFunction() ||
+ function.IsImplicitGetterFunction()) ? "getter" : "method",
+ name.ToCString(),
class_name.ToCString(),
- function_name.ToCString(),
+ name.ToCString(),
super_class_name.ToCString());
}
// The function may be a still unresolved redirecting factory. Do not yet
// try to resolve it in order to avoid cycles in class finalization.
- } else if (FLAG_error_on_bad_override && !function.IsConstructor()) {
- // A constructor cannot override anything.
- for (int i = 0; i < interfaces.Length(); i++) {
- super_class ^= interfaces.At(i);
- overridden_function = super_class.LookupDynamicFunction(function_name);
- if (!overridden_function.IsNull() &&
- !function.HasCompatibleParametersWith(overridden_function,
- &error)) {
- // Function types are purposely not checked for subtyping.
- const String& class_name = String::Handle(cls.Name());
- const String& super_class_name = String::Handle(super_class.Name());
- const Script& script = Script::Handle(cls.script());
- ReportError(error, script, function.token_pos(),
- "class '%s' overrides function '%s' of super class '%s' "
- "with incompatible parameters",
- class_name.ToCString(),
- function_name.ToCString(),
- super_class_name.ToCString());
- }
- }
- }
- if (function.IsGetterFunction()) {
- name = Field::NameFromGetter(function_name);
+ } else if (function.IsGetterFunction() ||
+ function.IsImplicitGetterFunction()) {
super_class = FindSuperOwnerOfFunction(cls, name);
if (!super_class.IsNull()) {
const String& class_name = String::Handle(cls.Name());
@@ -1200,28 +1278,28 @@
ReportError(Error::Handle(), // No previous error.
script, function.token_pos(),
"getter '%s' of class '%s' conflicts with "
- "function '%s' of super class '%s'",
+ "method '%s' of super class '%s'",
name.ToCString(),
class_name.ToCString(),
name.ToCString(),
super_class_name.ToCString());
}
- } else if (!function.IsSetterFunction()) {
+ } else if (!function.IsSetterFunction() &&
+ !function.IsImplicitSetterFunction()) {
// A function cannot conflict with a setter, since they cannot
// have the same name. Thus, we do not need to check setters.
- name = Field::GetterName(function_name);
- super_class = FindSuperOwnerOfFunction(cls, name);
+ super_class = FindSuperOwnerOfFunction(cls, getter_name);
if (!super_class.IsNull()) {
const String& class_name = String::Handle(cls.Name());
const String& super_class_name = String::Handle(super_class.Name());
const Script& script = Script::Handle(cls.script());
ReportError(Error::Handle(), // No previous error.
script, function.token_pos(),
- "function '%s' of class '%s' conflicts with "
+ "method '%s' of class '%s' conflicts with "
"getter '%s' of super class '%s'",
- function_name.ToCString(),
+ name.ToCString(),
class_name.ToCString(),
- function_name.ToCString(),
+ name.ToCString(),
super_class_name.ToCString());
}
}
@@ -1352,7 +1430,7 @@
const Class& mixin_cls = Class::Handle(mixin_type.type_class());
if (FLAG_trace_class_finalization) {
- OS::Print("Applying mixin type '%s' to '%s' at pos %"Pd"\n",
+ OS::Print("Applying mixin type '%s' to '%s' at pos %" Pd "\n",
String::Handle(mixin_type.Name()).ToCString(),
cls.ToCString(),
cls.token_pos());
@@ -1446,7 +1524,7 @@
mixin_cls.EnsureIsFinalized(isolate);
if (FLAG_trace_class_finalization) {
- OS::Print("Applying mixin '%s' to '%s' at pos %"Pd"\n",
+ OS::Print("Applying mixin '%s' to '%s' at pos %" Pd "\n",
String::Handle(mixin_cls.Name()).ToCString(),
cls.ToCString(),
cls.token_pos());
diff --git a/runtime/vm/class_table.cc b/runtime/vm/class_table.cc
index 2eac4c9..2cf1ac1 100644
--- a/runtime/vm/class_table.cc
+++ b/runtime/vm/class_table.cc
@@ -90,7 +90,7 @@
cls = At(i);
if (cls.raw() != reinterpret_cast<RawClass*>(0)) {
name = cls.Name();
- OS::Print("%"Pd": %s\n", i, name.ToCString());
+ OS::Print("%" Pd ": %s\n", i, name.ToCString());
}
}
}
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
index 2f72473..a5a597f 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -352,7 +352,7 @@
const Type& instance_type = Type::Handle(instance.GetType());
ASSERT(instance_type.IsInstantiated());
if (type.IsInstantiated()) {
- OS::PrintErr("%s: '%s' %"Pd" %s '%s' %"Pd" (pc: %#"Px").\n",
+ OS::PrintErr("%s: '%s' %" Pd " %s '%s' %" Pd " (pc: %#" Px ").\n",
message,
String::Handle(instance_type.Name()).ToCString(),
Class::Handle(instance_type.type_class()).id(),
@@ -365,7 +365,7 @@
Error& malformed_error = Error::Handle();
const AbstractType& instantiated_type = AbstractType::Handle(
type.InstantiateFrom(instantiator_type_arguments, &malformed_error));
- OS::PrintErr("%s: '%s' %s '%s' instantiated from '%s' (pc: %#"Px").\n",
+ OS::PrintErr("%s: '%s' %s '%s' instantiated from '%s' (pc: %#" Px ").\n",
message,
String::Handle(instance_type.Name()).ToCString(),
(result.raw() == Bool::True().raw()) ? "is" : "is !",
@@ -488,7 +488,7 @@
(last_instantiator_type_arguments.raw() ==
instantiator_type_arguments.raw())) {
if (FLAG_trace_type_checks) {
- OS::PrintErr("%"Pd" ", i);
+ OS::PrintErr("%" Pd " ", i);
if (type_arguments_replaced) {
PrintTypeCheck("Duplicate cache entry (canonical.)", instance, type,
instantiator_type_arguments, result);
@@ -517,10 +517,10 @@
&malformed_error);
ASSERT(malformed_error.IsNull()); // Malformed types are not optimized.
}
- OS::PrintErr(" Updated test cache %p ix: %"Pd" with "
- "(cid: %"Pd", type-args: %p, instantiator: %p, result: %s)\n"
- " instance [class: (%p '%s' cid: %"Pd"), type-args: %p %s]\n"
- " test-type [class: (%p '%s' cid: %"Pd"), in-type-args: %p %s]\n",
+ OS::PrintErr(" Updated test cache %p ix: %" Pd " with "
+ "(cid: %" Pd ", type-args: %p, instantiator: %p, result: %s)\n"
+ " instance [class: (%p '%s' cid: %" Pd "), type-args: %p %s]\n"
+ " test-type [class: (%p '%s' cid: %" Pd "), in-type-args: %p %s]\n",
new_cache.raw(),
len,
@@ -739,7 +739,7 @@
target_code.EntryPoint());
caller_code.SetStaticCallTargetCodeAt(caller_frame->pc(), target_code);
if (FLAG_trace_patching) {
- OS::PrintErr("PatchStaticCall: patching from %#"Px" to '%s' %#"Px"\n",
+ OS::PrintErr("PatchStaticCall: patching from %#" Px " to '%s' %#" Px "\n",
caller_frame->pc(),
target_function.ToFullyQualifiedCString(),
target_code.EntryPoint());
@@ -899,8 +899,8 @@
}
}
if (FLAG_trace_ic) {
- OS::PrintErr("InlineCacheMissHandler %d call at %#"Px"' "
- "adding <%s> id:%"Pd" -> <%s>\n",
+ OS::PrintErr("InlineCacheMissHandler %d call at %#" Px "' "
+ "adding <%s> id:%" Pd " -> <%s>\n",
args.length(),
caller_frame->pc(),
Class::Handle(receiver.clazz()).ToCString(),
@@ -1007,8 +1007,9 @@
DartFrameIterator iterator;
StackFrame* caller_frame = iterator.NextFrame();
ASSERT(caller_frame != NULL);
- OS::PrintErr("StaticCallMissHandler at %#"Px" target %s (%"Pd", %"Pd")\n",
- caller_frame->pc(), target.ToCString(), cids[0], cids[1]);
+ OS::PrintErr("StaticCallMissHandler at %#" Px
+ " target %s (%" Pd ", %" Pd ")\n",
+ caller_frame->pc(), target.ToCString(), cids[0], cids[1]);
}
arguments.SetReturn(target);
}
@@ -1178,7 +1179,7 @@
ASSERT(!target_function.IsNull());
ic_data.AddReceiverCheck(receiver.GetClassId(), target_function);
if (FLAG_trace_ic) {
- OS::PrintErr("InvokeField IC miss: adding <%s> id:%"Pd" -> <%s>\n",
+ OS::PrintErr("InvokeField IC miss: adding <%s> id:%" Pd " -> <%s>\n",
Class::Handle(receiver.clazz()).ToCString(),
receiver.GetClassId(),
target_function.ToCString());
@@ -1255,7 +1256,7 @@
ic_data.AddCheck(class_ids, target_function);
}
if (FLAG_trace_ic) {
- OS::PrintErr("NoSuchMethod IC miss: adding <%s> id:%"Pd" -> <%s>\n",
+ OS::PrintErr("NoSuchMethod IC miss: adding <%s> id:%" Pd " -> <%s>\n",
Class::Handle(receiver.clazz()).ToCString(),
receiver_cid,
target_function.ToCString());
@@ -1368,7 +1369,7 @@
intptr_t osr_id =
Code::Handle(function.unoptimized_code()).GetDeoptIdForOsr(frame->pc());
if (FLAG_trace_osr) {
- OS::Print("Attempting OSR for %s at id=%"Pd", count=%"Pd"\n",
+ OS::Print("Attempting OSR for %s at id=%" Pd ", count=%" Pd "\n",
function.ToFullyQualifiedCString(),
osr_id,
function.usage_counter());
@@ -1403,7 +1404,8 @@
DartFrameIterator iterator;
StackFrame* frame = iterator.NextFrame();
ASSERT(frame != NULL);
- OS::PrintErr("IC call @%#"Px": ICData: %p cnt:%"Pd" nchecks: %"Pd" %s %s\n",
+ OS::PrintErr("IC call @%#" Px ": ICData: %p cnt:%" Pd " nchecks: %" Pd
+ " %s %s\n",
frame->pc(),
ic_data.raw(),
function.usage_counter(),
@@ -1464,7 +1466,7 @@
target_code.EntryPoint());
caller_code.SetStaticCallTargetCodeAt(frame->pc(), target_code);
if (FLAG_trace_patching) {
- OS::PrintErr("FixCallersTarget: patching from %#"Px" to '%s' %#"Px"\n",
+ OS::PrintErr("FixCallersTarget: patching from %#" Px " to '%s' %#" Px "\n",
frame->pc(),
Function::Handle(target_code.function()).ToFullyQualifiedCString(),
target_code.EntryPoint());
@@ -1639,7 +1641,7 @@
if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) {
Function& function = Function::Handle(optimized_code.function());
OS::PrintErr(
- "Deoptimizing (reason %"Pd" '%s') at pc %#"Px" '%s' (count %d)\n",
+ "Deoptimizing (reason %" Pd " '%s') at pc %#" Px " '%s' (count %d)\n",
deopt_reason,
DeoptReasonToText(deopt_reason),
caller_frame->pc(),
@@ -1723,7 +1725,7 @@
if (FLAG_trace_deoptimization_verbose) {
for (intptr_t i = 0; i < frame_size; i++) {
- OS::PrintErr("*%"Pd". [%"Px"] %#014"Px" [%s]\n",
+ OS::PrintErr("*%" Pd ". [%" Px "] %#014" Px " [%s]\n",
i,
reinterpret_cast<uword>(&start[i]),
start[i],
@@ -1814,8 +1816,8 @@
script.GetTokenLocation(token_pos, &line, &column);
String& line_string = String::Handle(script.GetLine(line));
OS::PrintErr(" Function: %s\n", top_function.ToFullyQualifiedCString());
- OS::PrintErr(" Line %"Pd": '%s'\n", line, line_string.ToCString());
- OS::PrintErr(" Deopt args: %"Pd"\n", deopt_arguments);
+ OS::PrintErr(" Line %" Pd ": '%s'\n", line, line_string.ToCString());
+ OS::PrintErr(" Deopt args: %" Pd "\n", deopt_arguments);
}
}
@@ -1851,6 +1853,31 @@
}
+static intptr_t GetListLength(const Object& value) {
+ const intptr_t cid = value.GetClassId();
+ ASSERT(RawObject::IsBuiltinListClassId(cid));
+ // Extract list length.
+ if (value.IsTypedData()) {
+ const TypedData& list = TypedData::Cast(value);
+ return list.Length();
+ } else if (value.IsArray()) {
+ const Array& list = Array::Cast(value);
+ return list.Length();
+ } else if (value.IsGrowableObjectArray()) {
+ // List length is variable.
+ return Field::kNoFixedLength;
+ } else if (value.IsExternalTypedData()) {
+ // TODO(johnmccutchan): Enable for external typed data.
+ return Field::kNoFixedLength;
+ } else if (RawObject::IsTypedDataViewClassId(cid)) {
+ // TODO(johnmccutchan): Enable for typed data views.
+ return Field::kNoFixedLength;
+ }
+ UNIMPLEMENTED();
+ return Field::kNoFixedLength;
+}
+
+
// Update global type feedback recorded for a field recording the assignment
// of the given value.
// Arg0: Field object;
@@ -1859,8 +1886,14 @@
ASSERT(arguments.ArgCount() == kUpdateFieldCidRuntimeEntry.argument_count());
const Field& field = Field::CheckedHandle(arguments.ArgAt(0));
const Object& value = Object::Handle(arguments.ArgAt(1));
-
- field.UpdateCid(value.GetClassId());
+ const intptr_t cid = value.GetClassId();
+ field.UpdateCid(cid);
+ intptr_t list_length = Field::kNoFixedLength;
+ if ((field.guarded_cid() != kDynamicCid) &&
+ field.is_final() && RawObject::IsBuiltinListClassId(cid)) {
+ list_length = GetListLength(value);
+ }
+ field.UpdateLength(list_length);
}
} // namespace dart
diff --git a/runtime/vm/code_generator_test.cc b/runtime/vm/code_generator_test.cc
index 6dceb4c..cac140a 100644
--- a/runtime/vm/code_generator_test.cc
+++ b/runtime/vm/code_generator_test.cc
@@ -224,6 +224,7 @@
function,
native_name,
native_function,
+ local_scope,
false /* not bootstrap native */)));
}
@@ -406,6 +407,7 @@
function,
native_name,
native_function,
+ local_scope,
false /* Not bootstrap native */)));
}
@@ -495,6 +497,7 @@
function,
native_name,
native_function,
+ local_scope,
false /* Not bootstrap native */)));
}
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index 73c6d63..9864e56 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -229,12 +229,12 @@
// Disable optimized code.
ASSERT(function.HasOptimizedCode());
if (FLAG_trace_compiler) {
- OS::Print("--> patching entry %#"Px"\n",
+ OS::Print("--> patching entry %#" Px "\n",
Code::Handle(function.CurrentCode()).EntryPoint());
}
function.SwitchToUnoptimizedCode();
if (FLAG_trace_compiler) {
- OS::Print("--> restoring entry at %#"Px"\n",
+ OS::Print("--> restoring entry at %#" Px "\n",
Code::Handle(function.unoptimized_code()).EntryPoint());
}
}
@@ -342,6 +342,17 @@
if (FLAG_use_inlining) {
TimerScope timer(FLAG_compiler_stats,
&CompilerStats::graphinliner_timer);
+ // Propagate types to create more inlining opportunities.
+ if (FLAG_propagate_types) {
+ FlowGraphTypePropagator propagator(flow_graph);
+ propagator.Propagate();
+ DEBUG_ASSERT(flow_graph->VerifyUseLists());
+ }
+
+ // Use propagated class-ids to create more inlining opportunities.
+ optimizer.ApplyClassIds();
+ DEBUG_ASSERT(flow_graph->VerifyUseLists());
+
FlowGraphInliner inliner(flow_graph, &guarded_fields);
inliner.Inline();
// Use lists are maintained and validated by the inliner.
@@ -528,7 +539,7 @@
if (osr_id == Isolate::kNoDeoptId) {
CodePatcher::PatchEntry(Code::Handle(function.CurrentCode()));
if (FLAG_trace_compiler) {
- OS::Print("--> patching entry %#"Px"\n",
+ OS::Print("--> patching entry %#" Px "\n",
Code::Handle(function.unoptimized_code()).EntryPoint());
}
}
@@ -595,7 +606,7 @@
const uword addr = code.GetPointerOffsetAt(i) + code.EntryPoint();
Object& obj = Object::Handle();
obj = *reinterpret_cast<RawObject**>(addr);
- OS::Print(" %d : %#"Px" '%s'\n",
+ OS::Print(" %d : %#" Px " '%s'\n",
code.GetPointerOffsetAt(i), addr, obj.ToCString());
}
OS::Print("}\n");
@@ -616,7 +627,7 @@
Smi& reason = Smi::Handle();
for (intptr_t i = 0; i < deopt_table_length; ++i) {
DeoptTable::GetEntry(deopt_table, i, &offset, &info, &reason);
- OS::Print("%4"Pd": 0x%"Px" %s (%s)\n",
+ OS::Print("%4" Pd ": 0x%" Px " %s (%s)\n",
i,
start + offset.Value(),
info.ToCString(),
@@ -629,7 +640,7 @@
if (object_table.Length() > 0) {
OS::Print("Object Table: {\n");
for (intptr_t i = 0; i < object_table.Length(); i++) {
- OS::Print(" %"Pd": %s\n", i,
+ OS::Print(" %" Pd ": %s\n", i,
Object::Handle(object_table.At(i)).ToCString());
}
OS::Print("}\n");
@@ -658,22 +669,22 @@
RawLocalVarDescriptors::VarInfo var_info;
var_descriptors.GetInfo(i, &var_info);
if (var_info.kind == RawLocalVarDescriptors::kSavedEntryContext) {
- OS::Print(" saved caller's CTX reg offset %"Pd"\n", var_info.index);
+ OS::Print(" saved caller's CTX reg offset %" Pd "\n", var_info.index);
} else if (var_info.kind == RawLocalVarDescriptors::kSavedCurrentContext) {
- OS::Print(" saved current CTX reg offset %"Pd"\n", var_info.index);
+ OS::Print(" saved current CTX reg offset %" Pd "\n", var_info.index);
} else {
if (var_info.kind == RawLocalVarDescriptors::kContextLevel) {
- OS::Print(" context level %"Pd" scope %d",
+ OS::Print(" context level %" Pd " scope %d",
var_info.index, var_info.scope_id);
} else if (var_info.kind == RawLocalVarDescriptors::kStackVar) {
- OS::Print(" stack var '%s' offset %"Pd"",
+ OS::Print(" stack var '%s' offset %" Pd "",
var_name.ToCString(), var_info.index);
} else {
ASSERT(var_info.kind == RawLocalVarDescriptors::kContextVar);
- OS::Print(" context var '%s' level %d offset %"Pd"",
+ OS::Print(" context var '%s' level %d offset %" Pd "",
var_name.ToCString(), var_info.scope_id, var_info.index);
}
- OS::Print(" (valid %"Pd"-%"Pd")\n",
+ OS::Print(" (valid %" Pd "-%" Pd ")\n",
var_info.begin_pos, var_info.end_pos);
}
}
@@ -695,7 +706,7 @@
offset ^= table.At(i + Code::kSCallTableOffsetEntry);
function ^= table.At(i + Code::kSCallTableFunctionEntry);
code ^= table.At(i + Code::kSCallTableCodeEntry);
- OS::Print(" 0x%"Px": %s, %p\n",
+ OS::Print(" 0x%" Px ": %s, %p\n",
start + offset.Value(),
function.ToFullyQualifiedCString(),
code.raw());
@@ -726,7 +737,7 @@
ParsedFunction* parsed_function = new ParsedFunction(
Function::ZoneHandle(function.raw()));
if (FLAG_trace_compiler) {
- OS::Print("Compiling %s%sfunction: '%s' @ token %"Pd", size %"Pd"\n",
+ OS::Print("Compiling %s%sfunction: '%s' @ token %" Pd ", size %" Pd "\n",
(osr_id == Isolate::kNoDeoptId ? "" : "osr "),
(optimized ? "optimized " : ""),
function.ToFullyQualifiedCString(),
@@ -758,7 +769,7 @@
per_compile_timer.Stop();
if (FLAG_trace_compiler) {
- OS::Print("--> '%s' entry: %#"Px" size: %"Pd" time: %"Pd64" us\n",
+ OS::Print("--> '%s' entry: %#" Px " size: %" Pd " time: %" Pd64 " us\n",
function.ToFullyQualifiedCString(),
Code::Handle(function.CurrentCode()).EntryPoint(),
Code::Handle(function.CurrentCode()).Size(),
diff --git a/runtime/vm/compiler_stats.cc b/runtime/vm/compiler_stats.cc
index e9081f99..2a0671f 100644
--- a/runtime/vm/compiler_stats.cc
+++ b/runtime/vm/compiler_stats.cc
@@ -66,69 +66,69 @@
return;
}
OS::Print("==== Compiler Stats ====\n");
- OS::Print("Number of tokens: %"Pd"\n", num_tokens_total);
- OS::Print(" Literal tokens: %"Pd"\n", num_literal_tokens_total);
- OS::Print(" Ident tokens: %"Pd"\n", num_ident_tokens_total);
- OS::Print("Tokens consumed: %"Pd" (%.2f times number of tokens)\n",
+ OS::Print("Number of tokens: %" Pd "\n", num_tokens_total);
+ OS::Print(" Literal tokens: %" Pd "\n", num_literal_tokens_total);
+ OS::Print(" Ident tokens: %" Pd "\n", num_ident_tokens_total);
+ OS::Print("Tokens consumed: %" Pd " (%.2f times number of tokens)\n",
num_tokens_consumed,
(1.0 * num_tokens_consumed) / num_tokens_total);
- OS::Print("Tokens checked: %"Pd" (%.2f times tokens consumed)\n",
+ OS::Print("Tokens checked: %" Pd " (%.2f times tokens consumed)\n",
num_token_checks, (1.0 * num_token_checks) / num_tokens_consumed);
- OS::Print("Token rewind: %"Pd" (%"Pd"%% of tokens checked)\n",
+ OS::Print("Token rewind: %" Pd " (%" Pd "%% of tokens checked)\n",
num_tokens_rewind, (100 * num_tokens_rewind) / num_token_checks);
- OS::Print("Token lookahead: %"Pd" (%"Pd"%% of tokens checked)\n",
+ OS::Print("Token lookahead: %" Pd " (%" Pd "%% of tokens checked)\n",
num_tokens_lookahead,
(100 * num_tokens_lookahead) / num_token_checks);
- OS::Print("Source length: %"Pd" characters\n", src_length);
+ OS::Print("Source length: %" Pd " characters\n", src_length);
int64_t scan_usecs = scanner_timer.TotalElapsedTime();
- OS::Print("Scanner time: %"Pd64" msecs\n",
+ OS::Print("Scanner time: %" Pd64 " msecs\n",
scan_usecs / 1000);
int64_t parse_usecs = parser_timer.TotalElapsedTime();
- OS::Print("Parser time: %"Pd64" msecs\n",
+ OS::Print("Parser time: %" Pd64 " msecs\n",
parse_usecs / 1000);
int64_t codegen_usecs = codegen_timer.TotalElapsedTime();
- OS::Print("Code gen. time: %"Pd64" msecs\n",
+ OS::Print("Code gen. time: %" Pd64 " msecs\n",
codegen_usecs / 1000);
int64_t graphbuilder_usecs = graphbuilder_timer.TotalElapsedTime();
- OS::Print(" Graph builder: %"Pd64" msecs\n", graphbuilder_usecs / 1000);
+ OS::Print(" Graph builder: %" Pd64 " msecs\n", graphbuilder_usecs / 1000);
int64_t ssa_usecs = ssa_timer.TotalElapsedTime();
- OS::Print(" Graph SSA: %"Pd64" msecs\n", ssa_usecs / 1000);
+ OS::Print(" Graph SSA: %" Pd64 " msecs\n", ssa_usecs / 1000);
int64_t graphinliner_usecs = graphinliner_timer.TotalElapsedTime();
- OS::Print(" Graph inliner: %"Pd64" msecs\n", graphinliner_usecs / 1000);
+ OS::Print(" Graph inliner: %" Pd64 " msecs\n", graphinliner_usecs / 1000);
int64_t graphinliner_parse_usecs =
graphinliner_parse_timer.TotalElapsedTime();
- OS::Print(" Parsing: %"Pd64" msecs\n",
+ OS::Print(" Parsing: %" Pd64 " msecs\n",
graphinliner_parse_usecs / 1000);
int64_t graphinliner_build_usecs =
graphinliner_build_timer.TotalElapsedTime();
- OS::Print(" Building: %"Pd64" msecs\n",
+ OS::Print(" Building: %" Pd64 " msecs\n",
graphinliner_build_usecs / 1000);
int64_t graphinliner_ssa_usecs = graphinliner_ssa_timer.TotalElapsedTime();
- OS::Print(" SSA: %"Pd64" msecs\n",
+ OS::Print(" SSA: %" Pd64 " msecs\n",
graphinliner_ssa_usecs / 1000);
int64_t graphinliner_opt_usecs = graphinliner_opt_timer.TotalElapsedTime();
- OS::Print(" Optimization: %"Pd64" msecs\n",
+ OS::Print(" Optimization: %" Pd64 " msecs\n",
graphinliner_opt_usecs / 1000);
int64_t graphinliner_subst_usecs =
graphinliner_subst_timer.TotalElapsedTime();
- OS::Print(" Substitution: %"Pd64" msecs\n",
+ OS::Print(" Substitution: %" Pd64 " msecs\n",
graphinliner_subst_usecs / 1000);
int64_t graphoptimizer_usecs = graphoptimizer_timer.TotalElapsedTime();
- OS::Print(" Graph optimizer: %"Pd64" msecs\n",
+ OS::Print(" Graph optimizer: %" Pd64 " msecs\n",
(graphoptimizer_usecs - graphinliner_usecs) / 1000);
int64_t graphcompiler_usecs = graphcompiler_timer.TotalElapsedTime();
- OS::Print(" Graph compiler: %"Pd64" msecs\n",
+ OS::Print(" Graph compiler: %" Pd64 " msecs\n",
graphcompiler_usecs / 1000);
int64_t codefinalizer_usecs = codefinalizer_timer.TotalElapsedTime();
- OS::Print(" Code finalizer: %"Pd64" msecs\n",
+ OS::Print(" Code finalizer: %" Pd64 " msecs\n",
codefinalizer_usecs / 1000);
- OS::Print("Compilation speed: %"Pd64" tokens per msec\n",
+ OS::Print("Compilation speed: %" Pd64 " tokens per msec\n",
1000 * num_tokens_total / (parse_usecs + codegen_usecs));
- OS::Print("Code size: %"Pd" KB\n",
+ OS::Print("Code size: %" Pd " KB\n",
code_allocated / 1024);
- OS::Print("Code density: %"Pd" tokens per KB\n",
+ OS::Print("Code density: %" Pd " tokens per KB\n",
num_tokens_total * 1024 / code_allocated);
}
diff --git a/runtime/vm/compiler_test.cc b/runtime/vm/compiler_test.cc
index f2abb8a..e962155 100644
--- a/runtime/vm/compiler_test.cc
+++ b/runtime/vm/compiler_test.cc
@@ -5,6 +5,7 @@
#include "platform/assert.h"
#include "vm/class_finalizer.h"
#include "vm/compiler.h"
+#include "vm/dart_api_impl.h"
#include "vm/object.h"
#include "vm/symbols.h"
#include "vm/unit_test.h"
@@ -63,4 +64,34 @@
EXPECT(function_moo.HasCode());
}
+
+TEST_CASE(EvalExpression) {
+ const char* kScriptChars =
+ "int ten = 2 * 5; \n"
+ "get dot => '.'; \n"
+ "class A { \n"
+ " var apa = 'Herr Nilsson'; \n"
+ " calc(x) => '${x*ten}'; \n"
+ "} \n"
+ "makeObj() => new A(); \n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
+ Dart_Handle obj_handle =
+ Dart_Invoke(lib, Dart_NewStringFromCString("makeObj"), 0, NULL);
+ EXPECT(!Dart_IsNull(obj_handle));
+ EXPECT(!Dart_IsError(obj_handle));
+ const Object& obj = Object::Handle(Api::UnwrapHandle(obj_handle));
+ EXPECT(!obj.IsNull());
+ EXPECT(obj.IsInstance());
+
+ String& expr_text = String::Handle();
+ expr_text = String::New("apa + ' ${calc(10)}' + dot");
+ Object& val = Object::Handle();
+ val = Instance::Cast(obj).Evaluate(expr_text);
+ EXPECT(!val.IsNull());
+ EXPECT(!val.IsError());
+ EXPECT(val.IsString());
+ EXPECT_STREQ("Herr Nilsson 100.", val.ToCString());
+}
+
} // namespace dart
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index fdc7e50..4c082e8 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -1836,7 +1836,7 @@
if ((length < str_size) || (length > String::kMaxElements)) {
return Api::NewError("Dart_MakeExternalString "
"expects argument length to be in the range"
- "[%"Pd"..%"Pd"].",
+ "[%" Pd "..%" Pd "].",
str_size, String::kMaxElements);
}
if (str_obj.InVMHeap()) {
@@ -3719,6 +3719,108 @@
}
+DART_EXPORT Dart_Handle Dart_GetNativeIntegerArgument(Dart_NativeArguments args,
+ int index,
+ int64_t* value) {
+ NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
+ if ((index < 0) || (index >= arguments->NativeArgCount())) {
+ return Api::NewError(
+ "%s: argument 'index' out of range. Expected 0..%d but saw %d.",
+ CURRENT_FUNC, arguments->NativeArgCount() - 1, index);
+ }
+ Isolate* isolate = arguments->isolate();
+ ReusableObjectHandleScope reused_obj_handle(isolate);
+ Object& obj = reused_obj_handle.Handle();
+ obj = arguments->NativeArgAt(index);
+ intptr_t cid = obj.GetClassId();
+ if (cid == kSmiCid) {
+ *value = Smi::Cast(obj).Value();
+ return Api::Success();
+ }
+ if (cid == kMintCid) {
+ *value = Mint::Cast(obj).value();
+ return Api::Success();
+ }
+ if (cid == kBigintCid) {
+ const Bigint& bigint = Bigint::Cast(obj);
+ if (BigintOperations::FitsIntoInt64(bigint)) {
+ *value = BigintOperations::ToInt64(bigint);
+ return Api::Success();
+ }
+ return Api::NewError(
+ "%s: argument %d is a big integer that does not fit in 'value'.",
+ CURRENT_FUNC, index);
+ }
+ return Api::NewError(
+ "%s: argument %d is not an Integer argument.",
+ CURRENT_FUNC, index);
+}
+
+
+DART_EXPORT Dart_Handle Dart_GetNativeBooleanArgument(Dart_NativeArguments args,
+ int index,
+ bool* value) {
+ NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
+ if ((index < 0) || (index >= arguments->NativeArgCount())) {
+ return Api::NewError(
+ "%s: argument 'index' out of range. Expected 0..%d but saw %d.",
+ CURRENT_FUNC, arguments->NativeArgCount() - 1, index);
+ }
+ Isolate* isolate = arguments->isolate();
+ ReusableObjectHandleScope reused_obj_handle(isolate);
+ Object& obj = reused_obj_handle.Handle();
+ obj = arguments->NativeArgAt(index);
+ intptr_t cid = obj.GetClassId();
+ if (cid == kBoolCid) {
+ *value = Bool::Cast(obj).value();
+ return Api::Success();
+ }
+ if (obj.IsNull()) {
+ *value = false;
+ return Api::Success();
+ }
+ return Api::NewError(
+ "%s: argument %d is not a Boolean argument.",
+ CURRENT_FUNC, index);
+}
+
+
+DART_EXPORT Dart_Handle Dart_GetNativeDoubleArgument(Dart_NativeArguments args,
+ int index,
+ double* value) {
+ NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
+ if ((index < 0) || (index >= arguments->NativeArgCount())) {
+ return Api::NewError(
+ "%s: argument 'index' out of range. Expected 0..%d but saw %d.",
+ CURRENT_FUNC, arguments->NativeArgCount() - 1, index);
+ }
+ Isolate* isolate = arguments->isolate();
+ ReusableObjectHandleScope reused_obj_handle(isolate);
+ Object& obj = reused_obj_handle.Handle();
+ obj = arguments->NativeArgAt(index);
+ intptr_t cid = obj.GetClassId();
+ if (cid == kDoubleCid) {
+ *value = Double::Cast(obj).value();
+ return Api::Success();
+ }
+ if (cid == kSmiCid) {
+ *value = Smi::Cast(obj).AsDoubleValue();
+ return Api::Success();
+ }
+ if (cid == kMintCid) {
+ *value = Mint::Cast(obj).AsDoubleValue();
+ return Api::Success();
+ }
+ if (cid == kBigintCid) {
+ *value = Bigint::Cast(obj).AsDoubleValue();
+ return Api::Success();
+ }
+ return Api::NewError(
+ "%s: argument %d is not a Double argument.",
+ CURRENT_FUNC, index);
+}
+
+
DART_EXPORT void Dart_SetReturnValue(Dart_NativeArguments args,
Dart_Handle retval) {
NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
@@ -3754,7 +3856,7 @@
DART_EXPORT void Dart_SetIntegerReturnValue(Dart_NativeArguments args,
- intptr_t retval) {
+ int64_t retval) {
NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
Isolate* isolate = arguments->isolate();
CHECK_ISOLATE(isolate);
@@ -3879,7 +3981,7 @@
" snapshot.", CURRENT_FUNC);
}
if (snapshot->length() != buffer_len) {
- return Api::NewError("%s: 'buffer_len' of %"Pd" is not equal to %d which"
+ return Api::NewError("%s: 'buffer_len' of %" Pd " is not equal to %d which"
" is the expected length in the snapshot.",
CURRENT_FUNC, buffer_len, snapshot->length());
}
@@ -3981,7 +4083,7 @@
if (cls.NumTypeArguments() == 0) {
if (number_of_type_arguments != 0) {
return Api::NewError("Invalid number of type arguments specified, "
- "got %"Pd" expected 0", number_of_type_arguments);
+ "got %" Pd " expected 0", number_of_type_arguments);
}
return Api::NewHandle(isolate, Type::NewNonParameterizedType(cls));
}
@@ -3993,7 +4095,7 @@
}
if (num_expected_type_arguments != number_of_type_arguments) {
return Api::NewError("Invalid number of type arguments specified, "
- "got %"Pd" expected %"Pd,
+ "got %" Pd " expected %" Pd,
number_of_type_arguments,
num_expected_type_arguments);
}
@@ -4003,7 +4105,7 @@
}
if (array.Length() != num_expected_type_arguments) {
return Api::NewError("Invalid type arguments specified, expected an "
- "array of len %"Pd" but got an array of len %"Pd,
+ "array of len %" Pd " but got an array of len %" Pd,
number_of_type_arguments,
array.Length());
}
diff --git a/runtime/vm/dart_api_impl.h b/runtime/vm/dart_api_impl.h
index dc2f88c..322a265 100644
--- a/runtime/vm/dart_api_impl.h
+++ b/runtime/vm/dart_api_impl.h
@@ -86,7 +86,7 @@
intptr_t max = (max_elements); \
if (len < 0 || len > max) { \
return Api::NewError( \
- "%s expects argument '%s' to be in the range [0..%"Pd"].", \
+ "%s expects argument '%s' to be in the range [0..%" Pd "].", \
CURRENT_FUNC, #length, max); \
} \
} while (0)
@@ -203,7 +203,7 @@
static void SetSmiReturnValue(NativeArguments* args, intptr_t retval) {
args->SetReturnUnsafe(Smi::New(retval));
}
- static void SetIntegerReturnValue(NativeArguments* args, intptr_t retval) {
+ static void SetIntegerReturnValue(NativeArguments* args, int64_t retval) {
args->SetReturnUnsafe(Integer::New(retval));
}
static void SetDoubleReturnValue(NativeArguments* args, double retval) {
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index d73aa85..f92f29c 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -6207,8 +6207,23 @@
Dart_EnterScope();
intptr_t i = Dart_GetNativeArgumentCount(args);
EXPECT_EQ(2, i);
- Dart_Handle arg = Dart_GetNativeArgument(args, 1);
- Dart_SetReturnValue(args, Dart_NewInteger(GetValue(arg)));
+ Dart_Handle arg1 = Dart_GetNativeArgument(args, 1);
+ EXPECT_VALID(arg1);
+ int64_t value = 0;
+ EXPECT_VALID(Dart_IntegerToInt64(arg1, &value));
+ int64_t integer_value = 0;
+ Dart_Handle result = Dart_GetNativeIntegerArgument(args,
+ 1,
+ &integer_value);
+ EXPECT_VALID(result);
+ EXPECT_EQ(value, integer_value);
+ double double_value;
+ result = Dart_GetNativeDoubleArgument(args, 1, &double_value);
+ EXPECT_VALID(result);
+ bool bool_value;
+ result = Dart_GetNativeBooleanArgument(args, 1, &bool_value);
+ EXPECT(Dart_IsError(result));
+ Dart_SetReturnValue(args, Dart_NewInteger(GetValue(arg1)));
Dart_ExitScope();
}
diff --git a/runtime/vm/dart_api_state.h b/runtime/vm/dart_api_state.h
index 5a2cddf..4db8fab 100644
--- a/runtime/vm/dart_api_state.h
+++ b/runtime/vm/dart_api_state.h
@@ -40,7 +40,7 @@
}
#ifdef DEBUG
if (FLAG_trace_zones) {
- OS::PrintErr("*** Starting a new Api zone 0x%"Px"(0x%"Px")\n",
+ OS::PrintErr("*** Starting a new Api zone 0x%" Px "(0x%" Px ")\n",
reinterpret_cast<intptr_t>(this),
reinterpret_cast<intptr_t>(&zone_));
}
@@ -55,7 +55,7 @@
}
#ifdef DEBUG
if (FLAG_trace_zones) {
- OS::PrintErr("*** Deleting Api zone 0x%"Px"(0x%"Px")\n",
+ OS::PrintErr("*** Deleting Api zone 0x%" Px "(0x%" Px ")\n",
reinterpret_cast<intptr_t>(this),
reinterpret_cast<intptr_t>(&zone_));
}
@@ -256,7 +256,7 @@
kOffsetOfRawPtrInLocalHandle>() {
#ifdef DEBUG
if (FLAG_trace_handles) {
- OS::PrintErr("*** Starting a new Local handle block 0x%"Px"\n",
+ OS::PrintErr("*** Starting a new Local handle block 0x%" Px "\n",
reinterpret_cast<intptr_t>(this));
}
#endif
@@ -264,10 +264,10 @@
~LocalHandles() {
#ifdef DEBUG
if (FLAG_trace_handles) {
- OS::PrintErr("*** Handle Counts for 0x(%"Px"):Scoped = %d\n",
+ OS::PrintErr("*** Handle Counts for 0x(%" Px "):Scoped = %d\n",
reinterpret_cast<intptr_t>(this),
CountHandles());
- OS::PrintErr("*** Deleting Local handle block 0x%"Px"\n",
+ OS::PrintErr("*** Deleting Local handle block 0x%" Px "\n",
reinterpret_cast<intptr_t>(this));
}
#endif
@@ -325,7 +325,7 @@
free_list_(NULL) {
#ifdef DEBUG
if (FLAG_trace_handles) {
- OS::PrintErr("*** Starting a new Persistent handle block 0x%"Px"\n",
+ OS::PrintErr("*** Starting a new Persistent handle block 0x%" Px "\n",
reinterpret_cast<intptr_t>(this));
}
#endif
@@ -334,10 +334,10 @@
free_list_ = NULL;
#ifdef DEBUG
if (FLAG_trace_handles) {
- OS::PrintErr("*** Handle Counts for 0x(%"Px"):Scoped = %d\n",
+ OS::PrintErr("*** Handle Counts for 0x(%" Px "):Scoped = %d\n",
reinterpret_cast<intptr_t>(this),
CountHandles());
- OS::PrintErr("*** Deleting Persistent handle block 0x%"Px"\n",
+ OS::PrintErr("*** Deleting Persistent handle block 0x%" Px "\n",
reinterpret_cast<intptr_t>(this));
}
#endif
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index bdecf76..ff19e46 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -295,6 +295,11 @@
}
+bool ActivationFrame::IsDebuggable() const {
+ return Debugger::IsDebuggable(function());
+}
+
+
// Calculate the context level at the current token index of the frame.
intptr_t ActivationFrame::ContextLevel() {
if (context_level_ < 0 && !ctx_.IsNull()) {
@@ -377,8 +382,8 @@
Array& handled_types = Array::Handle();
AbstractType& type = Type::Handle();
const TypeArguments& no_instantiator = TypeArguments::Handle();
- for (int frame_index = 0; frame_index < Length(); frame_index++) {
- ActivationFrame* frame = trace_[frame_index];
+ for (int frame_index = 0; frame_index < UnfilteredLength(); frame_index++) {
+ ActivationFrame* frame = UnfilteredFrameAt(frame_index);
intptr_t try_index = frame->TryIndex();
if (try_index < 0) continue;
handlers = frame->code().exception_handlers();
@@ -580,6 +585,9 @@
void DebuggerStackTrace::AddActivation(ActivationFrame* frame) {
trace_.Add(frame);
+ if (frame->IsDebuggable()) {
+ user_trace_.Add(frame);
+ }
}
@@ -963,7 +971,7 @@
script.GetTokenLocation(activation->TokenPos(), &line, &col);
OS::Print("CollectStackTrace error: no saved context in function "
"'%s' which calls closure '%s' "
- " in line %"Pd" column %"Pd"\n",
+ " in line %" Pd " column %" Pd "\n",
caller.ToFullyQualifiedCString(),
callee.ToFullyQualifiedCString(),
line, col);
@@ -977,10 +985,7 @@
ASSERT(!ctx.IsNull());
activation->SetContext(ctx);
}
- // Check if frame is a debuggable function.
- if (IsDebuggable(activation->function())) {
- stack_trace->AddActivation(activation);
- }
+ stack_trace->AddActivation(activation);
callee_activation = activation;
// Get caller's context if this function saved it on entry.
ctx = activation->GetSavedEntryContext(ctx);
@@ -1191,7 +1196,7 @@
// already exists.
if (FLAG_verbose_debug) {
OS::Print("Pending breakpoint for uncompiled function"
- " '%s' at line %"Pd" already exists\n",
+ " '%s' at line %" Pd " already exists\n",
target_function.ToFullyQualifiedCString(),
source_bpt->LineNumber());
}
@@ -1202,7 +1207,7 @@
RegisterSourceBreakpoint(source_bpt);
if (FLAG_verbose_debug) {
OS::Print("Registering pending breakpoint for "
- "uncompiled function '%s' at line %"Pd"\n",
+ "uncompiled function '%s' at line %" Pd "\n",
target_function.ToFullyQualifiedCString(),
source_bpt->LineNumber());
}
@@ -1286,7 +1291,7 @@
if (first_token_idx < 0) {
// Script does not contain the given line number.
if (FLAG_verbose_debug) {
- OS::Print("Script '%s' does not contain line number %"Pd"\n",
+ OS::Print("Script '%s' does not contain line number %" Pd "\n",
script_url.ToCString(), line_number);
}
return NULL;
@@ -1307,7 +1312,7 @@
}
if (func.IsNull()) {
if (FLAG_verbose_debug) {
- OS::Print("No executable code at line %"Pd" in '%s'\n",
+ OS::Print("No executable code at line %" Pd " in '%s'\n",
line_number, script_url.ToCString());
}
return NULL;
@@ -1588,7 +1593,7 @@
}
if (FLAG_verbose_debug) {
- OS::Print(">>> single step break at %s:%"Pd" (func %s token %"Pd")\n",
+ OS::Print(">>> single step break at %s:%" Pd " (func %s token %" Pd ")\n",
String::Handle(frame->SourceUrl()).ToCString(),
frame->LineNumber(),
String::Handle(frame->QualifiedFunctionName()).ToCString(),
@@ -1603,7 +1608,7 @@
InstrumentForStepping(func);
} else if (resume_action_ == kStepOut) {
if (stack_trace_->Length() > 1) {
- ActivationFrame* caller_frame = stack_trace_->ActivationFrameAt(1);
+ ActivationFrame* caller_frame = stack_trace_->FrameAt(1);
InstrumentForStepping(caller_frame->function());
}
}
@@ -1619,8 +1624,8 @@
return;
}
DebuggerStackTrace* stack_trace = CollectStackTrace();
- ASSERT(stack_trace->Length() > 0);
- ActivationFrame* top_frame = stack_trace->ActivationFrameAt(0);
+ ASSERT(stack_trace->UnfilteredLength() > 0);
+ ActivationFrame* top_frame = stack_trace->UnfilteredFrameAt(0);
ASSERT(top_frame != NULL);
CodeBreakpoint* bpt = GetCodeBreakpoint(top_frame->pc());
ASSERT(bpt != NULL);
@@ -1630,8 +1635,8 @@
report_bp = false;
}
if (FLAG_verbose_debug) {
- OS::Print(">>> %s %s breakpoint at %s:%"Pd" "
- "(token %"Pd") (address %#"Px")\n",
+ OS::Print(">>> %s %s breakpoint at %s:%" Pd " "
+ "(token %" Pd ") (address %#" Px ")\n",
report_bp ? "hit" : "ignore",
bpt->IsInternal() ? "internal" : "user",
String::Handle(bpt->SourceUrl()).ToCString(),
@@ -1657,7 +1662,7 @@
}
} else if (resume_action_ == kStepOut) {
if (stack_trace->Length() > 1) {
- ActivationFrame* caller_frame = stack_trace->ActivationFrameAt(1);
+ ActivationFrame* caller_frame = stack_trace->FrameAt(1);
func_to_instrument = caller_frame->function().raw();
}
} else {
diff --git a/runtime/vm/debugger.h b/runtime/vm/debugger.h
index 90ec050..bf4bc73 100644
--- a/runtime/vm/debugger.h
+++ b/runtime/vm/debugger.h
@@ -144,6 +144,10 @@
intptr_t LineNumber();
void SetContext(const Context& ctx) { ctx_ = ctx.raw(); }
+ // Returns true if this frame is for a function that is visible
+ // to the user and can be debugged.
+ bool IsDebuggable() const;
+
// The context level of a frame is the context level at the
// PC/token index of the frame. It determines the depth of the context
// chain that belongs to the function of this activation frame.
@@ -201,18 +205,27 @@
class DebuggerStackTrace : public ZoneAllocated {
public:
explicit DebuggerStackTrace(int capacity)
- : trace_(capacity) { }
+ : trace_(capacity),
+ user_trace_(capacity) { }
- intptr_t Length() const { return trace_.length(); }
+ intptr_t Length() const { return user_trace_.length(); }
- ActivationFrame* ActivationFrameAt(int i) const {
- ASSERT(i < trace_.length());
+ ActivationFrame* FrameAt(int i) const {
+ return user_trace_[i];
+ }
+
+ ActivationFrame* GetHandlerFrame(const Instance& exc_obj) const;
+
+ private:
+ intptr_t UnfilteredLength() const { return trace_.length(); }
+
+ ActivationFrame* UnfilteredFrameAt(int i) const {
return trace_[i];
}
- ActivationFrame* GetHandlerFrame(const Instance& exc_obj) const;
- private:
+
void AddActivation(ActivationFrame* frame);
ZoneGrowableArray<ActivationFrame*> trace_;
+ ZoneGrowableArray<ActivationFrame*> user_trace_;
friend class Debugger;
DISALLOW_COPY_AND_ASSIGN(DebuggerStackTrace);
@@ -315,6 +328,8 @@
uword GetPatchedStubAddress(uword breakpoint_address);
+ static bool IsDebuggable(const Function& func);
+
private:
enum ResumeAction {
kContinue,
@@ -350,8 +365,6 @@
void SignalBpResolved(SourceBreakpoint *bpt);
void SignalPausedEvent(ActivationFrame* top_frame);
- static bool IsDebuggable(const Function& func);
-
intptr_t nextId() { return next_id_++; }
bool ShouldPauseOnException(DebuggerStackTrace* stack_trace,
diff --git a/runtime/vm/debugger_api_impl.cc b/runtime/vm/debugger_api_impl.cc
index 32e8a3a..0df495b 100644
--- a/runtime/vm/debugger_api_impl.cc
+++ b/runtime/vm/debugger_api_impl.cc
@@ -5,6 +5,7 @@
#include "include/dart_debugger_api.h"
#include "vm/class_finalizer.h"
+#include "vm/compiler.h"
#include "vm/dart_api_impl.h"
#include "vm/dart_api_state.h"
#include "vm/debugger.h"
@@ -64,7 +65,7 @@
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
if (!isolate->debugger()->IsValidObjectId(obj_id)) {
- return Api::NewError("%s: object id %"Pd" is invalid",
+ return Api::NewError("%s: object id %" Pd " is invalid",
CURRENT_FUNC, obj_id);
}
return Api::NewHandle(isolate, isolate->debugger()->GetCachedObject(obj_id));
@@ -96,7 +97,7 @@
CURRENT_FUNC);
}
*frame = reinterpret_cast<Dart_ActivationFrame>(
- stack_trace->ActivationFrameAt(frame_index));
+ stack_trace->FrameAt(frame_index));
return Api::Success();
}
@@ -289,12 +290,18 @@
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
UNWRAP_AND_CHECK_PARAM(String, script_url, script_url_in);
+
+ Dart_Handle state = Api::CheckIsolateState(isolate);
+ if (::Dart_IsError(state)) {
+ return state;
+ }
+
Debugger* debugger = isolate->debugger();
ASSERT(debugger != NULL);
SourceBreakpoint* bpt =
debugger->SetBreakpointAtLine(script_url, line_number);
if (bpt == NULL) {
- return Api::NewError("%s: could not set breakpoint at line %"Pd" in '%s'",
+ return Api::NewError("%s: could not set breakpoint at line %" Pd " in '%s'",
CURRENT_FUNC, line_number, script_url.ToCString());
}
return Dart_NewInteger(bpt->id());
@@ -309,7 +316,7 @@
SourceBreakpoint* bpt = debugger->GetBreakpointById(bp_id);
if (bpt == NULL) {
- return Api::NewError("%s: breakpoint with id %"Pd" does not exist",
+ return Api::NewError("%s: breakpoint with id %" Pd " does not exist",
CURRENT_FUNC, bp_id);
}
return Api::NewHandle(isolate, bpt->SourceUrl());
@@ -324,7 +331,7 @@
SourceBreakpoint* bpt = debugger->GetBreakpointById(bp_id);
if (bpt == NULL) {
- return Api::NewError("%s: breakpoint with id %"Pd" does not exist",
+ return Api::NewError("%s: breakpoint with id %" Pd " does not exist",
CURRENT_FUNC, bp_id);
}
return Dart_NewInteger(bpt->LineNumber());
@@ -471,7 +478,7 @@
const Library& lib =
Library::Handle(isolate, Library::GetLibrary(library_id));
if (lib.IsNull()) {
- return Api::NewError("%s: %"Pd" is not a valid library id",
+ return Api::NewError("%s: %" Pd " is not a valid library id",
CURRENT_FUNC, library_id);
}
return Api::NewHandle(isolate, isolate->debugger()->GetLibraryFields(lib));
@@ -484,13 +491,23 @@
DARTSCOPE(isolate);
const Library& lib = Library::Handle(Library::GetLibrary(library_id));
if (lib.IsNull()) {
- return Api::NewError("%s: %"Pd" is not a valid library id",
+ return Api::NewError("%s: %" Pd " is not a valid library id",
CURRENT_FUNC, library_id);
}
return Api::NewHandle(isolate, isolate->debugger()->GetGlobalFields(lib));
}
+DART_EXPORT Dart_Handle Dart_EvaluateExpr(Dart_Handle target,
+ Dart_Handle expr_in) {
+ Isolate* isolate = Isolate::Current();
+ DARTSCOPE(isolate);
+ UNWRAP_AND_CHECK_PARAM(Instance, obj, target);
+ UNWRAP_AND_CHECK_PARAM(String, expr, expr_in);
+ return Api::NewHandle(isolate, obj.Evaluate(expr));
+}
+
+
DART_EXPORT Dart_Handle Dart_GetObjClass(Dart_Handle object_in) {
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
@@ -574,7 +591,7 @@
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
if (!isolate->class_table()->IsValidIndex(cls_id)) {
- return Api::NewError("%s: %"Pd" is not a valid class id",
+ return Api::NewError("%s: %" Pd " is not a valid class id",
CURRENT_FUNC, cls_id);
}
Class& cls = Class::Handle(isolate, isolate->class_table()->At(cls_id));
@@ -607,7 +624,7 @@
DARTSCOPE(isolate);
const Library& lib = Library::Handle(Library::GetLibrary(library_id));
if (lib.IsNull()) {
- return Api::NewError("%s: %"Pd" is not a valid library id",
+ return Api::NewError("%s: %" Pd " is not a valid library id",
CURRENT_FUNC, library_id);
}
UNWRAP_AND_CHECK_PARAM(String, script_url, script_url_in);
@@ -628,7 +645,7 @@
DARTSCOPE(isolate);
const Library& lib = Library::Handle(Library::GetLibrary(library_id));
if (lib.IsNull()) {
- return Api::NewError("%s: %"Pd" is not a valid library id",
+ return Api::NewError("%s: %" Pd " is not a valid library id",
CURRENT_FUNC, library_id);
}
UNWRAP_AND_CHECK_PARAM(String, script_url, script_url_in);
@@ -749,7 +766,7 @@
DARTSCOPE(isolate);
const Library& lib = Library::Handle(Library::GetLibrary(library_id));
if (lib.IsNull()) {
- return Api::NewError("%s: %"Pd" is not a valid library id",
+ return Api::NewError("%s: %" Pd " is not a valid library id",
CURRENT_FUNC, library_id);
}
const GrowableObjectArray& import_list =
@@ -788,7 +805,7 @@
DARTSCOPE(isolate);
const Library& lib = Library::Handle(Library::GetLibrary(library_id));
if (lib.IsNull()) {
- return Api::NewError("%s: %"Pd" is not a valid library id",
+ return Api::NewError("%s: %" Pd " is not a valid library id",
CURRENT_FUNC, library_id);
}
return Api::NewHandle(isolate, lib.url());
@@ -803,7 +820,7 @@
CHECK_NOT_NULL(is_debuggable);
const Library& lib = Library::Handle(Library::GetLibrary(library_id));
if (lib.IsNull()) {
- return Api::NewError("%s: %"Pd" is not a valid library id",
+ return Api::NewError("%s: %" Pd " is not a valid library id",
CURRENT_FUNC, library_id);
}
*is_debuggable = lib.IsDebuggable();
@@ -818,7 +835,7 @@
DARTSCOPE(isolate);
const Library& lib = Library::Handle(Library::GetLibrary(library_id));
if (lib.IsNull()) {
- return Api::NewError("%s: %"Pd" is not a valid library id",
+ return Api::NewError("%s: %" Pd " is not a valid library id",
CURRENT_FUNC, library_id);
}
lib.set_debuggable(is_debuggable);
diff --git a/runtime/vm/debugger_api_impl_test.cc b/runtime/vm/debugger_api_impl_test.cc
index 070cf3f..2cec246 100644
--- a/runtime/vm/debugger_api_impl_test.cc
+++ b/runtime/vm/debugger_api_impl_test.cc
@@ -49,6 +49,24 @@
}
+static int64_t ToInt64(Dart_Handle h) {
+ EXPECT(Dart_IsInteger(h));
+ int64_t i = 0;
+ Dart_Handle res = Dart_IntegerToInt64(h, &i);
+ EXPECT_VALID(res);
+ return i;
+}
+
+
+static double ToDouble(Dart_Handle h) {
+ EXPECT(Dart_IsDouble(h));
+ double d = 0.0;
+ Dart_Handle res = Dart_DoubleValue(h, &d);
+ EXPECT_VALID(res);
+ return d;
+}
+
+
static char const* BreakpointInfo(Dart_StackTrace trace) {
static char info_str[128];
Dart_ActivationFrame frame;
@@ -61,7 +79,7 @@
res = Dart_ActivationFrameInfo(
frame, &func_name, &url, &line_number, &library_id);
EXPECT_TRUE(res);
- OS::SNPrint(info_str, sizeof(info_str), "function %s (%s:%"Pd")",
+ OS::SNPrint(info_str, sizeof(info_str), "function %s (%s:%" Pd ")",
ToCString(func_name), ToCString(url), line_number);
return info_str;
}
@@ -151,6 +169,28 @@
}
+static Dart_Handle GetLocalVariable(Dart_ActivationFrame frame,
+ const char* name) {
+ Dart_Handle locals = Dart_GetLocalVariables(frame);
+ EXPECT_VALID(locals);
+ intptr_t list_length = 0;
+ Dart_Handle ret = Dart_ListLength(locals, &list_length);
+ EXPECT_VALID(ret);
+ for (int i = 0; i + 1 < list_length; i += 2) {
+ Dart_Handle name_handle = Dart_ListGetAt(locals, i);
+ EXPECT_VALID(name_handle);
+ EXPECT(Dart_IsString(name_handle));
+ if (strcmp(ToCString(name_handle), name) == 0) {
+ Dart_Handle value_handle = Dart_ListGetAt(locals, i + 1);
+ EXPECT_VALID(value_handle);
+ return value_handle;
+ }
+ }
+ EXPECT(!"local variable not found");
+ return Dart_Null();
+}
+
+
static void PrintStackTrace(Dart_StackTrace trace) {
intptr_t trace_len;
Dart_Handle res = Dart_StackTraceLength(trace, &trace_len);
@@ -344,8 +384,7 @@
Dart_Handle retval = Invoke("main");
EXPECT_VALID(retval);
EXPECT(Dart_IsInteger(retval));
- int64_t int_value = 0;
- Dart_IntegerToInt64(retval, &int_value);
+ int64_t int_value = ToInt64(retval);
EXPECT_EQ(2, int_value);
EXPECT(breakpoint_hit == true);
}
@@ -426,8 +465,7 @@
Dart_Handle retval = Invoke("main");
EXPECT_VALID(retval);
EXPECT(Dart_IsInteger(retval));
- int64_t int_value = 0;
- Dart_IntegerToInt64(retval, &int_value);
+ int64_t int_value = ToInt64(retval);
EXPECT_EQ(7, int_value);
EXPECT(breakpoint_hit == true);
}
@@ -472,8 +510,7 @@
Dart_Handle retval = Invoke("main");
EXPECT_VALID(retval);
EXPECT(Dart_IsInteger(retval));
- int64_t int_value = 0;
- Dart_IntegerToInt64(retval, &int_value);
+ int64_t int_value = ToInt64(retval);
EXPECT_EQ(101, int_value);
EXPECT(breakpoint_hit == true);
}
@@ -510,8 +547,7 @@
Dart_Handle retval = Invoke("main");
EXPECT_VALID(retval);
EXPECT(Dart_IsInteger(retval));
- int64_t int_value = 0;
- Dart_IntegerToInt64(retval, &int_value);
+ int64_t int_value = ToInt64(retval);
EXPECT_EQ(2 * 99, int_value);
EXPECT(breakpoint_hit == true);
}
@@ -624,8 +660,7 @@
breakpoint_hit_counter = 0;
Dart_Handle retval = Invoke("main");
EXPECT_VALID(retval);
- int64_t int_value = 0;
- Dart_IntegerToInt64(retval, &int_value);
+ int64_t int_value = ToInt64(retval);
EXPECT_EQ(442, int_value);
EXPECT_EQ(2, breakpoint_hit_counter);
}
@@ -671,8 +706,7 @@
breakpoint_hit_counter = 0;
Dart_Handle retval = Invoke("main");
EXPECT_VALID(retval);
- int64_t int_value = 0;
- Dart_IntegerToInt64(retval, &int_value);
+ int64_t int_value = ToInt64(retval);
EXPECT_EQ(30, int_value);
EXPECT_EQ(1, breakpoint_hit_counter);
}
@@ -737,8 +771,7 @@
Dart_Handle res = Dart_SetBreakpoint(script_url, line_no);
EXPECT_VALID(res);
EXPECT(Dart_IsInteger(res));
- int64_t bp_id = 0;
- Dart_IntegerToInt64(res, &bp_id);
+ int64_t bp_id = ToInt64(res);
// Function main() calls foo() 3 times. On the second iteration, the
// breakpoint is removed by the handler, so we expect the breakpoint
@@ -888,8 +921,7 @@
Dart_Handle triple_six = Invoke("get_int");
EXPECT_VALID(triple_six);
EXPECT(Dart_IsInteger(triple_six));
- int64_t int_value = 0;
- Dart_IntegerToInt64(triple_six, &int_value);
+ int64_t int_value = ToInt64(triple_six);
EXPECT_EQ(666, int_value);
fields = Dart_GetInstanceFields(triple_six);
EXPECT_VALID(fields);
@@ -1281,8 +1313,7 @@
breakpoint_hit_counter = 0;
Dart_Handle retval = Invoke("main");
EXPECT_VALID(retval);
- int64_t int_value = 0;
- Dart_IntegerToInt64(retval, &int_value);
+ int64_t int_value = ToInt64(retval);
EXPECT_EQ(195, int_value);
EXPECT_EQ(1, breakpoint_hit_counter);
}
@@ -1448,6 +1479,89 @@
}
+void TestEvaluateHandler(Dart_IsolateId isolate_id,
+ const Dart_CodeLocation& location) {
+ Dart_StackTrace trace;
+ Dart_GetStackTrace(&trace);
+ intptr_t trace_len;
+ Dart_Handle res = Dart_StackTraceLength(trace, &trace_len);
+ EXPECT_VALID(res);
+ EXPECT_EQ(1, trace_len);
+ Dart_ActivationFrame frame;
+ res = Dart_GetActivationFrame(trace, 0, &frame);
+ EXPECT_VALID(res);
+
+ // Get the local variable p and evaluate an expression in the
+ // context of p.
+ Dart_Handle p = GetLocalVariable(frame, "p");
+ EXPECT_VALID(p);
+ EXPECT(!Dart_IsNull(p));
+
+ Dart_Handle r = Dart_EvaluateExpr(p, NewString("sqrt(x*x + y*this.y)"));
+ EXPECT_VALID(r);
+ EXPECT(Dart_IsNumber(r));
+ EXPECT_EQ(5.0, ToDouble(r));
+
+ // Set top-level variable to a new value.
+ Dart_Handle h = Dart_EvaluateExpr(p, NewString("_factor = 10"));
+ EXPECT_VALID(h);
+ EXPECT(Dart_IsInteger(h));
+ EXPECT_EQ(10, ToInt64(h));
+
+ // Check that the side effect of the previous expression is
+ // persistent.
+ h = Dart_EvaluateExpr(p, NewString("_factor"));
+ EXPECT_VALID(h);
+ EXPECT(Dart_IsInteger(h));
+ EXPECT_EQ(10, ToInt64(h));
+
+ breakpoint_hit = true;
+ breakpoint_hit_counter++;
+}
+
+
+TEST_CASE(Debug_EvaluateExpr) {
+ const char* kScriptChars =
+ "import 'dart:math'; \n"
+ "main() { \n"
+ " var p = new Point(3, 4); \n"
+ " l = [1, 2, 3]; /*BP*/ \n"
+ " return p; \n"
+ "} \n"
+ "var _factor = 2; \n"
+ "var l; \n"
+ "class Point { \n"
+ " var x, y; \n"
+ " Point(this.x, this.y); \n"
+ "} \n";
+
+ LoadScript(kScriptChars);
+ Dart_SetPausedEventHandler(&TestEvaluateHandler);
+
+
+ Dart_Handle script_url = NewString(TestCase::url());
+ intptr_t line_no = 4;
+ Dart_Handle res = Dart_SetBreakpoint(script_url, line_no);
+ EXPECT_VALID(res);
+
+ breakpoint_hit = false;
+ Dart_Handle point = Invoke("main");
+ EXPECT_VALID(point);
+ EXPECT(breakpoint_hit == true);
+
+ Dart_Handle r =
+ Dart_EvaluateExpr(point, NewString("_factor * sqrt(x*x + y*y)"));
+ EXPECT_VALID(r);
+ EXPECT(Dart_IsDouble(r));
+ EXPECT_EQ(50.0, ToDouble(r));
+
+ Dart_Handle len = Dart_EvaluateExpr(point, NewString("l.length"));
+ EXPECT_VALID(len);
+ EXPECT(Dart_IsNumber(len));
+ EXPECT_EQ(3, ToInt64(len));
+}
+
+
TEST_CASE(Debug_GetSupertype) {
const char* kScriptChars =
"class Test {\n"
diff --git a/runtime/vm/deopt_instructions.cc b/runtime/vm/deopt_instructions.cc
index 834cfd0..f374053 100644
--- a/runtime/vm/deopt_instructions.cc
+++ b/runtime/vm/deopt_instructions.cc
@@ -87,7 +87,7 @@
virtual const char* ToCString() const {
return Isolate::Current()->current_zone()->PrintToString(
- "s%"Pd"", stack_slot_index_);
+ "s%" Pd "", stack_slot_index_);
}
void Execute(DeoptimizationContext* deopt_context, intptr_t* to_addr) {
@@ -116,7 +116,7 @@
virtual const char* ToCString() const {
return Isolate::Current()->current_zone()->PrintToString(
- "ds%"Pd"", stack_slot_index_);
+ "ds%" Pd "", stack_slot_index_);
}
void Execute(DeoptimizationContext* deopt_context, intptr_t* to_addr) {
@@ -148,7 +148,7 @@
virtual const char* ToCString() const {
return Isolate::Current()->current_zone()->PrintToString(
- "ms%"Pd"", stack_slot_index_);
+ "ms%" Pd "", stack_slot_index_);
}
void Execute(DeoptimizationContext* deopt_context, intptr_t* to_addr) {
@@ -185,7 +185,7 @@
virtual const char* ToCString() const {
return Isolate::Current()->current_zone()->PrintToString(
- "f32x4s%"Pd"", stack_slot_index_);
+ "f32x4s%" Pd "", stack_slot_index_);
}
void Execute(DeoptimizationContext* deopt_context, intptr_t* to_addr) {
@@ -217,7 +217,7 @@
virtual const char* ToCString() const {
return Isolate::Current()->current_zone()->PrintToString(
- "ui32x4s%"Pd"", stack_slot_index_);
+ "ui32x4s%" Pd "", stack_slot_index_);
}
void Execute(DeoptimizationContext* deopt_context, intptr_t* to_addr) {
@@ -261,7 +261,7 @@
virtual const char* ToCString() const {
return Isolate::Current()->current_zone()->PrintToString(
- "ret oti:%"Pd"(%"Pd")", object_table_index_, deopt_id_);
+ "ret oti:%" Pd "(%" Pd ")", object_table_index_, deopt_id_);
}
void Execute(DeoptimizationContext* deopt_context, intptr_t* to_addr) {
@@ -315,7 +315,7 @@
virtual const char* ToCString() const {
return Isolate::Current()->current_zone()->PrintToString(
- "const oti:%"Pd"", object_table_index_);
+ "const oti:%" Pd "", object_table_index_);
}
void Execute(DeoptimizationContext* deopt_context, intptr_t* to_addr) {
@@ -484,7 +484,7 @@
virtual const char* ToCString() const {
return Isolate::Current()->current_zone()->PrintToString(
- "pcmark oti:%"Pd"", object_table_index_);
+ "pcmark oti:%" Pd "", object_table_index_);
}
void Execute(DeoptimizationContext* deopt_context, intptr_t* to_addr) {
@@ -536,7 +536,7 @@
virtual const char* ToCString() const {
return Isolate::Current()->current_zone()->PrintToString(
- "pp oti:%"Pd"", object_table_index_);
+ "pp oti:%" Pd "", object_table_index_);
}
void Execute(DeoptimizationContext* deopt_context, intptr_t* to_addr) {
@@ -647,7 +647,7 @@
virtual const char* ToCString() const {
return Isolate::Current()->current_zone()->PrintToString(
- "suffix %"Pd":%"Pd, info_number_, suffix_length_);
+ "suffix %" Pd ":%" Pd, info_number_, suffix_length_);
}
void Execute(DeoptimizationContext* deopt_context, intptr_t* to_addr) {
@@ -686,7 +686,7 @@
virtual const char* ToCString() const {
return Isolate::Current()->current_zone()->PrintToString(
- "mat ref #%"Pd"", index_);
+ "mat ref #%" Pd "", index_);
}
void Execute(DeoptimizationContext* deopt_context, intptr_t* to_addr) {
@@ -717,7 +717,7 @@
virtual const char* ToCString() const {
return Isolate::Current()->current_zone()->PrintToString(
- "mat obj len:%"Pd"", field_count_);
+ "mat obj len:%" Pd "", field_count_);
}
void Execute(DeoptimizationContext* deopt_context, intptr_t* to_addr) {
diff --git a/runtime/vm/disassembler_arm.cc b/runtime/vm/disassembler_arm.cc
index 6acd20f..491d185 100644
--- a/runtime/vm/disassembler_arm.cc
+++ b/runtime/vm/disassembler_arm.cc
@@ -428,7 +428,7 @@
uword destination = reinterpret_cast<uword>(instr) + off;
buffer_pos_ += OS::SNPrint(current_position_in_buffer(),
remaining_size_in_buffer(),
- "%#"Px"",
+ "%#" Px "",
destination);
return 4;
} else {
diff --git a/runtime/vm/disassembler_ia32.cc b/runtime/vm/disassembler_ia32.cc
index 5f1131e..9272794 100644
--- a/runtime/vm/disassembler_ia32.cc
+++ b/runtime/vm/disassembler_ia32.cc
@@ -467,7 +467,7 @@
void X86Decoder::PrintAddress(uword addr) {
NoGCScope no_gc;
char addr_buffer[32];
- OS::SNPrint(addr_buffer, sizeof(addr_buffer), "%#"Px"", addr);
+ OS::SNPrint(addr_buffer, sizeof(addr_buffer), "%#" Px "", addr);
Print(addr_buffer);
// Try to print as heap object or stub name
if (((addr & kSmiTagMask) == kHeapObjectTag) &&
@@ -1392,7 +1392,7 @@
Print(",");
data += PrintRightXmmOperand(data);
} else if (f0byte == 0x50) {
- Print("movmskpd ");
+ Print("movmskps ");
int mod, regop, rm;
GetModRm(*data, &mod, ®op, &rm);
PrintCPURegister(regop);
@@ -1505,16 +1505,7 @@
PrintCPURegister(regop);
} else if (*data == 0x0F) {
data++;
- if (*data == 0x2F) {
- data++;
- int mod, regop, rm;
- GetModRm(*data, &mod, ®op, &rm);
- Print("comisd ");
- PrintXmmRegister(regop);
- Print(",");
- PrintXmmRegister(rm);
- data++;
- } else if (*data == 0X6E) {
+ if (*data == 0X6E) {
data++;
int mod, regop, rm;
GetModRm(*data, &mod, ®op, &rm);
@@ -1609,8 +1600,20 @@
Print(",");
PrintXmmRegister(rm);
data += 2;
+ } else if ((*data == 0xFE) || (*data == 0xFA) || (*data == 0x2F)) {
+ const char* mnemonic = NULL;
+ if (*data == 0xFE) mnemonic = "paddd ";
+ if (*data == 0xFA) mnemonic = "psubd ";
+ if (*data == 0x2F) mnemonic = "comisd ";
+ int mod, regop, rm;
+ GetModRm(*(data+1), &mod, ®op, &rm);
+ Print(mnemonic);
+ PrintXmmRegister(regop);
+ Print(",");
+ PrintXmmRegister(rm);
+ data += 2;
} else {
- UNIMPLEMENTED();
+ UNIMPLEMENTED();
}
} else if (*data == 0x90) {
data++;
diff --git a/runtime/vm/disassembler_mips.cc b/runtime/vm/disassembler_mips.cc
index 8c5dbd4..b47aaf2 100644
--- a/runtime/vm/disassembler_mips.cc
+++ b/runtime/vm/disassembler_mips.cc
@@ -215,7 +215,7 @@
reinterpret_cast<uword>(instr) + off + Instr::kInstrSize;
buffer_pos_ += OS::SNPrint(current_position_in_buffer(),
remaining_size_in_buffer(),
- "%#"Px"",
+ "%#" Px "",
destination);
return 4;
}
diff --git a/runtime/vm/disassembler_x64.cc b/runtime/vm/disassembler_x64.cc
index f42ebac..7aefeb5 100644
--- a/runtime/vm/disassembler_x64.cc
+++ b/runtime/vm/disassembler_x64.cc
@@ -566,7 +566,7 @@
value = 0; // Initialize variables on all paths to satisfy the compiler.
count = 0;
}
- AppendToBuffer("%#"Px64"", value);
+ AppendToBuffer("%#" Px64 "", value);
return count;
}
@@ -804,7 +804,7 @@
void DisassemblerX64::AppendAddressToBuffer(uint8_t* addr_byte_ptr) {
NoGCScope no_gc;
uword addr = reinterpret_cast<uword>(addr_byte_ptr);
- AppendToBuffer("%#"Px"", addr);
+ AppendToBuffer("%#" Px "", addr);
// Try to print as heap object or stub name
if (((addr & kSmiTagMask) == kHeapObjectTag) &&
!Isolate::Current()->heap()->CodeContains(addr) &&
@@ -1282,6 +1282,10 @@
mnemonic = "ucomisd";
} else if (opcode == 0x2F) {
mnemonic = "comisd";
+ } else if (opcode == 0xFE) {
+ mnemonic = "paddd";
+ } else if (opcode == 0xFA) {
+ mnemonic = "psubd";
} else {
UnimplementedInstruction();
}
@@ -1418,6 +1422,11 @@
get_modrm(*current, &mod, ®op, &rm);
AppendToBuffer("movups %s, ", NameOfXMMRegister(regop));
current += PrintRightXMMOperand(current);
+ } else if (opcode == 0x50) {
+ int mod, regop, rm;
+ get_modrm(*current, &mod, ®op, &rm);
+ AppendToBuffer("movmskps %s,", NameOfCPURegister(regop));
+ current += PrintRightXMMOperand(current);
} else if (opcode == 0xA2 || opcode == 0x31) {
// RDTSC or CPUID
AppendToBuffer("%s", mnemonic);
@@ -1823,7 +1832,7 @@
default:
UNREACHABLE();
}
- AppendToBuffer("test%c rax,%#"Px64"",
+ AppendToBuffer("test%c rax,%#" Px64 "",
operand_size_code(),
value);
break;
diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc
index 8ff2c10..6259451 100644
--- a/runtime/vm/exceptions.cc
+++ b/runtime/vm/exceptions.cc
@@ -539,7 +539,7 @@
}
intptr_t line, column;
script.GetTokenLocation(location, &line, &column);
- OS::Print("'%s': Failed type check: line %"Pd" pos %"Pd": ",
+ OS::Print("'%s': Failed type check: line %" Pd " pos %" Pd ": ",
String::Handle(script.url()).ToCString(), line, column);
if (!dst_name.IsNull() && (dst_name.Length() > 0)) {
OS::Print("type '%s' is not a subtype of type '%s' of '%s'.\n",
diff --git a/runtime/vm/flow_graph.cc b/runtime/vm/flow_graph.cc
index 0d80ae7..7cabc29 100644
--- a/runtime/vm/flow_graph.cc
+++ b/runtime/vm/flow_graph.cc
@@ -289,7 +289,7 @@
static void PrintBitVector(const char* tag, BitVector* v) {
OS::Print("%s:", tag);
for (BitVector::Iterator it(v); !it.Done(); it.Advance()) {
- OS::Print(" %"Pd"", it.Current());
+ OS::Print(" %" Pd "", it.Current());
}
OS::Print("\n");
}
@@ -299,12 +299,12 @@
const intptr_t block_count = postorder_.length();
for (intptr_t i = 0; i < block_count; i++) {
BlockEntryInstr* block = postorder_[i];
- OS::Print("block @%"Pd" -> ", block->block_id());
+ OS::Print("block @%" Pd " -> ", block->block_id());
Instruction* last = block->last_instruction();
for (intptr_t j = 0; j < last->SuccessorCount(); j++) {
BlockEntryInstr* succ = last->SuccessorAt(j);
- OS::Print(" @%"Pd"", succ->block_id());
+ OS::Print(" @%" Pd "", succ->block_id());
}
OS::Print("\n");
@@ -984,7 +984,7 @@
n->set_loop_info(loop);
if (FLAG_trace_optimization) {
for (BitVector::Iterator it(loop); !it.Done(); it.Advance()) {
- OS::Print(" B%"Pd"\n", preorder_[it.Current()]->block_id());
+ OS::Print(" B%" Pd "\n", preorder_[it.Current()]->block_id());
}
}
}
@@ -1002,7 +1002,7 @@
BlockEntryInstr* pred = block->PredecessorAt(i);
if (block->Dominates(pred)) {
if (FLAG_trace_optimization) {
- OS::Print("Back edge B%"Pd" -> B%"Pd"\n", pred->block_id(),
+ OS::Print("Back edge B%" Pd " -> B%" Pd "\n", pred->block_id(),
block->block_id());
}
FindLoop(pred, block);
diff --git a/runtime/vm/flow_graph_allocator.cc b/runtime/vm/flow_graph_allocator.cc
index 5548c43..ab2d296 100644
--- a/runtime/vm/flow_graph_allocator.cc
+++ b/runtime/vm/flow_graph_allocator.cc
@@ -369,7 +369,8 @@
return;
}
- OS::Print(" live range v%"Pd" [%"Pd", %"Pd") in ", vreg(), Start(), End());
+ OS::Print(" live range v%" Pd " [%" Pd ", %" Pd ") in ",
+ vreg(), Start(), End());
assigned_location().Print();
OS::Print("\n");
@@ -377,11 +378,11 @@
for (UseInterval* interval = first_use_interval_;
interval != NULL;
interval = interval->next()) {
- OS::Print(" use interval [%"Pd", %"Pd")\n",
+ OS::Print(" use interval [%" Pd ", %" Pd ")\n",
interval->start(),
interval->end());
while ((use_pos != NULL) && (use_pos->pos() <= interval->end())) {
- OS::Print(" use at %"Pd"", use_pos->pos());
+ OS::Print(" use at %" Pd "", use_pos->pos());
if (use_pos->location_slot() != NULL) {
OS::Print(" as ");
use_pos->location_slot()->Print();
@@ -1482,7 +1483,7 @@
first_safepoint_after_split,
next_sibling_);
- TRACE_ALLOC(OS::Print(" split sibling [%"Pd", %"Pd")\n",
+ TRACE_ALLOC(OS::Print(" split sibling [%" Pd ", %" Pd ")\n",
next_sibling_->Start(), next_sibling_->End()));
last_use_interval_ = last_before_split;
@@ -1499,7 +1500,8 @@
LiveRange* FlowGraphAllocator::SplitBetween(LiveRange* range,
intptr_t from,
intptr_t to) {
- TRACE_ALLOC(OS::Print("split v%"Pd" [%"Pd", %"Pd") between [%"Pd", %"Pd")\n",
+ TRACE_ALLOC(OS::Print("split v%" Pd " [%" Pd ", %" Pd
+ ") between [%" Pd ", %" Pd ")\n",
range->vreg(), range->Start(), range->End(), from, to));
intptr_t split_pos = kIllegalPosition;
@@ -1537,8 +1539,8 @@
intptr_t from,
intptr_t to) {
ASSERT(from < to);
- TRACE_ALLOC(OS::Print("spill v%"Pd" [%"Pd", %"Pd") "
- "between [%"Pd", %"Pd")\n",
+ TRACE_ALLOC(OS::Print("spill v%" Pd " [%" Pd ", %" Pd ") "
+ "between [%" Pd ", %" Pd ")\n",
range->vreg(), range->Start(), range->End(), from, to));
LiveRange* tail = range->SplitAt(from);
@@ -1555,7 +1557,7 @@
void FlowGraphAllocator::SpillAfter(LiveRange* range, intptr_t from) {
- TRACE_ALLOC(OS::Print("spill v%"Pd" [%"Pd", %"Pd") after %"Pd"\n",
+ TRACE_ALLOC(OS::Print("spill v%" Pd " [%" Pd ", %" Pd ") after %" Pd "\n",
range->vreg(), range->Start(), range->End(), from));
// When spilling the value inside the loop check if this spill can
@@ -1569,7 +1571,7 @@
RangeHasOnlyUnconstrainedUsesInLoop(range, loop_header->loop_id())) {
ASSERT(loop_header->entry()->start_pos() <= from);
from = loop_header->entry()->start_pos();
- TRACE_ALLOC(OS::Print(" moved spill position to loop header %"Pd"\n",
+ TRACE_ALLOC(OS::Print(" moved spill position to loop header %" Pd "\n",
from));
}
}
@@ -1791,7 +1793,7 @@
candidate = hint.register_code();
}
- TRACE_ALLOC(OS::Print("found hint %s for v%"Pd": free until %"Pd"\n",
+ TRACE_ALLOC(OS::Print("found hint %s for v%" Pd ": free until %" Pd "\n",
hint.Name(),
unallocated->vreg(),
free_until));
@@ -1853,8 +1855,8 @@
if (used_on_backedge[candidate]) {
TRACE_ALLOC(OS::Print(
- "considering %s for v%"Pd": has interference on the back edge"
- " {loop [%"Pd", %"Pd")}\n",
+ "considering %s for v%" Pd ": has interference on the back edge"
+ " {loop [%" Pd ", %" Pd ")}\n",
MakeRegisterLocation(candidate).Name(),
unallocated->vreg(),
loop_header->entry()->start_pos(),
@@ -1872,7 +1874,7 @@
candidate = reg;
free_until = intersection;
TRACE_ALLOC(OS::Print(
- "found %s for v%"Pd" with no interference on the back edge\n",
+ "found %s for v%" Pd " with no interference on the back edge\n",
MakeRegisterLocation(candidate).Name(),
candidate));
break;
@@ -1883,11 +1885,11 @@
TRACE_ALLOC(OS::Print("assigning free register "));
TRACE_ALLOC(MakeRegisterLocation(candidate).Print());
- TRACE_ALLOC(OS::Print(" to v%"Pd"\n", unallocated->vreg()));
+ TRACE_ALLOC(OS::Print(" to v%" Pd "\n", unallocated->vreg()));
if (free_until != kMaxPosition) {
// There was an intersection. Split unallocated.
- TRACE_ALLOC(OS::Print(" splitting at %"Pd"\n", free_until));
+ TRACE_ALLOC(OS::Print(" splitting at %" Pd "\n", free_until));
LiveRange* tail = unallocated->SplitAt(free_until);
AddToUnallocated(tail);
}
@@ -1985,7 +1987,7 @@
TRACE_ALLOC(OS::Print("assigning blocked register "));
TRACE_ALLOC(MakeRegisterLocation(candidate).Print());
- TRACE_ALLOC(OS::Print(" to live range v%"Pd" until %"Pd"\n",
+ TRACE_ALLOC(OS::Print(" to live range v%" Pd " until %" Pd "\n",
unallocated->vreg(), blocked_at));
if (blocked_at < unallocated->End()) {
@@ -2142,7 +2144,7 @@
ASSERT(use->location_slot() != NULL);
Location* slot = use->location_slot();
ASSERT(slot->IsUnallocated());
- TRACE_ALLOC(OS::Print(" use at %"Pd" converted to ", use->pos()));
+ TRACE_ALLOC(OS::Print(" use at %" Pd " converted to ", use->pos()));
TRACE_ALLOC(loc.Print());
TRACE_ALLOC(OS::Print("\n"));
*slot = loc;
@@ -2155,8 +2157,8 @@
const Location loc = range->assigned_location();
ASSERT(!loc.IsInvalid());
- TRACE_ALLOC(OS::Print("range [%"Pd", %"Pd") "
- "for v%"Pd" has been allocated to ",
+ TRACE_ALLOC(OS::Print("range [%" Pd ", %" Pd ") "
+ "for v%" Pd " has been allocated to ",
range->Start(), range->End(), range->vreg()));
TRACE_ALLOC(loc.Print());
TRACE_ALLOC(OS::Print(":\n"));
@@ -2321,8 +2323,8 @@
while (!unallocated_.is_empty()) {
LiveRange* range = unallocated_.RemoveLast();
const intptr_t start = range->Start();
- TRACE_ALLOC(OS::Print("Processing live range for v%"Pd" "
- "starting at %"Pd"\n",
+ TRACE_ALLOC(OS::Print("Processing live range for v%" Pd " "
+ "starting at %" Pd "\n",
range->vreg(),
start));
@@ -2358,13 +2360,13 @@
void FlowGraphAllocator::ConnectSplitSiblings(LiveRange* parent,
BlockEntryInstr* source_block,
BlockEntryInstr* target_block) {
- TRACE_ALLOC(OS::Print("Connect v%"Pd" on the edge B%"Pd" -> B%"Pd"\n",
+ TRACE_ALLOC(OS::Print("Connect v%" Pd " on the edge B%" Pd " -> B%" Pd "\n",
parent->vreg(),
source_block->block_id(),
target_block->block_id()));
if (parent->next_sibling() == NULL) {
// Nothing to connect. The whole range was allocated to the same location.
- TRACE_ALLOC(OS::Print("range v%"Pd" has no siblings\n", parent->vreg()));
+ TRACE_ALLOC(OS::Print("range v%" Pd " has no siblings\n", parent->vreg()));
return;
}
@@ -2401,8 +2403,8 @@
range = range->next_sibling();
}
- TRACE_ALLOC(OS::Print("connecting v%"Pd" between [%"Pd", %"Pd") {%s} "
- "to [%"Pd", %"Pd") {%s}\n",
+ TRACE_ALLOC(OS::Print("connecting v%" Pd " between [%" Pd ", %" Pd ") {%s} "
+ "to [%" Pd ", %" Pd ") {%s}\n",
parent->vreg(),
source_cover->Start(),
source_cover->End(),
@@ -2438,10 +2440,10 @@
while (range->next_sibling() != NULL) {
LiveRange* sibling = range->next_sibling();
- TRACE_ALLOC(OS::Print("connecting [%"Pd", %"Pd") [",
+ TRACE_ALLOC(OS::Print("connecting [%" Pd ", %" Pd ") [",
range->Start(), range->End()));
TRACE_ALLOC(range->assigned_location().Print());
- TRACE_ALLOC(OS::Print("] to [%"Pd", %"Pd") [",
+ TRACE_ALLOC(OS::Print("] to [%" Pd ", %" Pd ") [",
sibling->Start(), sibling->End()));
TRACE_ALLOC(sibling->assigned_location().Print());
TRACE_ALLOC(OS::Print("]\n"));
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
index e818aa2..2ff3dc1 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -1879,7 +1879,7 @@
ASSERT(value->definition()->temp_index() == temp_index() - 1);
intptr_t index = GetCurrentTempLocalIndex();
char name[64];
- OS::SNPrint(name, 64, ":tmp_local%"Pd, index);
+ OS::SNPrint(name, 64, ":tmp_local%" Pd, index);
LocalVariable* var =
new LocalVariable(0,
String::ZoneHandle(Symbols::New(name)),
@@ -2850,8 +2850,74 @@
}
+static intptr_t OffsetForLengthGetter(MethodRecognizer::Kind kind) {
+ switch (kind) {
+ case MethodRecognizer::kObjectArrayLength:
+ case MethodRecognizer::kImmutableArrayLength:
+ return Array::length_offset();
+ case MethodRecognizer::kTypedDataLength:
+ // .length is defined in _TypedList which is the base class for internal
+ // and external typed data.
+ ASSERT(TypedData::length_offset() == ExternalTypedData::length_offset());
+ return TypedData::length_offset();
+ case MethodRecognizer::kGrowableArrayLength:
+ return GrowableObjectArray::length_offset();
+ default:
+ UNREACHABLE();
+ return 0;
+ }
+}
+
+
void EffectGraphVisitor::VisitNativeBodyNode(NativeBodyNode* node) {
+ const Function& function = owner()->parsed_function()->function();
+ if (!function.IsClosureFunction()) {
+ MethodRecognizer::Kind kind = MethodRecognizer::RecognizeKind(function);
+ switch (kind) {
+ case MethodRecognizer::kStringBaseLength: {
+ LocalVariable* receiver_var =
+ node->scope()->LookupVariable(Symbols::This(),
+ true); // Test only.
+ Value* receiver = Bind(new LoadLocalInstr(*receiver_var));
+ // Treat length loads as mutable (i.e. affected by side effects) to
+ // avoid hoisting them since we can't hoist the preceding class-check.
+ // This is because of externalization of strings that affects their
+ // class-id.
+ const bool is_immutable = false;
+ LoadFieldInstr* load = new LoadFieldInstr(
+ receiver,
+ String::length_offset(),
+ Type::ZoneHandle(Type::SmiType()),
+ is_immutable);
+ load->set_result_cid(kSmiCid);
+ load->set_recognized_kind(MethodRecognizer::kStringBaseLength);
+ return ReturnDefinition(load);
+ }
+ case MethodRecognizer::kGrowableArrayLength:
+ case MethodRecognizer::kObjectArrayLength:
+ case MethodRecognizer::kImmutableArrayLength:
+ case MethodRecognizer::kTypedDataLength: {
+ LocalVariable* receiver_var =
+ node->scope()->LookupVariable(Symbols::This(),
+ true); // Test only.
+ Value* receiver = Bind(new LoadLocalInstr(*receiver_var));
+ const bool is_immutable =
+ (kind != MethodRecognizer::kGrowableArrayLength);
+ LoadFieldInstr* load = new LoadFieldInstr(
+ receiver,
+ OffsetForLengthGetter(kind),
+ Type::ZoneHandle(Type::SmiType()),
+ is_immutable);
+ load->set_result_cid(kSmiCid);
+ load->set_recognized_kind(kind);
+ return ReturnDefinition(load);
+ }
+ default:
+ break;
+ }
+ }
InlineBailout("EffectGraphVisitor::VisitNativeBodyNode");
+ function.set_is_optimizable(false);
NativeCallInstr* native_call = new NativeCallInstr(node);
ReturnDefinition(native_call);
}
@@ -2938,6 +3004,12 @@
dst_name);
}
+ if (!node->field().is_final()) {
+ // For now, disable list length guarding on non-final fields by specifying
+ // that the field doesn't have a length. See issue #12485.
+ node->field().set_guarded_list_length(Field::kNoFixedLength);
+ }
+
store_value = Bind(BuildStoreExprTemp(store_value));
GuardFieldInstr* guard =
new GuardFieldInstr(store_value,
@@ -3210,10 +3282,8 @@
// memory leaks.
// In this case, the parser pre-allocates a variable to save the context.
if (MustSaveRestoreContext(node)) {
- Value* current_context = Bind(new CurrentContextInstr());
- Do(BuildStoreTemp(
- *owner()->parsed_function()->saved_entry_context_var(),
- current_context));
+ BuildSaveContext(
+ *owner()->parsed_function()->saved_entry_context_var());
Value* null_context = Bind(new ConstantInstr(Object::ZoneHandle()));
AddInstruction(new StoreContextInstr(null_context));
}
@@ -3630,11 +3700,14 @@
graph_entry_ = new GraphEntryInstr(*parsed_function(), normal_entry, osr_id_);
EffectGraphVisitor for_effect(this, 0);
// This check may be deleted if the generated code is leaf.
- CheckStackOverflowInstr* check =
- new CheckStackOverflowInstr(function.token_pos(), 0);
- // If we are inlining don't actually attach the stack check. We must still
- // create the stack check in order to allocate a deopt id.
- if (!IsInlining()) for_effect.AddInstruction(check);
+ // Native functions don't need a stack check at entry.
+ if (!function.is_native()) {
+ CheckStackOverflowInstr* check =
+ new CheckStackOverflowInstr(function.token_pos(), 0);
+ // If we are inlining don't actually attach the stack check. We must still
+ // create the stack check in order to allocate a deopt id.
+ if (!IsInlining()) for_effect.AddInstruction(check);
+ }
parsed_function()->node_sequence()->Visit(&for_effect);
AppendFragment(normal_entry, for_effect);
// Check that the graph is properly terminated.
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index 4df5137..13516a1 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -152,7 +152,6 @@
if (is_leaf) {
// Remove the stack overflow check at function entry.
Instruction* first = flow_graph_.graph_entry()->normal_entry()->next();
- ASSERT(first->IsCheckStackOverflow());
if (first->IsCheckStackOverflow()) first->RemoveFromGraph();
}
}
@@ -226,7 +225,7 @@
for (intptr_t i = 0; i < block_order().length(); ++i) {
// Compile the block entry.
BlockEntryInstr* entry = block_order()[i];
- assembler()->Comment("B%"Pd"", entry->block_id());
+ assembler()->Comment("B%" Pd "", entry->block_id());
set_current_block(entry);
if (WasCompacted(entry)) {
diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc
index 2dc5f64..c155fe3 100644
--- a/runtime/vm/flow_graph_compiler_arm.cc
+++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -150,7 +150,7 @@
ASSERT(reason() != kDeoptAtCall);
Assembler* assem = compiler->assembler();
#define __ assem->
- __ Comment("Deopt stub for id %"Pd"", deopt_id());
+ __ Comment("Deopt stub for id %" Pd "", deopt_id());
__ Bind(entry_label());
if (FLAG_trap_on_deoptimization) __ bkpt(0);
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
index e2a7bc8..924ade9 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -148,7 +148,7 @@
ASSERT(reason() != kDeoptAtCall);
Assembler* assem = compiler->assembler();
#define __ assem->
- __ Comment("Deopt stub for id %"Pd"", deopt_id());
+ __ Comment("Deopt stub for id %" Pd "", deopt_id());
__ Bind(entry_label());
if (FLAG_trap_on_deoptimization) __ int3();
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index 98527cf..49e8c3a 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -150,7 +150,7 @@
ASSERT(reason() != kDeoptAtCall);
Assembler* assem = compiler->assembler();
#define __ assem->
- __ Comment("Deopt stub for id %"Pd"", deopt_id());
+ __ Comment("Deopt stub for id %" Pd "", deopt_id());
__ Bind(entry_label());
if (FLAG_trap_on_deoptimization) __ break_(0);
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index f07d491..398fe3a 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -145,7 +145,7 @@
ASSERT(reason() != kDeoptAtCall);
Assembler* assem = compiler->assembler();
#define __ assem->
- __ Comment("Deopt stub for id %"Pd"", deopt_id());
+ __ Comment("Deopt stub for id %" Pd "", deopt_id());
__ Bind(entry_label());
if (FLAG_trap_on_deoptimization) __ int3();
diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc
index 247b0fe..15e6df8 100644
--- a/runtime/vm/flow_graph_inliner.cc
+++ b/runtime/vm/flow_graph_inliner.cc
@@ -165,9 +165,11 @@
!it.Done();
it.Advance()) {
++instruction_count_;
- if (it.Current()->IsStaticCall() ||
- it.Current()->IsClosureCall() ||
- it.Current()->IsPolymorphicInstanceCall()) {
+ Instruction* current = it.Current();
+ if (current->IsStaticCall() ||
+ current->IsClosureCall() ||
+ (current->IsPolymorphicInstanceCall() &&
+ !current->AsPolymorphicInstanceCall()->HasRecognizedTarget())) {
++call_site_count_;
}
}
@@ -184,11 +186,10 @@
// A collection of call sites to consider for inlining.
-class CallSites : public FlowGraphVisitor {
+class CallSites : public ValueObject {
public:
explicit CallSites(FlowGraph* flow_graph)
- : FlowGraphVisitor(flow_graph->postorder()), // We don't use this order.
- static_calls_(),
+ : static_calls_(),
closure_calls_(),
instance_calls_() { }
@@ -269,8 +270,15 @@
}
}
- void FindCallSites(FlowGraph* graph) {
+ void FindCallSites(FlowGraph* graph, intptr_t depth) {
ASSERT(graph != NULL);
+ // If depth is less than the threshold recursively add call sites.
+ if (depth > FLAG_inlining_depth_threshold) return;
+
+ // Recognized methods are not treated as normal calls. They don't have
+ // calls in themselves, so we keep adding those even when at the threshold.
+ const bool only_recognized_methods =
+ (depth == FLAG_inlining_depth_threshold);
const intptr_t instance_call_start_ix = instance_calls_.length();
const intptr_t static_call_start_ix = static_calls_.length();
@@ -280,25 +288,39 @@
for (ForwardInstructionIterator it(block_it.Current());
!it.Done();
it.Advance()) {
- it.Current()->Accept(this);
+ Instruction* current = it.Current();
+ if (only_recognized_methods) {
+ PolymorphicInstanceCallInstr* instance_call =
+ current->AsPolymorphicInstanceCall();
+ if ((instance_call != NULL) && instance_call->HasRecognizedTarget()) {
+ instance_calls_.Add(InstanceCallInfo(instance_call));
+ }
+ continue;
+ }
+ // Collect all call sites (!only_recognized_methods).
+ ClosureCallInstr* closure_call = current->AsClosureCall();
+ if (closure_call != NULL) {
+ closure_calls_.Add(closure_call);
+ continue;
+ }
+ StaticCallInstr* static_call = current->AsStaticCall();
+ if (static_call != NULL) {
+ if (static_call->function().IsInlineable()) {
+ static_calls_.Add(StaticCallInfo(static_call));
+ }
+ continue;
+ }
+ PolymorphicInstanceCallInstr* instance_call =
+ current->AsPolymorphicInstanceCall();
+ if (instance_call != NULL) {
+ instance_calls_.Add(InstanceCallInfo(instance_call));
+ continue;
+ }
}
}
ComputeCallSiteRatio(static_call_start_ix, instance_call_start_ix);
}
- void VisitClosureCall(ClosureCallInstr* call) {
- closure_calls_.Add(call);
- }
-
- void VisitPolymorphicInstanceCall(PolymorphicInstanceCallInstr* call) {
- instance_calls_.Add(InstanceCallInfo(call));
- }
-
- void VisitStaticCall(StaticCallInstr* call) {
- if (!call->function().IsInlineable()) return;
- static_calls_.Add(StaticCallInfo(call));
- }
-
private:
GrowableArray<StaticCallInfo> static_calls_;
GrowableArray<ClosureCallInstr*> closure_calls_;
@@ -394,8 +416,6 @@
return false;
}
- // TODO(srdjan): Handle large 'skip_static_call_deopt_ids'. Currently
- // max. size observed is 11 (dart2js).
void InlineCalls() {
// If inlining depth is less then one abort.
if (FLAG_inlining_depth_threshold < 1) return;
@@ -410,9 +430,10 @@
collected_call_sites_ = &sites1;
inlining_call_sites_ = &sites2;
// Collect initial call sites.
- collected_call_sites_->FindCallSites(caller_graph_);
+ collected_call_sites_->FindCallSites(caller_graph_, inlining_depth_);
while (collected_call_sites_->HasCalls()) {
- TRACE_INLINING(OS::Print(" Depth %"Pd" ----------\n", inlining_depth_));
+ TRACE_INLINING(OS::Print(" Depth %" Pd " ----------\n",
+ inlining_depth_));
// Swap collected and inlining arrays and clear the new collecting array.
call_sites_temp = collected_call_sites_;
collected_call_sites_ = inlining_call_sites_;
@@ -471,9 +492,9 @@
function.optimized_call_site_count(),
constant_arguments)) {
TRACE_INLINING(OS::Print(" Bailout: early heuristics with "
- "code size: %"Pd", "
- "call sites: %"Pd", "
- "const args: %"Pd"\n",
+ "code size: %" Pd ", "
+ "call sites: %" Pd ", "
+ "const args: %" Pd "\n",
function.optimized_instruction_count(),
function.optimized_call_site_count(),
constant_arguments));
@@ -489,7 +510,8 @@
}
// Abort if the callee has an intrinsic translation.
- if (Intrinsifier::CanIntrinsify(function)) {
+ if (Intrinsifier::CanIntrinsify(function) &&
+ !function.is_optimizable()) {
function.set_is_inlinable(false);
TRACE_INLINING(OS::Print(" Bailout: can intrinsify\n"));
return false;
@@ -623,19 +645,16 @@
isolate->set_long_jump_base(base);
isolate->set_deopt_id(prev_deopt_id);
TRACE_INLINING(OS::Print(" Bailout: heuristics with "
- "code size: %"Pd", "
- "call sites: %"Pd", "
- "const args: %"Pd"\n",
+ "code size: %" Pd ", "
+ "call sites: %" Pd ", "
+ "const args: %" Pd "\n",
size,
call_site_count,
constants_count));
return false;
}
- // If depth is less or equal to threshold recursively add call sites.
- if (inlining_depth_ < FLAG_inlining_depth_threshold) {
- collected_call_sites_->FindCallSites(callee_graph);
- }
+ collected_call_sites_->FindCallSites(callee_graph, inlining_depth_);
// Add the function to the cache.
if (!in_cache) function_cache_.Add(parsed_function);
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index 84879f5..8affac2 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -303,7 +303,7 @@
EnsureSSATempIndex(graph, current_defn, replacement_defn);
if (FLAG_trace_optimization) {
- OS::Print("Replacing v%"Pd" with v%"Pd"\n",
+ OS::Print("Replacing v%" Pd " with v%" Pd "\n",
current_defn->ssa_temp_index(),
replacement_defn->ssa_temp_index());
}
@@ -312,7 +312,7 @@
OS::Print("Removing %s\n", current->DebugName());
} else {
ASSERT(!current_defn->HasUses());
- OS::Print("Removing v%"Pd".\n", current_defn->ssa_temp_index());
+ OS::Print("Removing v%" Pd ".\n", current_defn->ssa_temp_index());
}
}
iterator->RemoveCurrentFromGraph();
@@ -1083,6 +1083,8 @@
operands_type = kDoubleCid;
} else if (HasOnlyTwoOf(ic_data, kFloat32x4Cid)) {
operands_type = kFloat32x4Cid;
+ } else if (HasOnlyTwoOf(ic_data, kUint32x4Cid)) {
+ operands_type = kUint32x4Cid;
} else {
return false;
}
@@ -1388,23 +1390,6 @@
}
-void FlowGraphOptimizer::InlineArrayLengthGetter(InstanceCallInstr* call,
- intptr_t length_offset,
- bool is_immutable,
- MethodRecognizer::Kind kind) {
- AddReceiverCheck(call);
-
- LoadFieldInstr* load = new LoadFieldInstr(
- new Value(call->ArgumentAt(0)),
- length_offset,
- Type::ZoneHandle(Type::SmiType()),
- is_immutable);
- load->set_result_cid(kSmiCid);
- load->set_recognized_kind(kind);
- ReplaceCall(call, load);
-}
-
-
void FlowGraphOptimizer::InlineGrowableArrayCapacityGetter(
InstanceCallInstr* call) {
AddReceiverCheck(call);
@@ -1444,13 +1429,6 @@
}
-void FlowGraphOptimizer::InlineStringLengthGetter(InstanceCallInstr* call) {
- AddReceiverCheck(call);
- LoadFieldInstr* load = BuildLoadStringLength(call->ArgumentAt(0));
- ReplaceCall(call, load);
-}
-
-
void FlowGraphOptimizer::InlineStringIsEmptyGetter(InstanceCallInstr* call) {
AddReceiverCheck(call);
@@ -1473,25 +1451,6 @@
}
-static intptr_t OffsetForLengthGetter(MethodRecognizer::Kind kind) {
- switch (kind) {
- case MethodRecognizer::kObjectArrayLength:
- case MethodRecognizer::kImmutableArrayLength:
- return Array::length_offset();
- case MethodRecognizer::kTypedDataLength:
- // .length is defined in _TypedList which is the base class for internal
- // and external typed data.
- ASSERT(TypedData::length_offset() == ExternalTypedData::length_offset());
- return TypedData::length_offset();
- case MethodRecognizer::kGrowableArrayLength:
- return GrowableObjectArray::length_offset();
- default:
- UNREACHABLE();
- return 0;
- }
-}
-
-
bool FlowGraphOptimizer::InlineFloat32x4Getter(InstanceCallInstr* call,
MethodRecognizer::Kind getter) {
if (!ShouldInlineSimd()) {
@@ -1505,8 +1464,8 @@
call);
intptr_t mask = 0;
if (getter == MethodRecognizer::kFloat32x4Shuffle) {
- ASSERT(call->ArgumentCount() == 2);
// Extract shuffle mask.
+ ASSERT(call->ArgumentCount() == 2);
Definition* mask_definition = call->ArgumentAt(1);
if (!mask_definition->IsConstant()) {
// Not a constant.
@@ -1526,13 +1485,29 @@
return false;
}
}
- Float32x4ShuffleInstr* instr = new Float32x4ShuffleInstr(
- getter,
- new Value(call->ArgumentAt(0)),
- mask,
- call->deopt_id());
- ReplaceCall(call, instr);
- return true;
+ if (getter == MethodRecognizer::kFloat32x4GetSignMask) {
+ Simd32x4GetSignMaskInstr* instr = new Simd32x4GetSignMaskInstr(
+ getter,
+ new Value(call->ArgumentAt(0)),
+ call->deopt_id());
+ ReplaceCall(call, instr);
+ return true;
+ } else {
+ ASSERT((getter == MethodRecognizer::kFloat32x4Shuffle) ||
+ (getter == MethodRecognizer::kFloat32x4ShuffleX) ||
+ (getter == MethodRecognizer::kFloat32x4ShuffleY) ||
+ (getter == MethodRecognizer::kFloat32x4ShuffleZ) ||
+ (getter == MethodRecognizer::kFloat32x4ShuffleW));
+ Float32x4ShuffleInstr* instr = new Float32x4ShuffleInstr(
+ getter,
+ new Value(call->ArgumentAt(0)),
+ mask,
+ call->deopt_id());
+ ReplaceCall(call, instr);
+ return true;
+ }
+ UNREACHABLE();
+ return false;
}
@@ -1547,12 +1522,21 @@
call->deopt_id(),
call->env(),
call);
- Uint32x4GetFlagInstr* instr = new Uint32x4GetFlagInstr(
- getter,
- new Value(call->ArgumentAt(0)),
- call->deopt_id());
- ReplaceCall(call, instr);
- return true;
+ if (getter == MethodRecognizer::kUint32x4GetSignMask) {
+ Simd32x4GetSignMaskInstr* instr = new Simd32x4GetSignMaskInstr(
+ getter,
+ new Value(call->ArgumentAt(0)),
+ call->deopt_id());
+ ReplaceCall(call, instr);
+ return true;
+ } else {
+ Uint32x4GetFlagInstr* instr = new Uint32x4GetFlagInstr(
+ getter,
+ new Value(call->ArgumentAt(0)),
+ call->deopt_id());
+ ReplaceCall(call, instr);
+ return true;
+ }
}
@@ -1651,34 +1635,9 @@
InlineObjectCid(call);
return true;
}
- case MethodRecognizer::kObjectArrayLength:
- case MethodRecognizer::kImmutableArrayLength:
- case MethodRecognizer::kTypedDataLength:
- case MethodRecognizer::kGrowableArrayLength: {
- if (!ic_data.HasOneTarget()) {
- // TODO(srdjan): Implement for mutiple targets.
- return false;
- }
- const bool is_immutable =
- (recognized_kind == MethodRecognizer::kObjectArrayLength) ||
- (recognized_kind == MethodRecognizer::kImmutableArrayLength) ||
- (recognized_kind == MethodRecognizer::kTypedDataLength);
- InlineArrayLengthGetter(call,
- OffsetForLengthGetter(recognized_kind),
- is_immutable,
- recognized_kind);
- return true;
- }
case MethodRecognizer::kGrowableArrayCapacity:
InlineGrowableArrayCapacityGetter(call);
return true;
- case MethodRecognizer::kStringBaseLength:
- if (!ic_data.HasOneTarget()) {
- // Target is not only StringBase_get_length.
- return false;
- }
- InlineStringLengthGetter(call);
- return true;
case MethodRecognizer::kStringBaseIsEmpty:
if (!ic_data.HasOneTarget()) {
// Target is not only StringBase_get_isEmpty.
@@ -1690,6 +1649,7 @@
case MethodRecognizer::kFloat32x4ShuffleY:
case MethodRecognizer::kFloat32x4ShuffleZ:
case MethodRecognizer::kFloat32x4ShuffleW:
+ case MethodRecognizer::kFloat32x4GetSignMask:
if (!ic_data.HasReceiverClassId(kFloat32x4Cid) ||
!ic_data.HasOneTarget()) {
return false;
@@ -1698,7 +1658,8 @@
case MethodRecognizer::kUint32x4GetFlagX:
case MethodRecognizer::kUint32x4GetFlagY:
case MethodRecognizer::kUint32x4GetFlagZ:
- case MethodRecognizer::kUint32x4GetFlagW: {
+ case MethodRecognizer::kUint32x4GetFlagW:
+ case MethodRecognizer::kUint32x4GetSignMask: {
if (!ic_data.HasReceiverClassId(kUint32x4Cid) ||
!ic_data.HasOneTarget()) {
return false;
@@ -1706,7 +1667,7 @@
return InlineUint32x4Getter(call, recognized_kind);
}
default:
- ASSERT(recognized_kind == MethodRecognizer::kUnknown);
+ break;
}
return false;
}
@@ -1761,7 +1722,7 @@
args->Add(new Value(call->ArgumentAt(i)));
}
InvokeMathCFunctionInstr* invoke =
- new InvokeMathCFunctionInstr(args, call, recognized_kind);
+ new InvokeMathCFunctionInstr(args, call->deopt_id(), recognized_kind);
ReplaceCall(call, invoke);
}
@@ -1900,7 +1861,6 @@
return true;
}
case MethodRecognizer::kDoubleMod:
- case MethodRecognizer::kDoublePow:
case MethodRecognizer::kDoubleRound:
ReplaceWithMathCFunction(call, recognized_kind);
return true;
@@ -2808,6 +2768,18 @@
ReplaceCall(call, min_max);
}
}
+ } else if (recognized_kind == MethodRecognizer::kMathDoublePow) {
+ // We know that first argument is double, the second is num.
+ // InvokeMathCFunctionInstr requires unboxed doubles. UnboxDouble
+ // instructions contain type checks and conversions to double.
+ ZoneGrowableArray<Value*>* args =
+ new ZoneGrowableArray<Value*>(call->ArgumentCount());
+ for (intptr_t i = 0; i < call->ArgumentCount(); i++) {
+ args->Add(new Value(call->ArgumentAt(i)));
+ }
+ InvokeMathCFunctionInstr* invoke =
+ new InvokeMathCFunctionInstr(args, call->deopt_id(), recognized_kind);
+ ReplaceCall(call, invoke);
}
}
@@ -3823,7 +3795,7 @@
// TODO(fschneider): Avoid repeated deoptimization when
// speculatively hoisting checks.
if (FLAG_trace_optimization) {
- OS::Print("Hoisting instruction %s:%"Pd" from B%"Pd" to B%"Pd"\n",
+ OS::Print("Hoisting instruction %s:%" Pd " from B%" Pd " to B%" Pd "\n",
current->DebugName(),
current->GetDeoptId(),
current->GetBlock()->block_id(),
@@ -4172,17 +4144,18 @@
return field_name;
}
return Isolate::Current()->current_zone()->PrintToString(
- "<v%"Pd".%s>", instance()->ssa_temp_index(), field_name);
+ "<v%" Pd ".%s>", instance()->ssa_temp_index(), field_name);
}
case kVMField: {
return Isolate::Current()->current_zone()->PrintToString(
- "<v%"Pd"@%"Pd">", instance()->ssa_temp_index(), offset_in_bytes());
+ "<v%" Pd "@%" Pd ">",
+ instance()->ssa_temp_index(), offset_in_bytes());
}
case kIndexed: {
return Isolate::Current()->current_zone()->PrintToString(
- "<v%"Pd"[v%"Pd"]>",
+ "<v%" Pd "[v%" Pd "]>",
instance()->ssa_temp_index(),
index()->ssa_temp_index());
}
@@ -4637,7 +4610,7 @@
map->Insert(result);
places->Add(result);
if (FLAG_trace_optimization) {
- OS::Print(" adding place %s as %"Pd"\n",
+ OS::Print(" adding place %s as %" Pd "\n",
result->ToCString(),
result->id());
}
@@ -4683,7 +4656,7 @@
places->Add(result);
if (FLAG_trace_optimization) {
- OS::Print("numbering %s as %"Pd"\n",
+ OS::Print("numbering %s as %" Pd "\n",
result->ToCString(),
result->id());
}
@@ -4929,7 +4902,7 @@
Definition* replacement = (*out_values)[place_id];
EnsureSSATempIndex(graph_, defn, replacement);
if (FLAG_trace_optimization) {
- OS::Print("Replacing load v%"Pd" with v%"Pd"\n",
+ OS::Print("Replacing load v%" Pd " with v%" Pd "\n",
defn->ssa_temp_index(),
replacement->ssa_temp_index());
}
@@ -5139,7 +5112,7 @@
}
if (FLAG_trace_load_optimization) {
- OS::Print("B%"Pd"\n", block->block_id());
+ OS::Print("B%" Pd "\n", block->block_id());
OS::Print(" IN: ");
aliased_set_->PrintSet(in_[preorder_number]);
OS::Print("\n");
@@ -5203,7 +5176,7 @@
if (FLAG_trace_optimization) {
for (BitVector::Iterator it(loop_gen); !it.Done(); it.Advance()) {
- OS::Print("place %s is loop invariant for B%"Pd"\n",
+ OS::Print("place %s is loop invariant for B%" Pd "\n",
aliased_set_->places()[it.Current()]->ToCString(),
header->block_id());
}
@@ -5274,7 +5247,7 @@
phis_.Add(phi); // Postpone phi insertion until after load forwarding.
if (FLAG_trace_load_optimization) {
- OS::Print("created pending phi %s for %s at B%"Pd"\n",
+ OS::Print("created pending phi %s for %s at B%" Pd "\n",
phi->ToCString(),
aliased_set_->places()[place_id]->ToCString(),
block->block_id());
@@ -5313,7 +5286,7 @@
EnsureSSATempIndex(graph_, load, replacement);
if (FLAG_trace_optimization) {
- OS::Print("Replacing load v%"Pd" with v%"Pd"\n",
+ OS::Print("Replacing load v%" Pd " with v%" Pd "\n",
load->ssa_temp_index(),
replacement->ssa_temp_index());
}
@@ -6510,6 +6483,12 @@
}
+void ConstantPropagator::VisitSimd32x4GetSignMask(
+ Simd32x4GetSignMaskInstr* instr) {
+ SetValue(instr, non_constant_);
+}
+
+
void ConstantPropagator::VisitFloat32x4Zero(Float32x4ZeroInstr* instr) {
SetValue(instr, non_constant_);
}
@@ -6561,6 +6540,7 @@
SetValue(instr, non_constant_);
}
+
void ConstantPropagator::VisitFloat32x4TwoArgShuffle(
Float32x4TwoArgShuffleInstr* instr) {
SetValue(instr, non_constant_);
@@ -6771,7 +6751,7 @@
JoinEntryInstr* join = block->AsJoinEntry();
if (!reachable_->Contains(block->preorder_number())) {
if (FLAG_trace_constant_propagation) {
- OS::Print("Unreachable B%"Pd"\n", block->block_id());
+ OS::Print("Unreachable B%" Pd "\n", block->block_id());
}
// Remove all uses in unreachable blocks.
if (join != NULL) {
@@ -6851,7 +6831,7 @@
!defn->IsStoreStaticField() &&
!defn->IsStoreVMField()) {
if (FLAG_trace_constant_propagation) {
- OS::Print("Constant v%"Pd" = %s\n",
+ OS::Print("Constant v%" Pd " = %s\n",
defn->ssa_temp_index(),
defn->constant_value().ToCString());
}
@@ -7321,7 +7301,7 @@
ASSERT(IsAllocationSinkingCandidate(alloc));
if (FLAG_trace_optimization) {
- OS::Print("removing allocation from the graph: v%"Pd"\n",
+ OS::Print("removing allocation from the graph: v%" Pd "\n",
alloc->ssa_temp_index());
}
@@ -7360,7 +7340,7 @@
AllocateObjectInstr* alloc = it.Current()->AsAllocateObject();
if ((alloc != NULL) && IsAllocationSinkingCandidate(alloc)) {
if (FLAG_trace_optimization) {
- OS::Print("discovered allocation sinking candidate: v%"Pd"\n",
+ OS::Print("discovered allocation sinking candidate: v%" Pd "\n",
alloc->ssa_temp_index());
}
diff --git a/runtime/vm/flow_graph_optimizer.h b/runtime/vm/flow_graph_optimizer.h
index d92ee29..117ea99 100644
--- a/runtime/vm/flow_graph_optimizer.h
+++ b/runtime/vm/flow_graph_optimizer.h
@@ -156,12 +156,7 @@
bool InlineUint32x4BinaryOp(InstanceCallInstr* call,
Token::Kind op_kind);
void InlineImplicitInstanceGetter(InstanceCallInstr* call);
- void InlineArrayLengthGetter(InstanceCallInstr* call,
- intptr_t length_offset,
- bool is_immutable,
- MethodRecognizer::Kind kind);
void InlineGrowableArrayCapacityGetter(InstanceCallInstr* call);
- void InlineStringLengthGetter(InstanceCallInstr* call);
void InlineStringIsEmptyGetter(InstanceCallInstr* call);
void InlineObjectCid(InstanceCallInstr* call);
diff --git a/runtime/vm/flow_graph_type_propagator.cc b/runtime/vm/flow_graph_type_propagator.cc
index 41e83b6..2ea65ba 100644
--- a/runtime/vm/flow_graph_type_propagator.cc
+++ b/runtime/vm/flow_graph_type_propagator.cc
@@ -65,7 +65,7 @@
while (!worklist_.is_empty()) {
Definition* def = RemoveLastFromWorklist();
if (FLAG_trace_type_propagation) {
- OS::Print("recomputing type of v%"Pd": %s\n",
+ OS::Print("recomputing type of v%" Pd ": %s\n",
def->ssa_temp_index(),
def->Type()->ToCString());
}
@@ -234,7 +234,7 @@
value->SetReachingType(type);
if (FLAG_trace_type_propagation) {
- OS::Print("reaching type to v%"Pd" for v%"Pd" is %s\n",
+ OS::Print("reaching type to v%" Pd " for v%" Pd " is %s\n",
value->instruction()->IsDefinition() ?
value->instruction()->AsDefinition()->ssa_temp_index() : -1,
value->definition()->ssa_temp_index(),
@@ -646,7 +646,7 @@
CompileType result = CompileType::None();
for (intptr_t i = 0; i < InputCount(); i++) {
if (FLAG_trace_type_propagation) {
- OS::Print(" phi %"Pd" input %"Pd": v%"Pd" has reaching type %s\n",
+ OS::Print(" phi %" Pd " input %" Pd ": v%" Pd " has reaching type %s\n",
ssa_temp_index(),
i,
InputAt(i)->definition()->ssa_temp_index(),
@@ -1044,6 +1044,11 @@
}
+CompileType Simd32x4GetSignMaskInstr::ComputeType() const {
+ return CompileType::Int();
+}
+
+
CompileType Float32x4ConstructorInstr::ComputeType() const {
return CompileType::FromCid(kFloat32x4Cid);
}
@@ -1108,6 +1113,7 @@
return CompileType::FromCid(kUint32x4Cid);
}
+
CompileType Uint32x4GetFlagInstr::ComputeType() const {
return CompileType::FromCid(kBoolCid);
}
diff --git a/runtime/vm/freelist.cc b/runtime/vm/freelist.cc
index bbd1bea..54f2bdd 100644
--- a/runtime/vm/freelist.cc
+++ b/runtime/vm/freelist.cc
@@ -163,7 +163,7 @@
intptr_t list_bytes = list_length * i * kObjectAlignment;
small_bytes += list_bytes;
OS::Print("small %3d [%8d bytes] : "
- "%8"Pd" objs; %8.1f KB; %8.1f cum KB\n",
+ "%8" Pd " objs; %8.1f KB; %8.1f cum KB\n",
i,
i * kObjectAlignment,
list_length,
@@ -195,8 +195,8 @@
intptr_t list_length = it->second;
intptr_t list_bytes = list_length * size;
large_bytes += list_bytes;
- OS::Print("large %3"Pd" [%8"Pd" bytes] : "
- "%8"Pd" objs; %8.1f KB; %8.1f cum KB\n",
+ OS::Print("large %3" Pd " [%8" Pd " bytes] : "
+ "%8" Pd " objs; %8.1f KB; %8.1f cum KB\n",
size / kObjectAlignment,
size,
list_length,
diff --git a/runtime/vm/handles.cc b/runtime/vm/handles.cc
index 66f87e6..a7564db 100644
--- a/runtime/vm/handles.cc
+++ b/runtime/vm/handles.cc
@@ -25,10 +25,11 @@
VMHandles::~VMHandles() {
#ifdef DEBUG
if (FLAG_trace_handles) {
- OS::PrintErr("*** Handle Counts for 0x(%"Px"):Zone = %d,Scoped = %d\n",
+ OS::PrintErr("*** Handle Counts for 0x(%" Px
+ "):Zone = %d,Scoped = %d\n",
reinterpret_cast<intptr_t>(this),
CountZoneHandles(), CountScopedHandles());
- OS::PrintErr("*** Deleting VM handle block 0x%"Px"\n",
+ OS::PrintErr("*** Deleting VM handle block 0x%" Px "\n",
reinterpret_cast<intptr_t>(this));
}
#endif
diff --git a/runtime/vm/handles.h b/runtime/vm/handles.h
index be1133b..612682c 100644
--- a/runtime/vm/handles.h
+++ b/runtime/vm/handles.h
@@ -251,7 +251,7 @@
kOffsetOfRawPtr>() {
#ifdef DEBUG
if (FLAG_trace_handles) {
- OS::PrintErr("*** Starting a new VM handle block 0x%"Px"\n",
+ OS::PrintErr("*** Starting a new VM handle block 0x%" Px "\n",
reinterpret_cast<intptr_t>(this));
}
#endif
diff --git a/runtime/vm/handles_impl.h b/runtime/vm/handles_impl.h
index 7f21c32..a40a671 100644
--- a/runtime/vm/handles_impl.h
+++ b/runtime/vm/handles_impl.h
@@ -176,7 +176,7 @@
kOffsetOfRawPtr>::SetupNextScopeBlock() {
#if defined(DEBUG)
if (FLAG_trace_handles) {
- OS::PrintErr("*** Handle Counts for (0x%"Px"):Zone = %d,Scoped = %d\n",
+ OS::PrintErr("*** Handle Counts for (0x%" Px "):Zone = %d,Scoped = %d\n",
reinterpret_cast<intptr_t>(this),
CountZoneHandles(), CountScopedHandles());
}
@@ -231,7 +231,7 @@
kOffsetOfRawPtr>::SetupNextZoneBlock() {
#if defined(DEBUG)
if (FLAG_trace_handles) {
- OS::PrintErr("*** Handle Counts for (0x%"Px"):Zone = %d,Scoped = %d\n",
+ OS::PrintErr("*** Handle Counts for (0x%" Px "):Zone = %d,Scoped = %d\n",
reinterpret_cast<intptr_t>(this),
CountZoneHandles(), CountScopedHandles());
}
diff --git a/runtime/vm/heap.cc b/runtime/vm/heap.cc
index 851f6a6..8f6633c 100644
--- a/runtime/vm/heap.cc
+++ b/runtime/vm/heap.cc
@@ -84,7 +84,7 @@
CollectAllGarbage();
addr = old_space_->TryAllocate(size, type, PageSpace::kForceGrowth);
if (addr == 0) {
- OS::PrintErr("Exhausted heap space, trying to allocate %"Pd" bytes.\n",
+ OS::PrintErr("Exhausted heap space, trying to allocate %" Pd " bytes.\n",
size);
return 0;
}
@@ -296,8 +296,8 @@
void Heap::PrintSizes() const {
- OS::PrintErr("New space (%"Pd"k of %"Pd"k) "
- "Old space (%"Pd"k of %"Pd"k)\n",
+ OS::PrintErr("New space (%" Pd "k of %" Pd "k) "
+ "Old space (%" Pd "k of %" Pd "k)\n",
(Used(kNew) / KB), (Capacity(kNew) / KB),
(Used(kOld) / KB), (Capacity(kOld) / KB));
}
@@ -467,14 +467,16 @@
const char* space_str = stats_.space_ == kNew ? "Scavenge" : "Mark-Sweep";
OS::PrintErr(
- "[ GC(%"Pd64"): %s(%s), " // GC(isolate), space(reason)
- "%"Pd", " // count
+ "[ GC(%" Pd64 "): %s(%s), " // GC(isolate), space(reason)
+ "%" Pd ", " // count
"%.3f, " // start time
"%.3f, " // total time
- "%"Pd", %"Pd", %"Pd", %"Pd", " // new gen: in use, capacity before/after
- "%"Pd", %"Pd", %"Pd", %"Pd", " // old gen: in use, capacity before/after
+ "%" Pd ", %" Pd ", " // new gen: in use before/after
+ "%" Pd ", %" Pd ", " // new gen: capacity before/after
+ "%" Pd ", %" Pd ", " // old gen: in use before/after
+ "%" Pd ", %" Pd ", " // old gen: capacity before/after
"%.3f, %.3f, %.3f, %.3f, " // times
- "%"Pd", %"Pd", %"Pd", %"Pd", " // data
+ "%" Pd ", %" Pd ", %" Pd ", %" Pd ", " // data
"]\n", // End with a comma to make it easier to import in spreadsheets.
isolate->main_port(), space_str, GCReasonToString(stats_.reason_),
stats_.num_,
diff --git a/runtime/vm/heap_histogram.cc b/runtime/vm/heap_histogram.cc
index bfd7e61..0ea4139 100644
--- a/runtime/vm/heap_histogram.cc
+++ b/runtime/vm/heap_histogram.cc
@@ -124,7 +124,7 @@
cls = isolate_->class_table()->At(e->class_id_);
str = cls.Name();
lib = cls.library();
- OS::Print("%9"Pd" %7"Pd" ",
+ OS::Print("%9" Pd " %7" Pd " ",
e->size_ / major_gc_count_,
e->count_ / major_gc_count_);
if (e->class_id_ < kInstanceCid) {
diff --git a/runtime/vm/heap_profiler.cc b/runtime/vm/heap_profiler.cc
index 174a61a..bdfdd83 100644
--- a/runtime/vm/heap_profiler.cc
+++ b/runtime/vm/heap_profiler.cc
@@ -784,7 +784,7 @@
uword obj_addr = RawObject::ToAddr(raw_obj);
if (!Isolate::Current()->heap()->Contains(obj_addr) &&
!Dart::vm_isolate()->heap()->Contains(obj_addr)) {
- FATAL1("Invalid object pointer encountered %#"Px"\n", obj_addr);
+ FATAL1("Invalid object pointer encountered %#" Px "\n", obj_addr);
}
}
profiler_->WriteRoot(raw_obj);
diff --git a/runtime/vm/il_printer.cc b/runtime/vm/il_printer.cc
index 2aab9ba..715b695 100644
--- a/runtime/vm/il_printer.cc
+++ b/runtime/vm/il_printer.cc
@@ -83,7 +83,7 @@
instr->locs()->PrintTo(&f);
}
if (instr->lifetime_position() != -1) {
- OS::Print("%3"Pd": ", instr->lifetime_position());
+ OS::Print("%3" Pd ": ", instr->lifetime_position());
}
if (!instr->IsBlockEntry()) OS::Print(" ");
OS::Print("%s", str);
@@ -133,7 +133,7 @@
static void PrintICData(BufferFormatter* f, const ICData& ic_data) {
- f->Print(" IC[%"Pd": ", ic_data.NumberOfChecks());
+ f->Print(" IC[%" Pd ": ", ic_data.NumberOfChecks());
Function& target = Function::Handle();
for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) {
GrowableArray<intptr_t> class_ids;
@@ -151,7 +151,7 @@
f->Print("%s", String::Handle(cls.Name()).ToCString());
}
if (count > 0) {
- f->Print(" #%"Pd, count);
+ f->Print(" #%" Pd, count);
}
f->Print(" <%p>", static_cast<void*>(target.raw()));
}
@@ -162,9 +162,9 @@
static void PrintUse(BufferFormatter* f, const Definition& definition) {
if (definition.is_used()) {
if (definition.HasSSATemp()) {
- f->Print("v%"Pd, definition.ssa_temp_index());
+ f->Print("v%" Pd, definition.ssa_temp_index());
} else if (definition.temp_index() != -1) {
- f->Print("t%"Pd, definition.temp_index());
+ f->Print("t%" Pd, definition.temp_index());
}
}
}
@@ -180,7 +180,7 @@
void Instruction::PrintTo(BufferFormatter* f) const {
if (GetDeoptId() != Isolate::kNoDeoptId) {
- f->Print("%s:%"Pd"(", DebugName(), GetDeoptId());
+ f->Print("%s:%" Pd "(", DebugName(), GetDeoptId());
} else {
f->Print("%s(", DebugName());
}
@@ -203,7 +203,7 @@
if (HasSSATemp() || (temp_index() != -1)) f->Print(" <- ");
}
if (GetDeoptId() != Isolate::kNoDeoptId) {
- f->Print("%s:%"Pd"(", DebugName(), GetDeoptId());
+ f->Print("%s:%" Pd "(", DebugName(), GetDeoptId());
} else {
f->Print("%s(", DebugName());
}
@@ -283,8 +283,9 @@
void RangeBoundary::PrintTo(BufferFormatter* f) const {
switch (kind_) {
case kSymbol:
- f->Print("v%"Pd, reinterpret_cast<Definition*>(value_)->ssa_temp_index());
- if (offset_ != 0) f->Print("%+"Pd, offset_);
+ f->Print("v%" Pd,
+ reinterpret_cast<Definition*>(value_)->ssa_temp_index());
+ if (offset_ != 0) f->Print("%+" Pd, offset_);
break;
case kConstant:
if (value_ == kMinusInfinity) {
@@ -292,7 +293,7 @@
} else if (value_ == kPlusInfinity) {
f->Print("+inf");
} else {
- f->Print("%"Pd, value_);
+ f->Print("%" Pd, value_);
}
break;
case kUnknown:
@@ -419,7 +420,7 @@
void StoreInstanceFieldInstr::PrintOperandsTo(BufferFormatter* f) const {
- f->Print("%s {%"Pd"}, ",
+ f->Print("%s {%" Pd "}, ",
String::Handle(field().name()).ToCString(),
field().Offset());
instance()->PrintTo(f);
@@ -432,7 +433,7 @@
left()->PrintTo(f);
f->Print(" %s ", Token::Str(kind_));
right()->PrintTo(f);
- f->Print(" ? %"Pd" : %"Pd,
+ f->Print(" ? %" Pd " : %" Pd,
if_true_,
if_false_);
}
@@ -524,7 +525,7 @@
void LoadFieldInstr::PrintOperandsTo(BufferFormatter* f) const {
instance()->PrintTo(f);
- f->Print(", %"Pd, offset_in_bytes());
+ f->Print(", %" Pd, offset_in_bytes());
if (field() != NULL) {
f->Print(" {%s}", String::Handle(field()->name()).ToCString());
@@ -546,7 +547,7 @@
void StoreVMFieldInstr::PrintOperandsTo(BufferFormatter* f) const {
dest()->PrintTo(f);
- f->Print(", %"Pd", ", offset_in_bytes());
+ f->Print(", %" Pd ", ", offset_in_bytes());
value()->PrintTo(f);
}
@@ -574,7 +575,7 @@
void AllocateContextInstr::PrintOperandsTo(BufferFormatter* f) const {
- f->Print("%"Pd"", num_context_variables());
+ f->Print("%" Pd "", num_context_variables());
}
@@ -616,6 +617,17 @@
}
+void Simd32x4GetSignMaskInstr::PrintOperandsTo(BufferFormatter* f) const {
+ if (op_kind() == MethodRecognizer::kFloat32x4GetSignMask) {
+ f->Print("Float32x4.getSignMask ");
+ } else {
+ ASSERT(op_kind() == MethodRecognizer::kUint32x4GetSignMask);
+ f->Print("Uint32x4.getSignMask ");
+ }
+ value()->PrintTo(f);
+}
+
+
void Float32x4ZeroInstr::PrintOperandsTo(BufferFormatter* f) const {
f->Print("ZERO ");
}
@@ -806,7 +818,7 @@
void GraphEntryInstr::PrintTo(BufferFormatter* f) const {
const GrowableArray<Definition*>& defns = initial_definitions_;
- f->Print("B%"Pd"[graph]:%"Pd, block_id(), GetDeoptId());
+ f->Print("B%" Pd "[graph]:%" Pd, block_id(), GetDeoptId());
if (defns.length() > 0) {
f->Print(" {");
for (intptr_t i = 0; i < defns.length(); ++i) {
@@ -821,14 +833,14 @@
void JoinEntryInstr::PrintTo(BufferFormatter* f) const {
if (try_index() != CatchClauseNode::kInvalidTryIndex) {
- f->Print("B%"Pd"[join try_idx %"Pd"]:%"Pd" pred(",
+ f->Print("B%" Pd "[join try_idx %" Pd "]:%" Pd " pred(",
block_id(), try_index(), GetDeoptId());
} else {
- f->Print("B%"Pd"[join]:%"Pd" pred(", block_id(), GetDeoptId());
+ f->Print("B%" Pd "[join]:%" Pd " pred(", block_id(), GetDeoptId());
}
for (intptr_t i = 0; i < predecessors_.length(); ++i) {
if (i > 0) f->Print(", ");
- f->Print("B%"Pd, predecessors_[i]->block_id());
+ f->Print("B%" Pd, predecessors_[i]->block_id());
}
f->Print(")");
if (phis_ != NULL) {
@@ -848,7 +860,7 @@
void PhiInstr::PrintTo(BufferFormatter* f) const {
- f->Print("v%"Pd" <- phi(", ssa_temp_index());
+ f->Print("v%" Pd " <- phi(", ssa_temp_index());
for (intptr_t i = 0; i < inputs_.length(); ++i) {
if (inputs_[i] != NULL) inputs_[i]->PrintTo(f);
if (i < inputs_.length() - 1) f->Print(", ");
@@ -871,21 +883,21 @@
void ParameterInstr::PrintOperandsTo(BufferFormatter* f) const {
- f->Print("%"Pd, index());
+ f->Print("%" Pd, index());
}
void CheckStackOverflowInstr::PrintOperandsTo(BufferFormatter* f) const {
- if (in_loop()) f->Print("depth %"Pd, loop_depth());
+ if (in_loop()) f->Print("depth %" Pd, loop_depth());
}
void TargetEntryInstr::PrintTo(BufferFormatter* f) const {
if (try_index() != CatchClauseNode::kInvalidTryIndex) {
- f->Print("B%"Pd"[target try_idx %"Pd"]:%"Pd,
+ f->Print("B%" Pd "[target try_idx %" Pd "]:%" Pd,
block_id(), try_index(), GetDeoptId());
} else {
- f->Print("B%"Pd"[target]:%"Pd, block_id(), GetDeoptId());
+ f->Print("B%" Pd "[target]:%" Pd, block_id(), GetDeoptId());
}
if (HasParallelMove()) {
f->Print(" ");
@@ -895,7 +907,7 @@
void CatchBlockEntryInstr::PrintTo(BufferFormatter* f) const {
- f->Print("B%"Pd"[target catch try_idx %"Pd" catch_try_idx %"Pd"]",
+ f->Print("B%" Pd "[target catch try_idx %" Pd " catch_try_idx %" Pd "]",
block_id(), try_index(), catch_try_index());
if (HasParallelMove()) {
f->Print("\n");
@@ -926,9 +938,9 @@
f->Print(" ");
}
if (GetDeoptId() != Isolate::kNoDeoptId) {
- f->Print("goto:%"Pd" %"Pd"", GetDeoptId(), successor()->block_id());
+ f->Print("goto:%" Pd " %" Pd "", GetDeoptId(), successor()->block_id());
} else {
- f->Print("goto: %"Pd"", successor()->block_id());
+ f->Print("goto: %" Pd "", successor()->block_id());
}
}
@@ -938,7 +950,7 @@
f->Print("if ");
comparison()->PrintTo(f);
- f->Print(" goto (%"Pd", %"Pd")",
+ f->Print(" goto (%" Pd ", %" Pd ")",
true_successor()->block_id(),
false_successor()->block_id());
}
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index 2fdb792..06c3d3a 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -1427,6 +1427,52 @@
}
+Definition* BoxFloat32x4Instr::Canonicalize(FlowGraph* flow_graph) {
+ if (input_use_list() == NULL) {
+ // Environments can accomodate any representation. No need to box.
+ return value()->definition();
+ }
+
+ // Fold away BoxFloat32x4(UnboxFloat32x4(v)).
+ UnboxFloat32x4Instr* defn = value()->definition()->AsUnboxFloat32x4();
+ if ((defn != NULL) && (defn->value()->Type()->ToCid() == kFloat32x4Cid)) {
+ return defn->value()->definition();
+ }
+
+ return this;
+}
+
+
+Definition* UnboxFloat32x4Instr::Canonicalize(FlowGraph* flow_graph) {
+ // Fold away UnboxFloat32x4(BoxFloat32x4(v)).
+ BoxFloat32x4Instr* defn = value()->definition()->AsBoxFloat32x4();
+ return (defn != NULL) ? defn->value()->definition() : this;
+}
+
+
+Definition* BoxUint32x4Instr::Canonicalize(FlowGraph* flow_graph) {
+ if (input_use_list() == NULL) {
+ // Environments can accomodate any representation. No need to box.
+ return value()->definition();
+ }
+
+ // Fold away BoxUint32x4(UnboxUint32x4(v)).
+ UnboxUint32x4Instr* defn = value()->definition()->AsUnboxUint32x4();
+ if ((defn != NULL) && (defn->value()->Type()->ToCid() == kUint32x4Cid)) {
+ return defn->value()->definition();
+ }
+
+ return this;
+}
+
+
+Definition* UnboxUint32x4Instr::Canonicalize(FlowGraph* flow_graph) {
+ // Fold away UnboxUint32x4(BoxUint32x4(v)).
+ BoxUint32x4Instr* defn = value()->definition()->AsBoxUint32x4();
+ return (defn != NULL) ? defn->value()->definition() : this;
+}
+
+
Instruction* BranchInstr::Canonicalize(FlowGraph* flow_graph) {
// Only handle strict-compares.
if (comparison()->IsStrictCompare()) {
@@ -1458,7 +1504,7 @@
comp->RemoveFromGraph();
SetComparison(comp);
if (FLAG_trace_optimization) {
- OS::Print("Merging comparison v%"Pd"\n", comp->ssa_temp_index());
+ OS::Print("Merging comparison v%" Pd "\n", comp->ssa_temp_index());
}
// Clear the comparison's temp index and ssa temp index since the
// value of the comparison is not used outside the branch anymore.
@@ -1776,6 +1822,14 @@
}
+bool PolymorphicInstanceCallInstr::HasRecognizedTarget() const {
+ return ic_data().HasOneTarget() &&
+ (MethodRecognizer::RecognizeKind(
+ Function::Handle(ic_data().GetTargetAt(0))) !=
+ MethodRecognizer::kUnknown);
+}
+
+
LocationSummary* StaticCallInstr::MakeLocationSummary() const {
return MakeCallSummary();
}
@@ -2174,7 +2228,7 @@
if (target() == branch->true_successor()) {
// True unreachable.
if (FLAG_trace_constant_propagation) {
- OS::Print("Range analysis: True unreachable (B%"Pd")\n",
+ OS::Print("Range analysis: True unreachable (B%" Pd ")\n",
branch->true_successor()->block_id());
}
branch->set_constant_target(branch->false_successor());
@@ -2182,7 +2236,7 @@
ASSERT(target() == branch->false_successor());
// False unreachable.
if (FLAG_trace_constant_propagation) {
- OS::Print("Range analysis: False unreachable (B%"Pd")\n",
+ OS::Print("Range analysis: False unreachable (B%" Pd ")\n",
branch->false_successor()->block_id());
}
branch->set_constant_target(branch->true_successor());
@@ -2520,7 +2574,7 @@
InvokeMathCFunctionInstr::InvokeMathCFunctionInstr(
ZoneGrowableArray<Value*>* inputs,
- InstanceCallInstr* instance_call,
+ intptr_t original_deopt_id,
MethodRecognizer::Kind recognized_kind)
: inputs_(inputs),
locs_(NULL),
@@ -2531,7 +2585,7 @@
(*inputs)[i]->set_instruction(this);
(*inputs)[i]->set_use_index(i);
}
- deopt_id_ = instance_call->deopt_id();
+ deopt_id_ = original_deopt_id;
}
@@ -2547,7 +2601,7 @@
case MethodRecognizer::kDoubleRound:
return 1;
case MethodRecognizer::kDoubleMod:
- case MethodRecognizer::kDoublePow:
+ case MethodRecognizer::kMathDoublePow:
return 2;
default:
UNREACHABLE();
@@ -2594,7 +2648,7 @@
return kFloorRuntimeEntry;
case MethodRecognizer::kDoubleCeil:
return kCeilRuntimeEntry;
- case MethodRecognizer::kDoublePow:
+ case MethodRecognizer::kMathDoublePow:
return kPowRuntimeEntry;
case MethodRecognizer::kDoubleMod:
return kModRuntimeEntry;
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index a3b7fc7..644cb99 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -79,13 +79,13 @@
V(_Double, roundToDouble, DoubleRound, 500368418) \
V(_Double, floorToDouble, DoubleFloor, 763548522) \
V(_Double, ceilToDouble, DoubleCeil, 976697019) \
- V(_Double, pow, DoublePow, 1240251670) \
V(_Double, _modulo, DoubleMod, 1850917533) \
V(::, sqrt, MathSqrt, 465520247) \
V(::, sin, MathSin, 730107143) \
V(::, cos, MathCos, 1282146521) \
V(::, min, MathMin, 1584022354) \
V(::, max, MathMax, 328632232) \
+ V(::, _doublePow, MathDoublePow, 2002448359) \
V(Float32x4, Float32x4., Float32x4Constructor, 1876089990) \
V(Float32x4, Float32x4.zero, Float32x4Zero, 1903586222) \
V(Float32x4, Float32x4.splat, Float32x4Splat, 38462589) \
@@ -94,6 +94,7 @@
V(_Float32x4, get:y, Float32x4ShuffleY, 710282243) \
V(_Float32x4, get:z, Float32x4ShuffleZ, 1612806041) \
V(_Float32x4, get:w, Float32x4ShuffleW, 1113701403) \
+ V(_Float32x4, get:signMask, Float32x4GetSignMask, 465347632) \
V(_Float32x4, _cmpequal, Float32x4Equal, 1559121703) \
V(_Float32x4, _cmpgt, Float32x4GreaterThan, 1959692892) \
V(_Float32x4, _cmpgte, Float32x4GreaterThanOrEqual, 2128251808) \
@@ -124,6 +125,7 @@
V(_Uint32x4, get:flagY, Uint32x4GetFlagY, 1226233321) \
V(_Uint32x4, get:flagZ, Uint32x4GetFlagZ, 1455452476) \
V(_Uint32x4, get:flagW, Uint32x4GetFlagW, 1608549245) \
+ V(_Uint32x4, get:signMask, Uint32x4GetSignMask, 231202664) \
V(_Uint32x4, select, Uint32x4Select, 881590808) \
V(_Uint32x4, withFlagX, Uint32x4WithFlagX, 1987921054) \
V(_Uint32x4, withFlagY, Uint32x4WithFlagY, 831632614) \
@@ -134,6 +136,11 @@
// A list of core function that should always be inlined.
#define INLINE_WHITE_LIST(V) \
+ V(_ObjectArray, get:length, ObjectArrayLength, 1441000484) \
+ V(_ImmutableArray, get:length, ImmutableArrayLength, 1430953867) \
+ V(_TypedList, get:length, TypedDataLength, 117589485) \
+ V(_GrowableObjectArray, get:length, GrowableArrayLength, 767561362) \
+ V(_StringBase, get:length, StringBaseLength, 1158042795) \
V(ListIterator, moveNext, ListIteratorMoveNext, 657540761) \
V(_GrowableObjectArray, get:iterator, GrowableArrayIterator, 281980741) \
V(_GrowableObjectArray, forEach, GrowableArrayForEach, 334448248)
@@ -613,6 +620,7 @@
M(IfThenElse) \
M(BinaryFloat32x4Op) \
M(Float32x4Shuffle) \
+ M(Simd32x4GetSignMask) \
M(Float32x4Constructor) \
M(Float32x4Zero) \
M(Float32x4Splat) \
@@ -902,6 +910,7 @@
friend class Float32x4ZeroInstr;
friend class Float32x4SplatInstr;
friend class Float32x4ShuffleInstr;
+ friend class Simd32x4GetSignMaskInstr;
friend class Float32x4ConstructorInstr;
friend class Float32x4ComparisonInstr;
friend class Float32x4MinMaxInstr;
@@ -2699,6 +2708,8 @@
return instance_call()->PushArgumentAt(index);
}
+ bool HasRecognizedTarget() const;
+
DECLARE_INSTRUCTION(PolymorphicInstanceCall)
const ICData& ic_data() const { return ic_data_; }
@@ -4398,6 +4409,8 @@
virtual bool MayThrow() const { return false; }
+ Definition* Canonicalize(FlowGraph* flow_graph);
+
private:
DISALLOW_COPY_AND_ASSIGN(BoxFloat32x4Instr);
};
@@ -4428,6 +4441,8 @@
virtual bool MayThrow() const { return false; }
+ Definition* Canonicalize(FlowGraph* flow_graph);
+
private:
DISALLOW_COPY_AND_ASSIGN(BoxUint32x4Instr);
};
@@ -4525,6 +4540,8 @@
virtual bool MayThrow() const { return false; }
+ Definition* Canonicalize(FlowGraph* flow_graph);
+
private:
DISALLOW_COPY_AND_ASSIGN(UnboxFloat32x4Instr);
};
@@ -4557,6 +4574,8 @@
virtual bool MayThrow() const { return false; }
+ Definition* Canonicalize(FlowGraph* flow_graph);
+
private:
DISALLOW_COPY_AND_ASSIGN(UnboxUint32x4Instr);
};
@@ -5527,6 +5546,60 @@
};
+class Simd32x4GetSignMaskInstr : public TemplateDefinition<1> {
+ public:
+ Simd32x4GetSignMaskInstr(MethodRecognizer::Kind op_kind, Value* value,
+ intptr_t deopt_id) : op_kind_(op_kind) {
+ SetInputAt(0, value);
+ deopt_id_ = deopt_id;
+ }
+
+ Value* value() const { return inputs_[0]; }
+
+ MethodRecognizer::Kind op_kind() const { return op_kind_; }
+
+ virtual void PrintOperandsTo(BufferFormatter* f) const;
+
+ virtual bool CanDeoptimize() const { return false; }
+
+ virtual Representation representation() const {
+ return kTagged;
+ }
+
+ virtual Representation RequiredInputRepresentation(intptr_t idx) const {
+ ASSERT(idx == 0);
+ if (op_kind_ == MethodRecognizer::kFloat32x4GetSignMask) {
+ return kUnboxedFloat32x4;
+ }
+ ASSERT(op_kind_ == MethodRecognizer::kUint32x4GetSignMask);
+ return kUnboxedUint32x4;
+ }
+
+ virtual intptr_t DeoptimizationTarget() const {
+ // Direct access since this instruction cannot deoptimize, and the deopt-id
+ // was inherited from another instruction that could deoptimize.
+ return deopt_id_;
+ }
+
+ DECLARE_INSTRUCTION(Simd32x4GetSignMask)
+ virtual CompileType ComputeType() const;
+
+ virtual bool AllowsCSE() const { return true; }
+ virtual EffectSet Effects() const { return EffectSet::None(); }
+ virtual EffectSet Dependencies() const { return EffectSet::None(); }
+ virtual bool AttributesEqual(Instruction* other) const {
+ return other->AsSimd32x4GetSignMask()->op_kind() == op_kind();
+ }
+
+ virtual bool MayThrow() const { return false; }
+
+ private:
+ const MethodRecognizer::Kind op_kind_;
+
+ DISALLOW_COPY_AND_ASSIGN(Simd32x4GetSignMaskInstr);
+};
+
+
class Float32x4TwoArgShuffleInstr : public TemplateDefinition<2> {
public:
Float32x4TwoArgShuffleInstr(MethodRecognizer::Kind op_kind, Value* left,
@@ -6279,7 +6352,7 @@
class InvokeMathCFunctionInstr : public Definition {
public:
InvokeMathCFunctionInstr(ZoneGrowableArray<Value*>* inputs,
- InstanceCallInstr* instance_call,
+ intptr_t original_deopt_id,
MethodRecognizer::Kind recognized_kind);
static intptr_t ArgumentCountFor(MethodRecognizer::Kind recognized_kind_);
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index 04edbc1..88ebbab 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -1517,11 +1517,17 @@
LocationSummary* summary =
new LocationSummary(kNumInputs, 0, LocationSummary::kNoCall);
summary->set_in(0, Location::RequiresRegister());
- if ((value()->Type()->ToCid() == kDynamicCid) &&
- (field().guarded_cid() != kSmiCid)) {
+ const bool field_has_length = field().needs_length_check();
+ const bool need_value_temp_reg =
+ (field_has_length || ((value()->Type()->ToCid() == kDynamicCid) &&
+ (field().guarded_cid() != kSmiCid)));
+ if (need_value_temp_reg) {
+ summary->AddTemp(Location::RequiresRegister());
summary->AddTemp(Location::RequiresRegister());
}
- if (field().guarded_cid() == kIllegalCid) {
+ const bool need_field_temp_reg =
+ field_has_length || (field().guarded_cid() == kIllegalCid);
+ if (need_field_temp_reg) {
summary->AddTemp(Location::RequiresRegister());
}
return summary;
@@ -1531,6 +1537,17 @@
void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
const intptr_t field_cid = field().guarded_cid();
const intptr_t nullability = field().is_nullable() ? kNullCid : kIllegalCid;
+ const intptr_t field_length = field().guarded_list_length();
+ const bool field_has_length = field().needs_length_check();
+ const bool needs_value_temp_reg =
+ (field_has_length || ((value()->Type()->ToCid() == kDynamicCid) &&
+ (field().guarded_cid() != kSmiCid)));
+ const bool needs_field_temp_reg =
+ field_has_length || (field().guarded_cid() == kIllegalCid);
+ if (field_has_length) {
+ // Currently, we should only see final fields that remember length.
+ ASSERT(field().is_final());
+ }
if (field_cid == kDynamicCid) {
ASSERT(!compiler->is_optimizing());
@@ -1541,10 +1558,12 @@
Register value_reg = locs()->in(0).reg();
- Register value_cid_reg = ((value_cid == kDynamicCid) &&
- (field_cid != kSmiCid)) ? locs()->temp(0).reg() : kNoRegister;
+ Register value_cid_reg = needs_value_temp_reg ?
+ locs()->temp(0).reg() : kNoRegister;
+ Register temp_reg = needs_value_temp_reg ?
+ locs()->temp(1).reg() : kNoRegister;
- Register field_reg = (field_cid == kIllegalCid) ?
+ Register field_reg = needs_field_temp_reg ?
locs()->temp(locs()->temp_count() - 1).reg() : kNoRegister;
Label ok, fail_label;
@@ -1557,7 +1576,7 @@
const bool ok_is_fall_through = (deopt != NULL);
if (!compiler->is_optimizing() || (field_cid == kIllegalCid)) {
- if (!compiler->is_optimizing()) {
+ if (!compiler->is_optimizing() && (field_reg == kNoRegister)) {
// Currently we can't have different location summaries for optimized
// and non-optimized code. So instead we manually pick up a register
// that is known to be free because we know how non-optimizing compiler
@@ -1571,6 +1590,8 @@
FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset());
FieldAddress field_nullability_operand(
field_reg, Field::is_nullable_offset());
+ FieldAddress field_length_operand(
+ field_reg, Field::guarded_list_length_offset());
if (value_cid_reg == kNoRegister) {
ASSERT(!compiler->is_optimizing());
@@ -1580,17 +1601,56 @@
if (value_cid == kDynamicCid) {
LoadValueCid(compiler, value_cid_reg, value_reg);
+ Label skip_length_check;
__ ldr(IP, field_cid_operand);
__ cmp(value_cid_reg, ShifterOperand(IP));
- __ b(&ok, EQ);
+ __ b(&skip_length_check, NE);
+ if (field_has_length) {
+ ASSERT(temp_reg != kNoRegister);
+ // Field guard may have remembered list length, check it.
+ if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
+ __ ldr(temp_reg,
+ FieldAddress(value_reg, Array::length_offset()));
+ __ CompareImmediate(temp_reg, field_length);
+ } else if (RawObject::IsTypedDataClassId(field_cid)) {
+ __ ldr(temp_reg,
+ FieldAddress(value_reg, TypedData::length_offset()));
+ __ CompareImmediate(temp_reg, field_length);
+ } else {
+ ASSERT(field_cid == kIllegalCid);
+ // Following branch cannot not occur, fall through.
+ }
+ __ b(fail, NE);
+ }
+ __ Bind(&skip_length_check);
__ ldr(IP, field_nullability_operand);
__ cmp(value_cid_reg, ShifterOperand(IP));
} else if (value_cid == kNullCid) {
__ ldr(value_cid_reg, field_nullability_operand);
__ CompareImmediate(value_cid_reg, value_cid);
} else {
+ Label skip_length_check;
__ ldr(value_cid_reg, field_cid_operand);
__ CompareImmediate(value_cid_reg, value_cid);
+ __ b(&skip_length_check, NE);
+ if (field_has_length) {
+ ASSERT(value_cid_reg != kNoRegister);
+ ASSERT(temp_reg != kNoRegister);
+ if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
+ __ ldr(temp_reg,
+ FieldAddress(value_reg, Array::length_offset()));
+ __ CompareImmediate(temp_reg, field_length);
+ } else if (RawObject::IsTypedDataClassId(field_cid)) {
+ __ ldr(temp_reg,
+ FieldAddress(value_reg, TypedData::length_offset()));
+ __ CompareImmediate(temp_reg, field_length);
+ } else {
+ ASSERT(field_cid == kIllegalCid);
+ // Following jump cannot not occur, fall through.
+ }
+ }
+ // Not identical, possibly null.
+ __ Bind(&skip_length_check);
}
__ b(&ok, EQ);
@@ -1601,16 +1661,65 @@
if (value_cid == kDynamicCid) {
__ str(value_cid_reg, field_cid_operand);
__ str(value_cid_reg, field_nullability_operand);
+ if (field_has_length) {
+ Label check_array, local_exit, local_fail;
+ __ CompareImmediate(value_cid_reg, kNullCid);
+ __ b(&local_fail, EQ);
+ // Check for typed data array.
+ __ CompareImmediate(value_cid_reg, kTypedDataFloat32x4ArrayCid);
+ __ b(&local_fail, GT);
+ __ CompareImmediate(value_cid_reg, kTypedDataInt8ArrayCid);
+ __ b(&check_array, LT); // Could still be a regular array.
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ ldr(value_cid_reg,
+ FieldAddress(value_reg, TypedData::length_offset()));
+ __ str(value_cid_reg, field_length_operand);
+ __ b(&local_exit); // Updated field length typed data array.
+ // Check for regular array.
+ __ Bind(&check_array);
+ __ CompareImmediate(value_cid_reg, kImmutableArrayCid);
+ __ b(&local_fail, GT);
+ __ CompareImmediate(value_cid_reg, kArrayCid);
+ __ b(&local_fail, LT);
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ ldr(value_cid_reg,
+ FieldAddress(value_reg, Array::length_offset()));
+ __ str(value_cid_reg, field_length_operand);
+ __ b(&local_exit); // Updated field length from regular array.
+
+ __ Bind(&local_fail);
+ __ LoadImmediate(IP, Field::kNoFixedLength);
+ __ str(IP, field_length_operand);
+
+ __ Bind(&local_exit);
+ }
} else {
__ LoadImmediate(IP, value_cid);
__ str(IP, field_cid_operand);
__ str(IP, field_nullability_operand);
+ if ((value_cid == kArrayCid) || (value_cid == kImmutableArrayCid)) {
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ ldr(value_cid_reg,
+ FieldAddress(value_reg, Array::length_offset()));
+ __ str(value_cid_reg, field_length_operand);
+ } else if (RawObject::IsTypedDataClassId(value_cid)) {
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ ldr(value_cid_reg,
+ FieldAddress(value_reg, TypedData::length_offset()));
+ __ str(value_cid_reg, field_length_operand);
+ } else {
+ __ LoadImmediate(IP, Field::kNoFixedLength);
+ __ str(IP, field_length_operand);
+ }
}
if (!ok_is_fall_through) {
__ b(&ok);
}
} else {
+ if (field_reg != kNoRegister) {
+ __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
+ }
if (value_cid == kDynamicCid) {
// Field's guarded class id is fixed by value's class id is not known.
__ tst(value_reg, ShifterOperand(kSmiTagMask));
@@ -1621,6 +1730,26 @@
__ CompareImmediate(value_cid_reg, field_cid);
}
+ if (field_has_length) {
+ __ b(fail, NE);
+ // Classes are same, perform guarded list length check.
+ ASSERT(field_reg != kNoRegister);
+ ASSERT(value_cid_reg != kNoRegister);
+ FieldAddress field_length_operand(
+ field_reg, Field::guarded_list_length_offset());
+ if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ ldr(value_cid_reg,
+ FieldAddress(value_reg, Array::length_offset()));
+ } else if (RawObject::IsTypedDataClassId(field_cid)) {
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ ldr(value_cid_reg,
+ FieldAddress(value_reg, TypedData::length_offset()));
+ }
+ __ ldr(IP, field_length_operand);
+ __ cmp(value_cid_reg, ShifterOperand(IP));
+ }
+
if (field().is_nullable() && (field_cid != kNullCid)) {
__ b(&ok, EQ);
__ CompareImmediate(value_reg,
@@ -1638,6 +1767,22 @@
if (ok_is_fall_through) {
__ b(fail);
}
+ } else if (field_has_length && (value_cid == field_cid)) {
+ ASSERT(value_cid_reg != kNoRegister);
+ if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ ldr(value_cid_reg,
+ FieldAddress(value_reg, Array::length_offset()));
+ } else if (RawObject::IsTypedDataClassId(field_cid)) {
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ ldr(value_cid_reg,
+ FieldAddress(value_reg, TypedData::length_offset()));
+ }
+ __ LoadImmediate(IP, field_length);
+ __ cmp(value_cid_reg, ShifterOperand(IP));
+ if (ok_is_fall_through) {
+ __ b(fail, NE);
+ }
} else {
// Nothing to emit.
ASSERT(!compiler->is_optimizing());
@@ -3030,6 +3175,46 @@
}
+LocationSummary* Simd32x4GetSignMaskInstr::MakeLocationSummary() const {
+ const intptr_t kNumInputs = 1;
+ const intptr_t kNumTemps = 1;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ summary->set_in(0, Location::FpuRegisterLocation(Q5));
+ summary->set_temp(0, Location::RequiresRegister());
+ summary->set_out(Location::RequiresRegister());
+ return summary;
+}
+
+
+void Simd32x4GetSignMaskInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ QRegister value = locs()->in(0).fpu_reg();
+ DRegister dvalue0 = EvenDRegisterOf(value);
+ DRegister dvalue1 = OddDRegisterOf(value);
+
+ Register out = locs()->out().reg();
+ Register temp = locs()->temp(0).reg();
+
+ // X lane.
+ __ vmovrs(out, EvenSRegisterOf(dvalue0));
+ __ Lsr(out, out, 31);
+ // Y lane.
+ __ vmovrs(temp, OddSRegisterOf(dvalue0));
+ __ Lsr(temp, temp, 31);
+ __ orr(out, out, ShifterOperand(temp, LSL, 1));
+ // Z lane.
+ __ vmovrs(temp, EvenSRegisterOf(dvalue1));
+ __ Lsr(temp, temp, 31);
+ __ orr(out, out, ShifterOperand(temp, LSL, 2));
+ // W lane.
+ __ vmovrs(temp, OddSRegisterOf(dvalue1));
+ __ Lsr(temp, temp, 31);
+ __ orr(out, out, ShifterOperand(temp, LSL, 3));
+ // Tag.
+ __ SmiTag(out);
+}
+
+
LocationSummary* Float32x4ConstructorInstr::MakeLocationSummary() const {
const intptr_t kNumInputs = 4;
const intptr_t kNumTemps = 0;
@@ -3632,6 +3817,12 @@
__ veorq(result, left, right);
break;
}
+ case Token::kADD:
+ UNIMPLEMENTED();
+ break;
+ case Token::kSUB:
+ UNIMPLEMENTED();
+ break;
default: UNREACHABLE();
}
}
@@ -3949,7 +4140,7 @@
void InvokeMathCFunctionInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
// For pow-function return NaN if exponent is NaN.
Label do_call, skip_call;
- if (recognized_kind() == MethodRecognizer::kDoublePow) {
+ if (recognized_kind() == MethodRecognizer::kMathDoublePow) {
DRegister exp = EvenDRegisterOf(locs()->in(1).fpu_reg());
DRegister result = EvenDRegisterOf(locs()->out().fpu_reg());
__ vcmpd(exp, exp);
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index 412248c..a57cc42 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -1577,11 +1577,16 @@
LocationSummary* summary =
new LocationSummary(kNumInputs, 0, LocationSummary::kNoCall);
summary->set_in(0, Location::RequiresRegister());
- if ((value()->Type()->ToCid() == kDynamicCid) &&
- (field().guarded_cid() != kSmiCid)) {
+ const bool field_has_length = field().needs_length_check();
+ const bool need_value_temp_reg =
+ (field_has_length || ((value()->Type()->ToCid() == kDynamicCid) &&
+ (field().guarded_cid() != kSmiCid)));
+ if (need_value_temp_reg) {
summary->AddTemp(Location::RequiresRegister());
}
- if (field().guarded_cid() == kIllegalCid) {
+ const bool need_field_temp_reg =
+ field_has_length || (field().guarded_cid() == kIllegalCid);
+ if (need_field_temp_reg) {
summary->AddTemp(Location::RequiresRegister());
}
return summary;
@@ -1591,6 +1596,17 @@
void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
const intptr_t field_cid = field().guarded_cid();
const intptr_t nullability = field().is_nullable() ? kNullCid : kIllegalCid;
+ const intptr_t field_length = field().guarded_list_length();
+ const bool field_has_length = field().needs_length_check();
+ const bool needs_value_temp_reg =
+ (field_has_length || ((value()->Type()->ToCid() == kDynamicCid) &&
+ (field().guarded_cid() != kSmiCid)));
+ const bool needs_field_temp_reg =
+ field_has_length || (field().guarded_cid() == kIllegalCid);
+ if (field_has_length) {
+ // Currently, we should only see final fields that remember length.
+ ASSERT(field().is_final());
+ }
if (field_cid == kDynamicCid) {
ASSERT(!compiler->is_optimizing());
@@ -1601,10 +1617,10 @@
Register value_reg = locs()->in(0).reg();
- Register value_cid_reg = ((value_cid == kDynamicCid) &&
- (field_cid != kSmiCid)) ? locs()->temp(0).reg() : kNoRegister;
+ Register value_cid_reg = needs_value_temp_reg ?
+ locs()->temp(0).reg() : kNoRegister;
- Register field_reg = (field_cid == kIllegalCid) ?
+ Register field_reg = needs_field_temp_reg ?
locs()->temp(locs()->temp_count() - 1).reg() : kNoRegister;
Label ok, fail_label;
@@ -1617,7 +1633,7 @@
const bool ok_is_fall_through = (deopt != NULL);
if (!compiler->is_optimizing() || (field_cid == kIllegalCid)) {
- if (!compiler->is_optimizing()) {
+ if (!compiler->is_optimizing() && (field_reg == kNoRegister)) {
// Currently we can't have different location summaries for optimized
// and non-optimized code. So instead we manually pick up a register
// that is known to be free because we know how non-optimizing compiler
@@ -1631,6 +1647,8 @@
FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset());
FieldAddress field_nullability_operand(
field_reg, Field::is_nullable_offset());
+ FieldAddress field_length_operand(
+ field_reg, Field::guarded_list_length_offset());
if (value_cid == kDynamicCid) {
if (value_cid_reg == kNoRegister) {
@@ -1641,33 +1659,154 @@
LoadValueCid(compiler, value_cid_reg, value_reg);
+ Label skip_length_check;
__ cmpl(value_cid_reg, field_cid_operand);
- __ j(EQUAL, &ok);
+ // Value CID != Field guard CID, skip length check.
+ __ j(NOT_EQUAL, &skip_length_check);
+ if (field_has_length) {
+ // Field guard may have remembered list length, check it.
+ if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
+ __ pushl(value_cid_reg);
+ __ movl(value_cid_reg,
+ FieldAddress(value_reg, Array::length_offset()));
+ __ cmpl(value_cid_reg, Immediate(field_length));
+ __ popl(value_cid_reg);
+ } else if (RawObject::IsTypedDataClassId(field_cid)) {
+ __ pushl(value_cid_reg);
+ __ movl(value_cid_reg,
+ FieldAddress(value_reg, TypedData::length_offset()));
+ __ cmpl(value_cid_reg, Immediate(field_length));
+ __ popl(value_cid_reg);
+ } else {
+ ASSERT(field_cid == kIllegalCid);
+ // Following jump cannot not occur, fall through.
+ }
+ __ j(NOT_EQUAL, fail);
+ }
+ __ Bind(&skip_length_check);
__ cmpl(value_cid_reg, field_nullability_operand);
} else if (value_cid == kNullCid) {
+ // Value in graph known to be null.
+ // Compare with null.
__ cmpl(field_nullability_operand, Immediate(value_cid));
} else {
+ // Value in graph known to be non-null.
+ Label skip_length_check;
+ // Compare class id with guard field class id.
__ cmpl(field_cid_operand, Immediate(value_cid));
+ // If not equal, skip over length check.
+ __ j(NOT_EQUAL, &skip_length_check);
+ // Insert length check.
+ if (field_has_length) {
+ if (value_cid_reg == kNoRegister) {
+ ASSERT(!compiler->is_optimizing());
+ value_cid_reg = EDX;
+ ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg));
+ }
+ ASSERT(value_cid_reg != kNoRegister);
+ if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
+ __ pushl(value_cid_reg);
+ __ movl(value_cid_reg,
+ FieldAddress(value_reg, Array::length_offset()));
+ __ cmpl(value_cid_reg, Immediate(field_length));
+ __ popl(value_cid_reg);
+ } else if (RawObject::IsTypedDataClassId(field_cid)) {
+ __ pushl(value_cid_reg);
+ __ movl(value_cid_reg,
+ FieldAddress(value_reg, TypedData::length_offset()));
+ __ cmpl(value_cid_reg, Immediate(field_length));
+ __ popl(value_cid_reg);
+ } else {
+ ASSERT(field_cid == kIllegalCid);
+ // Following jump cannot not occur, fall through.
+ }
+ }
+ // Not identical, possibly null.
+ __ Bind(&skip_length_check);
}
+ // Jump when class id guard and list length guard are okay.
__ j(EQUAL, &ok);
+
+ // Check if guard field is uninitialized.
__ cmpl(field_cid_operand, Immediate(kIllegalCid));
+ // Jump to failure path when guard field has been initialized and
+ // the field and value class ids do not not match.
__ j(NOT_EQUAL, fail);
+ // At this point the field guard is being initialized for the first time.
if (value_cid == kDynamicCid) {
+ // Do not know value's class id.
__ movl(field_cid_operand, value_cid_reg);
__ movl(field_nullability_operand, value_cid_reg);
+ if (field_has_length) {
+ Label check_array, local_exit, local_fail;
+ __ cmpl(value_cid_reg, Immediate(kNullCid));
+ __ j(EQUAL, &local_fail);
+ // Check for typed data array.
+ __ cmpl(value_cid_reg, Immediate(kTypedDataFloat32x4ArrayCid));
+ __ j(GREATER, &local_fail); // Not a typed array or a regular array.
+ __ cmpl(value_cid_reg, Immediate(kTypedDataInt8ArrayCid));
+ __ j(LESS, &check_array); // Could still be a regular array.
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ movl(value_cid_reg,
+ FieldAddress(value_reg, TypedData::length_offset()));
+ __ movl(field_length_operand, value_cid_reg);
+ __ jmp(&local_exit); // Updated field length typed data array.
+ // Check for regular array.
+ __ Bind(&check_array);
+ __ cmpl(value_cid_reg, Immediate(kImmutableArrayCid));
+ __ j(GREATER, &local_fail);
+ __ cmpl(value_cid_reg, Immediate(kArrayCid));
+ __ j(LESS, &local_fail);
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ movl(value_cid_reg,
+ FieldAddress(value_reg, Array::length_offset()));
+ __ movl(field_length_operand, value_cid_reg);
+ __ jmp(&local_exit); // Updated field length from regular array.
+
+ __ Bind(&local_fail);
+ __ movl(field_length_operand, Immediate(Field::kNoFixedLength));
+
+ __ Bind(&local_exit);
+ }
} else {
+ if (value_cid_reg == kNoRegister) {
+ ASSERT(!compiler->is_optimizing());
+ value_cid_reg = EDX;
+ ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg));
+ }
+ ASSERT(value_cid_reg != kNoRegister);
+ ASSERT(field_reg != kNoRegister);
__ movl(field_cid_operand, Immediate(value_cid));
__ movl(field_nullability_operand, Immediate(value_cid));
+ if ((value_cid == kArrayCid) || (value_cid == kImmutableArrayCid)) {
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ movl(value_cid_reg,
+ FieldAddress(value_reg, Array::length_offset()));
+ __ movl(field_length_operand, value_cid_reg);
+ } else if (RawObject::IsTypedDataClassId(value_cid)) {
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ movl(value_cid_reg,
+ FieldAddress(value_reg, TypedData::length_offset()));
+ __ movl(field_length_operand, value_cid_reg);
+ } else {
+ __ movl(field_length_operand, Immediate(Field::kNoFixedLength));
+ }
}
if (!ok_is_fall_through) {
__ jmp(&ok);
}
} else {
+ // Field guard class has been initialized and is known.
+
+ if (field_reg != kNoRegister) {
+ __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
+ }
+
if (value_cid == kDynamicCid) {
- // Field's guarded class id is fixed by value's class id is not known.
+ // Value's class id is not known.
__ testl(value_reg, Immediate(kSmiTagMask));
if (field_cid != kSmiCid) {
@@ -1676,6 +1815,27 @@
__ cmpl(value_cid_reg, Immediate(field_cid));
}
+ if (field_has_length) {
+ // Jump when Value CID != Field guard CID
+ __ j(NOT_EQUAL, fail);
+
+ // Classes are same, perform guarded list length check.
+ ASSERT(field_reg != kNoRegister);
+ ASSERT(value_cid_reg != kNoRegister);
+ FieldAddress field_length_operand(
+ field_reg, Field::guarded_list_length_offset());
+ if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ movl(value_cid_reg,
+ FieldAddress(value_reg, Array::length_offset()));
+ } else if (RawObject::IsTypedDataClassId(field_cid)) {
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ movl(value_cid_reg,
+ FieldAddress(value_reg, TypedData::length_offset()));
+ }
+ __ cmpl(value_cid_reg, field_length_operand);
+ }
+
if (field().is_nullable() && (field_cid != kNullCid)) {
__ j(EQUAL, &ok);
const Immediate& raw_null =
@@ -1694,6 +1854,21 @@
if (ok_is_fall_through) {
__ jmp(fail);
}
+ } else if (field_has_length && (value_cid == field_cid)) {
+ ASSERT(value_cid_reg != kNoRegister);
+ if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ movl(value_cid_reg,
+ FieldAddress(value_reg, Array::length_offset()));
+ } else if (RawObject::IsTypedDataClassId(field_cid)) {
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ movl(value_cid_reg,
+ FieldAddress(value_reg, TypedData::length_offset()));
+ }
+ __ cmpl(value_cid_reg, Immediate(field_length));
+ if (ok_is_fall_through) {
+ __ j(NOT_EQUAL, fail);
+ }
} else {
// Nothing to emit.
ASSERT(!compiler->is_optimizing());
@@ -3065,6 +3240,26 @@
}
+LocationSummary* Simd32x4GetSignMaskInstr::MakeLocationSummary() const {
+ const intptr_t kNumInputs = 1;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ summary->set_in(0, Location::RequiresFpuRegister());
+ summary->set_out(Location::RequiresRegister());
+ return summary;
+}
+
+
+void Simd32x4GetSignMaskInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ XmmRegister value = locs()->in(0).fpu_reg();
+ Register out = locs()->out().reg();
+
+ __ movmskps(out, value);
+ __ SmiTag(out);
+}
+
+
LocationSummary* Float32x4ConstructorInstr::MakeLocationSummary() const {
const intptr_t kNumInputs = 4;
const intptr_t kNumTemps = 0;
@@ -3687,6 +3882,12 @@
__ xorps(left, right);
break;
}
+ case Token::kADD:
+ __ addpl(left, right);
+ break;
+ case Token::kSUB:
+ __ subpl(left, right);
+ break;
default: UNREACHABLE();
}
}
@@ -4000,7 +4201,7 @@
}
// For pow-function return NaN if exponent is NaN.
Label do_call, skip_call;
- if (recognized_kind() == MethodRecognizer::kDoublePow) {
+ if (recognized_kind() == MethodRecognizer::kMathDoublePow) {
XmmRegister exp = locs()->in(1).fpu_reg();
__ comisd(exp, exp);
__ j(PARITY_ODD, &do_call, Assembler::kNearJump); // NaN -> false;
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc
index e84f418..d32428a 100644
--- a/runtime/vm/intermediate_language_mips.cc
+++ b/runtime/vm/intermediate_language_mips.cc
@@ -1573,11 +1573,16 @@
LocationSummary* summary =
new LocationSummary(kNumInputs, 0, LocationSummary::kNoCall);
summary->set_in(0, Location::RequiresRegister());
- if ((value()->Type()->ToCid() == kDynamicCid) &&
- (field().guarded_cid() != kSmiCid)) {
+ const bool field_has_length = field().needs_length_check();
+ const bool need_value_temp_reg =
+ (field_has_length || ((value()->Type()->ToCid() == kDynamicCid) &&
+ (field().guarded_cid() != kSmiCid)));
+ if (need_value_temp_reg) {
summary->AddTemp(Location::RequiresRegister());
}
- if (field().guarded_cid() == kIllegalCid) {
+ const bool need_field_temp_reg =
+ field_has_length || (field().guarded_cid() == kIllegalCid);
+ if (need_field_temp_reg) {
summary->AddTemp(Location::RequiresRegister());
}
return summary;
@@ -1588,6 +1593,17 @@
__ TraceSimMsg("GuardFieldInstr");
const intptr_t field_cid = field().guarded_cid();
const intptr_t nullability = field().is_nullable() ? kNullCid : kIllegalCid;
+ const intptr_t field_length = field().guarded_list_length();
+ const bool field_has_length = field().needs_length_check();
+ const bool needs_value_temp_reg =
+ (field_has_length || ((value()->Type()->ToCid() == kDynamicCid) &&
+ (field().guarded_cid() != kSmiCid)));
+ const bool needs_field_temp_reg =
+ field_has_length || (field().guarded_cid() == kIllegalCid);
+ if (field_has_length) {
+ // Currently, we should only see final fields that remember length.
+ ASSERT(field().is_final());
+ }
if (field_cid == kDynamicCid) {
ASSERT(!compiler->is_optimizing());
@@ -1598,10 +1614,10 @@
Register value_reg = locs()->in(0).reg();
- Register value_cid_reg = ((value_cid == kDynamicCid) &&
- (field_cid != kSmiCid)) ? locs()->temp(0).reg() : kNoRegister;
+ Register value_cid_reg = needs_value_temp_reg ?
+ locs()->temp(0).reg() : kNoRegister;
- Register field_reg = (field_cid == kIllegalCid) ?
+ Register field_reg = needs_field_temp_reg ?
locs()->temp(locs()->temp_count() - 1).reg() : kNoRegister;
Label ok, fail_label;
@@ -1614,7 +1630,7 @@
const bool ok_is_fall_through = (deopt != NULL);
if (!compiler->is_optimizing() || (field_cid == kIllegalCid)) {
- if (!compiler->is_optimizing()) {
+ if (!compiler->is_optimizing() && (field_reg == kNoRegister)) {
// Currently we can't have different location summaries for optimized
// and non-optimized code. So instead we manually pick up a register
// that is known to be free because we know how non-optimizing compiler
@@ -1628,6 +1644,8 @@
FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset());
FieldAddress field_nullability_operand(
field_reg, Field::is_nullable_offset());
+ FieldAddress field_length_operand(
+ field_reg, Field::guarded_list_length_offset());
if (value_cid == kDynamicCid) {
if (value_cid_reg == kNoRegister) {
@@ -1638,8 +1656,27 @@
LoadValueCid(compiler, value_cid_reg, value_reg);
+ Label skip_length_check;
+
__ lw(CMPRES1, field_cid_operand);
- __ beq(value_cid_reg, CMPRES1, &ok);
+ __ bne(value_cid_reg, CMPRES1, &skip_length_check);
+ if (field_has_length) {
+ // Field guard may have remembered list length, check it.
+ if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
+ __ lw(TMP, FieldAddress(value_reg, Array::length_offset()));
+ __ LoadImmediate(CMPRES1, field_length);
+ __ subu(CMPRES1, TMP, CMPRES1);
+ } else if (RawObject::IsTypedDataClassId(field_cid)) {
+ __ lw(TMP, FieldAddress(value_reg, TypedData::length_offset()));
+ __ LoadImmediate(CMPRES1, field_length);
+ __ subu(CMPRES1, TMP, CMPRES1);
+ } else {
+ ASSERT(field_cid == kIllegalCid);
+ __ LoadImmediate(CMPRES1, 0x1);
+ }
+ __ bne(CMPRES1, ZR, fail);
+ }
+ __ Bind(&skip_length_check);
__ lw(TMP1, field_nullability_operand);
__ subu(CMPRES, value_cid_reg, TMP1);
} else if (value_cid == kNullCid) {
@@ -1648,10 +1685,34 @@
__ LoadImmediate(CMPRES, value_cid);
__ subu(CMPRES, TMP1, CMPRES);
} else {
+ Label skip_length_check;
// TODO(regis): TMP1 may conflict. Revisit.
__ lw(TMP1, field_cid_operand);
__ LoadImmediate(CMPRES, value_cid);
__ subu(CMPRES, TMP1, CMPRES);
+ __ bne(CMPRES, ZR, &skip_length_check);
+ // Insert length check.
+ if (field_has_length) {
+ if (value_cid_reg == kNoRegister) {
+ ASSERT(!compiler->is_optimizing());
+ value_cid_reg = A1;
+ ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg));
+ }
+ ASSERT(value_cid_reg != kNoRegister);
+ if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
+ __ lw(TMP, FieldAddress(value_reg, Array::length_offset()));
+ __ LoadImmediate(CMPRES, field_length);
+ __ subu(CMPRES, TMP, CMPRES);
+ } else if (RawObject::IsTypedDataClassId(field_cid)) {
+ __ lw(TMP, FieldAddress(value_reg, TypedData::length_offset()));
+ __ LoadImmediate(CMPRES, field_length);
+ __ subu(CMPRES, TMP, CMPRES);
+ } else {
+ ASSERT(field_cid == kIllegalCid);
+ __ LoadImmediate(CMPRES, 0x1);
+ }
+ }
+ __ Bind(&skip_length_check);
}
__ beq(CMPRES, ZR, &ok);
@@ -1661,16 +1722,72 @@
if (value_cid == kDynamicCid) {
__ sw(value_cid_reg, field_cid_operand);
__ sw(value_cid_reg, field_nullability_operand);
+ if (field_has_length) {
+ Label check_array, local_exit, local_fail;
+ __ BranchEqual(value_cid_reg, kNullCid, &local_fail);
+ // Check for typed data array.
+ __ BranchSignedGreater(value_cid_reg, kTypedDataFloat32x4ArrayCid,
+ &local_fail);
+ __ BranchSignedLess(value_cid_reg, kTypedDataInt8ArrayCid,
+ &check_array);
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ lw(value_cid_reg,
+ FieldAddress(value_reg, TypedData::length_offset()));
+ __ sw(value_cid_reg, field_length_operand);
+ __ b(&local_exit); // Updated field length typed data array.
+ // Check for regular array.
+ __ Bind(&check_array);
+ __ BranchSignedGreater(value_cid_reg, kImmutableArrayCid,
+ &local_fail);
+ __ BranchSignedLess(value_cid_reg, kArrayCid, &local_fail);
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ lw(value_cid_reg,
+ FieldAddress(value_reg, Array::length_offset()));
+ __ sw(value_cid_reg, field_length_operand);
+ __ b(&local_exit); // Updated field length from regular array.
+
+ __ Bind(&local_fail);
+ // TODO(regis): TMP1 may conflict. Revisit.
+ __ LoadImmediate(TMP1, Field::kNoFixedLength);
+ __ sw(TMP1, field_length_operand);
+
+ __ Bind(&local_exit);
+ }
} else {
+ if (value_cid_reg == kNoRegister) {
+ ASSERT(!compiler->is_optimizing());
+ value_cid_reg = A1;
+ ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg));
+ }
+ ASSERT(value_cid_reg != kNoRegister);
+ ASSERT(field_reg != kNoRegister);
__ LoadImmediate(TMP1, value_cid);
__ sw(TMP1, field_cid_operand);
__ sw(TMP1, field_nullability_operand);
+ if ((value_cid == kArrayCid) || (value_cid == kImmutableArrayCid)) {
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ lw(value_cid_reg,
+ FieldAddress(value_reg, Array::length_offset()));
+ __ sw(value_cid_reg, field_length_operand);
+ } else if (RawObject::IsTypedDataClassId(value_cid)) {
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ lw(value_cid_reg,
+ FieldAddress(value_reg, TypedData::length_offset()));
+ __ sw(value_cid_reg, field_length_operand);
+ } else {
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ LoadImmediate(value_cid_reg, Field::kNoFixedLength);
+ __ sw(value_cid_reg, field_length_operand);
+ }
}
if (!ok_is_fall_through) {
__ b(&ok);
}
} else {
+ if (field_reg != kNoRegister) {
+ __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
+ }
if (value_cid == kDynamicCid) {
// Field's guarded class id is fixed by value's class id is not known.
__ andi(CMPRES, value_reg, Immediate(kSmiTagMask));
@@ -1682,6 +1799,27 @@
__ subu(CMPRES, value_cid_reg, TMP1);
}
+ if (field_has_length) {
+ // Jump when Value CID != Field guard CID
+ __ bne(CMPRES, ZR, fail);
+ // Classes are same, perform guarded list length check.
+ ASSERT(field_reg != kNoRegister);
+ ASSERT(value_cid_reg != kNoRegister);
+ FieldAddress field_length_operand(
+ field_reg, Field::guarded_list_length_offset());
+ if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ lw(value_cid_reg,
+ FieldAddress(value_reg, Array::length_offset()));
+ } else if (RawObject::IsTypedDataClassId(field_cid)) {
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ lw(value_cid_reg,
+ FieldAddress(value_reg, TypedData::length_offset()));
+ }
+ __ lw(TMP1, field_length_operand);
+ __ subu(CMPRES, value_cid_reg, TMP1);
+ }
+
if (field().is_nullable() && (field_cid != kNullCid)) {
__ beq(CMPRES, ZR, &ok);
__ LoadImmediate(TMP, reinterpret_cast<int32_t>(Object::null()));
@@ -1699,6 +1837,22 @@
if (ok_is_fall_through) {
__ b(fail);
}
+ } else if (field_has_length && (value_cid == field_cid)) {
+ ASSERT(value_cid_reg != kNoRegister);
+ if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ lw(value_cid_reg,
+ FieldAddress(value_reg, Array::length_offset()));
+ } else if (RawObject::IsTypedDataClassId(field_cid)) {
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ lw(value_cid_reg,
+ FieldAddress(value_reg, TypedData::length_offset()));
+ }
+ __ LoadImmediate(TMP1, field_length);
+ __ subu(CMPRES, value_cid_reg, TMP1);
+ if (ok_is_fall_through) {
+ __ bne(CMPRES, ZR, fail);
+ }
} else {
// Nothing to emit.
ASSERT(!compiler->is_optimizing());
@@ -3041,6 +3195,17 @@
}
+LocationSummary* Simd32x4GetSignMaskInstr::MakeLocationSummary() const {
+ UNIMPLEMENTED();
+ return NULL;
+}
+
+
+void Simd32x4GetSignMaskInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ UNIMPLEMENTED();
+}
+
+
LocationSummary* Uint32x4SelectInstr::MakeLocationSummary() const {
UNIMPLEMENTED();
return NULL;
@@ -3375,7 +3540,7 @@
void InvokeMathCFunctionInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
// For pow-function return NaN if exponent is NaN.
Label do_call, skip_call;
- if (recognized_kind() == MethodRecognizer::kDoublePow) {
+ if (recognized_kind() == MethodRecognizer::kMathDoublePow) {
DRegister exp = locs()->in(1).fpu_reg();
__ cund(exp, exp);
__ bc1f(&do_call);
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index 2a1a546..c5a1bf3 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -1536,11 +1536,16 @@
LocationSummary* summary =
new LocationSummary(kNumInputs, 0, LocationSummary::kNoCall);
summary->set_in(0, Location::RequiresRegister());
- if ((value()->Type()->ToCid() == kDynamicCid) &&
- (field().guarded_cid() != kSmiCid)) {
+ const bool field_has_length = field().needs_length_check();
+ const bool need_value_temp_reg =
+ (field_has_length || ((value()->Type()->ToCid() == kDynamicCid) &&
+ (field().guarded_cid() != kSmiCid)));
+ if (need_value_temp_reg) {
summary->AddTemp(Location::RequiresRegister());
}
- if (field().guarded_cid() == kIllegalCid) {
+ const bool need_field_temp_reg =
+ field_has_length || (field().guarded_cid() == kIllegalCid);
+ if (need_field_temp_reg) {
summary->AddTemp(Location::RequiresRegister());
}
return summary;
@@ -1550,6 +1555,17 @@
void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
const intptr_t field_cid = field().guarded_cid();
const intptr_t nullability = field().is_nullable() ? kNullCid : kIllegalCid;
+ const intptr_t field_length = field().guarded_list_length();
+ const bool field_has_length = field().needs_length_check();
+ const bool needs_value_temp_reg =
+ (field_has_length || ((value()->Type()->ToCid() == kDynamicCid) &&
+ (field().guarded_cid() != kSmiCid)));
+ const bool needs_field_temp_reg =
+ field_has_length || (field().guarded_cid() == kIllegalCid);
+ if (field_has_length) {
+ // Currently, we should only see final fields that remember length.
+ ASSERT(field().is_final());
+ }
if (field_cid == kDynamicCid) {
ASSERT(!compiler->is_optimizing());
@@ -1560,10 +1576,10 @@
Register value_reg = locs()->in(0).reg();
- Register value_cid_reg = ((value_cid == kDynamicCid) &&
- (field_cid != kSmiCid)) ? locs()->temp(0).reg() : kNoRegister;
+ Register value_cid_reg = needs_value_temp_reg ?
+ locs()->temp(0).reg() : kNoRegister;
- Register field_reg = (field_cid == kIllegalCid) ?
+ Register field_reg = needs_field_temp_reg ?
locs()->temp(locs()->temp_count() - 1).reg() : kNoRegister;
Label ok, fail_label;
@@ -1576,7 +1592,7 @@
const bool ok_is_fall_through = (deopt != NULL);
if (!compiler->is_optimizing() || (field_cid == kIllegalCid)) {
- if (!compiler->is_optimizing()) {
+ if (!compiler->is_optimizing() && (field_reg == kNoRegister)) {
// Currently we can't have different location summaries for optimized
// and non-optimized code. So instead we manually pick up a register
// that is known to be free because we know how non-optimizing compiler
@@ -1590,6 +1606,8 @@
FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset());
FieldAddress field_nullability_operand(
field_reg, Field::is_nullable_offset());
+ FieldAddress field_length_operand(
+ field_reg, Field::guarded_list_length_offset());
if (value_cid == kDynamicCid) {
if (value_cid_reg == kNoRegister) {
@@ -1600,13 +1618,65 @@
LoadValueCid(compiler, value_cid_reg, value_reg);
+ Label skip_length_check;
__ cmpq(value_cid_reg, field_cid_operand);
- __ j(EQUAL, &ok);
+ __ j(NOT_EQUAL, &skip_length_check);
+ if (field_has_length) {
+ // Field guard may have remembered list length, check it.
+ if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
+ __ pushq(value_cid_reg);
+ __ movq(value_cid_reg,
+ FieldAddress(value_reg, Array::length_offset()));
+ __ cmpq(value_cid_reg, Immediate(field_length));
+ __ popq(value_cid_reg);
+ } else if (RawObject::IsTypedDataClassId(field_cid)) {
+ __ pushq(value_cid_reg);
+ __ movq(value_cid_reg,
+ FieldAddress(value_reg, TypedData::length_offset()));
+ __ cmpq(value_cid_reg, Immediate(field_length));
+ __ popq(value_cid_reg);
+ } else {
+ ASSERT(field_cid == kIllegalCid);
+ // Following jump cannot not occur, fall through.
+ }
+ __ j(NOT_EQUAL, fail);
+ }
+ __ Bind(&skip_length_check);
__ cmpq(value_cid_reg, field_nullability_operand);
} else if (value_cid == kNullCid) {
__ cmpq(field_nullability_operand, Immediate(value_cid));
} else {
+ Label skip_length_check;
__ cmpq(field_cid_operand, Immediate(value_cid));
+ // If not equal, skip over length check.
+ __ j(NOT_EQUAL, &skip_length_check);
+ // Insert length check.
+ if (field_has_length) {
+ if (value_cid_reg == kNoRegister) {
+ ASSERT(!compiler->is_optimizing());
+ value_cid_reg = RDX;
+ ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg));
+ }
+ ASSERT(value_cid_reg != kNoRegister);
+ if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
+ __ pushq(value_cid_reg);
+ __ movq(value_cid_reg,
+ FieldAddress(value_reg, Array::length_offset()));
+ __ cmpq(value_cid_reg, Immediate(field_length));
+ __ popq(value_cid_reg);
+ } else if (RawObject::IsTypedDataClassId(field_cid)) {
+ __ pushq(value_cid_reg);
+ __ movq(value_cid_reg,
+ FieldAddress(value_reg, TypedData::length_offset()));
+ __ cmpq(value_cid_reg, Immediate(field_length));
+ __ popq(value_cid_reg);
+ } else {
+ ASSERT(field_cid == kIllegalCid);
+ // Following jump cannot not occur, fall through.
+ }
+ }
+ // Not identical, possibly null.
+ __ Bind(&skip_length_check);
}
__ j(EQUAL, &ok);
@@ -1616,15 +1686,70 @@
if (value_cid == kDynamicCid) {
__ movq(field_cid_operand, value_cid_reg);
__ movq(field_nullability_operand, value_cid_reg);
+ if (field_has_length) {
+ Label check_array, local_exit, local_fail;
+ __ cmpq(value_cid_reg, Immediate(kNullCid));
+ __ j(EQUAL, &local_fail);
+ // Check for typed data array.
+ __ cmpq(value_cid_reg, Immediate(kTypedDataFloat32x4ArrayCid));
+ __ j(GREATER, &local_fail); // Not a typed array or a regular array.
+ __ cmpq(value_cid_reg, Immediate(kTypedDataInt8ArrayCid));
+ __ j(LESS, &check_array); // Could still be a regular array.
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ movq(value_cid_reg,
+ FieldAddress(value_reg, TypedData::length_offset()));
+ __ movq(field_length_operand, value_cid_reg);
+ __ jmp(&local_exit); // Updated field length typed data array.
+ // Check for regular array.
+ __ Bind(&check_array);
+ __ cmpq(value_cid_reg, Immediate(kImmutableArrayCid));
+ __ j(GREATER, &local_fail);
+ __ cmpq(value_cid_reg, Immediate(kArrayCid));
+ __ j(LESS, &local_fail);
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ movq(value_cid_reg,
+ FieldAddress(value_reg, Array::length_offset()));
+ __ movq(field_length_operand, value_cid_reg);
+ __ jmp(&local_exit); // Updated field length from regular array.
+
+ __ Bind(&local_fail);
+ __ movq(field_length_operand, Immediate(Field::kNoFixedLength));
+
+ __ Bind(&local_exit);
+ }
} else {
+ if (value_cid_reg == kNoRegister) {
+ ASSERT(!compiler->is_optimizing());
+ value_cid_reg = RDX;
+ ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg));
+ }
+ ASSERT(value_cid_reg != kNoRegister);
+ ASSERT(field_reg != kNoRegister);
__ movq(field_cid_operand, Immediate(value_cid));
__ movq(field_nullability_operand, Immediate(value_cid));
+ if ((value_cid == kArrayCid) || (value_cid == kImmutableArrayCid)) {
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ movq(value_cid_reg,
+ FieldAddress(value_reg, Array::length_offset()));
+ __ movq(field_length_operand, value_cid_reg);
+ } else if (RawObject::IsTypedDataClassId(value_cid)) {
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ movq(value_cid_reg,
+ FieldAddress(value_reg, TypedData::length_offset()));
+ __ movq(field_length_operand, value_cid_reg);
+ } else {
+ __ movq(field_length_operand, Immediate(Field::kNoFixedLength));
+ }
}
if (!ok_is_fall_through) {
__ jmp(&ok);
}
} else {
+ if (field_reg != kNoRegister) {
+ __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
+ }
+
if (value_cid == kDynamicCid) {
// Field's guarded class id is fixed but value's class id is not known.
__ testq(value_reg, Immediate(kSmiTagMask));
@@ -1635,6 +1760,27 @@
__ cmpq(value_cid_reg, Immediate(field_cid));
}
+ if (field_has_length) {
+ // Jump when Value CID != Field guard CID
+ __ j(NOT_EQUAL, fail);
+
+ // Classes are same, perform guarded list length check.
+ ASSERT(field_reg != kNoRegister);
+ ASSERT(value_cid_reg != kNoRegister);
+ FieldAddress field_length_operand(
+ field_reg, Field::guarded_list_length_offset());
+ if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ movq(value_cid_reg,
+ FieldAddress(value_reg, Array::length_offset()));
+ } else if (RawObject::IsTypedDataClassId(field_cid)) {
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ movq(value_cid_reg,
+ FieldAddress(value_reg, TypedData::length_offset()));
+ }
+ __ cmpq(value_cid_reg, field_length_operand);
+ }
+
if (field().is_nullable() && (field_cid != kNullCid)) {
__ j(EQUAL, &ok);
const Immediate& raw_null =
@@ -1653,6 +1799,21 @@
if (ok_is_fall_through) {
__ jmp(fail);
}
+ } else if (field_has_length && (value_cid == field_cid)) {
+ ASSERT(value_cid_reg != kNoRegister);
+ if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ movq(value_cid_reg,
+ FieldAddress(value_reg, Array::length_offset()));
+ } else if (RawObject::IsTypedDataClassId(field_cid)) {
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ movq(value_cid_reg,
+ FieldAddress(value_reg, TypedData::length_offset()));
+ }
+ __ cmpq(value_cid_reg, Immediate(field_length));
+ if (ok_is_fall_through) {
+ __ j(NOT_EQUAL, fail);
+ }
} else {
// Nothing to emit.
ASSERT(!compiler->is_optimizing());
@@ -3089,6 +3250,26 @@
}
+LocationSummary* Simd32x4GetSignMaskInstr::MakeLocationSummary() const {
+ const intptr_t kNumInputs = 1;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ summary->set_in(0, Location::RequiresFpuRegister());
+ summary->set_out(Location::RequiresRegister());
+ return summary;
+}
+
+
+void Simd32x4GetSignMaskInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ XmmRegister value = locs()->in(0).fpu_reg();
+ Register out = locs()->out().reg();
+
+ __ movmskps(out, value);
+ __ SmiTag(out);
+}
+
+
LocationSummary* Float32x4ConstructorInstr::MakeLocationSummary() const {
const intptr_t kNumInputs = 4;
const intptr_t kNumTemps = 0;
@@ -3728,6 +3909,12 @@
__ xorps(left, right);
break;
}
+ case Token::kADD:
+ __ addpl(left, right);
+ break;
+ case Token::kSUB:
+ __ subpl(left, right);
+ break;
default: UNREACHABLE();
}
}
@@ -4069,7 +4256,7 @@
}
// For pow-function return NaN if exponent is NaN.
Label do_call, skip_call;
- if (recognized_kind() == MethodRecognizer::kDoublePow) {
+ if (recognized_kind() == MethodRecognizer::kMathDoublePow) {
XmmRegister exp = locs()->in(1).fpu_reg();
__ comisd(exp, exp);
__ j(PARITY_ODD, &do_call, Assembler::kNearJump); // NaN -> false;
diff --git a/runtime/vm/intrinsifier.h b/runtime/vm/intrinsifier.h
index 3f22ad0..0391beb 100644
--- a/runtime/vm/intrinsifier.h
+++ b/runtime/vm/intrinsifier.h
@@ -66,8 +66,9 @@
V(_IntegerImplementation, _mulFromInteger, Integer_mulFromInteger, \
1145805333) \
V(_IntegerImplementation, *, Integer_mul, 1935440252) \
- V(_IntegerImplementation, %, Integer_modulo, 1121942909) \
V(_IntegerImplementation, remainder, Integer_remainder, 2140653009) \
+ V(_IntegerImplementation, _moduloFromInteger, Integer_moduloFromInteger, \
+ 713610917) \
V(_IntegerImplementation, ~/, Integer_truncDivide, 250357385) \
V(_IntegerImplementation, unary-, Integer_negate, 732448114) \
V(_IntegerImplementation, _bitAndFromInteger, \
diff --git a/runtime/vm/intrinsifier_arm.cc b/runtime/vm/intrinsifier_arm.cc
index b042601..312912e 100644
--- a/runtime/vm/intrinsifier_arm.cc
+++ b/runtime/vm/intrinsifier_arm.cc
@@ -712,10 +712,14 @@
// res = res + right;
// }
// }
-bool Intrinsifier::Integer_modulo(Assembler* assembler) {
+bool Intrinsifier::Integer_moduloFromInteger(Assembler* assembler) {
// Check to see if we have integer division
Label fall_through, subtract;
- TestBothArgumentsSmis(assembler, &fall_through);
+ __ ldr(R1, Address(SP, + 0 * kWordSize));
+ __ ldr(R0, Address(SP, + 1 * kWordSize));
+ __ orr(TMP, R0, ShifterOperand(R1));
+ __ tst(TMP, ShifterOperand(kSmiTagMask));
+ __ b(&fall_through, NE);
// R1: Tagged left (dividend).
// R0: Tagged right (divisor).
// Check if modulo by zero -> exception thrown in main function.
diff --git a/runtime/vm/intrinsifier_ia32.cc b/runtime/vm/intrinsifier_ia32.cc
index 650769a..07932b0 100644
--- a/runtime/vm/intrinsifier_ia32.cc
+++ b/runtime/vm/intrinsifier_ia32.cc
@@ -715,12 +715,10 @@
// res = res + right;
// }
// }
-bool Intrinsifier::Integer_modulo(Assembler* assembler) {
+bool Intrinsifier::Integer_moduloFromInteger(Assembler* assembler) {
Label fall_through, subtract;
TestBothArgumentsSmis(assembler, &fall_through);
- // EAX: right argument (divisor)
- __ movl(EBX, EAX);
- __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Left argument (dividend).
+ __ movl(EBX, Address(ESP, + 2 * kWordSize));
// EAX: Tagged left (dividend).
// EBX: Tagged right (divisor).
// Check if modulo by zero -> exception thrown in main function.
diff --git a/runtime/vm/intrinsifier_mips.cc b/runtime/vm/intrinsifier_mips.cc
index 61c0a82..517e89b 100644
--- a/runtime/vm/intrinsifier_mips.cc
+++ b/runtime/vm/intrinsifier_mips.cc
@@ -721,9 +721,14 @@
// res = res + right;
// }
// }
-bool Intrinsifier::Integer_modulo(Assembler* assembler) {
+bool Intrinsifier::Integer_moduloFromInteger(Assembler* assembler) {
Label fall_through, subtract;
- TestBothArgumentsSmis(assembler, &fall_through);
+ // Test arguments for smi.
+ __ lw(T1, Address(SP, 0 * kWordSize));
+ __ lw(T0, Address(SP, 1 * kWordSize));
+ __ or_(CMPRES, T0, T1);
+ __ andi(CMPRES, CMPRES, Immediate(kSmiTagMask));
+ __ bne(CMPRES, ZR, &fall_through);
// T1: Tagged left (dividend).
// T0: Tagged right (divisor).
// Check if modulo by zero -> exception thrown in main function.
diff --git a/runtime/vm/intrinsifier_x64.cc b/runtime/vm/intrinsifier_x64.cc
index c6916ec..aa3ebff 100644
--- a/runtime/vm/intrinsifier_x64.cc
+++ b/runtime/vm/intrinsifier_x64.cc
@@ -703,12 +703,10 @@
// res = res + right;
// }
// }
-bool Intrinsifier::Integer_modulo(Assembler* assembler) {
+bool Intrinsifier::Integer_moduloFromInteger(Assembler* assembler) {
Label fall_through, negative_result;
TestBothArgumentsSmis(assembler, &fall_through);
- // RAX: right argument (divisor)
- __ movq(RCX, RAX);
- __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Left argument (dividend).
+ __ movq(RCX, Address(RSP, + 2 * kWordSize));
// RAX: Tagged left (dividend).
// RCX: Tagged right (divisor).
__ cmpq(RCX, Immediate(0));
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 780f419..a572e76 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -273,7 +273,7 @@
*double_slot = Double::New(value());
if (FLAG_trace_deoptimization_verbose) {
- OS::PrintErr("materializing double at %"Px": %g\n",
+ OS::PrintErr("materializing double at %" Px ": %g\n",
reinterpret_cast<uword>(slot()), value());
}
}
@@ -287,7 +287,7 @@
*mint_slot = mint.raw();
if (FLAG_trace_deoptimization_verbose) {
- OS::PrintErr("materializing mint at %"Px": %"Pd64"\n",
+ OS::PrintErr("materializing mint at %" Px ": %" Pd64 "\n",
reinterpret_cast<uword>(slot()), value());
}
}
@@ -303,7 +303,7 @@
float y = raw_float32x4->y();
float z = raw_float32x4->z();
float w = raw_float32x4->w();
- OS::PrintErr("materializing Float32x4 at %"Px": %g,%g,%g,%g\n",
+ OS::PrintErr("materializing Float32x4 at %" Px ": %g,%g,%g,%g\n",
reinterpret_cast<uword>(slot()), x, y, z, w);
}
}
@@ -319,7 +319,7 @@
uint32_t y = raw_uint32x4->y();
uint32_t z = raw_uint32x4->z();
uint32_t w = raw_uint32x4->w();
- OS::PrintErr("materializing Uint32x4 at %"Px": %x,%x,%x,%x\n",
+ OS::PrintErr("materializing Uint32x4 at %" Px ": %x,%x,%x,%x\n",
reinterpret_cast<uword>(slot()), x, y, z, w);
}
}
@@ -329,7 +329,7 @@
DeferredObject* obj = Isolate::Current()->GetDeferredObject(index());
*slot() = obj->object();
if (FLAG_trace_deoptimization_verbose) {
- OS::PrintErr("writing instance ref at %"Px": %s\n",
+ OS::PrintErr("writing instance ref at %" Px ": %s\n",
reinterpret_cast<uword>(slot()),
Instance::Handle(obj->object()).ToCString());
}
@@ -349,7 +349,7 @@
cls ^= GetClass();
if (FLAG_trace_deoptimization_verbose) {
- OS::PrintErr("materializing instance of %s (%"Px", %"Pd" fields)\n",
+ OS::PrintErr("materializing instance of %s (%" Px ", %" Pd " fields)\n",
cls.ToCString(),
reinterpret_cast<uword>(args_),
field_count_);
@@ -730,7 +730,7 @@
}
invoked_functions.Sort(MostUsedFunctionFirst);
for (int i = 0; i < invoked_functions.length(); i++) {
- OS::Print("%10"Pd" x %s\n",
+ OS::Print("%10" Pd " x %s\n",
invoked_functions[i]->usage_counter(),
invoked_functions[i]->ToFullyQualifiedCString());
}
@@ -881,7 +881,7 @@
MonitorLocker ml(status_sync);
DebuggerStackTrace* stack = Debugger::CollectStackTrace();
TextBuffer buffer(256);
- buffer.Printf("{ \"handle\": \"0x%"Px64"\", \"stacktrace\": [ ",
+ buffer.Printf("{ \"handle\": \"0x%" Px64 "\", \"stacktrace\": [ ",
reinterpret_cast<int64_t>(isolate));
intptr_t n_frames = stack->Length();
String& url = String::Handle();
@@ -890,11 +890,11 @@
if (i > 0) {
buffer.Printf(", ");
}
- ActivationFrame* frame = stack->ActivationFrameAt(i);
+ ActivationFrame* frame = stack->FrameAt(i);
url ^= frame->SourceUrl();
function ^= frame->function().UserVisibleName();
buffer.Printf("{ \"url\": \"%s\", ", url.ToCString());
- buffer.Printf("\"line\": %"Pd", ", frame->LineNumber());
+ buffer.Printf("\"line\": %" Pd ", ", frame->LineNumber());
buffer.Printf("\"function\": \"%s\", ", function.ToCString());
const Code& code = frame->code();
@@ -920,13 +920,13 @@
// Frame no longer available.
return NULL;
}
- ActivationFrame* frame = stack->ActivationFrameAt(frame_index);
+ ActivationFrame* frame = stack->FrameAt(frame_index);
TextBuffer buffer(256);
- buffer.Printf("{ \"handle\": \"0x%"Px64"\", \"frame_index\": %"Pd", ",
+ buffer.Printf("{ \"handle\": \"0x%" Px64 "\", \"frame_index\": %" Pd ", ",
reinterpret_cast<int64_t>(isolate), frame_index);
const Code& code = frame->code();
- buffer.Printf("\"code\": { \"size\": %"Pd", ", code.Size());
+ buffer.Printf("\"code\": { \"size\": %" Pd ", ", code.Size());
buffer.Printf("\"alive\": %s, ", code.is_alive() ? "false" : "true");
buffer.Printf("\"optimized\": %s }, ",
code.is_optimized() ? "false" : "true");
@@ -943,7 +943,7 @@
intptr_t token_pos, end_pos;
frame->VariableAt(i, &var_name, &token_pos, &end_pos, &value);
buffer.Printf(
- "{ \"name\": \"%s\", \"pos\": %"Pd", \"end_pos\": %"Pd", "
+ "{ \"name\": \"%s\", \"pos\": %" Pd ", \"end_pos\": %" Pd ", "
"\"value\": \"%s\" }",
var_name.ToCString(), token_pos, end_pos, value.ToCString());
}
@@ -975,7 +975,7 @@
if (result == NULL) {
// Return empty stack.
TextBuffer buffer(256);
- buffer.Printf("{ \"handle\": \"0x%"Px64"\", \"stacktrace\": []}",
+ buffer.Printf("{ \"handle\": \"0x%" Px64 "\", \"stacktrace\": []}",
reinterpret_cast<int64_t>(this));
result = OS::StrNDup(buffer.buf(), buffer.length());
@@ -1002,18 +1002,18 @@
// Returns the isolate's general detail information.
char* Isolate::GetStatusDetails() {
const char* format = "{\n"
- " \"handle\": \"0x%"Px64"\",\n"
+ " \"handle\": \"0x%" Px64 "\",\n"
" \"name\": \"%s\",\n"
- " \"port\": %"Pd",\n"
- " \"starttime\": %"Pd",\n"
- " \"stacklimit\": %"Pd",\n"
+ " \"port\": %" Pd ",\n"
+ " \"starttime\": %" Pd ",\n"
+ " \"stacklimit\": %" Pd ",\n"
" \"newspace\": {\n"
- " \"used\": %"Pd",\n"
- " \"capacity\": %"Pd"\n"
+ " \"used\": %" Pd ",\n"
+ " \"capacity\": %" Pd "\n"
" },\n"
" \"oldspace\": {\n"
- " \"used\": %"Pd",\n"
- " \"capacity\": %"Pd"\n"
+ " \"used\": %" Pd ",\n"
+ " \"capacity\": %" Pd "\n"
" }\n"
"}";
char buffer[300];
diff --git a/runtime/vm/json_stream.cc b/runtime/vm/json_stream.cc
index 1aec0bc..ace783e 100644
--- a/runtime/vm/json_stream.cc
+++ b/runtime/vm/json_stream.cc
@@ -73,7 +73,7 @@
void JSONStream::PrintValue(intptr_t i) {
PrintCommaIfNeeded();
- buffer_->Printf("%"Pd"", i);
+ buffer_->Printf("%" Pd "", i);
}
diff --git a/runtime/vm/locations.cc b/runtime/vm/locations.cc
index 23ab978..fb19c1f 100644
--- a/runtime/vm/locations.cc
+++ b/runtime/vm/locations.cc
@@ -145,9 +145,9 @@
void Location::PrintTo(BufferFormatter* f) const {
if (kind() == kStackSlot) {
- f->Print("S%+"Pd"", stack_index());
+ f->Print("S%+" Pd "", stack_index());
} else if (kind() == kDoubleStackSlot) {
- f->Print("DS%+"Pd"", stack_index());
+ f->Print("DS%+" Pd "", stack_index());
} else {
f->Print("%s", Name());
}
@@ -156,7 +156,7 @@
void Location::Print() const {
if (kind() == kStackSlot) {
- OS::Print("S%+"Pd"", stack_index());
+ OS::Print("S%+" Pd "", stack_index());
} else {
OS::Print("%s", Name());
}
diff --git a/runtime/vm/megamorphic_cache_table.cc b/runtime/vm/megamorphic_cache_table.cc
index 6e6ed43..91272a1 100644
--- a/runtime/vm/megamorphic_cache_table.cc
+++ b/runtime/vm/megamorphic_cache_table.cc
@@ -92,7 +92,8 @@
size += MegamorphicCache::InstanceSize();
size += Array::InstanceSize(buckets.Length());
}
- OS::Print("%"Pd" megamorphic caches using %"Pd"KB.\n", length_, size / 1024);
+ OS::Print("%" Pd " megamorphic caches using %" Pd "KB.\n",
+ length_, size / 1024);
}
} // namespace dart
diff --git a/runtime/vm/message_handler.cc b/runtime/vm/message_handler.cc
index a3e2170..f5c068e 100644
--- a/runtime/vm/message_handler.cc
+++ b/runtime/vm/message_handler.cc
@@ -96,9 +96,9 @@
}
OS::Print("[>] Posting message:\n"
"\tsource: %s\n"
- "\treply_port: %"Pd64"\n"
+ "\treply_port: %" Pd64 "\n"
"\tdest: %s\n"
- "\tdest_port: %"Pd64"\n",
+ "\tdest_port: %" Pd64 "\n",
source_name, message->reply_port(), name(), message->dest_port());
}
@@ -142,7 +142,7 @@
if (FLAG_trace_isolates) {
OS::Print("[<] Handling message:\n"
"\thandler: %s\n"
- "\tport: %"Pd64"\n",
+ "\tport: %" Pd64 "\n",
name(), message->dest_port());
}
@@ -234,7 +234,7 @@
if (FLAG_trace_isolates) {
OS::Print("[-] Closing port:\n"
"\thandler: %s\n"
- "\tport: %"Pd64"\n",
+ "\tport: %" Pd64 "\n",
name(), port);
}
}
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index ca2a64d..af1c5e6 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -59,6 +59,8 @@
DECLARE_FLAG(bool, trace_compiler);
DECLARE_FLAG(bool, eliminate_type_checks);
DECLARE_FLAG(bool, enable_type_checks);
+DECLARE_FLAG(bool, trace_deoptimization);
+DECLARE_FLAG(bool, trace_deoptimization_verbose);
DECLARE_FLAG(bool, error_on_bad_override);
static const char* kGetterPrefix = "get:";
@@ -1887,7 +1889,7 @@
for (; i < desc.PositionalCount(); i++) {
invocation.SetParameterTypeAt(i, Type::Handle(Type::DynamicType()));
char name[64];
- OS::SNPrint(name, 64, ":p%"Pd, i);
+ OS::SNPrint(name, 64, ":p%" Pd, i);
invocation.SetParameterNameAt(i, String::Handle(Symbols::New(name)));
}
@@ -2511,6 +2513,11 @@
Error& args_malformed_error = Error::Handle();
for (intptr_t i = 0; i < interfaces.Length(); i++) {
interface ^= interfaces.At(i);
+ if (!interface.IsFinalized()) {
+ // We may be checking bounds at finalization time. Skipping this
+ // unfinalized interface will postpone bound checking to run time.
+ continue;
+ }
interface_class = interface.type_class();
interface_args = interface.arguments();
if (!interface_args.IsNull() && !interface_args.IsInstantiated()) {
@@ -2522,7 +2529,6 @@
// parameters of the interface are at the end of the type vector,
// after the type arguments of the super type of this type.
// The index of the type parameters is adjusted upon finalization.
- ASSERT(interface.IsFinalized());
args_malformed_error = Error::null();
interface_args = interface_args.InstantiateFrom(type_arguments,
&args_malformed_error);
@@ -3365,7 +3371,7 @@
RawTypeArguments* TypeArguments::New(intptr_t len, Heap::Space space) {
if (len < 0 || len > kMaxElements) {
// This should be caught before we reach here.
- FATAL1("Fatal error in TypeArguments::New: invalid len %"Pd"\n", len);
+ FATAL1("Fatal error in TypeArguments::New: invalid len %" Pd "\n", len);
}
TypeArguments& result = TypeArguments::Handle();
{
@@ -3693,7 +3699,7 @@
}
if (FLAG_trace_disabling_optimized_code) {
- OS::Print("Disabling optimized code: '%s' entry: %#"Px"\n",
+ OS::Print("Disabling optimized code: '%s' entry: %#" Px "\n",
ToFullyQualifiedCString(),
current_code.EntryPoint());
}
@@ -4076,7 +4082,6 @@
bool Function::is_optimizable() const {
if (OptimizableBit::decode(raw_ptr()->kind_tag_) &&
(script() != Script::null()) &&
- !is_native() &&
((end_token_pos() - token_pos()) < FLAG_huge_method_cutoff_in_tokens)) {
// Additional check needed for implicit getters.
if (HasCode() &&
@@ -4169,7 +4174,7 @@
char message_buffer[kMessageBufferSize];
OS::SNPrint(message_buffer,
kMessageBufferSize,
- "%"Pd" named passed, at most %"Pd" expected",
+ "%" Pd " named passed, at most %" Pd " expected",
num_named_arguments,
NumOptionalNamedParameters());
*error_message = String::New(message_buffer);
@@ -4187,7 +4192,7 @@
const intptr_t num_hidden_params = NumImplicitParameters();
OS::SNPrint(message_buffer,
kMessageBufferSize,
- "%"Pd"%s passed, %s%"Pd" expected",
+ "%" Pd "%s passed, %s%" Pd " expected",
num_pos_args - num_hidden_params,
num_opt_pos_params > 0 ? " positional" : "",
num_opt_pos_params > 0 ? "at most " : "",
@@ -4204,7 +4209,7 @@
const intptr_t num_hidden_params = NumImplicitParameters();
OS::SNPrint(message_buffer,
kMessageBufferSize,
- "%"Pd"%s passed, %s%"Pd" expected",
+ "%" Pd "%s passed, %s%" Pd " expected",
num_pos_args - num_hidden_params,
num_opt_pos_params > 0 ? " positional" : "",
num_opt_pos_params > 0 ? "at least " : "",
@@ -5301,6 +5306,7 @@
result.set_has_initializer(false);
result.set_guarded_cid(kIllegalCid);
result.set_is_nullable(false);
+ result.set_guarded_list_length(Field::kUnknownFixedLength);
result.set_dependent_code(Object::null_array());
return result.raw();
}
@@ -5424,6 +5430,12 @@
while (frame != NULL) {
code = frame->LookupDartCode();
if (IsDependentCode(code_objects, code)) {
+ if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) {
+ Function& function = Function::Handle(code.function());
+ OS::PrintErr("Deoptimizing %s because guard on field %s failed.\n",
+ function.ToFullyQualifiedCString(),
+ ToCString());
+ }
DeoptimizeAt(code, frame->pc());
}
frame = iterator.NextFrame();
@@ -5445,6 +5457,12 @@
// If function uses dependent code switch it to unoptimized.
if (function.CurrentCode() == code.raw()) {
ASSERT(function.HasOptimizedCode());
+ if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) {
+ OS::PrintErr("Switching %s to unoptimized code because guard"
+ " on field %s was violated.\n",
+ function.ToFullyQualifiedCString(),
+ ToCString());
+ }
function.SwitchToUnoptimizedCode();
}
}
@@ -5484,6 +5502,37 @@
}
+void Field::UpdateLength(intptr_t list_length) const {
+ ASSERT(is_final() || (!is_final() &&
+ (list_length < Field::kUnknownFixedLength)));
+ ASSERT((list_length == Field::kNoFixedLength) ||
+ (list_length > Field::kUnknownFixedLength));
+ ASSERT(guarded_cid() != kIllegalCid);
+
+ const bool force_invalidate = (guarded_cid() == kDynamicCid) &&
+ (list_length != Field::kNoFixedLength);
+
+ const bool list_length_unknown =
+ (guarded_list_length() == Field::kUnknownFixedLength);
+ const bool list_length_changed = (guarded_list_length() != list_length);
+
+ if (list_length_unknown && list_length_changed && !force_invalidate) {
+ // List length set for first time.
+ set_guarded_list_length(list_length);
+ return;
+ }
+
+ if (!list_length_changed && !force_invalidate) {
+ // List length unchanged.
+ return;
+ }
+
+ // Multiple list lengths assigned here, stop tracking length.
+ set_guarded_list_length(Field::kNoFixedLength);
+ DeoptimizeDependentCode();
+}
+
+
void LiteralToken::set_literal(const String& literal) const {
StorePointer(&raw_ptr()->literal_, literal.raw());
}
@@ -5745,7 +5794,7 @@
RawTokenStream* TokenStream::New(intptr_t len) {
if (len < 0 || len > kMaxElements) {
// This should be caught before we reach here.
- FATAL1("Fatal error in TokenStream::New: invalid len %"Pd"\n", len);
+ FATAL1("Fatal error in TokenStream::New: invalid len %" Pd "\n", len);
}
uint8_t* data = reinterpret_cast<uint8_t*>(::malloc(len));
ASSERT(data != NULL);
@@ -7641,57 +7690,85 @@
};
+
+// Return Function::null() if function does not exist in lib.
+static RawFunction* GetFunction(const GrowableArray<Library*>& libs,
+ const char* class_name,
+ const char* function_name) {
+ Function& func = Function::Handle();
+ String& class_str = String::Handle();
+ String& func_str = String::Handle();
+ Class& cls = Class::Handle();
+ for (intptr_t l = 0; l < libs.length(); l++) {
+ const Library& lib = *libs[l];
+ if (strcmp(class_name, "::") == 0) {
+ func_str = Symbols::New(function_name);
+ func = lib.LookupFunctionAllowPrivate(func_str, NULL);
+ } else {
+ class_str = String::New(class_name);
+ cls = lib.LookupClassAllowPrivate(class_str, NULL);
+ if (!cls.IsNull()) {
+ func_str = String::New(function_name);
+ if (function_name[0] == '.') {
+ func_str = String::Concat(class_str, func_str);
+ }
+ func = cls.LookupFunctionAllowPrivate(func_str);
+ }
+ }
+ if (!func.IsNull()) {
+ return func.raw();
+ }
+ }
+ return Function::null();
+}
+
+
void Library::CheckFunctionFingerprints() {
GrowableArray<FpDiff> collected_fp_diffs;
- Library& lib = Library::Handle();
- Class& cls = Class::Handle();
+ GrowableArray<Library*> all_libs;
Function& func = Function::Handle();
- String& str = String::Handle();
bool has_errors = false;
#define CHECK_FINGERPRINTS(class_name, function_name, dest, fp) \
- func = Function::null(); \
- if (strcmp(#class_name, "::") == 0) { \
- str = Symbols::New(#function_name); \
- func = lib.LookupFunctionAllowPrivate(str, NULL); \
- } else { \
- str = String::New(#class_name); \
- cls = lib.LookupClassAllowPrivate(str, NULL); \
- if (!cls.IsNull()) { \
- if (#function_name[0] == '.') { \
- str = String::New(#class_name#function_name); \
- } else { \
- str = String::New(#function_name); \
- } \
- func = cls.LookupFunctionAllowPrivate(str); \
- } \
- } \
- if (!func.IsNull() && (func.SourceFingerprint() != fp)) { \
+ func = GetFunction(all_libs, #class_name, #function_name); \
+ if (func.IsNull()) { \
+ has_errors = true; \
+ OS::Print("Function not found %s.%s\n", #class_name, #function_name); \
+ } else if (func.SourceFingerprint() != fp) { \
has_errors = true; \
OS::Print("Wrong fingerprint for '%s': expecting %d found %d\n", \
func.ToFullyQualifiedCString(), fp, func.SourceFingerprint()); \
collected_fp_diffs.Add(FpDiff(fp, func.SourceFingerprint())); \
} \
- lib = Library::CoreLibrary();
+ all_libs.Add(&Library::ZoneHandle(Library::CoreLibrary()));
CORE_LIB_INTRINSIC_LIST(CHECK_FINGERPRINTS);
CORE_INTEGER_LIB_INTRINSIC_LIST(CHECK_FINGERPRINTS);
+ all_libs.Add(&Library::ZoneHandle(Library::MathLibrary()));
+ all_libs.Add(&Library::ZoneHandle(Library::TypedDataLibrary()));
RECOGNIZED_LIST(CHECK_FINGERPRINTS);
- lib = Library::MathLibrary();
+ all_libs.Clear();
+ all_libs.Add(&Library::ZoneHandle(Library::MathLibrary()));
MATH_LIB_INTRINSIC_LIST(CHECK_FINGERPRINTS);
- lib = Library::TypedDataLibrary();
+ all_libs.Clear();
+ all_libs.Add(&Library::ZoneHandle(Library::TypedDataLibrary()));
TYPED_DATA_LIB_INTRINSIC_LIST(CHECK_FINGERPRINTS);
#undef CHECK_FINGERPRINTS
+Class& cls = Class::Handle();
+
#define CHECK_FACTORY_FINGERPRINTS(factory_symbol, cid, fp) \
cls = Isolate::Current()->class_table()->At(cid); \
func = cls.LookupFunctionAllowPrivate(Symbols::factory_symbol()); \
- ASSERT(!func.IsNull()); \
- if (func.SourceFingerprint() != fp) { \
+ if (func.IsNull()) { \
+ has_errors = true; \
+ OS::Print("Function not found %s.%s\n", cls.ToCString(), \
+ Symbols::factory_symbol().ToCString()); \
+ } else if (func.SourceFingerprint() != fp) { \
has_errors = true; \
OS::Print("Wrong fingerprint for '%s': expecting %d found %d\n", \
func.ToFullyQualifiedCString(), fp, func.SourceFingerprint()); \
@@ -7701,6 +7778,7 @@
RECOGNIZED_LIST_FACTORY_LIST(CHECK_FACTORY_FINGERPRINTS);
#undef CHECK_FACTORY_FINGERPRINTS
+
if (has_errors) {
for (intptr_t i = 0; i < collected_fp_diffs.length(); i++) {
OS::Print("s/%d/%d/\n",
@@ -7716,7 +7794,7 @@
ASSERT(Object::instructions_class() != Class::null());
if (size < 0 || size > kMaxElements) {
// This should be caught before we reach here.
- FATAL1("Fatal error in Instructions::New: invalid size %"Pd"\n", size);
+ FATAL1("Fatal error in Instructions::New: invalid size %" Pd "\n", size);
}
Instructions& result = Instructions::Handle();
{
@@ -7810,7 +7888,7 @@
if (num_descriptors < 0 || num_descriptors > kMaxElements) {
// This should be caught before we reach here.
FATAL1("Fatal error in PcDescriptors::New: "
- "invalid num_descriptors %"Pd"\n", num_descriptors);
+ "invalid num_descriptors %" Pd "\n", num_descriptors);
}
PcDescriptors& result = PcDescriptors::Handle();
{
@@ -7865,7 +7943,7 @@
// "*" in a printf format specifier tells it to read the field width from
// the printf argument list.
const char* kFormat =
- "%#-*"Px"\t%s\t%"Pd"\t\t%"Pd"\t%"Pd"\n";
+ "%#-*" Px "\t%s\t%" Pd "\t\t%" Pd "\t%" Pd "\n";
// First compute the buffer size required.
intptr_t len = 1; // Trailing '\0'.
for (intptr_t i = 0; i < Length(); i++) {
@@ -7909,7 +7987,7 @@
// the check for too large number of descriptors.
if (Length() > 3000) {
if (FLAG_trace_compiler) {
- OS::Print("Not checking pc decriptors, length %"Pd"\n", Length());
+ OS::Print("Not checking pc decriptors, length %" Pd "\n", Length());
}
return;
}
@@ -7997,7 +8075,7 @@
(payload_size >
(kSmiMax - static_cast<intptr_t>(sizeof(RawStackmap))))) {
// This should be caught before we reach here.
- FATAL1("Fatal error in Stackmap::New: invalid length %"Pd"\n",
+ FATAL1("Fatal error in Stackmap::New: invalid length %" Pd "\n",
length);
}
{
@@ -8027,7 +8105,7 @@
if (IsNull()) {
return "{null}";
} else {
- const char* kFormat = "%#"Px": ";
+ const char* kFormat = "%#" Px ": ";
intptr_t fixed_length = OS::SNPrint(NULL, 0, kFormat, PC()) + 1;
Isolate* isolate = Isolate::Current();
// Guard against integer overflow in the computation of alloc_size.
@@ -8035,7 +8113,7 @@
// TODO(kmillikin): We could just truncate the string if someone
// tries to print a 2 billion plus entry stackmap.
if (Length() > (kIntptrMax - fixed_length)) {
- FATAL1("Length() is unexpectedly large (%"Pd")", Length());
+ FATAL1("Length() is unexpectedly large (%" Pd ")", Length());
}
intptr_t alloc_size = fixed_length + Length();
char* chars = isolate->current_zone()->Alloc<char>(alloc_size);
@@ -8086,7 +8164,7 @@
const char* LocalVarDescriptors::ToCString() const {
intptr_t len = 1; // Trailing '\0'.
const char* kFormat =
- "%2"Pd" kind=%d scope=0x%04x begin=%"Pd" end=%"Pd" name=%s\n";
+ "%2" Pd " kind=%d scope=0x%04x begin=%" Pd " end=%" Pd " name=%s\n";
for (intptr_t i = 0; i < Length(); i++) {
String& var_name = String::Handle(GetName(i));
RawLocalVarDescriptors::VarInfo info;
@@ -8131,7 +8209,7 @@
if (num_variables < 0 || num_variables > kMaxElements) {
// This should be caught before we reach here.
FATAL1("Fatal error in LocalVarDescriptors::New: "
- "invalid num_variables %"Pd"\n", num_variables);
+ "invalid num_variables %" Pd "\n", num_variables);
}
LocalVarDescriptors& result = LocalVarDescriptors::Handle();
{
@@ -8217,7 +8295,7 @@
ASSERT(Object::exception_handlers_class() != Class::null());
if (num_handlers < 0 || num_handlers >= kMaxHandlers) {
FATAL1("Fatal error in ExceptionHandlers::New(): "
- "invalid num_handlers %"Pd"\n",
+ "invalid num_handlers %" Pd "\n",
num_handlers);
}
ExceptionHandlers& result = ExceptionHandlers::Handle();
@@ -8244,7 +8322,8 @@
Type& type = Type::Handle();
RawExceptionHandlers::HandlerInfo info;
// First compute the buffer size required.
- const char* kFormat = "%"Pd" => %#"Px" (%"Pd" types) (outer %"Pd")\n";
+ const char* kFormat = "%" Pd " => %#" Px " (%" Pd
+ " types) (outer %" Pd ")\n";
const char* kFormat2 = " %d. %s\n";
intptr_t len = 1; // Trailing '\0'.
for (intptr_t i = 0; i < Length(); i++) {
@@ -8430,7 +8509,8 @@
Comments* comments;
if (count < 0 || count > (kIntptrMax / kNumberOfEntries)) {
// This should be caught before we reach here.
- FATAL1("Fatal error in Code::Comments::New: invalid count %"Pd"\n", count);
+ FATAL1("Fatal error in Code::Comments::New: invalid count %" Pd "\n",
+ count);
}
if (count == 0) {
comments = new Comments(Object::empty_array());
@@ -8604,7 +8684,7 @@
RawCode* Code::New(intptr_t pointer_offsets_length) {
if (pointer_offsets_length < 0 || pointer_offsets_length > kMaxElements) {
// This should be caught before we reach here.
- FATAL1("Fatal error in Code::New: invalid pointer_offsets_length %"Pd"\n",
+ FATAL1("Fatal error in Code::New: invalid pointer_offsets_length %" Pd "\n",
pointer_offsets_length);
}
ASSERT(Object::code_class() != Class::null());
@@ -8894,7 +8974,7 @@
if (num_variables < 0 || num_variables > kMaxElements) {
// This should be caught before we reach here.
- FATAL1("Fatal error in Context::New: invalid num_variables %"Pd"\n",
+ FATAL1("Fatal error in Context::New: invalid num_variables %" Pd "\n",
num_variables);
}
Context& result = Context::Handle();
@@ -8926,7 +9006,7 @@
ASSERT(Object::context_scope_class() != Class::null());
if (num_variables < 0 || num_variables > kMaxElements) {
// This should be caught before we reach here.
- FATAL1("Fatal error in ContextScope::New: invalid num_variables %"Pd"\n",
+ FATAL1("Fatal error in ContextScope::New: invalid num_variables %" Pd "\n",
num_variables);
}
intptr_t size = ContextScope::InstanceSize(num_variables);
@@ -9043,7 +9123,8 @@
const char* ICData::ToCString() const {
- const char* kFormat = "ICData target:'%s' num-args: %"Pd" num-checks: %"Pd"";
+ const char* kFormat = "ICData target:'%s' num-args: %" Pd
+ " num-checks: %" Pd "";
const String& name = String::Handle(target_name());
const intptr_t num_args = num_args_tested();
const intptr_t num_checks = NumberOfChecks();
@@ -9931,6 +10012,58 @@
}
+static RawPatchClass* MakeTempPatchClass(const Class& cls,
+ const String& expr) {
+ String& src = String::Handle(String::New("() => "));
+ src = String::Concat(src, expr);
+ src = String::Concat(src, Symbols::Semicolon());
+ Script& script = Script::Handle();
+ script = Script::New(Symbols::Empty(), src, RawScript::kSourceTag);
+ // In order to tokenize the source, we need to get the key to mangle
+ // private names from the library from which the object's class
+ // originates.
+ const Library& lib = Library::Handle(cls.library());
+ ASSERT(!lib.IsNull());
+ const String& lib_key = String::Handle(lib.private_key());
+ script.Tokenize(lib_key);
+
+ const String& src_class_name = String::Handle(Symbols::New(":internal"));
+ const Class& src_class = Class::Handle(
+ Class::New(src_class_name, script, Scanner::kDummyTokenIndex));
+ src_class.set_is_finalized();
+ src_class.set_library(lib);
+ return PatchClass::New(cls, src_class);
+}
+
+
+RawObject* Instance::Evaluate(const String& expr) const {
+ const Class& cls = Class::Handle(clazz());
+ const PatchClass& temp_class =
+ PatchClass::Handle(MakeTempPatchClass(cls, expr));
+ const String& eval_func_name = String::Handle(Symbols::New(":eval"));
+ const Function& eval_func =
+ Function::Handle(Function::New(eval_func_name,
+ RawFunction::kRegularFunction,
+ false, // Not static.
+ false, // Not const.
+ false, // Not abstract.
+ false, // Not external.
+ temp_class,
+ 0));
+ eval_func.set_result_type(Type::Handle(Type::DynamicType()));
+ eval_func.set_num_fixed_parameters(1);
+ eval_func.SetNumOptionalParameters(0, true);
+ eval_func.set_is_optimizable(false);
+
+ const Array& args = Array::Handle(Array::New(1));
+ args.SetAt(0, *this);
+ const Object& result =
+ Object::Handle(DartEntry::InvokeFunction(eval_func, args));
+ return result.raw();
+}
+
+
+
bool Instance::Equals(const Instance& other) const {
if (this->raw() == other.raw()) {
return true; // "===".
@@ -12227,7 +12360,7 @@
RawBigint* Bigint::Allocate(intptr_t length, Heap::Space space) {
if (length < 0 || length > kMaxElements) {
// This should be caught before we reach here.
- FATAL1("Fatal error in Bigint::Allocate: invalid length %"Pd"\n", length);
+ FATAL1("Fatal error in Bigint::Allocate: invalid length %" Pd "\n", length);
}
ASSERT(Isolate::Current()->object_store()->bigint_class() != Class::null());
Bigint& result = Bigint::Handle();
@@ -13150,7 +13283,7 @@
Class::null());
if (len < 0 || len > kMaxElements) {
// This should be caught before we reach here.
- FATAL1("Fatal error in OneByteString::New: invalid len %"Pd"\n", len);
+ FATAL1("Fatal error in OneByteString::New: invalid len %" Pd "\n", len);
}
{
RawObject* raw = Object::Allocate(OneByteString::kClassId,
@@ -13327,7 +13460,7 @@
ASSERT(Isolate::Current()->object_store()->two_byte_string_class());
if (len < 0 || len > kMaxElements) {
// This should be caught before we reach here.
- FATAL1("Fatal error in TwoByteString::New: invalid len %"Pd"\n", len);
+ FATAL1("Fatal error in TwoByteString::New: invalid len %" Pd "\n", len);
}
String& result = String::Handle();
{
@@ -13456,7 +13589,7 @@
external_one_byte_string_class() != Class::null());
if (len < 0 || len > kMaxElements) {
// This should be caught before we reach here.
- FATAL1("Fatal error in ExternalOneByteString::New: invalid len %"Pd"\n",
+ FATAL1("Fatal error in ExternalOneByteString::New: invalid len %" Pd "\n",
len);
}
String& result = String::Handle();
@@ -13494,7 +13627,7 @@
Class::null());
if (len < 0 || len > kMaxElements) {
// This should be caught before we reach here.
- FATAL1("Fatal error in ExternalTwoByteString::New: invalid len %"Pd"\n",
+ FATAL1("Fatal error in ExternalTwoByteString::New: invalid len %" Pd "\n",
len);
}
String& result = String::Handle();
@@ -13593,7 +13726,7 @@
RawArray* Array::New(intptr_t class_id, intptr_t len, Heap::Space space) {
if (len < 0 || len > Array::kMaxElements) {
// This should be caught before we reach here.
- FATAL1("Fatal error in Array::New: invalid len %"Pd"\n", len);
+ FATAL1("Fatal error in Array::New: invalid len %" Pd "\n", len);
}
Array& result = Array::Handle();
{
@@ -13620,8 +13753,8 @@
if (IsNull()) {
return IsImmutable() ? "ImmutableArray NULL" : "Array NULL";
}
- const char* format = !IsImmutable() ? "Array len:%"Pd"" :
- "Immutable Array len:%"Pd"";
+ const char* format = !IsImmutable() ? "Array len:%" Pd "" :
+ "Immutable Array len:%" Pd "";
intptr_t len = OS::SNPrint(NULL, 0, format, Length()) + 1;
char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
OS::SNPrint(chars, len, format, Length());
@@ -13700,7 +13833,7 @@
this->SetAt(i, obj);
} else {
ASSERT(error_str != NULL);
- const char* kFormat = "element at index %"Pd": %s\n";
+ const char* kFormat = "element at index %" Pd ": %s\n";
const intptr_t len =
OS::SNPrint(NULL, 0, kFormat, i, obj.ToCString()) + 1;
char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
@@ -13832,7 +13965,7 @@
if (IsNull()) {
return "GrowableObjectArray NULL";
}
- const char* format = "GrowableObjectArray len:%"Pd"";
+ const char* format = "GrowableObjectArray len:%" Pd "";
intptr_t len = OS::SNPrint(NULL, 0, format, Length()) + 1;
char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
OS::SNPrint(chars, len, format, Length());
@@ -14438,7 +14571,7 @@
Class::null());
if (len < 0 || len > kMaxElements) {
// This should be caught before we reach here.
- FATAL1("Fatal error in JSRegexp::New: invalid len %"Pd"\n", len);
+ FATAL1("Fatal error in JSRegexp::New: invalid len %" Pd "\n", len);
}
JSRegExp& result = JSRegExp::Handle();
{
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index a27fae7..20c508b 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -1715,6 +1715,11 @@
return kind() == RawFunction::kSetterFunction;
}
+ // Returns true if this function represents an implicit setter function.
+ bool IsImplicitSetterFunction() const {
+ return kind() == RawFunction::kImplicitSetter;
+ }
+
// Returns true if this function represents a (possibly implicit) closure
// function.
bool IsClosureFunction() const {
@@ -1982,11 +1987,33 @@
static intptr_t guarded_cid_offset() {
return OFFSET_OF(RawField, guarded_cid_);
}
+ // Return the list length that any list stored in this field is guaranteed
+ // to have. If length is kUnknownFixedLength the length has not
+ // been determined. If length is kNoFixedLength this field has multiple
+ // list lengths associated with it and cannot be predicted.
+ intptr_t guarded_list_length() const {
+ return raw_ptr()->guarded_list_length_;
+ }
+ void set_guarded_list_length(intptr_t list_length) const {
+ raw_ptr()->guarded_list_length_ = list_length;
+ }
+ static intptr_t guarded_list_length_offset() {
+ return OFFSET_OF(RawField, guarded_list_length_);
+ }
+ bool needs_length_check() const {
+ const bool r = guarded_list_length() >= Field::kUnknownFixedLength;
+ ASSERT(!r || is_final());
+ return r;
+ }
static bool IsExternalizableCid(intptr_t cid) {
return (cid == kOneByteStringCid) || (cid == kTwoByteStringCid);
}
+ enum {
+ kUnknownFixedLength = -1,
+ kNoFixedLength = -2,
+ };
// Returns false if any value read from this field is guaranteed to be
// not null.
// Internally we is_nullable_ field contains either kNullCid (nullable) or
@@ -2003,8 +2030,12 @@
}
// Update guarded class id and nullability of the field to reflect assignment
- // of the value with the given class id to this field.
+ // of the value with the given class id to this field. May trigger
+ // deoptimization of dependent code.
void UpdateCid(intptr_t cid) const;
+ // Update guarded class length of the field to reflect assignment of the
+ // value with the given length. May trigger deoptimization of dependent code.
+ void UpdateLength(intptr_t length) const;
// Return the list of optimized code objects that were optimized under
// assumptions about guarded class id and nullability of this field.
@@ -3688,6 +3719,11 @@
// function.
bool IsCallable(Function* function, Context* context) const;
+ // Evaluate the given expression as if it appeared in an instance
+ // method of this instance and return the resulting value, or an
+ // error object if evaluating the expression fails.
+ RawObject* Evaluate(const String& expr) const;
+
static intptr_t InstanceSize() {
return RoundedAllocationSize(sizeof(RawInstance));
}
diff --git a/runtime/vm/object_store.cc b/runtime/vm/object_store.cc
index e53b5d9..a4b7ec6 100644
--- a/runtime/vm/object_store.cc
+++ b/runtime/vm/object_store.cc
@@ -63,6 +63,7 @@
utf_library_(Library::null()),
libraries_(GrowableObjectArray::null()),
pending_classes_(GrowableObjectArray::null()),
+ pending_functions_(GrowableObjectArray::null()),
sticky_error_(Error::null()),
unhandled_exception_handler_(String::null()),
empty_context_(Context::null()),
@@ -105,6 +106,9 @@
ASSERT(this->out_of_memory() == Instance::null());
ASSERT(this->preallocated_stack_trace() == Stacktrace::null());
+ ASSERT(this->pending_functions() == GrowableObjectArray::null());
+ this->pending_functions_ = GrowableObjectArray::New();
+
Object& result = Object::Handle();
const Library& library = Library::Handle(Library::CoreLibrary());
diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h
index 48e711a..6ccdff9 100644
--- a/runtime/vm/object_store.h
+++ b/runtime/vm/object_store.h
@@ -349,6 +349,10 @@
pending_classes_ = value.raw();
}
+ RawGrowableObjectArray* pending_functions() const {
+ return pending_functions_;
+ }
+
RawError* sticky_error() const { return sticky_error_; }
void set_sticky_error(const Error& value) {
ASSERT(!value.IsNull());
@@ -485,6 +489,7 @@
RawLibrary* utf_library_;
RawGrowableObjectArray* libraries_;
RawGrowableObjectArray* pending_classes_;
+ RawGrowableObjectArray* pending_functions_;
RawError* sticky_error_;
RawString* unhandled_exception_handler_;
RawContext* empty_context_;
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index e4145c6..61d9cbd 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -3263,7 +3263,7 @@
}
EXPECT(data.IsArray());
const Array& metadata = Array::Cast(data);
- OS::Print("Metadata for %s has %"Pd" values:\n", name, metadata.Length());
+ OS::Print("Metadata for %s has %" Pd " values:\n", name, metadata.Length());
Object& elem = Object::Handle();
for (int i = 0; i < metadata.Length(); i++) {
elem = metadata.At(i);
diff --git a/runtime/vm/os_android.cc b/runtime/vm/os_android.cc
index 17a378a..1c625e4 100644
--- a/runtime/vm/os_android.cc
+++ b/runtime/vm/os_android.cc
@@ -73,7 +73,7 @@
bool optimized) {
Dart_FileWriteCallback file_write = Isolate::file_write_callback();
ASSERT(file_write != NULL);
- const char* format = "%"Px" %"Px" %s%s\n";
+ const char* format = "%" Px " %" Px " %s%s\n";
const char* marker = optimized ? "*" : "";
intptr_t len = OS::SNPrint(NULL, 0, format, base, size, marker, name);
char* buffer = Isolate::Current()->current_zone()->Alloc<char>(len + 1);
diff --git a/runtime/vm/os_linux.cc b/runtime/vm/os_linux.cc
index 2b869d4..5a14414 100644
--- a/runtime/vm/os_linux.cc
+++ b/runtime/vm/os_linux.cc
@@ -157,7 +157,7 @@
bool optimized) {
Dart_FileWriteCallback file_write = Isolate::file_write_callback();
ASSERT(file_write != NULL);
- const char* format = "%"Px" %"Px" %s%s\n";
+ const char* format = "%" Px " %" Px " %s%s\n";
const char* marker = optimized ? "*" : "";
intptr_t len = OS::SNPrint(NULL, 0, format, base, size, marker, name);
char* buffer = Isolate::Current()->current_zone()->Alloc<char>(len + 1);
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index a63642d..1e96917 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -58,7 +58,7 @@
intptr_t line, column;
script.GetTokenLocation(token_pos, &line, &column);
PrintIndent();
- OS::Print("%s (line %"Pd", col %"Pd", token %"Pd")\n",
+ OS::Print("%s (line %" Pd ", col %" Pd ", token %" Pd ")\n",
msg, line, column, token_pos);
}
indent_++;
@@ -255,7 +255,8 @@
current_class_(Class::Handle(isolate_)),
library_(Library::Handle(isolate_, library.raw())),
try_blocks_list_(NULL),
- last_used_try_index_(CatchClauseNode::kInvalidTryIndex) {
+ last_used_try_index_(CatchClauseNode::kInvalidTryIndex),
+ unregister_pending_function_(false) {
ASSERT(tokens_iterator_.IsValid());
ASSERT(!library.IsNull());
}
@@ -284,7 +285,8 @@
isolate_,
parsed_function->function().origin()).library())),
try_blocks_list_(NULL),
- last_used_try_index_(CatchClauseNode::kInvalidTryIndex) {
+ last_used_try_index_(CatchClauseNode::kInvalidTryIndex),
+ unregister_pending_function_(false) {
ASSERT(tokens_iterator_.IsValid());
ASSERT(!current_function().IsNull());
if (FLAG_enable_type_checks) {
@@ -293,6 +295,19 @@
}
+Parser::~Parser() {
+ if (unregister_pending_function_) {
+ const GrowableObjectArray& pending_functions =
+ GrowableObjectArray::Handle(
+ isolate()->object_store()->pending_functions());
+ ASSERT(pending_functions.Length() > 0);
+ ASSERT(pending_functions.At(pending_functions.Length()-1) ==
+ current_function().raw());
+ pending_functions.RemoveLast();
+ }
+}
+
+
void Parser::SetScript(const Script & script, intptr_t token_pos) {
script_ = script.raw();
tokens_iterator_.SetStream(TokenStream::Handle(script.tokens()), token_pos);
@@ -1133,7 +1148,7 @@
for (; i < desc.PositionalCount(); ++i) {
ParamDesc p;
char name[64];
- OS::SNPrint(name, 64, ":p%"Pd, i);
+ OS::SNPrint(name, 64, ":p%" Pd, i);
p.name = &String::ZoneHandle(Symbols::New(name));
p.type = &Type::ZoneHandle(Type::DynamicType());
params.parameters->Add(p);
@@ -2087,6 +2102,7 @@
String::Handle(field.name()).ToCString());
} else {
field.UpdateCid(kNullCid);
+ field.UpdateLength(Field::kNoFixedLength);
}
}
}
@@ -2359,6 +2375,23 @@
}
+void Parser::CheckRecursiveInvocation() {
+ const GrowableObjectArray& pending_functions =
+ GrowableObjectArray::Handle(
+ isolate()->object_store()->pending_functions());
+ for (int i = 0; i < pending_functions.Length(); i++) {
+ if (pending_functions.At(i) == current_function().raw()) {
+ const String& fname =
+ String::Handle(current_function().UserVisibleName());
+ ErrorMsg("circular dependency for function %s", fname.ToCString());
+ }
+ }
+ ASSERT(!unregister_pending_function_);
+ pending_functions.Add(current_function());
+ unregister_pending_function_ = true;
+}
+
+
// Parser is at the opening parenthesis of the formal parameter declaration
// of function. Parse the formal parameters, initializers and code.
SequenceNode* Parser::ParseConstructor(const Function& func,
@@ -2371,6 +2404,8 @@
const Class& cls = Class::Handle(func.Owner());
ASSERT(!cls.IsNull());
+ CheckRecursiveInvocation();
+
if (func.IsImplicitConstructor()) {
// Special case: implicit constructor.
// The parser adds an implicit default constructor when a class
@@ -3122,7 +3157,7 @@
}
if (members->FieldNameExists(*field->name, !field->has_final)) {
ErrorMsg(field->name_pos,
- "'%s' field/method already defined\n", field->name->ToCString());
+ "field or method '%s' already defined", field->name->ToCString());
}
Function& getter = Function::Handle();
Function& setter = Function::Handle();
@@ -3260,7 +3295,7 @@
member.params.has_optional_named_parameters ||
(member.params.num_fixed_parameters != expected_num_parameters)) {
// Subtract receiver when reporting number of expected arguments.
- ErrorMsg(member.name_pos, "operator %s expects %"Pd" argument(s)",
+ ErrorMsg(member.name_pos, "operator %s expects %" Pd " argument(s)",
member.name->ToCString(), (expected_num_parameters - 1));
}
}
@@ -5018,6 +5053,7 @@
Function::ZoneHandle(func.raw()),
native_name,
native_function,
+ current_block_->scope,
is_bootstrap_native)));
}
@@ -6852,7 +6888,7 @@
if (token_pos >= 0) {
intptr_t line, column;
script.GetTokenLocation(token_pos, &line, &column);
- result = String::NewFormatted("'%s': %s: line %"Pd" pos %"Pd": ",
+ result = String::NewFormatted("'%s': %s: line %" Pd " pos %" Pd ": ",
script_url.ToCString(),
message_header,
line,
@@ -7241,7 +7277,7 @@
LocalVariable* Parser::CreateTempConstVariable(intptr_t token_pos,
const char* s) {
char name[64];
- OS::SNPrint(name, 64, ":%s%"Pd, s, token_pos);
+ OS::SNPrint(name, 64, ":%s%" Pd, s, token_pos);
LocalVariable* temp =
new LocalVariable(token_pos,
String::ZoneHandle(Symbols::New(name)),
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index 2af08c2..b2fbf97 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -182,6 +182,7 @@
Parser(const Script& script, const Library& library, intptr_t token_pos);
Parser(const Script& script, ParsedFunction* function, intptr_t token_pos);
+ ~Parser();
// The function for which we will generate code.
const Function& current_function() const;
@@ -320,6 +321,8 @@
const Error& prev_error, intptr_t token_pos, const char* format, ...)
PRINTF_ATTRIBUTE(4, 5);
+ void CheckRecursiveInvocation();
+
const Instance& EvaluateConstExpr(AstNode* expr);
AstNode* RunStaticFieldInitializer(const Field& field);
RawObject* EvaluateConstConstructorCall(
@@ -693,6 +696,8 @@
intptr_t AllocateTryIndex() { return ++last_used_try_index_; }
intptr_t last_used_try_index_;
+ bool unregister_pending_function_;
+
DISALLOW_COPY_AND_ASSIGN(Parser);
};
diff --git a/runtime/vm/raw_object.cc b/runtime/vm/raw_object.cc
index 7483d21..2ec7137 100644
--- a/runtime/vm/raw_object.cc
+++ b/runtime/vm/raw_object.cc
@@ -37,15 +37,15 @@
uword tags = ptr()->tags_;
intptr_t reserved = ReservedBits::decode(tags);
if (reserved != 0) {
- FATAL1("Invalid tags field encountered %#"Px"\n", tags);
+ FATAL1("Invalid tags field encountered %#" Px "\n", tags);
}
intptr_t class_id = ClassIdTag::decode(tags);
if (!isolate->class_table()->IsValidIndex(class_id)) {
- FATAL1("Invalid class id encountered %"Pd"\n", class_id);
+ FATAL1("Invalid class id encountered %" Pd "\n", class_id);
}
intptr_t size = SizeTag::decode(tags);
if (size != 0 && size != SizeFromClass()) {
- FATAL1("Inconsistent class size encountered %"Pd"\n", size);
+ FATAL1("Inconsistent class size encountered %" Pd "\n", size);
}
}
@@ -252,7 +252,7 @@
break;
}
default:
- OS::Print("Class Id: %"Pd"\n", class_id);
+ OS::Print("Class Id: %" Pd "\n", class_id);
UNREACHABLE();
break;
}
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 6d5892d..1be013c 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -688,6 +688,7 @@
intptr_t guarded_cid_;
intptr_t is_nullable_; // kNullCid if field can contain null value and
// any other value otherwise.
+ intptr_t guarded_list_length_;
uint8_t kind_bits_; // static, final, const, has initializer.
};
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index 3e48cdb..ab17198 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -257,7 +257,7 @@
reinterpret_cast<uword>(ptr()->type_class_) - kHeapObjectTag +
Object::tags_offset()));
if (cid == kUnresolvedClassCid) {
- OS::Print("Snapshotting unresolved type '%s' at token pos %"Pd"\n",
+ OS::Print("Snapshotting unresolved type '%s' at token pos %" Pd "\n",
RawOneByteStringToCString(
reinterpret_cast<RawOneByteString*>(
reinterpret_cast<RawUnresolvedClass*>(
@@ -265,7 +265,7 @@
ptr()->token_pos_);
} else {
// Assume cid == kClassId, but it can also be kIllegalCid.
- OS::Print("Snapshotting unfinalized type '%s' at token pos %"Pd"\n",
+ OS::Print("Snapshotting unfinalized type '%s' at token pos %" Pd "\n",
RawOneByteStringToCString(
reinterpret_cast<RawOneByteString*>(
reinterpret_cast<RawClass*>(
@@ -342,7 +342,7 @@
// to, making sure not to allocate any handles. Unfortunately, we cannot
// print the script name.
OS::Print("Snapshotting unfinalized type parameter '%s' of class '%s' at "
- "token pos %"Pd"\n",
+ "token pos %" Pd "\n",
RawOneByteStringToCString(
reinterpret_cast<RawOneByteString*>(ptr()->name_)),
RawOneByteStringToCString(
@@ -821,6 +821,7 @@
field.set_token_pos(reader->ReadIntptrValue());
field.set_guarded_cid(reader->ReadIntptrValue());
field.set_is_nullable(reader->ReadIntptrValue());
+ field.set_guarded_list_length(reader->ReadIntptrValue());
field.set_kind_bits(reader->Read<uint8_t>());
// Set all the object fields.
@@ -854,6 +855,7 @@
writer->WriteIntptrValue(ptr()->token_pos_);
writer->WriteIntptrValue(ptr()->guarded_cid_);
writer->WriteIntptrValue(ptr()->is_nullable_);
+ writer->WriteIntptrValue(ptr()->guarded_list_length_);
writer->Write<uint8_t>(ptr()->kind_bits_);
// Write out all the object pointer fields.
diff --git a/runtime/vm/scanner.cc b/runtime/vm/scanner.cc
index 8bf4926..0d6e5d0 100644
--- a/runtime/vm/scanner.cc
+++ b/runtime/vm/scanner.cc
@@ -947,7 +947,7 @@
}
char private_key[32];
OS::SNPrint(private_key, sizeof(private_key),
- "%c%#"Px"", kPrivateKeySeparator, key_value);
+ "%c%#" Px "", kPrivateKeySeparator, key_value);
const String& result = String::Handle(String::New(private_key, Heap::kOld));
return result.raw();
}
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index d19dbe1..687f2e5 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -167,7 +167,7 @@
String& url = String::Handle();
String& function = String::Handle();
for (int i = 0; i < n_frames; i++) {
- ActivationFrame* frame = stack->ActivationFrameAt(i);
+ ActivationFrame* frame = stack->FrameAt(i);
url ^= frame->SourceUrl();
function ^= frame->function().UserVisibleName();
js->OpenObject();
diff --git a/runtime/vm/simulator_arm.cc b/runtime/vm/simulator_arm.cc
index 7826a37..9135e2c 100644
--- a/runtime/vm/simulator_arm.cc
+++ b/runtime/vm/simulator_arm.cc
@@ -294,7 +294,8 @@
if (token_pos >= 0) {
script.GetTokenLocation(token_pos, &line, &column);
}
- OS::Print("pc=0x%"Px" fp=0x%"Px" sp=0x%"Px" %s%s (%s:%"Pd":%"Pd")\n",
+ OS::Print("pc=0x%" Px " fp=0x%" Px " sp=0x%" Px " %s%s (%s:%" Pd
+ ":%" Pd ")\n",
pc, fp, sp,
is_optimized ? (is_inlined ? "inlined " : "optimized ") : "",
func_name.ToCString(),
@@ -344,7 +345,7 @@
GetApproximateTokenIndex(code, frame->pc()),
code.is_optimized(), false);
} else {
- OS::Print("pc=0x%"Px" fp=0x%"Px" sp=0x%"Px" %s frame\n",
+ OS::Print("pc=0x%" Px " fp=0x%" Px " sp=0x%" Px " %s frame\n",
frame->pc(), frame->fp(), frame->sp(),
frame->IsEntryFrame() ? "entry" :
frame->IsExitFrame() ? "exit" :
@@ -422,7 +423,7 @@
if (last_pc != sim_->get_pc()) {
last_pc = sim_->get_pc();
if (Simulator::IsIllegalAddress(last_pc)) {
- OS::Print("pc is out of bounds: 0x%"Px"\n", last_pc);
+ OS::Print("pc is out of bounds: 0x%" Px "\n", last_pc);
} else {
Disassembler::Disassemble(last_pc, last_pc + Instr::kInstrSize);
}
@@ -976,7 +977,7 @@
// it will be possible to disassemble the code and inspect registers.
char buffer[128];
snprintf(buffer, sizeof(buffer),
- "illegal memory access at 0x%"Px", pc=0x%"Px"\n",
+ "illegal memory access at 0x%" Px ", pc=0x%" Px "\n",
addr, fault_pc);
SimulatorDebugger dbg(this);
dbg.Stop(instr, buffer);
@@ -998,7 +999,7 @@
// it will be possible to disassemble the code and inspect registers.
char buffer[64];
snprintf(buffer, sizeof(buffer),
- "unaligned %s at 0x%"Px", pc=%p\n", msg, addr, instr);
+ "unaligned %s at 0x%" Px ", pc=%p\n", msg, addr, instr);
SimulatorDebugger dbg(this);
dbg.Stop(instr, buffer);
// The debugger will return control in non-interactive mode.
@@ -1506,7 +1507,7 @@
Redirection* redirection = Redirection::FromSvcInstruction(instr);
uword external = redirection->external_function();
if (FLAG_trace_sim) {
- OS::Print("Call to host function at 0x%"Pd"\n", external);
+ OS::Print("Call to host function at 0x%" Pd "\n", external);
}
if ((redirection->call_kind() == kRuntimeCall) ||
diff --git a/runtime/vm/simulator_mips.cc b/runtime/vm/simulator_mips.cc
index fa8dbb8..7efabfa 100644
--- a/runtime/vm/simulator_mips.cc
+++ b/runtime/vm/simulator_mips.cc
@@ -314,7 +314,7 @@
if (last_pc != sim_->get_pc()) {
last_pc = sim_->get_pc();
if (Simulator::IsIllegalAddress(last_pc)) {
- OS::Print("pc is out of bounds: 0x%"Px"\n", last_pc);
+ OS::Print("pc is out of bounds: 0x%" Px "\n", last_pc);
} else {
Disassembler::Disassemble(last_pc, last_pc + Instr::kInstrSize);
}
@@ -818,7 +818,7 @@
// it will be possible to disassemble the code and inspect registers.
char buffer[128];
snprintf(buffer, sizeof(buffer),
- "illegal memory access at 0x%"Px", pc=0x%"Px"\n",
+ "illegal memory access at 0x%" Px ", pc=0x%" Px "\n",
addr, fault_pc);
SimulatorDebugger dbg(this);
dbg.Stop(instr, buffer);
@@ -832,7 +832,7 @@
// it will be possible to disassemble the code and inspect registers.
char buffer[128];
snprintf(buffer, sizeof(buffer),
- "pc=%p, unaligned %s at 0x%"Px"\n", instr, msg, addr);
+ "pc=%p, unaligned %s at 0x%" Px "\n", instr, msg, addr);
SimulatorDebugger dbg(this);
dbg.Stop(instr, buffer);
// The debugger will return control in non-interactive mode.
@@ -1005,7 +1005,7 @@
Redirection* redirection = Redirection::FromBreakInstruction(instr);
uword external = redirection->external_function();
if (FLAG_trace_sim) {
- OS::Print("Call to host function at 0x%"Pd"\n", external);
+ OS::Print("Call to host function at 0x%" Pd "\n", external);
}
if ((redirection->call_kind() == kRuntimeCall) ||
diff --git a/runtime/vm/snapshot_test.cc b/runtime/vm/snapshot_test.cc
index 0758462..0aac461 100644
--- a/runtime/vm/snapshot_test.cc
+++ b/runtime/vm/snapshot_test.cc
@@ -950,7 +950,7 @@
TestCase::LoadTestScript(kScriptChars, NULL);
EXPECT_VALID(Api::CheckIsolateState(isolate));
timer1.Stop();
- OS::PrintErr("Without Snapshot: %"Pd64"us\n", timer1.TotalElapsedTime());
+ OS::PrintErr("Without Snapshot: %" Pd64 "us\n", timer1.TotalElapsedTime());
// Write snapshot with object content.
FullSnapshotWriter writer(&buffer, &malloc_allocator);
@@ -965,7 +965,7 @@
{
Dart_EnterScope(); // Start a Dart API scope for invoking API functions.
timer2.Stop();
- OS::PrintErr("From Snapshot: %"Pd64"us\n", timer2.TotalElapsedTime());
+ OS::PrintErr("From Snapshot: %" Pd64 "us\n", timer2.TotalElapsedTime());
// Invoke a function which returns an object.
Dart_Handle cls =
@@ -1004,7 +1004,7 @@
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
EXPECT_VALID(Api::CheckIsolateState(isolate));
timer1.Stop();
- OS::PrintErr("Without Snapshot: %"Pd64"us\n", timer1.TotalElapsedTime());
+ OS::PrintErr("Without Snapshot: %" Pd64 "us\n", timer1.TotalElapsedTime());
// Write snapshot with object content.
FullSnapshotWriter writer(&buffer, &malloc_allocator);
@@ -1024,7 +1024,7 @@
{
Dart_EnterScope(); // Start a Dart API scope for invoking API functions.
timer2.Stop();
- OS::PrintErr("From Snapshot: %"Pd64"us\n", timer2.TotalElapsedTime());
+ OS::PrintErr("From Snapshot: %" Pd64 "us\n", timer2.TotalElapsedTime());
// Invoke a function which returns an object.
Dart_Handle cls = Dart_GetClass(TestCase::lib(),
diff --git a/runtime/vm/stack_frame.cc b/runtime/vm/stack_frame.cc
index 163e653..0a97d0b 100644
--- a/runtime/vm/stack_frame.cc
+++ b/runtime/vm/stack_frame.cc
@@ -27,7 +27,7 @@
void StackFrame::Print() const {
- OS::Print("[%-8s : sp(%#"Px") ]\n", GetName(), sp());
+ OS::Print("[%-8s : sp(%#" Px ") ]\n", GetName(), sp());
}
diff --git a/runtime/vm/symbols.cc b/runtime/vm/symbols.cc
index d35b1c1..22b970a 100644
--- a/runtime/vm/symbols.cc
+++ b/runtime/vm/symbols.cc
@@ -286,24 +286,24 @@
symbol_table = Dart::vm_isolate()->object_store()->symbol_table();
table_size = symbol_table.Length() - 1;
used ^= symbol_table.At(table_size);
- OS::Print("VM Isolate: Number of symbols : %"Pd"\n", used.Value());
- OS::Print("VM Isolate: Symbol table capacity : %"Pd"\n", table_size);
+ OS::Print("VM Isolate: Number of symbols : %" Pd "\n", used.Value());
+ OS::Print("VM Isolate: Symbol table capacity : %" Pd "\n", table_size);
// Now dump regular isolate symbol table stats.
symbol_table = Isolate::Current()->object_store()->symbol_table();
table_size = symbol_table.Length() - 1;
used ^= symbol_table.At(table_size);
- OS::Print("Isolate: Number of symbols : %"Pd"\n", used.Value());
- OS::Print("Isolate: Symbol table capacity : %"Pd"\n", table_size);
+ OS::Print("Isolate: Number of symbols : %" Pd "\n", used.Value());
+ OS::Print("Isolate: Symbol table capacity : %" Pd "\n", table_size);
// Dump overall collision and growth counts.
- OS::Print("Number of symbol table grows = %"Pd"\n", num_of_grows_);
+ OS::Print("Number of symbol table grows = %" Pd "\n", num_of_grows_);
OS::Print("Collision counts on add and lookup :\n");
intptr_t i = 0;
for (i = 0; i < (kMaxCollisionBuckets - 1); i++) {
- OS::Print(" %"Pd" collisions => %"Pd"\n", i, collision_count_[i]);
+ OS::Print(" %" Pd " collisions => %" Pd "\n", i, collision_count_[i]);
}
- OS::Print(" > %"Pd" collisions => %"Pd"\n", i, collision_count_[i]);
+ OS::Print(" > %" Pd " collisions => %" Pd "\n", i, collision_count_[i]);
}
}
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index c39133e..c892cbe 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -375,6 +375,9 @@
static const String& At() {
return *(symbol_handles_[kNullCharId + '@']);
}
+ static const String& Semicolon() {
+ return *(symbol_handles_[kNullCharId + ';']);
+ }
// Access methods for symbol handles stored in the vm isolate.
#define DEFINE_SYMBOL_HANDLE_ACCESSOR(symbol, literal) \
diff --git a/runtime/vm/thread_test.cc b/runtime/vm/thread_test.cc
index db850f4..ff8b563 100644
--- a/runtime/vm/thread_test.cc
+++ b/runtime/vm/thread_test.cc
@@ -53,7 +53,7 @@
// Check whether this attempt falls within the exptected time limits.
int64_t wakeup_time = stop - start;
- OS::Print("wakeup_time: %"Pd64"\n", wakeup_time);
+ OS::Print("wakeup_time: %" Pd64 "\n", wakeup_time);
const int kAcceptableTimeJitter = 20; // Measured in milliseconds.
const int kAcceptableWakeupDelay = 150; // Measured in milliseconds.
if (((wait_time - kAcceptableTimeJitter) <= wakeup_time) &&
diff --git a/runtime/vm/timer.cc b/runtime/vm/timer.cc
index 96c3224..d428af7 100644
--- a/runtime/vm/timer.cc
+++ b/runtime/vm/timer.cc
@@ -26,7 +26,7 @@
#define TIMER_FIELD_REPORT(name, msg) \
if (name().enabled() && name().message() != NULL) { \
- OS::Print("%s %"Pd64" micros.\n", \
+ OS::Print("%s %" Pd64 " micros.\n", \
name().message(), \
name().TotalElapsedTime()); \
}
diff --git a/runtime/vm/verifier.cc b/runtime/vm/verifier.cc
index ee6ac19..4270af2 100644
--- a/runtime/vm/verifier.cc
+++ b/runtime/vm/verifier.cc
@@ -32,7 +32,7 @@
if (raw_obj->IsHeapObject()) {
if (!allocated_set_->Contains(raw_obj)) {
uword raw_addr = RawObject::ToAddr(raw_obj);
- FATAL1("Invalid object pointer encountered %#"Px"\n", raw_addr);
+ FATAL1("Invalid object pointer encountered %#" Px "\n", raw_addr);
}
}
}
diff --git a/runtime/vm/zone.cc b/runtime/vm/zone.cc
index 5b43216..f0c7c5d 100644
--- a/runtime/vm/zone.cc
+++ b/runtime/vm/zone.cc
@@ -114,7 +114,7 @@
#if defined(DEBUG)
ASSERT(size >= 0);
if (FLAG_trace_zones) {
- OS::PrintErr("*** Expanding zone 0x%"Px"\n",
+ OS::PrintErr("*** Expanding zone 0x%" Px "\n",
reinterpret_cast<intptr_t>(this));
DumpZoneSizes();
}
@@ -179,8 +179,8 @@
for (Segment* s = large_segments_; s != NULL; s = s->next()) {
size += s->size();
}
- OS::PrintErr("*** Zone(0x%"Px") size in bytes,"
- " Total = %"Pd" Large Segments = %"Pd"\n",
+ OS::PrintErr("*** Zone(0x%" Px ") size in bytes,"
+ " Total = %" Pd " Large Segments = %" Pd "\n",
reinterpret_cast<intptr_t>(this), SizeInBytes(), size);
}
#endif
diff --git a/runtime/vm/zone.h b/runtime/vm/zone.h
index f932db9..ff53c21 100644
--- a/runtime/vm/zone.h
+++ b/runtime/vm/zone.h
@@ -162,7 +162,7 @@
zone_() {
#ifdef DEBUG
if (FLAG_trace_zones) {
- OS::PrintErr("*** Starting a new Stack zone 0x%"Px"(0x%"Px")\n",
+ OS::PrintErr("*** Starting a new Stack zone 0x%" Px "(0x%" Px ")\n",
reinterpret_cast<intptr_t>(this),
reinterpret_cast<intptr_t>(&zone_));
}
@@ -177,7 +177,7 @@
isolate()->set_current_zone(zone_.previous_);
#ifdef DEBUG
if (FLAG_trace_zones) {
- OS::PrintErr("*** Deleting Stack zone 0x%"Px"(0x%"Px")\n",
+ OS::PrintErr("*** Deleting Stack zone 0x%" Px "(0x%" Px ")\n",
reinterpret_cast<intptr_t>(this),
reinterpret_cast<intptr_t>(&zone_));
}
@@ -204,7 +204,7 @@
// Round up the requested size to fit the alignment.
if (size > (kIntptrMax - kAlignment)) {
- FATAL1("Zone::Alloc: 'size' is too large: size=%"Pd"", size);
+ FATAL1("Zone::Alloc: 'size' is too large: size=%" Pd "", size);
}
size = Utils::RoundUp(size, kAlignment);
@@ -227,7 +227,7 @@
inline ElementType* Zone::Alloc(intptr_t len) {
const intptr_t element_size = sizeof(ElementType);
if (len > (kIntptrMax / element_size)) {
- FATAL2("Zone::Alloc: 'len' is too large: len=%"Pd", element_size=%"Pd,
+ FATAL2("Zone::Alloc: 'len' is too large: len=%" Pd ", element_size=%" Pd,
len, element_size);
}
return reinterpret_cast<ElementType*>(AllocUnsafe(len * element_size));
diff --git a/sdk/lib/_internal/compiler/implementation/apiimpl.dart b/sdk/lib/_internal/compiler/implementation/apiimpl.dart
index 7923de79..b15631a 100644
--- a/sdk/lib/_internal/compiler/implementation/apiimpl.dart
+++ b/sdk/lib/_internal/compiler/implementation/apiimpl.dart
@@ -170,14 +170,10 @@
// directly. In effect, we don't support truly asynchronous API.
text = deprecatedFutureValue(provider(resourceUri));
} catch (exception) {
- if (node != null) {
- cancel("$exception", node: node);
- } else {
- reportError(
- null,
- leg.MessageKind.GENERIC, {'text': 'Error: $exception'});
- throw new leg.CompilerCancelledException("$exception");
- }
+ reportError(node,
+ leg.MessageKind.READ_SCRIPT_ERROR,
+ {'uri': readableUri, 'exception': exception});
+ return null;
}
SourceFile sourceFile = new SourceFile(resourceUri.toString(), text);
// We use [readableUri] as the URI for the script since need to preserve
@@ -216,34 +212,23 @@
}
}
if (!allowInternalLibraryAccess) {
- if (node != null && importingLibrary != null) {
+ if (importingLibrary != null) {
reportError(
node,
- leg.MessageKind.GENERIC,
- {'text':
- 'Error: Internal library $resolvedUri is not accessible from '
- '${importingLibrary.canonicalUri}.'});
+ leg.MessageKind.INTERNAL_LIBRARY_FROM,
+ {'resolvedUri': resolvedUri,
+ 'importingUri': importingLibrary.canonicalUri});
} else {
reportError(
- null,
- leg.MessageKind.GENERIC,
- {'text':
- 'Error: Internal library $resolvedUri is not accessible.'});
+ node,
+ leg.MessageKind.INTERNAL_LIBRARY,
+ {'resolvedUri': resolvedUri});
}
}
}
if (path == null) {
- if (node != null) {
- reportFatalError(
- node,
- leg.MessageKind.GENERIC,
- {'text': 'Error: Library not found ${resolvedUri}.'});
- } else {
- reportFatalError(
- null,
- leg.MessageKind.GENERIC,
- {'text': 'Error: Library not found ${resolvedUri}.'});
- }
+ reportError(node, leg.MessageKind.LIBRARY_NOT_FOUND,
+ {'resolvedUri': resolvedUri});
return null;
}
if (resolvedUri.path == 'html' ||
diff --git a/sdk/lib/_internal/compiler/implementation/closure.dart b/sdk/lib/_internal/compiler/implementation/closure.dart
index b0061d9..432292e 100644
--- a/sdk/lib/_internal/compiler/implementation/closure.dart
+++ b/sdk/lib/_internal/compiler/implementation/closure.dart
@@ -264,7 +264,7 @@
bool isClosure() => closureElement != null;
bool isVariableCaptured(Element element) {
- freeVariableMapping.containsKey(element);
+ return freeVariableMapping.containsKey(element);
}
bool isVariableBoxed(Element element) {
diff --git a/sdk/lib/_internal/compiler/implementation/compiler.dart b/sdk/lib/_internal/compiler/implementation/compiler.dart
index c5d9bb0..91ee72a 100644
--- a/sdk/lib/_internal/compiler/implementation/compiler.dart
+++ b/sdk/lib/_internal/compiler/implementation/compiler.dart
@@ -245,7 +245,7 @@
void registerStaticUse(Element element, Enqueuer enqueuer) {}
- void onLibraryScanned(LibraryElement library, Uri uri) {}
+ void onLibraryLoaded(LibraryElement library, Uri uri) {}
void registerMetadataInstantiatedType(DartType type, TreeElements elements) {}
void registerMetadataStaticUse(Element element) {}
@@ -754,7 +754,7 @@
* This method is called before [library] import and export scopes have been
* set up.
*/
- void onLibraryScanned(LibraryElement library, Uri uri) {
+ void onLibraryLoaded(LibraryElement library, Uri uri) {
if (dynamicClass != null) {
// When loading the built-in libraries, dynamicClass is null. We
// take advantage of this as core imports js_helper and sees [dynamic]
@@ -775,8 +775,14 @@
} else if (uri == new Uri(scheme: 'dart', path: 'async')) {
deferredLibraryClass =
findRequiredElement(library, const SourceString('DeferredLibrary'));
+ } else if (isolateHelperLibrary == null
+ && (uri == new Uri(scheme: 'dart', path: '_isolate_helper'))) {
+ isolateHelperLibrary = scanBuiltinLibrary('_isolate_helper');
+ } else if (foreignLibrary == null
+ && (uri == new Uri(scheme: 'dart', path: '_foreign_helper'))) {
+ foreignLibrary = scanBuiltinLibrary('_foreign_helper');
}
- backend.onLibraryScanned(library, uri);
+ backend.onLibraryLoaded(library, uri);
}
Element findRequiredElement(LibraryElement library, SourceString name) {
@@ -885,9 +891,6 @@
void scanBuiltinLibraries() {
jsHelperLibrary = scanBuiltinLibrary('_js_helper');
interceptorsLibrary = scanBuiltinLibrary('_interceptors');
- foreignLibrary = scanBuiltinLibrary('_foreign_helper');
- isolateHelperLibrary = scanBuiltinLibrary('_isolate_helper');
-
assertMethod = jsHelperLibrary.find(const SourceString('assertHelper'));
identicalFunction = coreLibrary.find(const SourceString('identical'));
diff --git a/sdk/lib/_internal/compiler/implementation/dart2jslib.dart b/sdk/lib/_internal/compiler/implementation/dart2jslib.dart
index 1af5315..b8a13a7 100644
--- a/sdk/lib/_internal/compiler/implementation/dart2jslib.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart2jslib.dart
@@ -29,6 +29,7 @@
import 'patch_parser.dart';
import 'types/types.dart' as ti;
import 'resolution/resolution.dart';
+import 'source_file.dart' show SourceFile;
import 'js/js.dart' as js;
import 'deferred_load.dart' show DeferredLoadTask;
import 'types/container_tracer.dart' show ContainerTracer;
diff --git a/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart b/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart
index 9f4c816..d9a6f1b 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart
@@ -409,7 +409,8 @@
&& isSafeToRemoveTypeDeclarations(classMembers));
renamePlaceholders(
compiler, collector, renames, imports,
- fixedMemberNames, shouldCutDeclarationTypes);
+ fixedMemberNames, shouldCutDeclarationTypes,
+ uniqueGlobalNaming: useMirrorHelperLibrary);
// Sort elements.
final sortedTopLevels = sortElements(topLevelElements);
diff --git a/sdk/lib/_internal/compiler/implementation/dart_backend/renamer.dart b/sdk/lib/_internal/compiler/implementation/dart_backend/renamer.dart
index 6dc9ad8..73480bf 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_backend/renamer.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_backend/renamer.dart
@@ -67,7 +67,8 @@
Map<Node, String> renames,
Map<LibraryElement, String> imports,
Set<String> fixedMemberNames,
- bool cutDeclarationTypes) {
+ bool cutDeclarationTypes,
+ {uniqueGlobalNaming: false}) {
final Map<LibraryElement, Map<String, String>> renamed
= new Map<LibraryElement, Map<String, String>>();
@@ -178,24 +179,34 @@
rename = makeRenamer(generateUniqueName);
renameElement = makeElementRenamer(rename, generateUniqueName);
- // Build a sorted (by usage) list 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.
- List<Set<Node>> allSortedLocals = new List<Set<Node>>();
- for (var 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((ph) => ph.nodes).toList();
- // Make room in all sorted locals list for new stuff.
- while (currentSortedNodes.length > allSortedLocals.length) {
- allSortedLocals.add(new Set<Node>());
+ List<Set<Node>> allLocals = new List<Set<Node>>();
+ // If we are using the mirror_helper library we need all names to be
+ // globally unique.
+ if (uniqueGlobalNaming) {
+ //TODO(zarah): Change this so that local variables don't get unique names.
+ for (var functionScope in placeholderCollector.functionScopes.values) {
+ functionScope.localPlaceholders.forEach(
+ (ph) => allLocals.add(ph.nodes.toSet()));
}
- for (int i = 0; i < currentSortedNodes.length; i++) {
- allSortedLocals[i].addAll(currentSortedNodes[i]);
+ } else {
+ // Build a sorted (by usage) list 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.
+ for (var 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((ph) => ph.nodes).toList();
+ // Make room in all sorted locals list for new stuff.
+ while (currentSortedNodes.length > allLocals.length) {
+ allLocals.add(new Set<Node>());
+ }
+ for (int i = 0; i < currentSortedNodes.length; i++) {
+ allLocals[i].addAll(currentSortedNodes[i]);
+ }
}
}
@@ -217,7 +228,7 @@
renamables.add(
new MemberRenamable(memberName, identifiers, memberRenamer));
});
- for (Set<Node> localIdentifiers in allSortedLocals) {
+ for (Set<Node> localIdentifiers in allLocals) {
renamables.add(new LocalRenamable(localIdentifiers, localRenamer));
}
renamables.sort((Renamable renamable1, Renamable renamable2) =>
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
index ee46294..7a809b7 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
@@ -366,7 +366,9 @@
}
bool canBeUsedForGlobalOptimizations(Element element) {
- if (element.isParameter() || element.isFieldParameter()) {
+ if (element.isParameter()
+ || element.isFieldParameter()
+ || element.isField()) {
element = element.enclosingElement;
}
return !helpersUsed.contains(element.declaration);
@@ -638,7 +640,7 @@
},
includeSuperAndInjectedMembers: true);
}
- enqueuer.registerInstantiatedClass(cls, elements);
+ enqueueClass(enqueuer, cls, elements);
}
void registerSpecializedGetInterceptor(Set<ClassElement> classes) {
@@ -660,11 +662,10 @@
if (enqueuer.isResolutionQueue) {
// TODO(9577): Make it so that these are not needed when there are no
// native classes.
- enqueuer.registerStaticUse(getNativeInterceptorMethod);
- enqueuer.registerStaticUse(defineNativeMethodsFinishMethod);
- enqueuer.registerStaticUse(initializeDispatchPropertyMethod);
- enqueuer.registerInstantiatedClass(jsInterceptorClass,
- compiler.globalDependencies);
+ enqueue(enqueuer, getNativeInterceptorMethod, elements);
+ enqueue(enqueuer, defineNativeMethodsFinishMethod, elements);
+ enqueue(enqueuer, initializeDispatchPropertyMethod, elements);
+ enqueueClass(enqueuer, jsInterceptorClass, compiler.globalDependencies);
}
}
@@ -675,24 +676,31 @@
|| cls == compiler.numClass) {
// The backend will try to optimize number operations and use the
// `iae` helper directly.
- enqueuer.registerStaticUse(
- compiler.findHelper(const SourceString('iae')));
+ enqueue(enqueuer,
+ compiler.findHelper(const SourceString('iae')),
+ elements);
} else if (cls == compiler.listClass
|| cls == compiler.stringClass) {
// The backend will try to optimize array and string access and use the
// `ioore` and `iae` helpers directly.
- enqueuer.registerStaticUse(
- compiler.findHelper(const SourceString('ioore')));
- enqueuer.registerStaticUse(
- compiler.findHelper(const SourceString('iae')));
+ enqueue(enqueuer,
+ compiler.findHelper(const SourceString('ioore')),
+ elements);
+ enqueue(enqueuer,
+ compiler.findHelper(const SourceString('iae')),
+ elements);
} else if (cls == compiler.functionClass) {
- enqueuer.registerInstantiatedClass(compiler.closureClass, elements);
+ enqueueClass(enqueuer, compiler.closureClass, elements);
} else if (cls == compiler.mapClass) {
// The backend will use a literal list to initialize the entries
// of the map.
- enqueuer.registerInstantiatedClass(compiler.listClass, elements);
- enqueuer.registerInstantiatedClass(mapLiteralClass, elements);
+ enqueueClass(enqueuer, compiler.listClass, elements);
+ enqueueClass(enqueuer, mapLiteralClass, elements);
enqueueInResolution(getMapMaker(), elements);
+ } else if (cls == compiler.boundClosureClass) {
+ // TODO(ngeoffray): Move the bound closure class in the
+ // backend.
+ enqueueClass(enqueuer, compiler.boundClosureClass, elements);
}
}
ClassElement result = null;
@@ -703,8 +711,8 @@
|| cls == jsFixedArrayClass
|| cls == jsExtendableArrayClass) {
addInterceptors(jsArrayClass, enqueuer, elements);
- enqueuer.registerInstantiatedClass(jsFixedArrayClass, elements);
- enqueuer.registerInstantiatedClass(jsExtendableArrayClass, elements);
+ enqueueClass(enqueuer, jsFixedArrayClass, elements);
+ enqueueClass(enqueuer, jsExtendableArrayClass, elements);
} else if (cls == compiler.intClass || cls == jsIntClass) {
addInterceptors(jsIntClass, enqueuer, elements);
addInterceptors(jsNumberClass, enqueuer, elements);
@@ -731,11 +739,11 @@
void registerUseInterceptor(Enqueuer enqueuer) {
assert(!enqueuer.isResolutionQueue);
if (!enqueuer.nativeEnqueuer.hasInstantiatedNativeClasses()) return;
- enqueuer.registerStaticUse(getNativeInterceptorMethod);
- enqueuer.registerStaticUse(defineNativeMethodsFinishMethod);
- enqueuer.registerStaticUse(initializeDispatchPropertyMethod);
TreeElements elements = compiler.globalDependencies;
- enqueuer.registerInstantiatedClass(jsPlainJavaScriptObjectClass, elements);
+ enqueue(enqueuer, getNativeInterceptorMethod, elements);
+ enqueue(enqueuer, defineNativeMethodsFinishMethod, elements);
+ enqueue(enqueuer, initializeDispatchPropertyMethod, elements);
+ enqueueClass(enqueuer, jsPlainJavaScriptObjectClass, elements);
needToInitializeDispatchProperty = true;
}
@@ -749,10 +757,14 @@
if (jsIndexingBehaviorInterface != null) {
world.registerIsCheck(jsIndexingBehaviorInterface.computeType(compiler),
elements);
- world.registerStaticUse(
- compiler.findHelper(const SourceString('isJsIndexable')));
- world.registerStaticUse(
- compiler.findInterceptor(const SourceString('dispatchPropertyName')));
+ enqueue(
+ world,
+ compiler.findHelper(const SourceString('isJsIndexable')),
+ elements);
+ enqueue(
+ world,
+ compiler.findInterceptor(const SourceString('dispatchPropertyName')),
+ elements);
}
if (compiler.enableTypeAssertions) {
@@ -774,7 +786,7 @@
void registerCatchStatement(Enqueuer enqueuer, TreeElements elements) {
void ensure(ClassElement classElement) {
if (classElement != null) {
- enqueuer.registerInstantiatedClass(classElement, elements);
+ enqueueClass(enqueuer, classElement, elements);
}
}
enqueueInResolution(getExceptionUnwrapper(), elements);
@@ -835,7 +847,7 @@
enqueue(enqueuer, getGetRuntimeTypeInfo(), elements);
enqueue(enqueuer, getComputeSignature(), elements);
enqueue(enqueuer, getGetRuntimeTypeArguments(), elements);
- enqueuer.registerInstantiatedClass(compiler.listClass, elements);
+ enqueueClass(enqueuer, compiler.listClass, elements);
}
void registerRuntimeType(Enqueuer enqueuer, TreeElements elements) {
@@ -843,23 +855,21 @@
enqueueInResolution(getSetRuntimeTypeInfo(), elements);
enqueueInResolution(getGetRuntimeTypeInfo(), elements);
registerGetRuntimeTypeArgument(elements);
- compiler.enqueuer.resolution.registerInstantiatedClass(
- compiler.listClass, elements);
+ enqueueClass(enqueuer, compiler.listClass, elements);
}
void registerTypeVariableExpression(TreeElements elements) {
enqueueInResolution(getSetRuntimeTypeInfo(), elements);
enqueueInResolution(getGetRuntimeTypeInfo(), elements);
registerGetRuntimeTypeArgument(elements);
- compiler.enqueuer.resolution.registerInstantiatedClass(
- compiler.listClass, elements);
+ enqueueClass(compiler.enqueuer.resolution, compiler.listClass, elements);
enqueueInResolution(getRuntimeTypeToString(), elements);
enqueueInResolution(getCreateRuntimeType(), elements);
}
void registerIsCheck(DartType type, Enqueuer world, TreeElements elements) {
type = type.unalias(compiler);
- world.registerInstantiatedClass(compiler.boolClass, elements);
+ enqueueClass(world, compiler.boolClass, elements);
bool inCheckedMode = compiler.enableTypeAssertions;
// [registerIsCheck] is also called for checked mode checks, so we
// need to register checked mode helpers.
@@ -885,7 +895,7 @@
enqueueInResolution(getAssertSubtypeOfRuntimeType(), elements);
}
}
- world.registerInstantiatedClass(compiler.listClass, elements);
+ enqueueClass(world, compiler.listClass, elements);
}
if (type is FunctionType) {
enqueueInResolution(getCheckFunctionSubtype(), elements);
@@ -914,24 +924,20 @@
void registerThrowNoSuchMethod(TreeElements elements) {
enqueueInResolution(getThrowNoSuchMethod(), elements);
// Also register the types of the arguments passed to this method.
- compiler.enqueuer.resolution.registerInstantiatedClass(
- compiler.listClass, elements);
- compiler.enqueuer.resolution.registerInstantiatedClass(
- compiler.stringClass, elements);
+ enqueueClass(compiler.enqueuer.resolution, compiler.listClass, elements);
+ enqueueClass(compiler.enqueuer.resolution, compiler.stringClass, elements);
}
void registerThrowRuntimeError(TreeElements elements) {
enqueueInResolution(getThrowRuntimeError(), elements);
// Also register the types of the arguments passed to this method.
- compiler.enqueuer.resolution.registerInstantiatedClass(
- compiler.stringClass, elements);
+ enqueueClass(compiler.enqueuer.resolution, compiler.stringClass, elements);
}
void registerAbstractClassInstantiation(TreeElements elements) {
enqueueInResolution(getThrowAbstractClassInstantiationError(), elements);
// Also register the types of the arguments passed to this method.
- compiler.enqueuer.resolution.registerInstantiatedClass(
- compiler.stringClass, elements);
+ enqueueClass(compiler.enqueuer.resolution, compiler.stringClass, elements);
}
void registerFallThroughError(TreeElements elements) {
@@ -943,8 +949,7 @@
enqueueInResolution(
compiler.objectClass.lookupLocalMember(Compiler.NO_SUCH_METHOD),
elements);
- compiler.enqueuer.resolution.registerInstantiatedClass(
- compiler.listClass, elements);
+ enqueueClass(compiler.enqueuer.resolution, compiler.listClass, elements);
}
void registerRequiredType(DartType type, Element enclosingElement) {
@@ -1016,6 +1021,7 @@
// Therefore we need to collect the list of helpers the backend may
// use.
void enqueue(Enqueuer enqueuer, Element e, TreeElements elements) {
+ if (e == null) return;
helpersUsed.add(e.declaration);
enqueuer.addToWorkList(e);
elements.registerDependency(e);
@@ -1027,14 +1033,25 @@
enqueue(enqueuer, e, elements);
}
+ void enqueueClass(Enqueuer enqueuer, Element cls, TreeElements elements) {
+ if (cls == null) return;
+ helpersUsed.add(cls.declaration);
+ // Both declaration and implementation may declare fields, so we
+ // add both to the list of helpers.
+ if (cls.declaration != cls.implementation) {
+ helpersUsed.add(cls.implementation);
+ }
+ enqueuer.registerInstantiatedClass(cls, elements);
+ }
+
void registerConstantMap(TreeElements elements) {
Element e = compiler.findHelper(const SourceString('ConstantMap'));
if (e != null) {
- compiler.enqueuer.resolution.registerInstantiatedClass(e, elements);
+ enqueueClass(compiler.enqueuer.resolution, e, elements);
}
e = compiler.findHelper(const SourceString('ConstantProtoMap'));
if (e != null) {
- compiler.enqueuer.resolution.registerInstantiatedClass(e, elements);
+ enqueueClass(compiler.enqueuer.resolution, e, elements);
}
}
@@ -1457,7 +1474,7 @@
return false;
}
- void onLibraryScanned(LibraryElement library, Uri uri) {
+ void onLibraryLoaded(LibraryElement library, Uri uri) {
if (uri == Uri.parse('dart:_js_mirrors')) {
disableTreeShakingMarker =
library.find(const SourceString('disableTreeShaking'));
diff --git a/sdk/lib/_internal/compiler/implementation/library_loader.dart b/sdk/lib/_internal/compiler/implementation/library_loader.dart
index 8f4f224..55031d2 100644
--- a/sdk/lib/_internal/compiler/implementation/library_loader.dart
+++ b/sdk/lib/_internal/compiler/implementation/library_loader.dart
@@ -220,6 +220,7 @@
class LibraryLoaderTask extends LibraryLoader {
LibraryLoaderTask(Compiler compiler) : super(compiler);
String get name => 'LibraryLoader';
+ List onLibraryLoadedCallbacks = [];
final Map<String, LibraryElement> libraryNames =
new LinkedHashMap<String, LibraryElement>();
@@ -234,6 +235,9 @@
createLibrary(currentHandler, null, resolvedUri, node, canonicalUri);
currentHandler.computeExports();
currentHandler = null;
+ var workList = onLibraryLoadedCallbacks;
+ onLibraryLoadedCallbacks = [];
+ workList.forEach((f) => f());
return library;
});
}
@@ -362,7 +366,9 @@
void scanPart(Part part, Uri resolvedUri, LibraryElement library) {
if (!resolvedUri.isAbsolute) throw new ArgumentError(resolvedUri);
Uri readableUri = compiler.translateResolvedUri(library, resolvedUri, part);
+ if (readableUri == null) return;
Script sourceScript = compiler.readScript(readableUri, part);
+ if (sourceScript == null) return;
CompilationUnitElement unit =
new CompilationUnitElementX(sourceScript, library);
compiler.withCurrentElement(unit, () {
@@ -385,6 +391,7 @@
Uri resolvedUri = base.resolve(tag.uri.dartString.slowToString());
LibraryElement loadedLibrary =
createLibrary(handler, library, resolvedUri, tag.uri, resolvedUri);
+ if (loadedLibrary == null) return;
handler.registerDependency(library, tag, loadedLibrary);
if (!loadedLibrary.hasLibraryName()) {
@@ -409,31 +416,32 @@
LibraryElement createLibrary(LibraryDependencyHandler handler,
LibraryElement importingLibrary,
Uri resolvedUri, Node node, Uri canonicalUri) {
- bool newLibrary = false;
+ // TODO(johnniwinther): Create erroneous library elements for missing
+ // libraries.
Uri readableUri =
compiler.translateResolvedUri(importingLibrary, resolvedUri, node);
if (readableUri == null) return null;
- LibraryElement createLibrary() {
- newLibrary = true;
- Script script = compiler.readScript(readableUri, node);
- LibraryElement element = new LibraryElementX(script, canonicalUri);
- handler.registerNewLibrary(element);
- native.maybeEnableNative(compiler, element);
- return element;
- }
LibraryElement library;
- if (canonicalUri == null) {
- library = createLibrary();
- } else {
- library = compiler.libraries.putIfAbsent(canonicalUri.toString(),
- createLibrary);
+ if (canonicalUri != null) {
+ library = compiler.libraries[canonicalUri.toString()];
}
- if (newLibrary) {
+ if (library == null) {
+ Script script = compiler.readScript(readableUri, node);
+ if (script == null) return null;
+
+ library = new LibraryElementX(script, canonicalUri);
+ handler.registerNewLibrary(library);
+ native.maybeEnableNative(compiler, library);
+ if (canonicalUri != null) {
+ compiler.libraries[canonicalUri.toString()] = library;
+ }
+
compiler.withCurrentElement(library, () {
compiler.scanner.scanLibrary(library);
processLibraryTags(handler, library);
handler.registerLibraryExports(library);
- compiler.onLibraryScanned(library, resolvedUri);
+ onLibraryLoadedCallbacks.add(
+ () => compiler.onLibraryLoaded(library, resolvedUri));
});
}
return library;
diff --git a/sdk/lib/_internal/compiler/implementation/native_handler.dart b/sdk/lib/_internal/compiler/implementation/native_handler.dart
index 724383c..5fc7944 100644
--- a/sdk/lib/_internal/compiler/implementation/native_handler.dart
+++ b/sdk/lib/_internal/compiler/implementation/native_handler.dart
@@ -119,10 +119,10 @@
void processNativeClasses(Iterable<LibraryElement> libraries) {
libraries.forEach(processNativeClassesInLibrary);
- processNativeClassesInLibrary(compiler.isolateHelperLibrary);
-
+ if (compiler.isolateHelperLibrary != null) {
+ processNativeClassesInLibrary(compiler.isolateHelperLibrary);
+ }
processSubclassesOfNativeClasses(libraries);
-
if (!enableLiveTypeAnalysis) {
nativeClasses.forEach((c) => enqueueClass(c, 'forced'));
flushQueue();
diff --git a/sdk/lib/_internal/compiler/implementation/script.dart b/sdk/lib/_internal/compiler/implementation/script.dart
index b130616..f6cda01 100644
--- a/sdk/lib/_internal/compiler/implementation/script.dart
+++ b/sdk/lib/_internal/compiler/implementation/script.dart
@@ -5,10 +5,7 @@
part of dart2js;
class Script {
- // TODO(kasperl): Once MockFile in tests/compiler/dart2js/parser_helper.dart
- // implements SourceFile, we should be able to type the [file] field as
- // such.
- final file;
+ final SourceFile file;
/**
* The readable URI from which this script was loaded.
diff --git a/sdk/lib/_internal/compiler/implementation/source_file_provider.dart b/sdk/lib/_internal/compiler/implementation/source_file_provider.dart
index 4cbd641..3188a3e 100644
--- a/sdk/lib/_internal/compiler/implementation/source_file_provider.dart
+++ b/sdk/lib/_internal/compiler/implementation/source_file_provider.dart
@@ -38,8 +38,8 @@
try {
source = readAll(uriPathToNative(resourceUri.path));
} on FileException catch (ex) {
- throw 'Error: Cannot read "${relativize(cwd, resourceUri, isWindows)}" '
- '(${ex.osError}).';
+ throw "Error reading '${relativize(cwd, resourceUri, isWindows)}' "
+ "(${ex.osError})";
}
dartCharactersRead += source.length;
sourceFiles[resourceUri.toString()] = new SourceFile(
diff --git a/sdk/lib/_internal/compiler/implementation/types/flat_type_mask.dart b/sdk/lib/_internal/compiler/implementation/types/flat_type_mask.dart
index b9a50a2..449ae88 100644
--- a/sdk/lib/_internal/compiler/implementation/types/flat_type_mask.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/flat_type_mask.dart
@@ -21,8 +21,6 @@
FlatTypeMask(DartType base, int kind, bool isNullable)
: this.internal(base, (kind << 1) | (isNullable ? 1 : 0));
- FlatTypeMask.empty()
- : this.internal(null, (EMPTY << 1) | 1);
FlatTypeMask.exact(DartType base)
: this.internal(base, (EXACT << 1) | 1);
FlatTypeMask.subclass(DartType base)
@@ -30,8 +28,9 @@
FlatTypeMask.subtype(DartType base)
: this.internal(base, (SUBTYPE << 1) | 1);
- FlatTypeMask.nonNullEmpty()
- : this.internal(null, EMPTY << 1);
+ const FlatTypeMask.nonNullEmpty(): base = null, flags = 0;
+ const FlatTypeMask.empty() : base = null, flags = 1;
+
FlatTypeMask.nonNullExact(DartType base)
: this.internal(base, EXACT << 1);
FlatTypeMask.nonNullSubclass(DartType base)
diff --git a/sdk/lib/_internal/compiler/implementation/types/inferrer_visitor.dart b/sdk/lib/_internal/compiler/implementation/types/inferrer_visitor.dart
index 00c9295..e835be0 100644
--- a/sdk/lib/_internal/compiler/implementation/types/inferrer_visitor.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/inferrer_visitor.dart
@@ -79,6 +79,12 @@
* Adds [newType] as an input of [phiType].
*/
T addPhiInput(Element element, T phiType, T newType);
+
+ /**
+ * Returns a new receiver type for this [selector] applied to
+ * [receiverType].
+ */
+ T refineReceiver(Selector selector, T receiverType);
}
/**
diff --git a/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart b/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart
index 6fe350d..519d1fd 100644
--- a/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart
@@ -122,6 +122,15 @@
TypeMask simplifyPhi(Node node, Element element, TypeMask phiType) {
return phiType;
}
+
+ TypeMask refineReceiver(Selector selector, TypeMask receiverType) {
+ // If the receiver is based on an element, we let the type
+ // inferrer handle it. Otherwise, we might prevent it from finding
+ // one-level cycles in the inference graph.
+ if (receiverType.isElement) return receiverType;
+ TypeMask newType = compiler.world.allFunctions.receiverType(selector);
+ return receiverType.intersection(newType, compiler);
+ }
}
/**
@@ -1582,6 +1591,7 @@
SideEffects sideEffects = new SideEffects.empty();
final Element outermostElement;
final InferrerEngine<T> inferrer;
+ final Set<Element> capturedVariables = new Set<Element>();
SimpleTypeInferrerVisitor.internal(analyzedElement,
this.outermostElement,
@@ -1735,11 +1745,14 @@
// same as [newType].
ClosureClassMap nestedClosureData =
compiler.closureToClassMapper.getMappingForNestedFunction(node);
- nestedClosureData.forEachNonBoxedCapturedVariable((variable, field) {
- // The type may be null for instance contexts: the 'this'
- // variable and type parameters.
- if (locals.locals[variable] == null) return;
- inferrer.recordType(field, locals.locals[variable]);
+ nestedClosureData.forEachCapturedVariable((variable, field) {
+ if (!nestedClosureData.isVariableBoxed(variable)) {
+ // The type may be null for instance contexts: the 'this'
+ // variable and type parameters.
+ if (locals.locals[variable] == null) return;
+ inferrer.recordType(field, locals.locals[variable]);
+ }
+ capturedVariables.add(variable);
});
return types.functionType;
@@ -2164,17 +2177,32 @@
T handleDynamicSend(Node node,
Selector selector,
- T receiver,
+ T receiverType,
ArgumentsTypes arguments,
[CallSite constraint]) {
- if (selector.mask != receiver) {
- selector = (receiver == types.dynamicType)
+ if (selector.mask != receiverType) {
+ selector = (receiverType == types.dynamicType)
? selector.asUntyped
- : types.newTypedSelector(receiver, selector);
+ : types.newTypedSelector(receiverType, selector);
updateSelectorInTree(node, selector);
}
+
+ // If the receiver of the call is a local, we may know more about
+ // its type by refining it with the potential targets of the
+ // calls.
+ if (node.asSend() != null) {
+ Node receiver = node.asSend().receiver;
+ if (receiver != null) {
+ Element element = elements[receiver];
+ if (Elements.isLocal(element) && !capturedVariables.contains(element)) {
+ T refinedType = types.refineReceiver(selector, receiverType);
+ locals.update(element, refinedType, node);
+ }
+ }
+ }
+
return inferrer.registerCalledSelector(
- node, selector, receiver, outermostElement, arguments,
+ node, selector, receiverType, outermostElement, arguments,
constraint, sideEffects, inLoop);
}
diff --git a/sdk/lib/_internal/compiler/implementation/types/type_mask.dart b/sdk/lib/_internal/compiler/implementation/types/type_mask.dart
index 334b520..47bd8bf 100644
--- a/sdk/lib/_internal/compiler/implementation/types/type_mask.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/type_mask.dart
@@ -13,14 +13,13 @@
factory TypeMask(DartType base, int kind, bool isNullable)
=> new FlatTypeMask(base, kind, isNullable);
- factory TypeMask.empty() => new FlatTypeMask.empty();
+ const factory TypeMask.empty() = FlatTypeMask.empty;
factory TypeMask.exact(DartType base) => new FlatTypeMask.exact(base);
factory TypeMask.subclass(DartType base) => new FlatTypeMask.subclass(base);
factory TypeMask.subtype(DartType base) => new FlatTypeMask.subtype(base);
- factory TypeMask.nonNullEmpty()
- => new FlatTypeMask.nonNullEmpty();
+ const factory TypeMask.nonNullEmpty() = FlatTypeMask.nonNullEmpty;
factory TypeMask.nonNullExact(DartType base)
=> new FlatTypeMask.nonNullExact(base);
factory TypeMask.nonNullSubclass(DartType base)
diff --git a/sdk/lib/_internal/compiler/implementation/universe/function_set.dart b/sdk/lib/_internal/compiler/implementation/universe/function_set.dart
index 6d3f4b7..a228736 100644
--- a/sdk/lib/_internal/compiler/implementation/universe/function_set.dart
+++ b/sdk/lib/_internal/compiler/implementation/universe/function_set.dart
@@ -49,20 +49,28 @@
* that may be invoked with the given [selector].
*/
Iterable<Element> filter(Selector selector) {
+ return query(selector).functions;
+ }
+
+ TypeMask receiverType(Selector selector) {
+ return query(selector).computeMask(compiler);
+ }
+
+ FunctionSetQuery query(Selector selector) {
SourceString name = selector.name;
FunctionSetNode node = nodes[name];
FunctionSetNode noSuchMethods = nodes[Compiler.NO_SUCH_METHOD];
if (node != null) {
- return node.query(selector, compiler, noSuchMethods).functions;
+ return node.query(selector, compiler, noSuchMethods);
}
// If there is no method that matches [selector] we know we can
// only hit [:noSuchMethod:].
- if (noSuchMethods == null) return const <Element>[];
+ if (noSuchMethods == null) return const FunctionSetQuery(const <Element>[]);
selector = (selector.mask == null)
? compiler.noSuchMethodSelector
: new TypedSelector(selector.mask, compiler.noSuchMethodSelector);
- return noSuchMethods.query(selector, compiler, null).functions;
+ return noSuchMethods.query(selector, compiler, null);
}
void forEach(Function action) {
@@ -186,11 +194,41 @@
FunctionSetQuery newQuery(Iterable<Element> functions,
Selector selector,
Compiler compiler) {
- return new FunctionSetQuery(functions);
+ return new FullFunctionSetQuery(functions);
}
}
class FunctionSetQuery {
final Iterable<Element> functions;
+ TypeMask computeMask(Compiler compiler) => const TypeMask.nonNullEmpty();
const FunctionSetQuery(this.functions);
}
+
+class FullFunctionSetQuery extends FunctionSetQuery {
+ TypeMask _mask;
+
+ /**
+ * Compute the type of all potential receivers of this function set.
+ */
+ TypeMask computeMask(Compiler compiler) {
+ if (_mask != null) return _mask;
+ return _mask = new TypeMask.unionOf(functions
+ .expand((element) {
+ ClassElement cls = element.getEnclosingClass();
+ return compiler.world.isUsedAsMixin(cls)
+ ? ([cls]..addAll(compiler.world.mixinUses[cls]))
+ : [cls];
+ })
+ .map((cls) {
+ if (compiler.backend.isNullImplementation(cls)) {
+ return const TypeMask.empty();
+ }
+ return compiler.world.hasSubclasses(cls)
+ ? new TypeMask.nonNullSubclass(cls.rawType)
+ : new TypeMask.nonNullExact(cls.rawType);
+ }),
+ compiler);
+ }
+
+ FullFunctionSetQuery(functions) : super(functions);
+}
diff --git a/sdk/lib/_internal/compiler/implementation/warnings.dart b/sdk/lib/_internal/compiler/implementation/warnings.dart
index 803d5a9..7edacfa 100644
--- a/sdk/lib/_internal/compiler/implementation/warnings.dart
+++ b/sdk/lib/_internal/compiler/implementation/warnings.dart
@@ -631,6 +631,16 @@
static const MessageKind PACKAGE_ROOT_NOT_SET = const MessageKind(
'Error: Cannot resolve "#{uri}". Package root has not been set.');
+ static const MessageKind INTERNAL_LIBRARY_FROM = const MessageKind(
+ 'Error: Internal library "#{resolvedUri}" is not accessible from '
+ '"#{importingUri}".');
+
+ static const MessageKind INTERNAL_LIBRARY = const MessageKind(
+ 'Error: Internal library "#{resolvedUri}" is not accessible.');
+
+ static const MessageKind LIBRARY_NOT_FOUND = const MessageKind(
+ 'Error: Library not found "#{resolvedUri}".');
+
static const MessageKind UNSUPPORTED_EQ_EQ_EQ = const MessageKind(
'Error: "===" is not an operator. '
'Did you mean "#{lhs} == #{rhs}" or "identical(#{lhs}, #{rhs})"?');
@@ -742,6 +752,16 @@
main() {}
"""]);
+ static const MessageKind READ_SCRIPT_ERROR = const MessageKind(
+ "Error: Can't read '#{uri}' (#{exception}).",
+ examples: const [
+ """
+// 'foo.dart' does not exist.
+import 'foo.dart';
+
+main() {}
+"""]);
+
static const MessageKind COMPILER_CRASHED = const MessageKind(
'Error: The compiler crashed when compiling this element.');
diff --git a/sdk/lib/_internal/compiler/implementation/world.dart b/sdk/lib/_internal/compiler/implementation/world.dart
index 9bcc17f..2382113 100644
--- a/sdk/lib/_internal/compiler/implementation/world.dart
+++ b/sdk/lib/_internal/compiler/implementation/world.dart
@@ -47,6 +47,11 @@
return _typesImplementedBySubclasses[cls.declaration];
}
+ bool hasSubclasses(ClassElement cls) {
+ Set<ClassElement> subclasses = compiler.world.subclassesOf(cls);
+ return subclasses != null && !subclasses.isEmpty;
+ }
+
World(Compiler compiler)
: allFunctions = new FunctionSet(compiler),
this.compiler = compiler;
diff --git a/sdk/lib/_internal/lib/interceptors.dart b/sdk/lib/_internal/lib/interceptors.dart
index fedc0f6..c40b797 100644
--- a/sdk/lib/_internal/lib/interceptors.dart
+++ b/sdk/lib/_internal/lib/interceptors.dart
@@ -365,7 +365,7 @@
/**
* The interceptor class for [Null].
*
- * This class defines implementations for *all* methods on [Object] since the
+ * This class defines implementations for *all* methods on [Object] since
* the methods on Object assume the receiver is non-null. This means that
* JSNull will always be in the interceptor set for methods defined on Object.
*/
diff --git a/sdk/lib/_internal/lib/io_patch.dart b/sdk/lib/_internal/lib/io_patch.dart
index e41a2ce..4216317 100644
--- a/sdk/lib/_internal/lib/io_patch.dart
+++ b/sdk/lib/_internal/lib/io_patch.dart
@@ -163,7 +163,13 @@
throw new UnsupportedError("Platform._localHostname");
}
patch static _executable() {
- throw new UnsupportedError("Platform_Executable");
+ throw new UnsupportedError("Platform._executable");
+ }
+ patch static List<String> _executableArguments() {
+ throw new UnsupportedError("Platform._executableArguments");
+ }
+ patch static String _packageRoot() {
+ throw new UnsupportedError("Platform._packageRoot");
}
patch static _environment() {
throw new UnsupportedError("Platform._environment");
diff --git a/sdk/lib/_internal/pub/lib/src/command/list_package_dirs.dart b/sdk/lib/_internal/pub/lib/src/command/list_package_dirs.dart
index ea5b140..fc05630 100644
--- a/sdk/lib/_internal/pub/lib/src/command/list_package_dirs.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/list_package_dirs.dart
@@ -8,6 +8,8 @@
import 'dart:io';
import 'dart:json' as json;
+import 'package:path/path.dart' as path;
+
import '../command.dart';
import '../exit_codes.dart' as exit_codes;
import '../log.dart' as log;
@@ -32,14 +34,26 @@
}
var output = {};
+
+ // Include the local paths to all locked packages.
+ var packages = {};
var futures = [];
entrypoint.loadLockFile().packages.forEach((name, package) {
var source = entrypoint.cache.sources[package.source];
futures.add(source.getDirectory(package).then((packageDir) {
- output[name] = packageDir;
+ packages[name] = path.join(packageDir, "lib");
}));
});
+ output["packages"] = packages;
+
+ // Include the self link.
+ packages[entrypoint.root.name] = path.join(entrypoint.root.dir, "lib");
+
+ // Include the file(s) which when modified will affect the results. For pub,
+ // that's just the lockfile.
+ output["input_files"] = [entrypoint.lockFilePath];
+
return Future.wait(futures).then((_) {
log.message(json.stringify(output));
});
diff --git a/sdk/lib/_internal/pub/lib/src/entrypoint.dart b/sdk/lib/_internal/pub/lib/src/entrypoint.dart
index 9ec81ec..aec7cf9 100644
--- a/sdk/lib/_internal/pub/lib/src/entrypoint.dart
+++ b/sdk/lib/_internal/pub/lib/src/entrypoint.dart
@@ -54,7 +54,10 @@
String get packagesDir => path.join(root.dir, 'packages');
/// `true` if the entrypoint package currently has a lock file.
- bool get lockFileExists => entryExists(_lockFilePath);
+ bool get lockFileExists => entryExists(lockFilePath);
+
+ /// The path to the entrypoint package's lockfile.
+ String get lockFilePath => path.join(root.dir, 'pubspec.lock');
/// Ensures that the package identified by [id] is installed to the directory.
/// Returns the resolved [PackageId].
@@ -150,7 +153,7 @@
/// exists. If it doesn't, this completes to an empty [LockFile].
LockFile loadLockFile() {
if (!lockFileExists) return new LockFile.empty();
- return new LockFile.load(_lockFilePath, cache.sources);
+ return new LockFile.load(lockFilePath, cache.sources);
}
/// Determines whether or not the lockfile is out of date with respect to the
@@ -183,9 +186,6 @@
return true;
}
- /// The path to the entrypoint package's lockfile.
- String get _lockFilePath => path.join(root.dir, 'pubspec.lock');
-
/// Saves a list of concrete package versions to the `pubspec.lock` file.
void _saveLockFile(List<PackageId> packageIds) {
var lockFile = new LockFile.empty();
diff --git a/sdk/lib/_internal/pub/lib/src/pub_package_provider.dart b/sdk/lib/_internal/pub/lib/src/pub_package_provider.dart
index 0c43571..0e2c51b 100644
--- a/sdk/lib/_internal/pub/lib/src/pub_package_provider.dart
+++ b/sdk/lib/_internal/pub/lib/src/pub_package_provider.dart
@@ -46,9 +46,6 @@
/// Gets the root directory of [package].
String getPackageDir(String package) => _packageDirs[package];
- // TODO(rnystrom): Actually support transformers.
- Iterable<Iterable<Transformer>> getTransformers(String package) => [];
-
Future<Asset> getAsset(AssetId id) {
var file = path.join(_packageDirs[id.package], id.path);
return new Future.value(new Asset.fromPath(id, file));
diff --git a/sdk/lib/_internal/pub/pub.status b/sdk/lib/_internal/pub/pub.status
index 7d8c4fb..951e99a 100644
--- a/sdk/lib/_internal/pub/pub.status
+++ b/sdk/lib/_internal/pub/pub.status
@@ -2,6 +2,11 @@
# 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.
+test/serve/missing_file_test: Pass, Fail # 12570
+test/oauth2/with_an_expired_credentials_refreshes_and_saves_test: Pass, Fail # 12581
+test/hosted/remove_removed_dependency_test: Pass, Fail # 12582
+test/hosted/remove_removed_transitive_dependency_test: Pass, Fail # 12582
+
# Pub only runs on the VM, so just rule out all compilers.
[ $compiler == dart2js || $compiler == dart2dart ]
*: Skip
diff --git a/sdk/lib/_internal/pub/test/list_package_dirs/ignores_updated_pubspec_test.dart b/sdk/lib/_internal/pub/test/list_package_dirs/ignores_updated_pubspec_test.dart
index bc13c27..6d539a6 100644
--- a/sdk/lib/_internal/pub/test/list_package_dirs/ignores_updated_pubspec_test.dart
+++ b/sdk/lib/_internal/pub/test/list_package_dirs/ignores_updated_pubspec_test.dart
@@ -4,8 +4,7 @@
import 'package:path/path.dart' as path;
-import '../../lib/src/exit_codes.dart' as exit_codes;
-
+import '../../lib/src/io.dart';
import '../descriptor.dart' as d;
import '../test_pub.dart';
@@ -32,9 +31,19 @@
})
]).create();
+ // Note: Using canonicalize here because pub gets the path to the
+ // entrypoint package from the working directory, which has had symlinks
+ // resolve. On Mac, "/tmp" is actually a symlink to "/private/tmp", so we
+ // need to accomodate that.
schedulePub(args: ["list-package-dirs", "--format=json"],
outputJson: {
- "foo": path.join(sandboxDir, "foo")
+ "packages": {
+ "foo": path.join(sandboxDir, "foo", "lib"),
+ "myapp": canonicalize(path.join(sandboxDir, appPath, "lib"))
+ },
+ "input_files": [
+ canonicalize(path.join(sandboxDir, appPath, "pubspec.lock"))
+ ]
});
});
}
\ No newline at end of file
diff --git a/sdk/lib/_internal/pub/test/list_package_dirs/includes_dev_dependencies_test.dart b/sdk/lib/_internal/pub/test/list_package_dirs/includes_dev_dependencies_test.dart
index 60c7786..a5761d2 100644
--- a/sdk/lib/_internal/pub/test/list_package_dirs/includes_dev_dependencies_test.dart
+++ b/sdk/lib/_internal/pub/test/list_package_dirs/includes_dev_dependencies_test.dart
@@ -4,6 +4,7 @@
import 'package:path/path.dart' as path;
+import '../../lib/src/io.dart';
import '../descriptor.dart' as d;
import '../test_pub.dart';
@@ -26,9 +27,19 @@
pubInstall();
+ // Note: Using canonicalize here because pub gets the path to the
+ // entrypoint package from the working directory, which has had symlinks
+ // resolve. On Mac, "/tmp" is actually a symlink to "/private/tmp", so we
+ // need to accomodate that.
schedulePub(args: ["list-package-dirs", "--format=json"],
outputJson: {
- "foo": path.join(sandboxDir, "foo")
+ "packages": {
+ "foo": path.join(sandboxDir, "foo", "lib"),
+ "myapp": canonicalize(path.join(sandboxDir, appPath, "lib"))
+ },
+ "input_files": [
+ canonicalize(path.join(sandboxDir, appPath, "pubspec.lock"))
+ ]
});
});
}
\ No newline at end of file
diff --git a/sdk/lib/_internal/pub/test/list_package_dirs/lists_dependency_directories_test.dart b/sdk/lib/_internal/pub/test/list_package_dirs/lists_dependency_directories_test.dart
index b3ac39b..0e8f9f3 100644
--- a/sdk/lib/_internal/pub/test/list_package_dirs/lists_dependency_directories_test.dart
+++ b/sdk/lib/_internal/pub/test/list_package_dirs/lists_dependency_directories_test.dart
@@ -4,6 +4,7 @@
import 'package:path/path.dart' as path;
+import '../../lib/src/io.dart';
import '../descriptor.dart' as d;
import '../test_pub.dart';
@@ -26,11 +27,21 @@
pubInstall();
+ // Note: Using canonicalize here because pub gets the path to the
+ // entrypoint package from the working directory, which has had symlinks
+ // resolve. On Mac, "/tmp" is actually a symlink to "/private/tmp", so we
+ // need to accomodate that.
schedulePub(args: ["list-package-dirs", "--format=json"],
outputJson: {
- "foo": path.join(sandboxDir, "foo"),
- "bar": port.then((p) => path.join(sandboxDir, cachePath, "hosted",
- "localhost%58$p", "bar-1.0.0"))
+ "packages": {
+ "foo": path.join(sandboxDir, "foo", "lib"),
+ "bar": port.then((p) => path.join(sandboxDir, cachePath, "hosted",
+ "localhost%58$p", "bar-1.0.0", "lib")),
+ "myapp": canonicalize(path.join(sandboxDir, appPath, "lib"))
+ },
+ "input_files": [
+ canonicalize(path.join(sandboxDir, appPath, "pubspec.lock"))
+ ]
});
});
}
\ No newline at end of file
diff --git a/sdk/lib/async/timer.dart b/sdk/lib/async/timer.dart
index ff7b07e..ed8103f 100644
--- a/sdk/lib/async/timer.dart
+++ b/sdk/lib/async/timer.dart
@@ -4,30 +4,43 @@
part of dart.async;
+/**
+ * A count-down timer that can be configured to fire once or repeatedly.
+ *
+ * The timer counts down from the specified duration to 0.
+ * When the timer reaches 0, the timer invokes the specified callback function.
+ * Use a periodic timer to repeatedly count down the same interval.
+ *
+ * A negative duration is treated the same as a duration of 0.
+ * If the duration is statically known to be 0, consider using [run].
+ *
+ * Frequently the duration is either a constant or computed as in the
+ * following example (taking advantage of the multiplication operator of
+ * the [Duration] class):
+ *
+ * const TIMEOUT = const Duration(seconds: 3);
+ * const ms = const Duration(milliseconds: 1);
+ *
+ * startTimeout([int milliseconds]) {
+ * var duration = milliseconds == null ? TIMEOUT : ms * milliseconds;
+ * return new Timer(duration, handleTimeout);
+ * }
+ * void handleTimeout(Timer _) { // callback function
+ * ...
+ * }
+ *
+ * Note: If Dart code using Timer is compiled to JavaScript, the finest
+ * granularity available in the browser is 4 milliseconds.
+ *
+ * See [Stopwatch] for measuring elapsed time.
+ */
abstract class Timer {
/**
* Creates a new timer.
*
- * The [callback] callback is invoked after the given [duration].
- * A negative duration is treated similar to a duration of 0.
+ * The [callback] function is invoked after the given [duration].
*
- * If the [duration] is statically known to be 0, consider using [run].
- *
- * Frequently the [duration] is either a constant or computed as in the
- * following example (taking advantage of the multiplication operator of
- * the Duration class):
- *
- * const TIMEOUT = const Duration(seconds: 3);
- * const ms = const Duration(milliseconds: 1);
- *
- * startTimeout([int milliseconds]) {
- * var duration = milliseconds == null ? TIMEOUT : ms * milliseconds;
- * return new Timer(duration, handleTimeout);
- * }
- *
- * Note: If Dart code using Timer is compiled to JavaScript, the finest
- * granularity available in the browser is 4 milliseconds.
*/
factory Timer(Duration duration, void callback()) {
return _Zone.current.createTimer(duration, callback);
@@ -37,7 +50,7 @@
* Creates a new repeating timer.
*
* The [callback] is invoked repeatedly with [duration] intervals until
- * canceled. A negative duration is treated similar to a duration of 0.
+ * canceled with the [cancel] function.
*/
factory Timer.periodic(Duration duration,
void callback(Timer timer)) {
diff --git a/sdk/lib/convert/encoding.dart b/sdk/lib/convert/encoding.dart
index 19989fb..0f6126c 100644
--- a/sdk/lib/convert/encoding.dart
+++ b/sdk/lib/convert/encoding.dart
@@ -9,8 +9,8 @@
*/
// TODO(floitsch): dart:io already has an Encoding class. If we can't
// consolitate them, we need to remove `Encoding` here.
-abstract class Encoding extends Codec<String, List<int>> {
- const Encoding();
+abstract class _Encoding extends Codec<String, List<int>> {
+ const _Encoding();
// TODO(floitsch): should we introduce a StringToByteEncoder and
// a ByteToStringDecoder so that we have better typing?
diff --git a/sdk/lib/convert/utf.dart b/sdk/lib/convert/utf.dart
index 2f92ef4..80f7a78 100644
--- a/sdk/lib/convert/utf.dart
+++ b/sdk/lib/convert/utf.dart
@@ -22,7 +22,7 @@
* A [Utf8Codec] encodes strings to utf-8 code units (bytes) and decodes
* UTF-8 code units to strings.
*/
-class Utf8Codec extends Encoding {
+class Utf8Codec extends _Encoding {
final bool _allowMalformed;
/**
@@ -177,7 +177,7 @@
for (stringIndex = start; stringIndex < end; stringIndex++) {
int codeUnit = str.codeUnitAt(stringIndex);
// ASCII has the same representation in UTF-8 and UTF-16.
- if (codeUnit < _ONE_BYTE_LIMIT) {
+ if (codeUnit <= _ONE_BYTE_LIMIT) {
if (_bufferIndex >= _buffer.length) break;
_buffer[_bufferIndex++] = codeUnit;
} else if (_isLeadSurrogate(codeUnit)) {
diff --git a/sdk/lib/core/core.dart b/sdk/lib/core/core.dart
index 89208f8..6cfe998 100644
--- a/sdk/lib/core/core.dart
+++ b/sdk/lib/core/core.dart
@@ -2,12 +2,121 @@
// 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.
+/**
+ *
+ * Built-in types, collections,
+ * and other core functionality for every Dart program.
+ *
+ * Some classes in this library,
+ * such as [String] and [num],
+ * support Dart's built-in data types.
+ * Other classes provide data structures
+ * for managing collections of objects.
+ * And still other classes represent commonly used types of data
+ * such as URIs, dates, and times.
+ *
+ *
+ * ## Built-in types
+ *
+ * [String], [int], [double], [bool], [List], and [Map]
+ * provide support for Dart's built-in data types.
+ * To declare and initialize variables of these types, write:
+ * String myString = 'A sequence of characters.';
+ * int meaningOfLife = 42;
+ * double valueOfPi = 3.141592;
+ * bool visible = true;
+ * List superHeros = [ 'Batman', 'Superman', 'Harry Potter' ];
+ * Map sidekicks = { 'Batman': 'Robin',
+ * 'Superman': 'Lois Lane',
+ * 'Harry Potter': 'Ron and Hermione' };
+ *
+ * ## Strings
+ *
+ * A [String] is immutable and represents a sequence of characters.
+ * [StringBuffer] provides a way to construct strings efficiently.
+ *
+ * The Dart language uses the [String] and [StringBuffer]
+ * behind the scenes to implement string concatenation, interpolation,
+ * and other features.
+ * String myString = 'Live on ';
+ * String get palindrome => myString + myString.split('').reversed.join();
+ *
+ *
+ * ## Collections
+ *
+ * The dart:core library provides basic collections,
+ * such as [List], [Map], and [Set].
+ *
+ * * A [List] is an ordered collection of objects, with a length.
+ * Lists are sometimes called arrays.
+ * Use a List when you need to access objects by index.
+ *
+ * * A [Set] is an unordered collection of unique objects.
+ * You cannot get an item by index (position).
+ * Adding a duplicate item has no effect.
+ * Use a [Set] when you need to guarantee object uniqueness.
+ *
+ * * A [Map] is an unordered collection of key-value pairs.
+ * Maps are sometimes called associative arrays because
+ * maps associate a key to some value for easy retrieval.
+ * Keys are unique.
+ * Use a [Map] when you need to access objects
+ * by a unique identifier.
+ *
+ * In addition to these classes,
+ * dart:core contains [Iterable],
+ * an interface that defines functionality
+ * common in collections of objects.
+ * Examples include the ability
+ * to run a function on each element in the collection,
+ * to apply a test to each element,
+ * to retrieve an object, and to determine length.
+ *
+ * Iterable is implemented by [List] and [Set],
+ * and used by [Map] for its lists of keys and values.
+ *
+ * For other kinds of collections, check out the dart:collection library.
+ *
+ * ## Date and time
+ *
+ * Use [DateTime] to represent a point in time
+ * and [Duration] to represent a span of time.
+ *
+ * You can create [DateTime] objects with constructors
+ * or by parsing a correctly formatted string.
+ * DateTime now = new DateTime.now();
+ * DateTime berlinWallFell = new DateTime(1989, 11, 9);
+ * DateTime moonLanding = DateTime.parse("1969-07-20");
+ *
+ * Create a [Duration] object specifying the individual time units.
+ * Duration timeRemaining = new Duration(hours:56, minutes:14);
+ *
+ * ## Uri
+ *
+ * A [Uri] object represents a uniform resource identifier,
+ * which identifies a resource on the web.
+ * Uri dartlang = Uri.parse('http://dartlang.org/');
+ *
+ * ## Other documentation
+ *
+ * For more information about how to use the built-in types, refer to
+ * [Built-in Types](http://www.dartlang.org/docs/dart-up-and-running/contents/ch02.html#built-in-types)
+ * in Chapter 2 of
+ * [Dart: Up and Running](http://www.dartlang.org/docs/dart-up-and-running/).
+ *
+ * Also, see
+ * [dart:core - Numbers, Collections, Strings, and More](http://www.dartlang.org/docs/dart-up-and-running/contents/ch03.html#ch03-dartcore---strings-collections-and-more)
+ * for more coverage of classes in this package.
+ *
+ */
+
+
library dart.core;
import "dart:collection";
import "dart:_collection-dev" hide Symbol;
import "dart:_collection-dev" as _collection_dev;
-import "dart:utf" show codepointsToUtf8, decodeUtf8;
+import "dart:convert" show UTF8;
part "bool.dart";
part "comparable.dart";
diff --git a/sdk/lib/core/date_time.dart b/sdk/lib/core/date_time.dart
index e0509d6..39a5f2f 100644
--- a/sdk/lib/core/date_time.dart
+++ b/sdk/lib/core/date_time.dart
@@ -5,13 +5,92 @@
part of dart.core;
/**
- * A DateTime object represents a point in time.
+ * An instant in time, such as July 20, 1969, 8:18pm PST.
*
- * It can represent time values that are at a distance of at most
- * 8,640,000,000,000,000ms (100,000,000 days) from epoch (1970-01-01 UTC). In
- * other words: [:millisecondsSinceEpoch.abs() <= 8640000000000000:].
+ * Create a DateTime object by using one of the constructors
+ * or by parsing a correctly formatted string,
+ * which complies with a subset of ISO 8601.
+ * Note that hours are specified between 0 and 23,
+ * as in a 24-hour clock.
+ * For example:
*
- * Also see [Stopwatch] for means to measure time-spans.
+ * DateTime now = new DateTime.now();
+ * DateTime berlinWallFell = new DateTime(1989, 11, 9);
+ * DateTime moonLanding = DateTime.parse("1969-07-20 20:18:00"); // 8:18pm
+ *
+ * A DateTime object is anchored either in the UTC time zone
+ * or in the local time zone of the current computer
+ * when the object is created.
+ *
+ * Once created, neither the value nor the time zone
+ * of a DateTime object may be changed.
+ *
+ * You can use properties to get
+ * the individual units of a DateTime object.
+ *
+ * assert(berlinWallFell.month == 11);
+ * assert(moonLanding.hour == 20);
+ *
+ * For convenience and readability,
+ * the DateTime class provides a constant for each day and month
+ * name—for example, [AUGUST] and [FRIDAY].
+ * You can use these constants to improve code readibility:
+ *
+ * DateTime berlinWallFell = new DateTime(1989, DateTime.NOVEMBER, 9);
+ * assert(berlinWallFell.month == DateTime.SATURDAY);
+ *
+ * Day and month values begin at 1, and the week starts on Monday.
+ * That is, the constants [JANUARY] and [MONDAY] are both 1.
+ *
+ * ## Working with UTC and local time
+ *
+ * A DateTime object is in the local time zone
+ * unless explicitly created in the UTC time zone.
+ *
+ * DateTime dDay = new DateTime.utc(1944, 6, 6);
+ *
+ * Use [isUtc] to determine whether a DateTime object is based in UTC.
+ * Use the methods [toLocal] and [toUtc]
+ * to get the equivalent date/time value specified in the other time zone.
+ * Use [timeZoneName] to get an abbreviated name of the time zone
+ * for the DateTime object.
+ * To find the difference
+ * between UTC and the time zone of a DateTime object
+ * call [timeZoneOffset].
+ *
+ * ## Comparing DateTime objects
+ *
+ * The DateTime class contains several handy methods,
+ * such as [isAfter], [isBefore], and [isAtSameMomentAs],
+ * for comparing DateTime objects.
+ *
+ * assert(berlinWallFell.isAfter(moonLanding) == true);
+ * assert(berlinWallFell.isBefore(moonLanding) == false);
+ *
+ * ## Using DateTime with Duration
+ *
+ * Use the [add] and [subtract] methods with a [Duration] object
+ * to create a new DateTime object based on another.
+ * For example, to find the date that is sixty days after today, write:
+ *
+ * DateTime today = new DateTime.now();
+ * DateTime sixtyDaysFromNow = today.add(new Duration(days: 60));
+ *
+ * To find out how much time is between two DateTime objects use
+ * [difference], which returns a [Duration] object:
+ *
+ * Duration difference = berlinWallFell.difference(dDay);
+ * assert(difference.inDays == 16592);
+ *
+ * ## Other resources
+ *
+ * See [Duration] to represent a span of time.
+ * See [Stopwatch] to measure timespans.
+ *
+ * The DateTime class does not provide internationalization.
+ * To internationalize your code, use
+ * the [intl](http://pub.dartlang.org/packages/intl) package.
+ *
*/
class DateTime implements Comparable {
// Weekday constants that are returned by [weekday] method:
@@ -40,24 +119,34 @@
static const int MONTHS_PER_YEAR = 12;
/**
- * The milliseconds since 1970-01-01T00:00:00Z (UTC). This value is
- * independent of the time zone.
+ * The number of milliseconds since
+ * the "Unix epoch" 1970-01-01T00:00:00Z (UTC).
*
- * See [Stopwatch] for means to measure time-spans.
+ * This value is independent of the time zone.
+ *
+ * This value is at most
+ * 8,640,000,000,000,000ms (100,000,000 days) from the Unix epoch.
+ * In other words: [:millisecondsSinceEpoch.abs() <= 8640000000000000:].
+ *
*/
final int millisecondsSinceEpoch;
/**
* True if this [DateTime] is set to UTC time.
+ *
+ * DateTime dDay = new DateTime.utc(1944, 6, 6);
+ * assert(dDay.isUtc);
+ *
*/
final bool isUtc;
/**
- * Constructs a [DateTime] instance based on the individual parts. The date is
- * in the local time zone.
+ * Constructs a [DateTime] instance specified in the local time zone.
*
- * [month] and [day] are one-based. For example
- * [:new DateTime(1938, 1, 10):] represents the 10th of January 1938.
+ * For example,
+ * to create a new DateTime object representing April 29, 2014, 6:04am:
+ *
+ * DateTime annularEclipse = new DateTime(2014, DateTime.APRIL, 29, 6, 4);
*/
// TODO(8042): This should be a redirecting constructor and not a factory.
factory DateTime(int year,
@@ -72,12 +161,9 @@
}
/**
- * Constructs a [DateTime] instance based on the individual parts. The date is
- * in the UTC time zone.
+ * Constructs a [DateTime] instance specified in the UTC time zone.
*
- * [month] and [day] are one-based. For example
- * [:new DateTime.utc(1938, 1, 10):] represents the 10th of January 1938 in
- * Coordinated Universal Time.
+ * DateTime dDay = new DateTime.utc(1944, DateTime.JUNE, 6);
*/
// TODO(8042): This should be a redirecting constructor and not a factory.
factory DateTime.utc(int year,
@@ -92,8 +178,11 @@
}
/**
- * Constructs a new [DateTime] instance with current date time value in the
+ * Constructs a [DateTime] instance with current date and time in the
* local time zone.
+ *
+ * DateTime thisInstant = new DateTime.now();
+ *
*/
// TODO(8042): This should be a redirecting constructor and not a factory.
factory DateTime.now() { return new DateTime._now(); }
@@ -159,11 +248,13 @@
static const int _MAX_MILLISECONDS_SINCE_EPOCH = 8640000000000000;
/**
- * Constructs a new [DateTime] instance with the given [millisecondsSinceEpoch].
+ * Constructs a new [DateTime] instance
+ * with the given [millisecondsSinceEpoch].
+ *
* If [isUtc] is false then the date is in the local time zone.
*
* The constructed [DateTime] represents
- * 1970-01-01T00:00:00Z + [millisecondsSinceEpoch]ms in the given
+ * 1970-01-01T00:00:00Z + [millisecondsSinceEpoch] ms in the given
* time zone (local or UTC).
*/
// TODO(lrn): Have two constructors instead of taking an optional bool.
@@ -179,9 +270,14 @@
/**
* Returns true if [other] is a [DateTime] at the same moment and in the
- * same timezone (UTC or local).
+ * same time zone (UTC or local).
*
- * See [isAtSameMomentAs] for a comparison that ignores the timezone.
+ * DateTime dDayUtc = new DateTime.utc(1944, DateTime.JUNE, 6);
+ * DateTime dDayLocal = new DateTime(1944, DateTime.JUNE, 6);
+ *
+ * assert(dDayUtc.isAtSameMomentAs(dDayLocal) == false);
+ *
+ * See [isAtSameMomentAs] for a comparison that adjusts for time zone.
*/
bool operator ==(other) {
if (!(other is DateTime)) return false;
@@ -190,38 +286,70 @@
}
/**
- * Returns true if [this] occurs before [other]. The comparison is independent
+ * Returns true if [this] occurs before [other].
+ *
+ * The comparison is independent
* of whether the time is in UTC or in the local time zone.
+ *
+ * DateTime berlinWallFell = new DateTime(1989, 11, 9);
+ * DateTime moonLanding = DateTime.parse("1969-07-20 20:18:00");
+ *
+ * assert(berlinWallFell.isBefore(moonLanding) == false);
+ *
*/
bool isBefore(DateTime other) {
return millisecondsSinceEpoch < other.millisecondsSinceEpoch;
}
/**
- * Returns true if [this] occurs after [other]. The comparison is independent
+ * Returns true if [this] occurs after [other].
+ *
+ * The comparison is independent
* of whether the time is in UTC or in the local time zone.
+ *
+ * DateTime berlinWallFell = new DateTime(1989, 11, 9);
+ * DateTime moonLanding = DateTime.parse("1969-07-20 20:18:00");
+ *
+ * assert(berlinWallFell.isAfter(moonLanding) == true);
+ *
*/
bool isAfter(DateTime other) {
return millisecondsSinceEpoch > other.millisecondsSinceEpoch;
}
/**
- * Returns true if [this] occurs at the same moment as [other]. The
- * comparison is independent of whether the time is in UTC or in the local
+ * Returns true if [this] occurs at the same moment as [other].
+ *
+ * The comparison is independent of whether the time is in UTC or in the local
* time zone.
+ *
+ * DateTime berlinWallFell = new DateTime(1989, 11, 9);
+ * DateTime moonLanding = DateTime.parse("1969-07-20 20:18:00");
+ *
+ * assert(berlinWallFell.isAtSameMomentAs(moonLanding) == false);
*/
bool isAtSameMomentAs(DateTime other) {
return millisecondsSinceEpoch == other.millisecondsSinceEpoch;
}
+ /**
+ * Compares this DateTime object to [other],
+ * returning zero if the values are equal.
+ *
+ * This function returns a negative integer
+ * if this DateTime is smaller (earlier) than [other],
+ * or a positive integer if it is greater (later).
+ */
int compareTo(DateTime other)
=> millisecondsSinceEpoch.compareTo(other.millisecondsSinceEpoch);
int get hashCode => millisecondsSinceEpoch;
/**
- * Returns [this] in the local time zone. Returns itself if it is already in
- * the local time zone. Otherwise, this method is equivalent to
+ * Returns this DateTime value in the local time zone.
+ *
+ * Returns [this] if it is already in the local time zone.
+ * Otherwise this method is equivalent to:
*
* new DateTime.fromMillisecondsSinceEpoch(millisecondsSinceEpoch,
* isUtc: false)
@@ -235,8 +363,10 @@
}
/**
- * Returns [this] in UTC. Returns itself if it is already in UTC. Otherwise,
- * this method is equivalent to
+ * Returns this DateTime value in the UTC time zone.
+ *
+ * Returns [this] if it is already in UTC.
+ * Otherwise this method is equivalent to:
*
* new DateTime.fromMillisecondsSinceEpoch(millisecondsSinceEpoch,
* isUtc: true)
@@ -248,8 +378,13 @@
}
/**
- * Returns a human readable string for this instance.
+ * Returns a human-readable string for this instance.
+ *
* The returned string is constructed for the time zone of this instance.
+ * The `toString()` method provides a simply formatted string.
+ * It does not support internationalized strings.
+ * Use the [intl](http://pub.dartlang.org/packages/intl) package
+ * at the pub shared packages repo.
*/
String toString() {
String fourDigits(int n) {
@@ -286,21 +421,41 @@
}
}
- /** Returns a new [DateTime] with the [duration] added to [this]. */
+ /**
+ * Returns a new [DateTime] instance with [duration] added to [this].
+ *
+ * DateTime today = new DateTime.now();
+ * DateTime sixtyDaysFromNow = today.add(new Duration(days: 60));
+ */
+
DateTime add(Duration duration) {
int ms = millisecondsSinceEpoch;
return new DateTime.fromMillisecondsSinceEpoch(
ms + duration.inMilliseconds, isUtc: isUtc);
}
- /** Returns a new [DateTime] with the [duration] subtracted from [this]. */
+ /**
+ * Returns a new [DateTime] instance with [duration] subtracted from [this].
+ *
+ * DateTime today = new DateTime.now();
+ * DateTime sixtyDaysAgo = today.subtract(new Duration(days: 60));
+ */
DateTime subtract(Duration duration) {
int ms = millisecondsSinceEpoch;
return new DateTime.fromMillisecondsSinceEpoch(
ms - duration.inMilliseconds, isUtc: isUtc);
}
- /** Returns a [Duration] with the difference of [this] and [other]. */
+ /**
+ * Returns a [Duration] with the difference between [this] and [other].
+ *
+ * DateTime berlinWallFell = new DateTime(1989, DateTime.NOVEMBER, 9);
+ * DateTime dDay = new DateTime(1944, DateTime.JUNE, 6);
+ *
+ * Duration difference = berlinWallFell.difference(dDay);
+ * assert(difference.inDays == 16592);
+ */
+
Duration difference(DateTime other) {
int ms = millisecondsSinceEpoch;
int otherMs = other.millisecondsSinceEpoch;
@@ -321,15 +476,16 @@
int millisecond, bool isUtc);
/**
- * Returns the abbreviated time-zone name.
- *
- * Examples: [:"CET":] or [:"CEST":].
+ * The abbreviated time zone name—for example,
+ * [:"CET":] or [:"CEST":].
*/
external String get timeZoneName;
/**
- * The time-zone offset is the difference between local time and UTC. That is,
- * the offset is positive for time zones west of UTC.
+ * The time zone offset, which
+ * is the difference between local time and UTC.
+ *
+ * The offset is positive for time zones west of UTC.
*
* Note, that JavaScript, Python and C return the difference between UTC and
* local time. Java, C# and Ruby return the difference between local time and
@@ -338,43 +494,72 @@
external Duration get timeZoneOffset;
/**
- * Returns the year.
+ * The year.
+ *
+ * DateTime moonLanding = DateTime.parse("1969-07-20 20:18:00");
+ * assert(moonLanding.year == 1969);
*/
external int get year;
/**
- * Returns the month into the year [1..12].
+ * The month [1..12].
+ *
+ * DateTime moonLanding = DateTime.parse("1969-07-20 20:18:00");
+ * assert(moonLanding.month == 7);
+ * assert(moonLanding.month == JULY);
*/
external int get month;
/**
- * Returns the day into the month [1..31].
+ * The day of the month [1..31].
+ *
+ * DateTime moonLanding = DateTime.parse("1969-07-20 20:18:00");
+ * assert(moonLanding.day == 20);
*/
external int get day;
/**
- * Returns the hour into the day [0..23].
+ * The hour of the day, expressed as in a 24-hour clock [0..23].
+ *
+ * DateTime moonLanding = DateTime.parse("1969-07-20 20:18:00");
+ * assert(moonLanding.hour == 20);
*/
external int get hour;
/**
- * Returns the minute into the hour [0...59].
+ * The minute [0...59].
+ *
+ * DateTime moonLanding = DateTime.parse("1969-07-20 20:18:00");
+ * assert(moonLanding.minute == 18);
*/
external int get minute;
/**
- * Returns the second into the minute [0...59].
+ * The second [0...59].
+ *
+ * DateTime moonLanding = DateTime.parse("1969-07-20 20:18:00");
+ * assert(moonLanding.second == 0);
*/
external int get second;
/**
- * Returns the millisecond into the second [0...999].
+ * The millisecond [0...999].
+ *
+ * DateTime moonLanding = DateTime.parse("1969-07-20 20:18:00");
+ * assert(moonLanding.millisecond == 0);
*/
external int get millisecond;
/**
- * Returns the week day [MON..SUN]. In accordance with ISO 8601
- * a week starts with Monday which has the value 1.
+ * The day of the week [MONDAY]..[SUNDAY].
+ *
+ * In accordance with ISO 8601
+ * a week starts with Monday, which has the value 1.
+ *
+ * DateTime moonLanding = DateTime.parse("1969-07-20 20:18:00");
+ * assert(moonLanding.weekday == 7);
+ * assert(moonLanding.weekday == DateTime.SUNDAY);
+ *
*/
external int get weekday;
}
diff --git a/sdk/lib/core/duration.dart b/sdk/lib/core/duration.dart
index a19c651..77633a6 100644
--- a/sdk/lib/core/duration.dart
+++ b/sdk/lib/core/duration.dart
@@ -5,7 +5,36 @@
part of dart.core;
/**
- * A [Duration] represents a time span. A duration can be negative.
+ * A span of time, such as 27 days, 4 hours, 12 minutes, and 3 seconds.
+ *
+ * To create a new Duration object, use this class's single constructor
+ * giving the appropriate arguments:
+ *
+ * Duration fastestMarathon = new Duration(hours:2, minutes:3, seconds:2);
+ *
+ * The Duration is the sum of all individual parts.
+ * This means that individual parts can be larger than the next-bigger unit.
+ * For example, [minutes] can be greater than 59.
+ *
+ * assert(fastestMarathon.inMinutes == 123);
+ *
+ * All individual parts are allowed to be negative.
+ *
+ * Use one of the properties, such as [inDays],
+ * to retrieve the integer value of the Duration in the specified time unit.
+ * Note that the returned value is rounded down.
+ * For example,
+ *
+ * Duration aLongWeekend = new Duration(hours:88);
+ * assert(aLongWeekend.inDays == 3);
+ *
+ * This class provides a collection of arithmetic
+ * and comparison operators,
+ * plus a set of constants useful for converting time units.
+ *
+ * See [DateTime] to represent a point in time.
+ * See [Stopwatch] to measure time-spans.
+ *
*/
class Duration implements Comparable<Duration> {
static const int MICROSECONDS_PER_MILLISECOND = 1000;
@@ -38,18 +67,20 @@
static const Duration ZERO = const Duration(seconds: 0);
- /**
- * This [Duration] in microseconds.
+ /*
+ * The value of this Duration object in microseconds.
*/
final int _duration;
/**
- * The duration is the sum of all individual parts. This means that individual
- * parts don't need to be less than the next-bigger unit. For example [hours]
- * is allowed to have a value greater than 23.
+ * Creates a new Duration object whose value
+ * is the sum of all individual parts.
+ *
+ * Individual parts can be larger than the next-bigger unit.
+ * For example, [hours] can be greater than 23.
*
* All individual parts are allowed to be negative.
- * All arguments are by default 0.
+ * All arguments are 0 by default.
*/
const Duration({int days: 0,
int hours: 0,
@@ -65,23 +96,24 @@
microseconds;
/**
- * Returns the sum of this [Duration] and [other] as a new [Duration].
+ * Adds this Duration and [other] and
+ * returns the sum as a new Duration object.
*/
Duration operator +(Duration other) {
return new Duration(microseconds: _duration + other._duration);
}
/**
- * Returns the difference of this [Duration] and [other] as a new
- * [Duration].
+ * Subtracts [other] from this Duration and
+ * returns the difference as a new Duration object.
*/
Duration operator -(Duration other) {
return new Duration(microseconds: _duration - other._duration);
}
/**
- * Multiplies this [Duration] by the given [factor] and returns the result
- * as a new [Duration].
+ * Multiplies this Duration by the given [factor] and returns the result
+ * as a new Duration object.
*
* Note that when [factor] is a double, and the duration is greater than
* 53 bits, precision is lost because of double-precision arithmetic.
@@ -91,8 +123,8 @@
}
/**
- * Divides this [Duration] by the given [quotient] and returns the truncated
- * result as a new [Duration].
+ * Divides this Duration by the given [quotient] and returns the truncated
+ * result as a new Duration object.
*
* Throws an [IntegerDivisionByZeroException] if [quotient] is `0`.
*/
@@ -103,52 +135,71 @@
return new Duration(microseconds: _duration ~/ quotient);
}
+ /**
+ * Returns `true` if the value of this Duration
+ * is less than the value of [other].
+ */
bool operator <(Duration other) => this._duration < other._duration;
+ /**
+ * Returns `true` if the value of this Duration
+ * is greater than the value of [other].
+ */
bool operator >(Duration other) => this._duration > other._duration;
+ /**
+ * Returns `true` if the value of this Duration
+ * is less than or equal to the value of [other].
+ */
bool operator <=(Duration other) => this._duration <= other._duration;
+ /**
+ * Returns `true` if the value of this Duration
+ * is greater than or equal to the value of [other].
+ */
bool operator >=(Duration other) => this._duration >= other._duration;
/**
- * This [Duration] in days. Incomplete days are discarded
+ * Returns the number of whole days spanned by this Duration.
*/
int get inDays => _duration ~/ Duration.MICROSECONDS_PER_DAY;
/**
- * This [Duration] in hours. Incomplete hours are discarded.
+ * Returns the number of whole hours spanned by this Duration.
*
* The returned value can be greater than 23.
*/
int get inHours => _duration ~/ Duration.MICROSECONDS_PER_HOUR;
/**
- * This [Duration] in minutes. Incomplete minutes are discarded.
+ * Returns the number of whole minutes spanned by this Duration.
*
* The returned value can be greater than 59.
*/
int get inMinutes => _duration ~/ Duration.MICROSECONDS_PER_MINUTE;
/**
- * This [Duration] in seconds. Incomplete seconds are discarded.
+ * Returns the number of whole seconds spanned by this Duration.
*
* The returned value can be greater than 59.
*/
int get inSeconds => _duration ~/ Duration.MICROSECONDS_PER_SECOND;
/**
- * This [Duration] in milliseconds. Incomplete milliseconds are discarded.
+ * Returns number of whole milliseconds spanned by this Duration.
*
* The returned value can be greater than 999.
*/
int get inMilliseconds => _duration ~/ Duration.MICROSECONDS_PER_MILLISECOND;
/**
- * This [Duration] in microseconds.
+ * Returns number of whole microseconds spanned by this Duration.
*/
int get inMicroseconds => _duration;
+ /**
+ * Returns `true` if this Duration is the same object as [other].
+ */
bool operator ==(other) {
if (other is !Duration) return false;
return _duration == other._duration;
@@ -156,6 +207,14 @@
int get hashCode => _duration.hashCode;
+ /**
+ * Compares this Duration to [other],
+ * returning zero if the values are equal.
+ *
+ * This function returns a negative integer
+ * if this Duration is smaller than [other],
+ * or a positive integer if it is greater.
+ */
int compareTo(Duration other) => _duration.compareTo(other._duration);
String toString() {
diff --git a/sdk/lib/core/list.dart b/sdk/lib/core/list.dart
index dc0ccfa..af9f895 100644
--- a/sdk/lib/core/list.dart
+++ b/sdk/lib/core/list.dart
@@ -5,72 +5,66 @@
part of dart.core;
/**
- * A [List] is an indexable collection with a length.
+ * An indexable collection of objects with a length.
*
- * A `List` implementation can choose not to support all methods
- * of the `List` interface.
+ * Subclasses of this class implement different kinds of lists.
+ * The most common kinds of lists are:
*
- * The most common list types are:
- * * Fixed length list. It is an error to use operations that can change
- * the list's length.
- * * Growable list. Full implementation of the interface.
- * * Unmodifiable list. It is an error to use operations that can change
- * the list's length, or that can change the values of the list.
- * If an unmodifable list is backed by another modifiable data structure,
- * the values read from it may still change over time.
+ * * Fixed-length list.
+ * An error occurs when attempting to use operations
+ * that can change the length of the list.
*
- * Example:
+ * * Growable list. Full implementation of the API defined in this class.
+ *
+ * The following code illustrates that some List implementations support
+ * only a subset of the API.
*
* var fixedLengthList = new List(5);
- * fixedLengthList.length = 0; // throws.
- * fixedLengthList.add(499); // throws
+ * fixedLengthList.length = 0; // Error.
+ * fixedLengthList.add(499); // Error.
* fixedLengthList[0] = 87;
+ *
* var growableList = [1, 2];
* growableList.length = 0;
* growableList.add(499);
* growableList[0] = 87;
- * var unmodifiableList = const [1, 2];
- * unmodifiableList.length = 0; // throws.
- * unmodifiableList.add(499); // throws
- * unmodifiableList[0] = 87; // throws.
*
* Lists are [Iterable].
- * List iteration iterates over values in index order.
- * Changing the values will not affect iteration,
- * but changing the valid indices -
- * that is, changing the list's length -
- * between iteration steps
- * will cause a [ConcurrentModificationError].
- * This means that only growable lists can throw [ConcurrentModificationError].
+ * Iteration occurs over values in index order.
+ * Changing the values does not affect iteration,
+ * but changing the valid indices—that is,
+ * changing the list's length—between
+ * iteration steps
+ * causes a [ConcurrentModificationError].
+ * This means that only growable lists can throw ConcurrentModificationError.
* If the length changes temporarily
* and is restored before continuing the iteration,
- * the iterator will not detect it.
+ * the iterator does not detect it.
*/
abstract class List<E> implements Iterable<E> {
/**
- * Creates a list of the given [length].
+ * Creates a list of the given _length_.
*
- * The list is a fixed-length list if [length] is provided, and an empty
- * growable list if [length] is omitted.
+ * The created list is fixed-length if _length_ is provided.
+ * The list has length 0 and is growable if _length_ is omitted.
*
- * It is an error if [length] is not a non-negative integer.
+ * An error occurs if _length_ is negative.
*/
external factory List([int length]);
/**
- * Creates a fixed-length list of the given [length] where each entry
- * contains [fill].
+ * Creates a fixed-length list of the given _length_
+ * and initializes the value at each position with [fill].
*/
external factory List.filled(int length, E fill);
/**
- * Creates an list with the elements of [other].
+ * Creates a list and initializes it using the contents of [other].
*
- * The order in the list will be
- * the order provided by the iterator of [other].
+ * The [Iterator] of [other] provides the order of the objects.
*
- * The returned list is growable if [growable] is true, otherwise it's
- * a fixed length list.
+ * This constructor returns a growable list if [growable] is true;
+ * otherwise, it returns a fixed-length list.
*/
factory List.from(Iterable other, { bool growable: true }) {
List<E> list = new List<E>();
@@ -87,14 +81,14 @@
}
/**
- * Generate a `List` of values.
+ * Generates a list of values.
*
- * Creates a list with [length] positions
- * and fills them by values created by calling [generator]
- * for each index in the range `0` .. `[length] - 1`
+ * Creates a list with _length_ positions
+ * and fills it with values created by calling [generator]
+ * for each index in the range `0` .. `length - 1`
* in increasing order.
*
- * The created list's length is fixed unless [growable] is true.
+ * The created list is fixed-length unless [growable] is true.
*/
factory List.generate(int length, E generator(int index),
{ bool growable: true }) {
@@ -111,202 +105,202 @@
}
/**
- * Returns the element at the given [index] in the list or throws
- * an [RangeError] if [index] is out of bounds.
+ * Returns the object at the given [index] in the list
+ * or throws a [RangeError] if [index] is out of bounds.
*/
E operator [](int index);
/**
- * Sets the entry at the given [index] in the list to [value].
- *
- * Throws an [RangeError] if [index] is out of bounds.
+ * Sets the value at the given [index] in the list to [value]
+ * or throws a [RangeError] if [index] is out of bounds.
*/
void operator []=(int index, E value);
/**
- * Returns the number of elements in the list.
+ * Returns the number of objects in this list.
*
- * The valid indices for a list are 0 through `length - 1`.
+ * The valid indices for a list are `0` through `length - 1`.
*/
int get length;
/**
- * Changes the length of the list. If [newLength] is greater than
+ * Changes the length of this list.
+ *
+ * If [newLength] is greater than
* the current [length], entries are initialized to [:null:].
*
- * Throws an [UnsupportedError] if the list is not extendable.
+ * Throws an [UnsupportedError] if the list is fixed-length.
*/
void set length(int newLength);
/**
- * Adds [value] at the end of the list, extending the length by
- * one.
+ * Adds [value] to the end of this list,
+ * extending the length by one.
*
- * Throws an [UnsupportedError] if the list is not extendable.
+ * Throws an [UnsupportedError] if the list is fixed-length.
*/
void add(E value);
/**
- * Appends all elements of the [iterable] to the end of this list.
+ * Appends all objects of [iterable] to the end of this list.
*
- * Extends the length of the list by the number of elements in [iterable].
- * Throws an [UnsupportedError] if this list is not extensible.
+ * Extends the length of the list by the number of objects in [iterable].
+ * Throws an [UnsupportedError] if this list is fixed-length.
*/
void addAll(Iterable<E> iterable);
/**
- * Returns an [Iterable] of the elements of this [List] in reverse order.
+ * Returns an [Iterable] of the objects in this list in reverse order.
*/
Iterable<E> get reversed;
/**
- * Sorts the list according to the order specified by the [compare] function.
+ * Sorts this list according to the order specified by the [compare] function.
*
* The [compare] function must act as a [Comparator].
*
- * The default [List] implementations use [Comparable.compare] if
+ * The default List implementations use [Comparable.compare] if
* [compare] is omitted.
*/
void sort([int compare(E a, E b)]);
/**
- * Returns the first index of [element] in the list.
+ * Returns the first index of [element] in this list.
*
* Searches the list from index [start] to the length of the list.
- * The first time an element [:e:] is encountered so that [:e == element:],
- * the index of [:e:] is returned.
+ * The first time an object [:o:] is encountered so that [:o == element:],
+ * the index of [:o:] is returned.
* Returns -1 if [element] is not found.
*/
int indexOf(E element, [int start = 0]);
/**
- * Returns the last index of [element] in the list.
+ * Returns the last index of [element] in this list.
*
- * Searches the list backwards from index [start] (inclusive) to 0.
+ * Searches the list backwards from index [start] to 0.
*
- * The first time an element [:e:] is encountered so that [:e == element:],
- * the index of [:e:] is returned.
+ * The first time an object [:o:] is encountered so that [:o == element:],
+ * the index of [:o:] is returned.
*
- * If start is not provided, it defaults to [:this.length - 1:].
+ * If [start] is not provided, it defaults to [:this.length - 1:].
*
* Returns -1 if [element] is not found.
*/
int lastIndexOf(E element, [int start]);
/**
- * Removes all elements in the list.
+ * Removes all objects from this list;
+ * the length of the list becomes zero.
*
- * The length of the list becomes zero.
- *
- * Throws an [UnsupportedError], and retains all elements, if the
- * length of the list cannot be changed.
+ * Throws an [UnsupportedError], and retains all objects, if this
+ * is a fixed-length list.
*/
void clear();
/**
- * Inserts the element at position [index] in the list.
+ * Inserts the object at position [index] in this list.
*
- * This increases the length of the list by one and shifts all elements
+ * This increases the length of the list by one and shifts all objects
* at or after the index towards the end of the list.
*
- * It is an error if the [index] does not point inside the list or at the
- * position after the last element.
+ * An error occurs if the [index] is less than 0 or greater than length.
+ * An [UnsupportedError] occurs if the list is fixed-length.
*/
void insert(int index, E element);
/**
- * Inserts all elements of [iterable] at position [index] in the list.
+ * Inserts all objects of [iterable] at position [index] in this list.
*
* This increases the length of the list by the length of [iterable] and
- * shifts all later elements towards the end of the list.
+ * shifts all later objects towards the end of the list.
*
- * It is an error if the [index] does not point inside the list or at the
- * position after the last element.
+ * An error occurs if the [index] is less than 0 or greater than length.
+ * An [UnsupportedError] occurs if the list is fixed-length.
*/
void insertAll(int index, Iterable<E> iterable);
/**
- * Overwrites elements of `this` with the elemenst of [iterable] starting
- * at position [index] in the list.
+ * Overwrites objects of `this` with the objects of [iterable], starting
+ * at position [index] in this list.
*
* This operation does not increase the length of `this`.
*
- * It is an error if the [index] does not point inside the list or at the
- * position after the last element.
- *
- * It is an error if the [iterable] is longer than [length] - [index].
+ * An error occurs if the [index] is less than 0 or greater than length.
+ * An error occurs if the [iterable] is longer than [length] - [index].
*/
void setAll(int index, Iterable<E> iterable);
/**
- * Removes [value] from the list. Returns true if [value] was
- * in the list. Returns false otherwise. The method has no effect
- * if [value] value was not in the list.
+ * Removes [value] from this list.
+ *
+ * Returns true if [value] was in the list.
+ * Returns false otherwise.
+ * The method has no effect if [value] was not in the list.
+ *
+ * An [UnsupportedError] occurs if the list is fixed-length.
*/
bool remove(Object value);
/**
- * Removes the element at position [index] from the list.
+ * Removes the object at position [index] from this list.
*
- * This reduces the length of `this` by one and moves all later elements
+ * This method reduces the length of `this` by one and moves all later objects
* down by one position.
*
- * Returns the removed element.
+ * Returns the removed object.
*
- * Throws an [ArgumentError] if [index] is not an [int].
- *
- * Throws an [RangeError] if the [index] does not point inside
- * the list.
- *
- * Throws an [UnsupportedError], and doesn't remove the element,
- * if the length of `this` cannot be changed.
+ * * Throws an [ArgumentError] if [index] is not an [int].
+ * * Throws a [RangeError] if the [index] is out of range for this list.
+ * * Throws an [UnsupportedError], and doesn't remove the object,
+ * if this is a fixed-length list.
*/
E removeAt(int index);
/**
- * Pops and returns the last element of the list.
- * Throws a [UnsupportedError] if the length of the
- * list cannot be changed.
+ * Pops and returns the last object in this list.
+ *
+ * Throws an [UnsupportedError] if this is a fixed-length list.
*/
E removeLast();
/**
- * Removes all elements of this list that satisfy [test].
+ * Removes all objects from this list that satisfy [test].
*
- * An elements [:e:] satisfies [test] if [:test(e):] is true.
+ * An object [:o:] satisfies [test] if [:test(o):] is true.
+ *
+ * Throws an [UnsupportedError] if this is a fixed-length list.
*/
void removeWhere(bool test(E element));
/**
- * Removes all elements of this list that fail to satisfy [test].
+ * Removes all objects from this list that fail to satisfy [test].
*
- * An elements [:e:] satisfies [test] if [:test(e):] is true.
+ * An object [:o:] satisfies [test] if [:test(o):] is true.
+ *
+ * Throws an [UnsupportedError] if this is a fixed-length list.
*/
void retainWhere(bool test(E element));
/**
- * Returns a new list containing the elements from [start] to [end].
- *
- * The result contains elements of this list with indices greater than or
- * equal to [start] and less than [end].
+ * Returns a new list containing the objects
+ * from [start] inclusive to [end] exclusive.
*
* If [end] is omitted, the [length] of `this` is used.
*
- * It is an error if [start] is outside the range `0` .. `[length]` or if
- * [end] is outside the range `[start]` .. `[length]`.
+ * An error occurs if [start] is outside the range `0` .. `length` or if
+ * [end] is outside the range `start` .. `length`.
*/
List<E> sublist(int start, [int end]);
/**
- * Returns an [Iterable] that iterates over the elements in the range
- * [start] to [end] exclusive. The result of this function
- * is backed by `this`.
+ * Returns an [Iterable] that iterates over the objects in the range
+ * [start] inclusive to [end] exclusive.
*
- * It is an error if [end] is before [start].
+ * An error occurs if [end] is before [start].
*
- * It is an error if the [start] and [end] are not valid ranges at the time
- * of the call to this method. The returned [Iterable] behaves similar to
- * `skip(start).take(end - start)`. That is, it will not throw exceptions
+ * An error occurs if the [start] and [end] are not valid ranges at the time
+ * of the call to this method. The returned [Iterable] behaves like
+ * `skip(start).take(end - start)`. That is, it does not throw exceptions
* if `this` changes size.
*
* Example:
@@ -320,17 +314,15 @@
Iterable<E> getRange(int start, int end);
/**
- * Copies the elements of [iterable], skipping the [skipCount] first elements,
- * into the range [start] to [end] exclusive of `this`.
+ * Copies the objects of [iterable], skipping [skipCount] objects first,
+ * into the range [start] inclusive to [end] exclusive of `this`.
*
* If [start] equals [end] and [start]..[end] represents a legal range, this
* method has no effect.
*
- * It is an error if [start]..[end] is not a valid range pointing into the
- * `this`.
- *
- * It is an error if the [iterable] does not have enough elements after
- * skipping [skipCount] elements.
+ * An error occurs if [start]..[end] is not a valid range for `this`.
+ * An error occurs if the [iterable] does not have enough objects after
+ * skipping [skipCount] objects.
*
* Example:
*
@@ -342,28 +334,26 @@
void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]);
/**
- * Removes the elements in the range [start] to [end] exclusive.
+ * Removes the objects in the range [start] inclusive to [end] exclusive.
*
- * It is an error if [start]..[end] is not a valid range pointing into the
- * `this`.
+ * An error occurs if [start]..[end] is not a valid range for `this`.
+ * Throws an [UnsupportedError] if this is a fixed-length list.
*/
void removeRange(int start, int end);
/**
- * Sets the elements in the range [start] to [end] exclusive to the given
- * [fillValue].
+ * Sets the objects in the range [start] inclusive to [end] exclusive
+ * to the given [fillValue].
*
- * It is an error if [start]..[end] is not a valid range pointing into the
- * `this`.
+ * An error occurs if [start]..[end] is not a valid range for `this`.
*/
void fillRange(int start, int end, [E fillValue]);
/**
- * Removes the elements in the range [start] to [end] exclusive and replaces
- * them with the contents of the [iterable].
+ * Removes the objects in the range [start] inclusive to [end] exclusive
+ * and replaces them with the contents of the [iterable].
*
- * It is an error if [start]..[end] is not a valid range pointing into the
- * `this`.
+ * An error occurs if [start]..[end] is not a valid range for `this`.
*
* Example:
*
@@ -376,8 +366,8 @@
/**
* Returns an unmodifiable [Map] view of `this`.
*
- * It has the indices of this list as keys, and the corresponding elements
- * as values. The [Map.keys] [Iterable] will iterate the indices of this list
+ * The map uses the indices of this list as keys and the corresponding objects
+ * as values. The `Map.keys` [Iterable] iterates the indices of this list
* in numerical order.
*/
Map<int, E> asMap();
diff --git a/sdk/lib/core/string.dart b/sdk/lib/core/string.dart
index 3f1a7cc..b2ca3f2 100644
--- a/sdk/lib/core/string.dart
+++ b/sdk/lib/core/string.dart
@@ -5,11 +5,11 @@
part of dart.core;
/**
- * The String class represents sequences of characters. Strings are
- * immutable. A string is represented by a sequence of Unicode UTF-16
- * code units accessible through the [codeUnitAt] or the
- * [codeUnits] members. Their string representation is accessible through
- * the index-operator.
+ * A class for working with a sequence of characters.
+ *
+ * A string is represented by a sequence of Unicode UTF-16 code units
+ * accessible through the [codeUnitAt] or the [codeUnits] members. Their
+ * string representation is accessible through the index-operator.
*
* The characters of a string are encoded in UTF-16. Decoding UTF-16, which
* combines surrogate pairs, yields Unicode code points. Following a similar
@@ -17,8 +17,13 @@
* Unicode code point. The runes of a string are accessible through the [runes]
* getter.
*
+ * Strings are immutable.
+ *
* It is a compile-time error for a class to attempt to extend or implement
* String.
+ *
+ * For concatenating strings efficiently, use the [StringBuffer] class. For
+ * working with regular expressions, use the [RegExp] class.
*/
abstract class String implements Comparable<String>, Pattern {
/**
diff --git a/sdk/lib/core/string_buffer.dart b/sdk/lib/core/string_buffer.dart
index 59d1aa9..e8bc72d 100644
--- a/sdk/lib/core/string_buffer.dart
+++ b/sdk/lib/core/string_buffer.dart
@@ -5,9 +5,11 @@
part of dart.core;
/**
- * The StringBuffer class is useful for concatenating strings
- * efficiently. Only on a call to [toString] are the strings
- * concatenated to a single String.
+ * A class for concatenating strings efficiently.
+ *
+ * Allows for the incremental building of a string using write*() methods.
+ * The strings are concatenated to a single string only when [toString] is
+ * called.
*/
class StringBuffer implements StringSink {
diff --git a/sdk/lib/core/uri.dart b/sdk/lib/core/uri.dart
index 47d6327..85e76ba 100644
--- a/sdk/lib/core/uri.dart
+++ b/sdk/lib/core/uri.dart
@@ -1083,11 +1083,11 @@
* pluses to spaces.
*
* It will create a byte-list of the decoded characters, and then use
- * [decode] to decode the byte-list to a String. Default is a UTF_8 decoder.
+ * [decode] to decode the byte-list to a String. Default is a UTF-8 decoder.
*/
static String decodeQueryComponent(
String encodedComponent,
- {String decode(List<int> bytes): decodeUtf8}) {
+ {String decode(List<int> bytes): null}) {
return _uriDecode(encodedComponent, plusToSpace: true, decode: decode);
}
@@ -1128,12 +1128,12 @@
* Keys in the query string that have no value are mapped to the
* empty string.
*
- * Each query component will be decoded using [decode]. Default is a UTF_8
+ * Each query component will be decoded using [decode]. Default is a UTF-8
* decoder.
*/
static Map<String, String> splitQueryString(
String query,
- {String decode(List<int> bytes): decodeUtf8}) {
+ {String decode(List<int> bytes): null}) {
return query.split("&").fold({}, (map, element) {
int index = element.indexOf("=");
if (index == -1) {
@@ -1202,7 +1202,8 @@
throw new ArgumentError('Malformed URI');
}
}
- for (int codepoint in codepointsToUtf8([ch])) {
+ // TODO(floitsch): don't allocate a new string.
+ for (int codepoint in UTF8.encode(new String.fromCharCode(ch))) {
result.write(byteToHex(codepoint));
}
}
@@ -1243,11 +1244,11 @@
* If [plusToSpace] is `true`, plus characters will be converted to spaces.
*
* The decoder will create a byte-list of the percent-encoded parts, and then
- * decode the byte-list using [decode]. Default is a UTF_8 decoder.
+ * decode the byte-list using [decode]. Default is a UTF-8 decoder.
*/
static String _uriDecode(String text,
{bool plusToSpace: false,
- String decode(List<int> bytes): decodeUtf8}) {
+ String decode(List<int> bytes): null}) {
StringBuffer result = new StringBuffer();
List<int> codepoints = new List<int>();
for (int i = 0; i < text.length;) {
@@ -1270,7 +1271,8 @@
if (i == text.length) break;
ch = text.codeUnitAt(i);
}
- result.write(decode(codepoints));
+ result.write(
+ decode == null ? UTF8.decode(codepoints) : decode(codepoints));
}
}
return result.toString();
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index 15b960c..b584d35 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -1122,6 +1122,11 @@
@DocsEditable()
String globalCompositeOperation;
+ @DomName('CanvasRenderingContext2D.imageSmoothingEnabled')
+ @DocsEditable()
+ @Experimental() // untriaged
+ bool imageSmoothingEnabled;
+
@DomName('CanvasRenderingContext2D.lineCap')
@DocsEditable()
String lineCap;
@@ -1176,14 +1181,6 @@
@Experimental()
final num backingStorePixelRatio;
- @JSName('webkitImageSmoothingEnabled')
- @DomName('CanvasRenderingContext2D.webkitImageSmoothingEnabled')
- @DocsEditable()
- @SupportedBrowser(SupportedBrowser.CHROME)
- @SupportedBrowser(SupportedBrowser.SAFARI)
- @Experimental()
- bool imageSmoothingEnabled;
-
@JSName('arc')
@DomName('CanvasRenderingContext2D.arc')
@DocsEditable()
@@ -1255,6 +1252,16 @@
@DocsEditable()
CanvasGradient createRadialGradient(num x0, num y0, num r0, num x1, num y1, num r1) native;
+ @DomName('CanvasRenderingContext2D.drawCustomFocusRing')
+ @DocsEditable()
+ @Experimental() // untriaged
+ bool drawCustomFocusRing(Element element) native;
+
+ @DomName('CanvasRenderingContext2D.drawSystemFocusRing')
+ @DocsEditable()
+ @Experimental() // untriaged
+ void drawSystemFocusRing(Element element) native;
+
@DomName('CanvasRenderingContext2D.fill')
@DocsEditable()
void fill([String winding]) native;
@@ -6422,7 +6429,7 @@
@JSName('getAsString')
@DomName('DataTransferItem.getAsString')
@DocsEditable()
- void _getAsString([_StringCallback callback]) native;
+ void _getAsString(_StringCallback callback) native;
@JSName('getAsString')
@DomName('DataTransferItem.getAsString')
@@ -7176,12 +7183,6 @@
@DocsEditable()
Event $dom_createEvent(String eventType) native;
- @JSName('createNodeIterator')
- @DomName('Document.createNodeIterator')
- @DocsEditable()
- @Unstable()
- NodeIterator $dom_createNodeIterator(Node root, [int whatToShow, NodeFilter filter, bool expandEntityReferences]) native;
-
@JSName('createRange')
@DomName('Document.createRange')
@DocsEditable()
@@ -7215,11 +7216,6 @@
@Experimental()
TouchList $dom_createTouchList() native;
- @JSName('createTreeWalker')
- @DomName('Document.createTreeWalker')
- @DocsEditable()
- TreeWalker $dom_createTreeWalker(Node root, [int whatToShow, NodeFilter filter, bool expandEntityReferences]) native;
-
@JSName('elementFromPoint')
@DomName('Document.elementFromPoint')
@DocsEditable()
@@ -7621,6 +7617,11 @@
ElementList queryAll(String selectors) {
return new _FrozenElementList._wrap($dom_querySelectorAll(selectors));
}
+
+ /// Checks if [register] is supported on the current platform.
+ bool get supportsRegister {
+ return JS('bool', '("register" in #)', this);
+ }
}
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
@@ -8478,7 +8479,7 @@
// https://dvcs.w3.org/hg/fullscreen/raw-file/tip/Overview.html
@Experimental()
ElementStream<Event> get onFullscreenError;
-
+
}
// TODO(jacobr): this is an inefficient implementation but it is hard to see
@@ -9619,6 +9620,18 @@
Point p = Element._offsetToHelper(parentOffset, parent);
return new Point(p.x + current.offsetLeft, p.y + current.offsetTop);
}
+
+ @JSName('innerHTML')
+ @DomName('HTMLElement.innerHTML')
+ String get innerHtml => JS('String', '#.innerHTML', this);
+
+ void set innerHtml(String value) {
+ JS('', '#.innerHTML = #', this, value);
+ // Polyfill relies on mutation observers for upgrading, but we want it
+ // immediate.
+ Platform.upgradeCustomElements(this);
+ }
+
// To suppress missing implicit constructor warnings.
factory Element._() { throw new UnsupportedError("Not supported"); }
@@ -9855,14 +9868,10 @@
@DocsEditable()
bool hidden;
- @DomName('Element.id')
+ @DomName('Element.inputMethodContext')
@DocsEditable()
- String id;
-
- @JSName('innerHTML')
- @DomName('Element.innerHTML')
- @DocsEditable()
- String innerHtml;
+ @Experimental() // untriaged
+ final InputMethodContext inputMethodContext;
@DomName('Element.isContentEditable')
@DocsEditable()
@@ -9910,12 +9919,6 @@
@DocsEditable()
void click() native;
- @DomName('Element.getInputContext')
- @DocsEditable()
- // http://www.w3.org/TR/ime-api/#the-getinputcontext-method
- @Experimental()
- InputMethodContext getInputContext() native;
-
@DomName('Element.ALLOW_KEYBOARD_INPUT')
@DocsEditable()
// https://dvcs.w3.org/hg/fullscreen/raw-file/tip/Overview.html#dom-element-requestfullscreen
@@ -9947,6 +9950,10 @@
@DocsEditable()
final int clientWidth;
+ @DomName('Element.id')
+ @DocsEditable()
+ String id;
+
@DomName('Element.offsetHeight')
@DocsEditable()
final int offsetHeight;
@@ -10039,6 +10046,13 @@
@Creates('_ClientRectList')
List<Rect> getClientRects() native;
+ @DomName('Element.getDestinationInsertionPoints')
+ @DocsEditable()
+ @Experimental() // untriaged
+ @Returns('NodeList')
+ @Creates('NodeList')
+ List<Node> getDestinationInsertionPoints() native;
+
@DomName('Element.getElementsByClassName')
@DocsEditable()
@Returns('NodeList')
@@ -10784,6 +10798,17 @@
// To suppress missing implicit constructor warnings.
factory ErrorEvent._() { throw new UnsupportedError("Not supported"); }
+ @DomName('ErrorEvent.colno')
+ @DocsEditable()
+ @Experimental() // untriaged
+ final int colno;
+
+ @DomName('ErrorEvent.error')
+ @DocsEditable()
+ @Experimental() // untriaged
+ @Creates('Null')
+ final Object error;
+
@DomName('ErrorEvent.filename')
@DocsEditable()
final String filename;
@@ -12485,6 +12510,18 @@
@DocsEditable()
final Element activeElement;
+ @DomName('HTMLDocument.captureEvents')
+ @DocsEditable()
+ // http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-flow-capture
+ @deprecated // deprecated
+ void captureEvents() native;
+
+ @DomName('HTMLDocument.releaseEvents')
+ @DocsEditable()
+ // http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-flow-capture
+ @deprecated // deprecated
+ void releaseEvents() native;
+
@DomName('Document.body')
BodyElement body;
@@ -13392,16 +13429,6 @@
@Experimental() // untriaged
final int width;
}
-// 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.
-
-// WARNING: Do not edit - generated code.
-
-
-@DomName('ImageBitmapCallback')
-@Experimental() // untriaged
-typedef void ImageBitmapCallback(ImageBitmap bitmap);
// 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.
@@ -13758,8 +13785,6 @@
@SupportedBrowser(SupportedBrowser.SAFARI)
@Experimental()
// http://www.whatwg.org/specs/web-apps/current-work/multipage/states-of-the-type-attribute.html#concept-input-type-file-selected
- @Returns('_EntryArray')
- @Creates('_EntryArray')
final List<Entry> entries;
@JSName('webkitGrammar')
@@ -14485,6 +14510,26 @@
// To suppress missing implicit constructor warnings.
factory KeyboardEvent._() { throw new UnsupportedError("Not supported"); }
+ @DomName('KeyboardEvent.DOM_KEY_LOCATION_LEFT')
+ @DocsEditable()
+ @Experimental() // untriaged
+ static const int DOM_KEY_LOCATION_LEFT = 0x01;
+
+ @DomName('KeyboardEvent.DOM_KEY_LOCATION_NUMPAD')
+ @DocsEditable()
+ @Experimental() // untriaged
+ static const int DOM_KEY_LOCATION_NUMPAD = 0x03;
+
+ @DomName('KeyboardEvent.DOM_KEY_LOCATION_RIGHT')
+ @DocsEditable()
+ @Experimental() // untriaged
+ static const int DOM_KEY_LOCATION_RIGHT = 0x02;
+
+ @DomName('KeyboardEvent.DOM_KEY_LOCATION_STANDARD')
+ @DocsEditable()
+ @Experimental() // untriaged
+ static const int DOM_KEY_LOCATION_STANDARD = 0x00;
+
@DomName('KeyboardEvent.altGraphKey')
@DocsEditable()
@Experimental() // nonstandard
@@ -14509,6 +14554,11 @@
@Experimental() // nonstandard
final int keyLocation;
+ @DomName('KeyboardEvent.location')
+ @DocsEditable()
+ @Experimental() // untriaged
+ final int location;
+
@DomName('KeyboardEvent.metaKey')
@DocsEditable()
final bool metaKey;
@@ -14517,6 +14567,11 @@
@DocsEditable()
final bool shiftKey;
+ @DomName('KeyboardEvent.getModifierState')
+ @DocsEditable()
+ @Experimental() // untriaged
+ bool getModifierState(String keyArgument) native;
+
}
// 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
@@ -17849,47 +17904,6 @@
@DocsEditable()
static const int SHOW_TEXT = 0x00000004;
}
-// 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.
-
-
-@DomName('NodeIterator')
-@Unstable()
-class NodeIterator extends Interceptor native "NodeIterator" {
- factory NodeIterator(Node root, int whatToShow) {
- return document.$dom_createNodeIterator(root, whatToShow, null, false);
- }
-
- @DomName('NodeIterator.pointerBeforeReferenceNode')
- @DocsEditable()
- final bool pointerBeforeReferenceNode;
-
- @DomName('NodeIterator.referenceNode')
- @DocsEditable()
- final Node referenceNode;
-
- @DomName('NodeIterator.root')
- @DocsEditable()
- final Node root;
-
- @DomName('NodeIterator.whatToShow')
- @DocsEditable()
- final int whatToShow;
-
- @DomName('NodeIterator.detach')
- @DocsEditable()
- void detach() native;
-
- @DomName('NodeIterator.nextNode')
- @DocsEditable()
- Node nextNode() native;
-
- @DomName('NodeIterator.previousNode')
- @DocsEditable()
- Node previousNode() native;
-
-}
// 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.
@@ -18121,11 +18135,6 @@
@DocsEditable()
int checkPermission() native;
- @JSName('createHTMLNotification')
- @DomName('NotificationCenter.createHTMLNotification')
- @DocsEditable()
- Notification createHtmlNotification(String url) native;
-
@DomName('NotificationCenter.createNotification')
@DocsEditable()
Notification createNotification(String iconUrl, String title, String body) native;
@@ -18605,7 +18614,9 @@
@SupportedBrowser(SupportedBrowser.CHROME)
@SupportedBrowser(SupportedBrowser.FIREFOX)
@SupportedBrowser(SupportedBrowser.IE)
-class Performance extends Interceptor native "Performance" {
+class Performance extends EventTarget native "Performance" {
+ // To suppress missing implicit constructor warnings.
+ factory Performance._() { throw new UnsupportedError("Not supported"); }
/// Checks if this type is supported on the current platform.
static bool get supported => JS('bool', '!!(window.performance)');
@@ -19567,6 +19578,45 @@
@DocsEditable()
+@DomName('RsaKeyGenParams')
+@Experimental() // untriaged
+class RsaKeyGenParams extends Algorithm native "RsaKeyGenParams" {
+ // To suppress missing implicit constructor warnings.
+ factory RsaKeyGenParams._() { throw new UnsupportedError("Not supported"); }
+
+ @DomName('RsaKeyGenParams.modulusLength')
+ @DocsEditable()
+ @Experimental() // untriaged
+ final int modulusLength;
+
+ @DomName('RsaKeyGenParams.publicExponent')
+ @DocsEditable()
+ @Experimental() // untriaged
+ final Uint8List publicExponent;
+}
+// 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.
+
+
+@DocsEditable()
+@DomName('RsaSsaParams')
+@Experimental() // untriaged
+class RsaSsaParams extends Algorithm native "RsaSsaParams" {
+ // To suppress missing implicit constructor warnings.
+ factory RsaSsaParams._() { throw new UnsupportedError("Not supported"); }
+
+ @DomName('RsaSsaParams.hash')
+ @DocsEditable()
+ @Experimental() // untriaged
+ final Algorithm hash;
+}
+// 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.
+
+
+@DocsEditable()
@DomName('RTCDataChannel')
// http://dev.w3.org/2011/webrtc/editor/webrtc.html#idl-def-RTCDataChannel
@Experimental()
@@ -19598,10 +19648,40 @@
@DocsEditable()
final int bufferedAmount;
+ @DomName('RTCDataChannel.id')
+ @DocsEditable()
+ @Experimental() // untriaged
+ final int id;
+
@DomName('RTCDataChannel.label')
@DocsEditable()
final String label;
+ @DomName('RTCDataChannel.maxRetransmitTime')
+ @DocsEditable()
+ @Experimental() // untriaged
+ final int maxRetransmitTime;
+
+ @DomName('RTCDataChannel.maxRetransmits')
+ @DocsEditable()
+ @Experimental() // untriaged
+ final int maxRetransmits;
+
+ @DomName('RTCDataChannel.negotiated')
+ @DocsEditable()
+ @Experimental() // untriaged
+ final bool negotiated;
+
+ @DomName('RTCDataChannel.ordered')
+ @DocsEditable()
+ @Experimental() // untriaged
+ final bool ordered;
+
+ @DomName('RTCDataChannel.protocol')
+ @DocsEditable()
+ @Experimental() // untriaged
+ final String protocol;
+
@DomName('RTCDataChannel.readyState')
@DocsEditable()
final String readyState;
@@ -20798,6 +20878,16 @@
// To suppress missing implicit constructor warnings.
factory SourceBuffer._() { throw new UnsupportedError("Not supported"); }
+ @DomName('SourceBuffer.appendWindowEnd')
+ @DocsEditable()
+ @Experimental() // untriaged
+ num appendWindowEnd;
+
+ @DomName('SourceBuffer.appendWindowStart')
+ @DocsEditable()
+ @Experimental() // untriaged
+ num appendWindowStart;
+
@DomName('SourceBuffer.buffered')
@DocsEditable()
final TimeRanges buffered;
@@ -20825,6 +20915,11 @@
@DocsEditable()
@Experimental() // untriaged
void appendBufferView(TypedData data) native;
+
+ @DomName('SourceBuffer.remove')
+ @DocsEditable()
+ @Experimental() // untriaged
+ void remove(num start, num end) native;
}
// 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
@@ -21951,15 +22046,15 @@
@DomName('SubtleCrypto.decrypt')
@DocsEditable()
@Experimental() // untriaged
- CryptoOperation decrypt(Map algorithm) {
+ CryptoOperation decrypt(Map algorithm, CryptoKey key) {
var algorithm_1 = convertDartToNative_Dictionary(algorithm);
- return _decrypt_1(algorithm_1);
+ return _decrypt_1(algorithm_1, key);
}
@JSName('decrypt')
@DomName('SubtleCrypto.decrypt')
@DocsEditable()
@Experimental() // untriaged
- CryptoOperation _decrypt_1(algorithm) native;
+ CryptoOperation _decrypt_1(algorithm, CryptoKey key) native;
@DomName('SubtleCrypto.digest')
@DocsEditable()
@@ -21977,15 +22072,28 @@
@DomName('SubtleCrypto.encrypt')
@DocsEditable()
@Experimental() // untriaged
- CryptoOperation encrypt(Map algorithm) {
+ CryptoOperation encrypt(Map algorithm, CryptoKey key) {
var algorithm_1 = convertDartToNative_Dictionary(algorithm);
- return _encrypt_1(algorithm_1);
+ return _encrypt_1(algorithm_1, key);
}
@JSName('encrypt')
@DomName('SubtleCrypto.encrypt')
@DocsEditable()
@Experimental() // untriaged
- CryptoOperation _encrypt_1(algorithm) native;
+ CryptoOperation _encrypt_1(algorithm, CryptoKey key) native;
+
+ @DomName('SubtleCrypto.generateKey')
+ @DocsEditable()
+ @Experimental() // untriaged
+ Object generateKey(Map algorithm, bool extractable, List<String> keyUsages) {
+ var algorithm_1 = convertDartToNative_Dictionary(algorithm);
+ return _generateKey_1(algorithm_1, extractable, keyUsages);
+ }
+ @JSName('generateKey')
+ @DomName('SubtleCrypto.generateKey')
+ @DocsEditable()
+ @Experimental() // untriaged
+ Object _generateKey_1(algorithm, extractable, List<String> keyUsages) native;
@DomName('SubtleCrypto.importKey')
@DocsEditable()
@@ -22003,28 +22111,28 @@
@DomName('SubtleCrypto.sign')
@DocsEditable()
@Experimental() // untriaged
- CryptoOperation sign(Map algorithm) {
+ CryptoOperation sign(Map algorithm, CryptoKey key) {
var algorithm_1 = convertDartToNative_Dictionary(algorithm);
- return _sign_1(algorithm_1);
+ return _sign_1(algorithm_1, key);
}
@JSName('sign')
@DomName('SubtleCrypto.sign')
@DocsEditable()
@Experimental() // untriaged
- CryptoOperation _sign_1(algorithm) native;
+ CryptoOperation _sign_1(algorithm, CryptoKey key) native;
@DomName('SubtleCrypto.verify')
@DocsEditable()
@Experimental() // untriaged
- CryptoOperation verify(Map algorithm) {
+ CryptoOperation verify(Map algorithm, CryptoKey key, TypedData signature) {
var algorithm_1 = convertDartToNative_Dictionary(algorithm);
- return _verify_1(algorithm_1);
+ return _verify_1(algorithm_1, key, signature);
}
@JSName('verify')
@DomName('SubtleCrypto.verify')
@DocsEditable()
@Experimental() // untriaged
- CryptoOperation _verify_1(algorithm) native;
+ CryptoOperation _verify_1(algorithm, CryptoKey key, TypedData signature) native;
}
// 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
@@ -22611,6 +22719,13 @@
@DocsEditable()
final String wholeText;
+ @DomName('Text.getDestinationInsertionPoints')
+ @DocsEditable()
+ @Experimental() // untriaged
+ @Returns('NodeList')
+ @Creates('NodeList')
+ List<Node> getDestinationInsertionPoints() native;
+
@DomName('Text.replaceWholeText')
@DocsEditable()
// http://dom.spec.whatwg.org/#dom-text-replacewholetext
@@ -23494,69 +23609,6 @@
@DocsEditable()
final String pseudoElement;
}
-// 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.
-
-
-@DomName('TreeWalker')
-@Unstable()
-class TreeWalker extends Interceptor native "TreeWalker" {
- factory TreeWalker(Node root, int whatToShow) {
- return document.$dom_createTreeWalker(root, whatToShow, null, false);
- }
-
- @DomName('TreeWalker.currentNode')
- @DocsEditable()
- Node currentNode;
-
- @DomName('TreeWalker.expandEntityReferences')
- @DocsEditable()
- // http://dom.spec.whatwg.org/#dom-traversal
- @deprecated // deprecated
- final bool expandEntityReferences;
-
- @DomName('TreeWalker.filter')
- @DocsEditable()
- final NodeFilter filter;
-
- @DomName('TreeWalker.root')
- @DocsEditable()
- final Node root;
-
- @DomName('TreeWalker.whatToShow')
- @DocsEditable()
- final int whatToShow;
-
- @DomName('TreeWalker.firstChild')
- @DocsEditable()
- Node firstChild() native;
-
- @DomName('TreeWalker.lastChild')
- @DocsEditable()
- Node lastChild() native;
-
- @DomName('TreeWalker.nextNode')
- @DocsEditable()
- Node nextNode() native;
-
- @DomName('TreeWalker.nextSibling')
- @DocsEditable()
- Node nextSibling() native;
-
- @DomName('TreeWalker.parentNode')
- @DocsEditable()
- Node parentNode() native;
-
- @DomName('TreeWalker.previousNode')
- @DocsEditable()
- Node previousNode() native;
-
- @DomName('TreeWalker.previousSibling')
- @DocsEditable()
- Node previousSibling() native;
-
-}
// 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.
@@ -24940,6 +24992,12 @@
@DocsEditable()
void alert(String message) native;
+ @DomName('Window.captureEvents')
+ @DocsEditable()
+ // http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-flow-capture
+ @deprecated // deprecated
+ void captureEvents() native;
+
@DomName('Window.close')
@DocsEditable()
void close() native;
@@ -24948,123 +25006,6 @@
@DocsEditable()
bool confirm(String message) native;
- @DomName('Window.createImageBitmap')
- @DocsEditable()
- @Experimental() // untriaged
- void _createImageBitmap(bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video, ImageBitmapCallback callback, [int sx, int sy, int sw, int sh]) {
- if ((bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video is ImageElement || bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video == null) && sx == null && sy == null && sw == null && sh == null) {
- _createImageBitmap_1(bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video, callback);
- return;
- }
- if (sh != null && sw != null && sy != null && sx != null && (bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video is ImageElement || bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video == null)) {
- _createImageBitmap_2(bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video, callback, sx, sy, sw, sh);
- return;
- }
- if ((bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video is VideoElement || bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video == null) && sx == null && sy == null && sw == null && sh == null) {
- _createImageBitmap_3(bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video, callback);
- return;
- }
- if (sh != null && sw != null && sy != null && sx != null && (bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video is VideoElement || bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video == null)) {
- _createImageBitmap_4(bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video, callback, sx, sy, sw, sh);
- return;
- }
- if ((bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video is CanvasRenderingContext2D || bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video == null) && sx == null && sy == null && sw == null && sh == null) {
- _createImageBitmap_5(bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video, callback);
- return;
- }
- if (sh != null && sw != null && sy != null && sx != null && (bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video is CanvasRenderingContext2D || bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video == null)) {
- _createImageBitmap_6(bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video, callback, sx, sy, sw, sh);
- return;
- }
- if ((bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video is CanvasElement || bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video == null) && sx == null && sy == null && sw == null && sh == null) {
- _createImageBitmap_7(bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video, callback);
- return;
- }
- if (sh != null && sw != null && sy != null && sx != null && (bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video is CanvasElement || bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video == null)) {
- _createImageBitmap_8(bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video, callback, sx, sy, sw, sh);
- return;
- }
- if ((bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video is ImageData || bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video == null) && sx == null && sy == null && sw == null && sh == null) {
- var data_1 = convertDartToNative_ImageData(bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video);
- _createImageBitmap_9(data_1, callback);
- return;
- }
- if (sh != null && sw != null && sy != null && sx != null && (bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video is ImageData || bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video == null)) {
- var data_2 = convertDartToNative_ImageData(bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video);
- _createImageBitmap_10(data_2, callback, sx, sy, sw, sh);
- return;
- }
- if ((bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video is ImageBitmap || bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video == null) && sx == null && sy == null && sw == null && sh == null) {
- _createImageBitmap_11(bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video, callback);
- return;
- }
- if (sh != null && sw != null && sy != null && sx != null && (bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video is ImageBitmap || bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video == null)) {
- _createImageBitmap_12(bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video, callback, sx, sy, sw, sh);
- return;
- }
- throw new ArgumentError("Incorrect number or type of arguments");
- }
- @JSName('createImageBitmap')
- @DomName('Window.createImageBitmap')
- @DocsEditable()
- @Experimental() // untriaged
- void _createImageBitmap_1(ImageElement image, ImageBitmapCallback callback) native;
- @JSName('createImageBitmap')
- @DomName('Window.createImageBitmap')
- @DocsEditable()
- @Experimental() // untriaged
- void _createImageBitmap_2(ImageElement image, ImageBitmapCallback callback, sx, sy, sw, sh) native;
- @JSName('createImageBitmap')
- @DomName('Window.createImageBitmap')
- @DocsEditable()
- @Experimental() // untriaged
- void _createImageBitmap_3(VideoElement video, ImageBitmapCallback callback) native;
- @JSName('createImageBitmap')
- @DomName('Window.createImageBitmap')
- @DocsEditable()
- @Experimental() // untriaged
- void _createImageBitmap_4(VideoElement video, ImageBitmapCallback callback, sx, sy, sw, sh) native;
- @JSName('createImageBitmap')
- @DomName('Window.createImageBitmap')
- @DocsEditable()
- @Experimental() // untriaged
- void _createImageBitmap_5(CanvasRenderingContext2D context, ImageBitmapCallback callback) native;
- @JSName('createImageBitmap')
- @DomName('Window.createImageBitmap')
- @DocsEditable()
- @Experimental() // untriaged
- void _createImageBitmap_6(CanvasRenderingContext2D context, ImageBitmapCallback callback, sx, sy, sw, sh) native;
- @JSName('createImageBitmap')
- @DomName('Window.createImageBitmap')
- @DocsEditable()
- @Experimental() // untriaged
- void _createImageBitmap_7(CanvasElement canvas, ImageBitmapCallback callback) native;
- @JSName('createImageBitmap')
- @DomName('Window.createImageBitmap')
- @DocsEditable()
- @Experimental() // untriaged
- void _createImageBitmap_8(CanvasElement canvas, ImageBitmapCallback callback, sx, sy, sw, sh) native;
- @JSName('createImageBitmap')
- @DomName('Window.createImageBitmap')
- @DocsEditable()
- @Experimental() // untriaged
- void _createImageBitmap_9(data, ImageBitmapCallback callback) native;
- @JSName('createImageBitmap')
- @DomName('Window.createImageBitmap')
- @DocsEditable()
- @Experimental() // untriaged
- void _createImageBitmap_10(data, ImageBitmapCallback callback, sx, sy, sw, sh) native;
- @JSName('createImageBitmap')
- @DomName('Window.createImageBitmap')
- @DocsEditable()
- @Experimental() // untriaged
- void _createImageBitmap_11(ImageBitmap bitmap, ImageBitmapCallback callback) native;
- @JSName('createImageBitmap')
- @DomName('Window.createImageBitmap')
- @DocsEditable()
- @Experimental() // untriaged
- void _createImageBitmap_12(ImageBitmap bitmap, ImageBitmapCallback callback, sx, sy, sw, sh) native;
-
@DomName('Window.find')
@DocsEditable()
@Experimental() // non-standard
@@ -25135,6 +25076,12 @@
@DocsEditable()
void print() native;
+ @DomName('Window.releaseEvents')
+ @DocsEditable()
+ // http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-flow-capture
+ @deprecated // deprecated
+ void releaseEvents() native;
+
@DomName('Window.resizeBy')
@DocsEditable()
void resizeBy(num x, num y) native;
@@ -26591,132 +26538,6 @@
@DocsEditable()
-@DomName('EntryArray')
-// http://www.w3.org/TR/file-system-api/#the-entry-interface
-@Experimental()
-class _EntryArray extends Interceptor with ListMixin<Entry>, ImmutableListMixin<Entry> implements JavaScriptIndexingBehavior, List<Entry> native "EntryArray" {
-
- @DomName('EntryArray.length')
- @DocsEditable()
- int get length => JS("int", "#.length", this);
-
- Entry operator[](int index) {
- if (JS("bool", "# >>> 0 !== # || # >= #", index,
- index, index, length))
- throw new RangeError.range(index, 0, length);
- return JS("Entry", "#[#]", this, index);
- }
- void operator[]=(int index, Entry value) {
- throw new UnsupportedError("Cannot assign element of immutable List.");
- }
- // -- start List<Entry> mixins.
- // Entry is the element type.
-
-
- void set length(int value) {
- throw new UnsupportedError("Cannot resize immutable List.");
- }
-
- Entry get first {
- if (this.length > 0) {
- return JS('Entry', '#[0]', this);
- }
- throw new StateError("No elements");
- }
-
- Entry get last {
- int len = this.length;
- if (len > 0) {
- return JS('Entry', '#[#]', this, len - 1);
- }
- throw new StateError("No elements");
- }
-
- Entry get single {
- int len = this.length;
- if (len == 1) {
- return JS('Entry', '#[0]', this);
- }
- if (len == 0) throw new StateError("No elements");
- throw new StateError("More than one element");
- }
-
- Entry elementAt(int index) => this[index];
- // -- end List<Entry> mixins.
-
- @DomName('EntryArray.item')
- @DocsEditable()
- Entry item(int index) native;
-}
-// 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.
-
-
-@DocsEditable()
-@DomName('EntryArraySync')
-// http://www.w3.org/TR/file-system-api/#idl-def-EntrySync
-@Experimental()
-class _EntryArraySync extends Interceptor with ListMixin<_EntrySync>, ImmutableListMixin<_EntrySync> implements JavaScriptIndexingBehavior, List<_EntrySync> native "EntryArraySync" {
-
- @DomName('EntryArraySync.length')
- @DocsEditable()
- int get length => JS("int", "#.length", this);
-
- _EntrySync operator[](int index) {
- if (JS("bool", "# >>> 0 !== # || # >= #", index,
- index, index, length))
- throw new RangeError.range(index, 0, length);
- return JS("_EntrySync", "#[#]", this, index);
- }
- void operator[]=(int index, _EntrySync value) {
- throw new UnsupportedError("Cannot assign element of immutable List.");
- }
- // -- start List<_EntrySync> mixins.
- // _EntrySync is the element type.
-
-
- void set length(int value) {
- throw new UnsupportedError("Cannot resize immutable List.");
- }
-
- _EntrySync get first {
- if (this.length > 0) {
- return JS('_EntrySync', '#[0]', this);
- }
- throw new StateError("No elements");
- }
-
- _EntrySync get last {
- int len = this.length;
- if (len > 0) {
- return JS('_EntrySync', '#[#]', this, len - 1);
- }
- throw new StateError("No elements");
- }
-
- _EntrySync get single {
- int len = this.length;
- if (len == 1) {
- return JS('_EntrySync', '#[0]', this);
- }
- if (len == 0) throw new StateError("No elements");
- throw new StateError("More than one element");
- }
-
- _EntrySync elementAt(int index) => this[index];
- // -- end List<_EntrySync> mixins.
-
- @DomName('EntryArraySync.item')
- @DocsEditable()
- _EntrySync item(int index) native;
-}
-// 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.
-
-
-@DocsEditable()
@DomName('EntrySync')
// http://www.w3.org/TR/file-system-api/#idl-def-EntrySync
@Experimental()
@@ -30860,9 +30681,6 @@
if (baseClassName == 'Element') baseClassName = 'HTMLElement';
var baseConstructor = JS('=Object', '#[#]', context, baseClassName);
- if (JS('bool', "typeof(#) != 'function'", baseConstructor)) {
- throw new ArgumentError(type);
- }
var properties = JS('=Object', '{}');
@@ -31193,6 +31011,19 @@
* error.
*/
static final supportsSimd = false;
+
+ /**
+ * Upgrade all custom elements in the subtree which have not been upgraded.
+ *
+ * This is needed to cover timing scenarios which the custom element polyfill
+ * does not cover.
+ */
+ static void upgradeCustomElements(Node node) {
+ if (JS('bool', '(#.CustomElements && #.CustomElements.upgradeAll)',
+ window, window)) {
+ JS('', '#.CustomElements.upgradeAll(#)', window, node);
+ }
+ }
}
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index 1daeb79..dc81135 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -1361,6 +1361,16 @@
@DocsEditable()
void set globalCompositeOperation(String value) native "CanvasRenderingContext2D_globalCompositeOperation_Setter";
+ @DomName('CanvasRenderingContext2D.imageSmoothingEnabled')
+ @DocsEditable()
+ @Experimental() // untriaged
+ bool get imageSmoothingEnabled native "CanvasRenderingContext2D_imageSmoothingEnabled_Getter";
+
+ @DomName('CanvasRenderingContext2D.imageSmoothingEnabled')
+ @DocsEditable()
+ @Experimental() // untriaged
+ void set imageSmoothingEnabled(bool value) native "CanvasRenderingContext2D_imageSmoothingEnabled_Setter";
+
@DomName('CanvasRenderingContext2D.lineCap')
@DocsEditable()
String get lineCap native "CanvasRenderingContext2D_lineCap_Getter";
@@ -1464,20 +1474,6 @@
@Experimental()
num get backingStorePixelRatio native "CanvasRenderingContext2D_webkitBackingStorePixelRatio_Getter";
- @DomName('CanvasRenderingContext2D.webkitImageSmoothingEnabled')
- @DocsEditable()
- @SupportedBrowser(SupportedBrowser.CHROME)
- @SupportedBrowser(SupportedBrowser.SAFARI)
- @Experimental()
- bool get imageSmoothingEnabled native "CanvasRenderingContext2D_webkitImageSmoothingEnabled_Getter";
-
- @DomName('CanvasRenderingContext2D.webkitImageSmoothingEnabled')
- @DocsEditable()
- @SupportedBrowser(SupportedBrowser.CHROME)
- @SupportedBrowser(SupportedBrowser.SAFARI)
- @Experimental()
- void set imageSmoothingEnabled(bool value) native "CanvasRenderingContext2D_webkitImageSmoothingEnabled_Setter";
-
@DomName('CanvasRenderingContext2D.arc')
@DocsEditable()
void $dom_arc(num x, num y, num radius, num startAngle, num endAngle, bool anticlockwise) native "CanvasRenderingContext2D_arc_Callback";
@@ -1539,6 +1535,11 @@
@DocsEditable()
CanvasGradient createRadialGradient(num x0, num y0, num r0, num x1, num y1, num r1) native "CanvasRenderingContext2D_createRadialGradient_Callback";
+ @DomName('CanvasRenderingContext2D.drawCustomFocusRing')
+ @DocsEditable()
+ @Experimental() // untriaged
+ bool drawCustomFocusRing(Element element) native "CanvasRenderingContext2D_drawCustomFocusRing_Callback";
+
void _drawImage(canvas_OR_image_OR_imageBitmap_OR_video, num sx_OR_x, num sy_OR_y, [num sw_OR_width, num height_OR_sh, num dx, num dy, num dw, num dh]) {
if ((sy_OR_y is num || sy_OR_y == null) && (sx_OR_x is num || sx_OR_x == null) && (canvas_OR_image_OR_imageBitmap_OR_video is ImageElement || canvas_OR_image_OR_imageBitmap_OR_video == null) && sw_OR_width == null && height_OR_sh == null && dx == null && dy == null && dw == null && dh == null) {
_drawImage_1(canvas_OR_image_OR_imageBitmap_OR_video, sx_OR_x, sy_OR_y);
@@ -1615,6 +1616,11 @@
void _drawImage_12(canvas_OR_image_OR_imageBitmap_OR_video, sx_OR_x, sy_OR_y, sw_OR_width, height_OR_sh, dx, dy, dw, dh) native "CanvasRenderingContext2D__drawImage_12_Callback";
+ @DomName('CanvasRenderingContext2D.drawSystemFocusRing')
+ @DocsEditable()
+ @Experimental() // untriaged
+ void drawSystemFocusRing(Element element) native "CanvasRenderingContext2D_drawSystemFocusRing_Callback";
+
void fill([String winding]) {
if (winding != null) {
_fill_1(winding);
@@ -6986,7 +6992,7 @@
@DomName('DataTransferItem.getAsString')
@DocsEditable()
- void _getAsString([_StringCallback callback]) native "DataTransferItem_getAsString_Callback";
+ void _getAsString(_StringCallback callback) native "DataTransferItem_getAsString_Callback";
Future<String> getAsString() {
var completer = new Completer<String>();
@@ -7718,27 +7724,6 @@
@DocsEditable()
Event $dom_createEvent(String eventType) native "Document_createEvent_Callback";
- NodeIterator $dom_createNodeIterator(Node root, [int whatToShow, NodeFilter filter, bool expandEntityReferences]) {
- if (expandEntityReferences != null) {
- return _createNodeIterator_1(root, whatToShow, filter, expandEntityReferences);
- }
- if (filter != null) {
- return _createNodeIterator_2(root, whatToShow, filter);
- }
- if (whatToShow != null) {
- return _createNodeIterator_3(root, whatToShow);
- }
- return _createNodeIterator_4(root);
- }
-
- NodeIterator _createNodeIterator_1(root, whatToShow, filter, expandEntityReferences) native "Document__createNodeIterator_1_Callback";
-
- NodeIterator _createNodeIterator_2(root, whatToShow, filter) native "Document__createNodeIterator_2_Callback";
-
- NodeIterator _createNodeIterator_3(root, whatToShow) native "Document__createNodeIterator_3_Callback";
-
- NodeIterator _createNodeIterator_4(root) native "Document__createNodeIterator_4_Callback";
-
@DomName('Document.createRange')
@DocsEditable()
Range $dom_createRange() native "Document_createRange_Callback";
@@ -7760,27 +7745,6 @@
@Experimental()
TouchList $dom_createTouchList() native "Document_createTouchList_Callback";
- TreeWalker $dom_createTreeWalker(Node root, [int whatToShow, NodeFilter filter, bool expandEntityReferences]) {
- if (expandEntityReferences != null) {
- return _createTreeWalker_1(root, whatToShow, filter, expandEntityReferences);
- }
- if (filter != null) {
- return _createTreeWalker_2(root, whatToShow, filter);
- }
- if (whatToShow != null) {
- return _createTreeWalker_3(root, whatToShow);
- }
- return _createTreeWalker_4(root);
- }
-
- TreeWalker _createTreeWalker_1(root, whatToShow, filter, expandEntityReferences) native "Document__createTreeWalker_1_Callback";
-
- TreeWalker _createTreeWalker_2(root, whatToShow, filter) native "Document__createTreeWalker_2_Callback";
-
- TreeWalker _createTreeWalker_3(root, whatToShow) native "Document__createTreeWalker_3_Callback";
-
- TreeWalker _createTreeWalker_4(root) native "Document__createTreeWalker_4_Callback";
-
@DomName('Document.elementFromPoint')
@DocsEditable()
Element $dom_elementFromPoint(int x, int y) native "Document_elementFromPoint_Callback";
@@ -8167,6 +8131,11 @@
ElementList queryAll(String selectors) {
return new _FrozenElementList._wrap($dom_querySelectorAll(selectors));
}
+
+ /// Checks if [register] is supported on the current platform.
+ bool get supportsRegister {
+ return true;
+ }
}
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
@@ -9046,7 +9015,7 @@
// https://dvcs.w3.org/hg/fullscreen/raw-file/tip/Overview.html
@Experimental()
ElementStream<Event> get onFullscreenError;
-
+
}
// TODO(jacobr): this is an inefficient implementation but it is hard to see
@@ -10029,6 +9998,8 @@
Point p = Element._offsetToHelper(parentOffset, parent);
return new Point(p.x + current.offsetLeft, p.y + current.offsetTop);
}
+
+
// To suppress missing implicit constructor warnings.
factory Element._() { throw new UnsupportedError("Not supported"); }
@@ -10267,10 +10238,10 @@
bool hidden;
- String id;
-
String innerHtml;
+ InputMethodContext get inputMethodContext;
+
bool get isContentEditable;
String lang;
@@ -10289,8 +10260,6 @@
void click();
- InputMethodContext getInputContext();
-
Element insertAdjacentElement(String where, Element element);
void insertAdjacentHtml(String where, String html);
@@ -10331,6 +10300,14 @@
@DocsEditable()
int get clientWidth native "Element_clientWidth_Getter";
+ @DomName('Element.id')
+ @DocsEditable()
+ String get id native "Element_id_Getter";
+
+ @DomName('Element.id')
+ @DocsEditable()
+ void set id(String value) native "Element_id_Setter";
+
@DomName('Element.offsetHeight')
@DocsEditable()
int get offsetHeight native "Element_offsetHeight_Getter";
@@ -10438,6 +10415,11 @@
@DocsEditable()
List<Rect> getClientRects() native "Element_getClientRects_Callback";
+ @DomName('Element.getDestinationInsertionPoints')
+ @DocsEditable()
+ @Experimental() // untriaged
+ List<Node> getDestinationInsertionPoints() native "Element_getDestinationInsertionPoints_Callback";
+
@DomName('Element.getElementsByClassName')
@DocsEditable()
List<Node> getElementsByClassName(String name) native "Element_getElementsByClassName_Callback";
@@ -11208,6 +11190,16 @@
// To suppress missing implicit constructor warnings.
factory ErrorEvent._() { throw new UnsupportedError("Not supported"); }
+ @DomName('ErrorEvent.colno')
+ @DocsEditable()
+ @Experimental() // untriaged
+ int get colno native "ErrorEvent_colno_Getter";
+
+ @DomName('ErrorEvent.error')
+ @DocsEditable()
+ @Experimental() // untriaged
+ Object get error native "ErrorEvent_error_Getter";
+
@DomName('ErrorEvent.filename')
@DocsEditable()
String get filename native "ErrorEvent_filename_Getter";
@@ -13012,6 +13004,18 @@
@DocsEditable()
Element get activeElement native "HTMLDocument_activeElement_Getter";
+ @DomName('HTMLDocument.captureEvents')
+ @DocsEditable()
+ // http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-flow-capture
+ @deprecated // deprecated
+ void captureEvents() native "HTMLDocument_captureEvents_Callback";
+
+ @DomName('HTMLDocument.releaseEvents')
+ @DocsEditable()
+ // http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-flow-capture
+ @deprecated // deprecated
+ void releaseEvents() native "HTMLDocument_releaseEvents_Callback";
+
@DomName('Document.body')
BodyElement get body => $dom_body;
@@ -13213,14 +13217,6 @@
@DocsEditable()
void set hidden(bool value) native "HTMLElement_hidden_Setter";
- @DomName('HTMLElement.id')
- @DocsEditable()
- String get id native "HTMLElement_id_Getter";
-
- @DomName('HTMLElement.id')
- @DocsEditable()
- void set id(String value) native "HTMLElement_id_Setter";
-
@DomName('HTMLElement.innerHTML')
@DocsEditable()
String get innerHtml native "HTMLElement_innerHTML_Getter";
@@ -13229,6 +13225,11 @@
@DocsEditable()
void set innerHtml(String value) native "HTMLElement_innerHTML_Setter";
+ @DomName('HTMLElement.inputMethodContext')
+ @DocsEditable()
+ @Experimental() // untriaged
+ InputMethodContext get inputMethodContext native "HTMLElement_inputMethodContext_Getter";
+
@DomName('HTMLElement.isContentEditable')
@DocsEditable()
bool get isContentEditable native "HTMLElement_isContentEditable_Getter";
@@ -13301,12 +13302,6 @@
@DocsEditable()
void click() native "HTMLElement_click_Callback";
- @DomName('HTMLElement.getInputContext')
- @DocsEditable()
- // http://www.w3.org/TR/ime-api/#the-getinputcontext-method
- @Experimental()
- InputMethodContext getInputContext() native "HTMLElement_getInputContext_Callback";
-
@DomName('HTMLElement.insertAdjacentElement')
@DocsEditable()
@Experimental() // non-standard
@@ -14172,16 +14167,6 @@
int get width native "ImageBitmap_width_Getter";
}
-// 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.
-
-// WARNING: Do not edit - generated code.
-
-
-@DomName('ImageBitmapCallback')
-@Experimental() // untriaged
-typedef void ImageBitmapCallback(ImageBitmap bitmap);
// 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.
@@ -15491,6 +15476,26 @@
// To suppress missing implicit constructor warnings.
factory KeyboardEvent._() { throw new UnsupportedError("Not supported"); }
+ @DomName('KeyboardEvent.DOM_KEY_LOCATION_LEFT')
+ @DocsEditable()
+ @Experimental() // untriaged
+ static const int DOM_KEY_LOCATION_LEFT = 0x01;
+
+ @DomName('KeyboardEvent.DOM_KEY_LOCATION_NUMPAD')
+ @DocsEditable()
+ @Experimental() // untriaged
+ static const int DOM_KEY_LOCATION_NUMPAD = 0x03;
+
+ @DomName('KeyboardEvent.DOM_KEY_LOCATION_RIGHT')
+ @DocsEditable()
+ @Experimental() // untriaged
+ static const int DOM_KEY_LOCATION_RIGHT = 0x02;
+
+ @DomName('KeyboardEvent.DOM_KEY_LOCATION_STANDARD')
+ @DocsEditable()
+ @Experimental() // untriaged
+ static const int DOM_KEY_LOCATION_STANDARD = 0x00;
+
@DomName('KeyboardEvent.altGraphKey')
@DocsEditable()
@Experimental() // nonstandard
@@ -15514,6 +15519,11 @@
@Experimental() // nonstandard
int get keyLocation native "KeyboardEvent_keyLocation_Getter";
+ @DomName('KeyboardEvent.location')
+ @DocsEditable()
+ @Experimental() // untriaged
+ int get location native "KeyboardEvent_location_Getter";
+
@DomName('KeyboardEvent.metaKey')
@DocsEditable()
bool get metaKey native "KeyboardEvent_metaKey_Getter";
@@ -15522,9 +15532,14 @@
@DocsEditable()
bool get shiftKey native "KeyboardEvent_shiftKey_Getter";
+ @DomName('KeyboardEvent.getModifierState')
+ @DocsEditable()
+ @Experimental() // untriaged
+ bool getModifierState(String keyArgument) native "KeyboardEvent_getModifierState_Callback";
+
@DomName('KeyboardEvent.initKeyboardEvent')
@DocsEditable()
- void $dom_initKeyboardEvent(String type, bool canBubble, bool cancelable, Window view, String keyIdentifier, int keyLocation, bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, bool altGraphKey) native "KeyboardEvent_initKeyboardEvent_Callback";
+ void $dom_initKeyboardEvent(String type, bool canBubble, bool cancelable, Window view, String keyIdentifier, int location, bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, bool altGraphKey) native "KeyboardEvent_initKeyboardEvent_Callback";
}
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
@@ -19270,47 +19285,6 @@
static const int SHOW_TEXT = 0x00000004;
}
-// 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.
-
-
-@DomName('NodeIterator')
-@Unstable()
-class NodeIterator extends NativeFieldWrapperClass1 {
- factory NodeIterator(Node root, int whatToShow) {
- return document.$dom_createNodeIterator(root, whatToShow, null, false);
- }
-
- @DomName('NodeIterator.pointerBeforeReferenceNode')
- @DocsEditable()
- bool get pointerBeforeReferenceNode native "NodeIterator_pointerBeforeReferenceNode_Getter";
-
- @DomName('NodeIterator.referenceNode')
- @DocsEditable()
- Node get referenceNode native "NodeIterator_referenceNode_Getter";
-
- @DomName('NodeIterator.root')
- @DocsEditable()
- Node get root native "NodeIterator_root_Getter";
-
- @DomName('NodeIterator.whatToShow')
- @DocsEditable()
- int get whatToShow native "NodeIterator_whatToShow_Getter";
-
- @DomName('NodeIterator.detach')
- @DocsEditable()
- void detach() native "NodeIterator_detach_Callback";
-
- @DomName('NodeIterator.nextNode')
- @DocsEditable()
- Node nextNode() native "NodeIterator_nextNode_Callback";
-
- @DomName('NodeIterator.previousNode')
- @DocsEditable()
- Node previousNode() native "NodeIterator_previousNode_Callback";
-
-}
// 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.
@@ -19571,10 +19545,6 @@
@DocsEditable()
int checkPermission() native "NotificationCenter_checkPermission_Callback";
- @DomName('NotificationCenter.createHTMLNotification')
- @DocsEditable()
- Notification createHtmlNotification(String url) native "NotificationCenter_createHTMLNotification_Callback";
-
@DomName('NotificationCenter.createNotification')
@DocsEditable()
Notification createNotification(String iconUrl, String title, String body) native "NotificationCenter_createNotification_Callback";
@@ -20178,7 +20148,9 @@
@SupportedBrowser(SupportedBrowser.CHROME)
@SupportedBrowser(SupportedBrowser.FIREFOX)
@SupportedBrowser(SupportedBrowser.IE)
-class Performance extends NativeFieldWrapperClass1 {
+class Performance extends EventTarget {
+ // To suppress missing implicit constructor warnings.
+ factory Performance._() { throw new UnsupportedError("Not supported"); }
/// Checks if this type is supported on the current platform.
static bool get supported => true;
@@ -20258,6 +20230,21 @@
// http://www.w3c-test.org/webperf/specs/ResourceTiming/#performanceresourcetiming-methods
void setResourceTimingBufferSize(int maxSize) native "Performance_webkitSetResourceTimingBufferSize_Callback";
+ @DomName('Performance.addEventListener')
+ @DocsEditable()
+ @Experimental() // untriaged
+ void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native "Performance_addEventListener_Callback";
+
+ @DomName('Performance.dispatchEvent')
+ @DocsEditable()
+ @Experimental() // untriaged
+ bool dispatchEvent(Event event) native "Performance_dispatchEvent_Callback";
+
+ @DomName('Performance.removeEventListener')
+ @DocsEditable()
+ @Experimental() // untriaged
+ void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native "Performance_removeEventListener_Callback";
+
}
// 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
@@ -21209,6 +21196,51 @@
@DocsEditable()
+@DomName('RsaKeyGenParams')
+@Experimental() // untriaged
+class RsaKeyGenParams extends Algorithm {
+ // To suppress missing implicit constructor warnings.
+ factory RsaKeyGenParams._() { throw new UnsupportedError("Not supported"); }
+
+ @DomName('RsaKeyGenParams.modulusLength')
+ @DocsEditable()
+ @Experimental() // untriaged
+ int get modulusLength native "RsaKeyGenParams_modulusLength_Getter";
+
+ @DomName('RsaKeyGenParams.publicExponent')
+ @DocsEditable()
+ @Experimental() // untriaged
+ Uint8List get publicExponent native "RsaKeyGenParams_publicExponent_Getter";
+
+}
+// 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.
+
+// WARNING: Do not edit - generated code.
+
+
+@DocsEditable()
+@DomName('RsaSsaParams')
+@Experimental() // untriaged
+class RsaSsaParams extends Algorithm {
+ // To suppress missing implicit constructor warnings.
+ factory RsaSsaParams._() { throw new UnsupportedError("Not supported"); }
+
+ @DomName('RsaSsaParams.hash')
+ @DocsEditable()
+ @Experimental() // untriaged
+ Algorithm get hash native "RsaSsaParams_hash_Getter";
+
+}
+// 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.
+
+// WARNING: Do not edit - generated code.
+
+
+@DocsEditable()
@DomName('RTCDataChannel')
// http://dev.w3.org/2011/webrtc/editor/webrtc.html#idl-def-RTCDataChannel
@Experimental()
@@ -21244,10 +21276,40 @@
@DocsEditable()
int get bufferedAmount native "RTCDataChannel_bufferedAmount_Getter";
+ @DomName('RTCDataChannel.id')
+ @DocsEditable()
+ @Experimental() // untriaged
+ int get id native "RTCDataChannel_id_Getter";
+
@DomName('RTCDataChannel.label')
@DocsEditable()
String get label native "RTCDataChannel_label_Getter";
+ @DomName('RTCDataChannel.maxRetransmitTime')
+ @DocsEditable()
+ @Experimental() // untriaged
+ int get maxRetransmitTime native "RTCDataChannel_maxRetransmitTime_Getter";
+
+ @DomName('RTCDataChannel.maxRetransmits')
+ @DocsEditable()
+ @Experimental() // untriaged
+ int get maxRetransmits native "RTCDataChannel_maxRetransmits_Getter";
+
+ @DomName('RTCDataChannel.negotiated')
+ @DocsEditable()
+ @Experimental() // untriaged
+ bool get negotiated native "RTCDataChannel_negotiated_Getter";
+
+ @DomName('RTCDataChannel.ordered')
+ @DocsEditable()
+ @Experimental() // untriaged
+ bool get ordered native "RTCDataChannel_ordered_Getter";
+
+ @DomName('RTCDataChannel.protocol')
+ @DocsEditable()
+ @Experimental() // untriaged
+ String get protocol native "RTCDataChannel_protocol_Getter";
+
@DomName('RTCDataChannel.readyState')
@DocsEditable()
String get readyState native "RTCDataChannel_readyState_Getter";
@@ -22528,6 +22590,26 @@
// To suppress missing implicit constructor warnings.
factory SourceBuffer._() { throw new UnsupportedError("Not supported"); }
+ @DomName('SourceBuffer.appendWindowEnd')
+ @DocsEditable()
+ @Experimental() // untriaged
+ num get appendWindowEnd native "SourceBuffer_appendWindowEnd_Getter";
+
+ @DomName('SourceBuffer.appendWindowEnd')
+ @DocsEditable()
+ @Experimental() // untriaged
+ void set appendWindowEnd(num value) native "SourceBuffer_appendWindowEnd_Setter";
+
+ @DomName('SourceBuffer.appendWindowStart')
+ @DocsEditable()
+ @Experimental() // untriaged
+ num get appendWindowStart native "SourceBuffer_appendWindowStart_Getter";
+
+ @DomName('SourceBuffer.appendWindowStart')
+ @DocsEditable()
+ @Experimental() // untriaged
+ void set appendWindowStart(num value) native "SourceBuffer_appendWindowStart_Setter";
+
@DomName('SourceBuffer.buffered')
@DocsEditable()
TimeRanges get buffered native "SourceBuffer_buffered_Getter";
@@ -22559,6 +22641,11 @@
@Experimental() // untriaged
void appendBufferView(TypedData data) native "SourceBuffer_appendBufferView_Callback";
+ @DomName('SourceBuffer.remove')
+ @DocsEditable()
+ @Experimental() // untriaged
+ void remove(num start, num end) native "SourceBuffer_remove_Callback";
+
@DomName('SourceBuffer.addEventListener')
@DocsEditable()
@Experimental() // untriaged
@@ -23929,7 +24016,7 @@
@DomName('SubtleCrypto.decrypt')
@DocsEditable()
@Experimental() // untriaged
- CryptoOperation decrypt(Map algorithm) native "SubtleCrypto_decrypt_Callback";
+ CryptoOperation decrypt(Map algorithm, CryptoKey key) native "SubtleCrypto_decrypt_Callback";
@DomName('SubtleCrypto.digest')
@DocsEditable()
@@ -23939,7 +24026,12 @@
@DomName('SubtleCrypto.encrypt')
@DocsEditable()
@Experimental() // untriaged
- CryptoOperation encrypt(Map algorithm) native "SubtleCrypto_encrypt_Callback";
+ CryptoOperation encrypt(Map algorithm, CryptoKey key) native "SubtleCrypto_encrypt_Callback";
+
+ @DomName('SubtleCrypto.generateKey')
+ @DocsEditable()
+ @Experimental() // untriaged
+ Object generateKey(Map algorithm, bool extractable, List<String> keyUsages) native "SubtleCrypto_generateKey_Callback";
@DomName('SubtleCrypto.importKey')
@DocsEditable()
@@ -23949,12 +24041,12 @@
@DomName('SubtleCrypto.sign')
@DocsEditable()
@Experimental() // untriaged
- CryptoOperation sign(Map algorithm) native "SubtleCrypto_sign_Callback";
+ CryptoOperation sign(Map algorithm, CryptoKey key) native "SubtleCrypto_sign_Callback";
@DomName('SubtleCrypto.verify')
@DocsEditable()
@Experimental() // untriaged
- CryptoOperation verify(Map algorithm) native "SubtleCrypto_verify_Callback";
+ CryptoOperation verify(Map algorithm, CryptoKey key, TypedData signature) native "SubtleCrypto_verify_Callback";
}
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
@@ -24567,6 +24659,11 @@
@DocsEditable()
String get wholeText native "Text_wholeText_Getter";
+ @DomName('Text.getDestinationInsertionPoints')
+ @DocsEditable()
+ @Experimental() // untriaged
+ List<Node> getDestinationInsertionPoints() native "Text_getDestinationInsertionPoints_Callback";
+
@DomName('Text.replaceWholeText')
@DocsEditable()
// http://dom.spec.whatwg.org/#dom-text-replacewholetext
@@ -25668,73 +25765,6 @@
String get pseudoElement native "TransitionEvent_pseudoElement_Getter";
}
-// 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.
-
-
-@DomName('TreeWalker')
-@Unstable()
-class TreeWalker extends NativeFieldWrapperClass1 {
- factory TreeWalker(Node root, int whatToShow) {
- return document.$dom_createTreeWalker(root, whatToShow, null, false);
- }
-
- @DomName('TreeWalker.currentNode')
- @DocsEditable()
- Node get currentNode native "TreeWalker_currentNode_Getter";
-
- @DomName('TreeWalker.currentNode')
- @DocsEditable()
- void set currentNode(Node value) native "TreeWalker_currentNode_Setter";
-
- @DomName('TreeWalker.expandEntityReferences')
- @DocsEditable()
- // http://dom.spec.whatwg.org/#dom-traversal
- @deprecated // deprecated
- bool get expandEntityReferences native "TreeWalker_expandEntityReferences_Getter";
-
- @DomName('TreeWalker.filter')
- @DocsEditable()
- NodeFilter get filter native "TreeWalker_filter_Getter";
-
- @DomName('TreeWalker.root')
- @DocsEditable()
- Node get root native "TreeWalker_root_Getter";
-
- @DomName('TreeWalker.whatToShow')
- @DocsEditable()
- int get whatToShow native "TreeWalker_whatToShow_Getter";
-
- @DomName('TreeWalker.firstChild')
- @DocsEditable()
- Node firstChild() native "TreeWalker_firstChild_Callback";
-
- @DomName('TreeWalker.lastChild')
- @DocsEditable()
- Node lastChild() native "TreeWalker_lastChild_Callback";
-
- @DomName('TreeWalker.nextNode')
- @DocsEditable()
- Node nextNode() native "TreeWalker_nextNode_Callback";
-
- @DomName('TreeWalker.nextSibling')
- @DocsEditable()
- Node nextSibling() native "TreeWalker_nextSibling_Callback";
-
- @DomName('TreeWalker.parentNode')
- @DocsEditable()
- Node parentNode() native "TreeWalker_parentNode_Callback";
-
- @DomName('TreeWalker.previousNode')
- @DocsEditable()
- Node previousNode() native "TreeWalker_previousNode_Callback";
-
- @DomName('TreeWalker.previousSibling')
- @DocsEditable()
- Node previousSibling() native "TreeWalker_previousSibling_Callback";
-
-}
// 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.
@@ -25885,13 +25915,13 @@
if ((blob_OR_source_OR_stream is Blob || blob_OR_source_OR_stream == null)) {
return _createObjectURL_1(blob_OR_source_OR_stream);
}
- if ((blob_OR_source_OR_stream is MediaStream || blob_OR_source_OR_stream == null)) {
+ if ((blob_OR_source_OR_stream is MediaSource || blob_OR_source_OR_stream == null)) {
return _createObjectURL_2(blob_OR_source_OR_stream);
}
- if ((blob_OR_source_OR_stream is MediaSource || blob_OR_source_OR_stream == null)) {
+ if ((blob_OR_source_OR_stream is _WebKitMediaSource || blob_OR_source_OR_stream == null)) {
return _createObjectURL_3(blob_OR_source_OR_stream);
}
- if ((blob_OR_source_OR_stream is _WebKitMediaSource || blob_OR_source_OR_stream == null)) {
+ if ((blob_OR_source_OR_stream is MediaStream || blob_OR_source_OR_stream == null)) {
return _createObjectURL_4(blob_OR_source_OR_stream);
}
throw new ArgumentError("Incorrect number or type of arguments");
@@ -26886,6 +26916,12 @@
@DocsEditable()
void cancelAnimationFrame(int id) native "Window_cancelAnimationFrame_Callback";
+ @DomName('Window.captureEvents')
+ @DocsEditable()
+ // http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-flow-capture
+ @deprecated // deprecated
+ void captureEvents() native "Window_captureEvents_Callback";
+
@DomName('Window.close')
@DocsEditable()
void close() native "Window_close_Callback";
@@ -26894,82 +26930,6 @@
@DocsEditable()
bool confirm(String message) native "Window_confirm_Callback";
- void _createImageBitmap(bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video, ImageBitmapCallback callback, [int sx, int sy, int sw, int sh]) {
- if ((callback is ImageBitmapCallback || callback == null) && (bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video is ImageElement || bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video == null) && sx == null && sy == null && sw == null && sh == null) {
- _createImageBitmap_1(bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video, callback);
- return;
- }
- if ((sh is int || sh == null) && (sw is int || sw == null) && (sy is int || sy == null) && (sx is int || sx == null) && (callback is ImageBitmapCallback || callback == null) && (bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video is ImageElement || bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video == null)) {
- _createImageBitmap_2(bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video, callback, sx, sy, sw, sh);
- return;
- }
- if ((callback is ImageBitmapCallback || callback == null) && (bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video is VideoElement || bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video == null) && sx == null && sy == null && sw == null && sh == null) {
- _createImageBitmap_3(bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video, callback);
- return;
- }
- if ((sh is int || sh == null) && (sw is int || sw == null) && (sy is int || sy == null) && (sx is int || sx == null) && (callback is ImageBitmapCallback || callback == null) && (bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video is VideoElement || bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video == null)) {
- _createImageBitmap_4(bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video, callback, sx, sy, sw, sh);
- return;
- }
- if ((callback is ImageBitmapCallback || callback == null) && (bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video is CanvasRenderingContext2D || bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video == null) && sx == null && sy == null && sw == null && sh == null) {
- _createImageBitmap_5(bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video, callback);
- return;
- }
- if ((sh is int || sh == null) && (sw is int || sw == null) && (sy is int || sy == null) && (sx is int || sx == null) && (callback is ImageBitmapCallback || callback == null) && (bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video is CanvasRenderingContext2D || bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video == null)) {
- _createImageBitmap_6(bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video, callback, sx, sy, sw, sh);
- return;
- }
- if ((callback is ImageBitmapCallback || callback == null) && (bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video is CanvasElement || bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video == null) && sx == null && sy == null && sw == null && sh == null) {
- _createImageBitmap_7(bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video, callback);
- return;
- }
- if ((sh is int || sh == null) && (sw is int || sw == null) && (sy is int || sy == null) && (sx is int || sx == null) && (callback is ImageBitmapCallback || callback == null) && (bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video is CanvasElement || bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video == null)) {
- _createImageBitmap_8(bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video, callback, sx, sy, sw, sh);
- return;
- }
- if ((callback is ImageBitmapCallback || callback == null) && (bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video is ImageData || bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video == null) && sx == null && sy == null && sw == null && sh == null) {
- _createImageBitmap_9(bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video, callback);
- return;
- }
- if ((sh is int || sh == null) && (sw is int || sw == null) && (sy is int || sy == null) && (sx is int || sx == null) && (callback is ImageBitmapCallback || callback == null) && (bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video is ImageData || bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video == null)) {
- _createImageBitmap_10(bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video, callback, sx, sy, sw, sh);
- return;
- }
- if ((callback is ImageBitmapCallback || callback == null) && (bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video is ImageBitmap || bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video == null) && sx == null && sy == null && sw == null && sh == null) {
- _createImageBitmap_11(bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video, callback);
- return;
- }
- if ((sh is int || sh == null) && (sw is int || sw == null) && (sy is int || sy == null) && (sx is int || sx == null) && (callback is ImageBitmapCallback || callback == null) && (bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video is ImageBitmap || bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video == null)) {
- _createImageBitmap_12(bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video, callback, sx, sy, sw, sh);
- return;
- }
- throw new ArgumentError("Incorrect number or type of arguments");
- }
-
- void _createImageBitmap_1(bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video, callback) native "Window__createImageBitmap_1_Callback";
-
- void _createImageBitmap_2(bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video, callback, sx, sy, sw, sh) native "Window__createImageBitmap_2_Callback";
-
- void _createImageBitmap_3(bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video, callback) native "Window__createImageBitmap_3_Callback";
-
- void _createImageBitmap_4(bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video, callback, sx, sy, sw, sh) native "Window__createImageBitmap_4_Callback";
-
- void _createImageBitmap_5(bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video, callback) native "Window__createImageBitmap_5_Callback";
-
- void _createImageBitmap_6(bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video, callback, sx, sy, sw, sh) native "Window__createImageBitmap_6_Callback";
-
- void _createImageBitmap_7(bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video, callback) native "Window__createImageBitmap_7_Callback";
-
- void _createImageBitmap_8(bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video, callback, sx, sy, sw, sh) native "Window__createImageBitmap_8_Callback";
-
- void _createImageBitmap_9(bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video, callback) native "Window__createImageBitmap_9_Callback";
-
- void _createImageBitmap_10(bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video, callback, sx, sy, sw, sh) native "Window__createImageBitmap_10_Callback";
-
- void _createImageBitmap_11(bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video, callback) native "Window__createImageBitmap_11_Callback";
-
- void _createImageBitmap_12(bitmap_OR_canvas_OR_context_OR_data_OR_image_OR_video, callback, sx, sy, sw, sh) native "Window__createImageBitmap_12_Callback";
-
@DomName('Window.find')
@DocsEditable()
@Experimental() // non-standard
@@ -27021,6 +26981,12 @@
@DocsEditable()
void print() native "Window_print_Callback";
+ @DomName('Window.releaseEvents')
+ @DocsEditable()
+ // http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-flow-capture
+ @deprecated // deprecated
+ void releaseEvents() native "Window_releaseEvents_Callback";
+
@DomName('Window.requestAnimationFrame')
@DocsEditable()
int requestAnimationFrame(RequestAnimationFrameCallback callback) native "Window_requestAnimationFrame_Callback";
@@ -28587,140 +28553,6 @@
@DocsEditable()
-@DomName('EntryArray')
-// http://www.w3.org/TR/file-system-api/#the-entry-interface
-@Experimental()
-class _EntryArray extends NativeFieldWrapperClass1 with ListMixin<Entry>, ImmutableListMixin<Entry> implements List<Entry> {
-
- @DomName('EntryArray.length')
- @DocsEditable()
- int get length native "EntryArray_length_Getter";
-
- Entry operator[](int index) {
- if (index < 0 || index >= length)
- throw new RangeError.range(index, 0, length);
- return _nativeIndexedGetter(index);
- }
- Entry _nativeIndexedGetter(int index) native "EntryArray_item_Callback";
-
- void operator[]=(int index, Entry value) {
- throw new UnsupportedError("Cannot assign element of immutable List.");
- }
- // -- start List<Entry> mixins.
- // Entry is the element type.
-
-
- void set length(int value) {
- throw new UnsupportedError("Cannot resize immutable List.");
- }
-
- Entry get first {
- if (this.length > 0) {
- return this[0];
- }
- throw new StateError("No elements");
- }
-
- Entry get last {
- int len = this.length;
- if (len > 0) {
- return this[len - 1];
- }
- throw new StateError("No elements");
- }
-
- Entry get single {
- int len = this.length;
- if (len == 1) {
- return this[0];
- }
- if (len == 0) throw new StateError("No elements");
- throw new StateError("More than one element");
- }
-
- Entry elementAt(int index) => this[index];
- // -- end List<Entry> mixins.
-
- @DomName('EntryArray.item')
- @DocsEditable()
- Entry item(int index) native "EntryArray_item_Callback";
-
-}
-// 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.
-
-// WARNING: Do not edit - generated code.
-
-
-@DocsEditable()
-@DomName('EntryArraySync')
-// http://www.w3.org/TR/file-system-api/#idl-def-EntrySync
-@Experimental()
-class _EntryArraySync extends NativeFieldWrapperClass1 with ListMixin<_EntrySync>, ImmutableListMixin<_EntrySync> implements List<_EntrySync> {
-
- @DomName('EntryArraySync.length')
- @DocsEditable()
- int get length native "EntryArraySync_length_Getter";
-
- _EntrySync operator[](int index) {
- if (index < 0 || index >= length)
- throw new RangeError.range(index, 0, length);
- return _nativeIndexedGetter(index);
- }
- _EntrySync _nativeIndexedGetter(int index) native "EntryArraySync_item_Callback";
-
- void operator[]=(int index, _EntrySync value) {
- throw new UnsupportedError("Cannot assign element of immutable List.");
- }
- // -- start List<_EntrySync> mixins.
- // _EntrySync is the element type.
-
-
- void set length(int value) {
- throw new UnsupportedError("Cannot resize immutable List.");
- }
-
- _EntrySync get first {
- if (this.length > 0) {
- return this[0];
- }
- throw new StateError("No elements");
- }
-
- _EntrySync get last {
- int len = this.length;
- if (len > 0) {
- return this[len - 1];
- }
- throw new StateError("No elements");
- }
-
- _EntrySync get single {
- int len = this.length;
- if (len == 1) {
- return this[0];
- }
- if (len == 0) throw new StateError("No elements");
- throw new StateError("More than one element");
- }
-
- _EntrySync elementAt(int index) => this[index];
- // -- end List<_EntrySync> mixins.
-
- @DomName('EntryArraySync.item')
- @DocsEditable()
- _EntrySync item(int index) native "EntryArraySync_item_Callback";
-
-}
-// 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.
-
-// WARNING: Do not edit - generated code.
-
-
-@DocsEditable()
@DomName('EntrySync')
// http://www.w3.org/TR/file-system-api/#idl-def-EntrySync
@Experimental()
@@ -32424,6 +32256,16 @@
* error.
*/
static final supportsSimd = true;
+
+ /**
+ * Upgrade all custom elements in the subtree which have not been upgraded.
+ *
+ * This is needed to cover timing scenarios which the custom element polyfill
+ * does not cover.
+ */
+ void upgradeCustomElements(Node node) {
+ // no-op, provided for dart2js polyfill.
+ }
}
// 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
@@ -33278,15 +33120,20 @@
// DOM node rather than just a class that extends Node.
static bool isNode(obj) => obj is Node;
+ static bool _isBuiltinType(ClassMirror cls) {
+ // TODO(vsm): Find a less hackish way to do this.
+ LibraryMirror lib = cls.owner;
+ String libName = lib.uri.toString();
+ return libName.startsWith('dart:');
+ }
+
static void register(String tag, Type type) {
// TODO(vsm): Move these checks into native code.
if (type == null) {
throw new UnsupportedError("Invalid null type.");
}
ClassMirror cls = reflectClass(type);
- LibraryMirror lib = cls.owner;
- String libName = lib.uri.toString();
- if (libName.startsWith('dart:')) {
+ if (_isBuiltinType(cls)) {
throw new UnsupportedError("Invalid custom element from $libName.");
}
ClassMirror superClass = cls.superclass;
@@ -33299,17 +33146,21 @@
bool isElement(ClassMirror cls) =>
cls != null && cls.qualifiedName == elementName;
+ ClassMirror nativeClass = _isBuiltinType(superClass) ? superClass : null;
while(!isRoot(superClass) && !isElement(superClass)) {
superClass = superClass.superclass;
+ if (nativeClass == null && _isBuiltinType(superClass)) {
+ nativeClass = superClass;
+ }
}
if (isRoot(superClass)) {
throw new UnsupportedError("Invalid custom element doesn't inherit from HtmlElement.");
}
- _register(tag, type);
+ _register(tag, type, nativeClass.reflectedType);
}
- static void _register(String tag, Type type) native "Utils_register";
+ static void _register(String tag, Type customType, Type nativeType) native "Utils_register";
}
class _NPObject extends NativeFieldWrapperClass1 {
diff --git a/sdk/lib/io/file_impl.dart b/sdk/lib/io/file_impl.dart
index f621360..1dd2b47 100644
--- a/sdk/lib/io/file_impl.dart
+++ b/sdk/lib/io/file_impl.dart
@@ -521,7 +521,7 @@
var controller = new StreamController(sync: true);
controller.stream
.transform(new StringDecoder(encoding))
- .transform(new LineTransformer())
+ .transform(new LineSplitter())
.listen((line) => list.add(line));
controller.add(bytes);
controller.close();
diff --git a/sdk/lib/io/http.dart b/sdk/lib/io/http.dart
index 1433ac8..df228f5 100644
--- a/sdk/lib/io/http.dart
+++ b/sdk/lib/io/http.dart
@@ -204,6 +204,17 @@
* added to each response.
*/
String serverHeader;
+
+ /**
+ * Get or set the timeout used for idle keep-alive connections. If no further
+ * request is seen within [idleTimeout] after the previous request was
+ * completed, the connection is droped.
+ *
+ * Default is 120 seconds.
+ *
+ * To disable, set [idleTimeout] to `null`.
+ */
+ Duration idleTimeout;
}
diff --git a/sdk/lib/io/http_impl.dart b/sdk/lib/io/http_impl.dart
index 615c59a..7eaf153 100644
--- a/sdk/lib/io/http_impl.dart
+++ b/sdk/lib/io/http_impl.dart
@@ -1824,14 +1824,17 @@
final _HttpServer _httpServer;
final _HttpParser _httpParser;
StreamSubscription _subscription;
+ Timer _idleTimer;
Future _streamFuture;
_HttpConnection(Socket this._socket, _HttpServer this._httpServer)
: _httpParser = new _HttpParser.requestParser() {
+ _startTimeout();
_socket.pipe(_httpParser);
_subscription = _httpParser.listen(
(incoming) {
+ _stopTimeout();
// If the incoming was closed, close the connection.
incoming.dataDone.then((closing) {
if (closing) destroy();
@@ -1854,6 +1857,7 @@
request.persistentConnection &&
incoming.fullBodyRead) {
_state = _IDLE;
+ _startTimeout();
// Resume the subscription for incoming requests as the
// request is now processed.
_subscription.resume();
@@ -1879,7 +1883,21 @@
});
}
+ void _startTimeout() {
+ assert(_state == _IDLE);
+ _stopTimeout();
+ if (_httpServer.idleTimeout == null) return;
+ _idleTimer = new Timer(_httpServer.idleTimeout, () {
+ destroy();
+ });
+ }
+
+ void _stopTimeout() {
+ if (_idleTimer != null) _idleTimer.cancel();
+ }
+
void destroy() {
+ _stopTimeout();
if (_state == _CLOSING || _state == _DETACHED) return;
_state = _CLOSING;
_socket.destroy();
@@ -1887,6 +1905,7 @@
}
Future<Socket> detachSocket() {
+ _stopTimeout();
_state = _DETACHED;
// Remove connection from server.
_httpServer._connectionClosed(this);
@@ -1911,6 +1930,8 @@
class _HttpServer extends Stream<HttpRequest> implements HttpServer {
String serverHeader = _getHttpVersion();
+ Duration idleTimeout = const Duration(seconds: 120);
+
static Future<HttpServer> bind(address, int port, int backlog) {
return ServerSocket.bind(address, port, backlog: backlog).then((socket) {
return new _HttpServer._(socket, true);
diff --git a/sdk/lib/io/platform.dart b/sdk/lib/io/platform.dart
index 16b3595..30a9a9f 100644
--- a/sdk/lib/io/platform.dart
+++ b/sdk/lib/io/platform.dart
@@ -89,6 +89,22 @@
*/
static String get script => _nativeScript;
+ /**
+ * Returns the flags passed to the executable used to run the script in this
+ * isolate. These are the command-line flags between the executable name
+ * and the script name. Each fetch of executableArguments returns a new
+ * List, containing the flags passed to the executable.
+ */
+ static List<String> get executableArguments => _Platform.executableArguments;
+
+ /**
+ * Returns the value of the --package-root flag passed to the executable
+ * used to run the script in this isolate. This is the directory in which
+ * Dart packages are looked up.
+ *
+ * If there is no --package-root flag, then the empty string is returned.
+ */
+ static String get packageRoot => _Platform.packageRoot;
/**
* Returns the version of the current Dart runtime.
diff --git a/sdk/lib/io/platform_impl.dart b/sdk/lib/io/platform_impl.dart
index 94d67b6..56a5869 100644
--- a/sdk/lib/io/platform_impl.dart
+++ b/sdk/lib/io/platform_impl.dart
@@ -11,6 +11,8 @@
external static _localHostname();
external static _executable();
external static _environment();
+ external static List<String> _executableArguments();
+ external static String _packageRoot();
external static String _version();
static int get numberOfProcessors => _numberOfProcessors();
@@ -27,6 +29,8 @@
}
static String executable = _executable();
+ static String packageRoot = _packageRoot();
+ static List<String> get executableArguments => _executableArguments();
static Map<String, String> get environment {
var env = _environment();
diff --git a/sdk/lib/io/secure_socket.dart b/sdk/lib/io/secure_socket.dart
index 1867050..0916023 100644
--- a/sdk/lib/io/secure_socket.dart
+++ b/sdk/lib/io/secure_socket.dart
@@ -441,7 +441,7 @@
bool _closedWrite = false; // The secure socket has been closed for writing.
Completer _closeCompleter = new Completer(); // The network socket is gone.
_FilterStatus _filterStatus = new _FilterStatus();
- bool _connectPending = false;
+ bool _connectPending = true;
bool _filterPending = false;
bool _filterActive = false;
@@ -526,7 +526,6 @@
futureSocket = new Future.value(socket);
}
futureSocket.then((rawSocket) {
- _connectPending = true;
_socket = rawSocket;
_socket.readEventsEnabled = true;
_socket.writeEventsEnabled = false;
@@ -775,8 +774,9 @@
if (_status == CLOSED) {
return;
} else if (_connectPending) {
- // _connectPending is true after the underlying connection has been
- // made, but before the handshake has completed.
+ // _connectPending is true until the handshake has completed, and the
+ // _handshakeComplete future returned from SecureSocket.connect has
+ // completed. Before this point, we must complete it with an error.
_handshakeComplete.completeError(e);
} else {
_controller.addError(e);
diff --git a/sdk/lib/io/string_transformer.dart b/sdk/lib/io/string_transformer.dart
index 56e322c..5324d69 100644
--- a/sdk/lib/io/string_transformer.dart
+++ b/sdk/lib/io/string_transformer.dart
@@ -259,22 +259,6 @@
return bytes;
}
-// TODO(floitsch) Remove usage of LineTransformer
-// TODO(kevmoo) Remove usage of LineTransformer
-/**
- * Use [LineSplitter] from `dart:convert` instead.
- *
- * [LineTransformer] will be removed the 28 August 2013.
- */
- @deprecated
- class LineTransformer implements StreamTransformer<String, String> {
- final _decoder = new LineSplitter();
-
- Stream<String> bind(Stream<String> stream) {
- return _decoder.bind(stream);
- }
-}
-
abstract class _SingleByteDecoder
extends StreamEventTransformer<List<int>, String> {
diff --git a/sdk/lib/math/math.dart b/sdk/lib/math/math.dart
index 0c1f67f..93ec416 100644
--- a/sdk/lib/math/math.dart
+++ b/sdk/lib/math/math.dart
@@ -137,7 +137,35 @@
* Returns [x] to the power of [exponent].
*
* If [x] is an [int] and [exponent] is a non-negative [int], the result is
- * an [int], otherwise the result it is a [double].
+ * an [int], otherwise both arguments are converted to doubles first, and the
+ * result is a [double].
+ *
+ * For integers, the power is always equal to the mathematical result of `x` to
+ * the power `exponent`, only limited by the available memory.
+ *
+ * For doubles, `pow(x, y)` handles edge cases as follows:
+ *
+ * - if `y` is zero (0.0 or -0.0), the result is always 1.0.
+ * - if `x` is 1.0, the result is always 1.0.
+ * - otherwise, if either `x` or `y` is NaN then the result is NaN.
+ * - if `x` is negative (but not -0.0) and `y` is a finite non-integer, the
+ * result is NaN.
+ * - if `x` is Infinity and `y` is negative, the result is 0.0.
+ * - if `x` is Infinity and `y` is positive, the result is Infinity.
+ * - if `x` is 0.0 and `y` is negative, the result is Infinity.
+ * - if `x` is 0.0 and `y` is positive, the result is 0.0.
+ * - if `x` is -Infinity or -0.0 and `y` is an odd integer, then the result is
+ * `-pow(-x ,y)`.
+ * - if `x` is -Infinity or -0.0 and `y` is not an odd integer, then the result
+ * is the same as `pow(-x , y)`.
+ * - if `y` is Infinity and the absolute value of `x` is less than 1, the
+ * result is 0.0.
+ * - if `y` is Infinity and `x` is -1, the result is 1.0.
+ * - if `y` is Infinity and the absolute value of `x` is greater than 1,
+ * the result is Infinity.
+ * - if `y` is -Infinity, the result is `1/pow(x, Infinity)`.
+ *
+ * This corresponds to the `pow` function defined in the IEEE Standard 754-2008.
*
* Notice that an [int] result cannot overflow, but a [double] result might
* be [double.INFINITY].
diff --git a/sdk/lib/mirrors/mirrors.dart b/sdk/lib/mirrors/mirrors.dart
index b0d39d9..c22d3c3 100644
--- a/sdk/lib/mirrors/mirrors.dart
+++ b/sdk/lib/mirrors/mirrors.dart
@@ -682,6 +682,18 @@
*/
abstract class ClassMirror implements TypeMirror, ObjectMirror {
/**
+ * Returns true if this mirror reflects a non-generic class or an instantiated
+ * generic class in the current isolate. Otherwise, returns false.
+ */
+ bool get hasReflectedType;
+
+ /**
+ * If [:hasReflectedType:] returns true, returns the corresponding [Type].
+ * Otherwise, an [UnsupportedError] is thrown.
+ */
+ Type get reflectedType;
+
+ /**
* A mirror on the superclass on the reflectee.
*
* If this type is [:Object:] or a typedef, the superClass will be
diff --git a/sdk/lib/svg/dart2js/svg_dart2js.dart b/sdk/lib/svg/dart2js/svg_dart2js.dart
index ac40dc1..f5066ee1 100644
--- a/sdk/lib/svg/dart2js/svg_dart2js.dart
+++ b/sdk/lib/svg/dart2js/svg_dart2js.dart
@@ -622,7 +622,7 @@
@DocsEditable()
@DomName('SVGDescElement')
@Unstable()
-class DescElement extends StyledElement native "SVGDescElement" {
+class DescElement extends SvgElement native "SVGDescElement" {
// To suppress missing implicit constructor warnings.
factory DescElement._() { throw new UnsupportedError("Not supported"); }
@@ -1085,7 +1085,7 @@
@SupportedBrowser(SupportedBrowser.IE, '10')
@SupportedBrowser(SupportedBrowser.SAFARI)
@Unstable()
-class FEBlendElement extends StyledElement implements FilterPrimitiveStandardAttributes native "SVGFEBlendElement" {
+class FEBlendElement extends SvgElement implements FilterPrimitiveStandardAttributes native "SVGFEBlendElement" {
// To suppress missing implicit constructor warnings.
factory FEBlendElement._() { throw new UnsupportedError("Not supported"); }
@@ -1166,7 +1166,7 @@
@SupportedBrowser(SupportedBrowser.IE, '10')
@SupportedBrowser(SupportedBrowser.SAFARI)
@Unstable()
-class FEColorMatrixElement extends StyledElement implements FilterPrimitiveStandardAttributes native "SVGFEColorMatrixElement" {
+class FEColorMatrixElement extends SvgElement implements FilterPrimitiveStandardAttributes native "SVGFEColorMatrixElement" {
// To suppress missing implicit constructor warnings.
factory FEColorMatrixElement._() { throw new UnsupportedError("Not supported"); }
@@ -1243,7 +1243,7 @@
@SupportedBrowser(SupportedBrowser.IE, '10')
@SupportedBrowser(SupportedBrowser.SAFARI)
@Unstable()
-class FEComponentTransferElement extends StyledElement implements FilterPrimitiveStandardAttributes native "SVGFEComponentTransferElement" {
+class FEComponentTransferElement extends SvgElement implements FilterPrimitiveStandardAttributes native "SVGFEComponentTransferElement" {
// To suppress missing implicit constructor warnings.
factory FEComponentTransferElement._() { throw new UnsupportedError("Not supported"); }
@@ -1288,7 +1288,7 @@
@DocsEditable()
@DomName('SVGFECompositeElement')
@Unstable()
-class FECompositeElement extends StyledElement implements FilterPrimitiveStandardAttributes native "SVGFECompositeElement" {
+class FECompositeElement extends SvgElement implements FilterPrimitiveStandardAttributes native "SVGFECompositeElement" {
// To suppress missing implicit constructor warnings.
factory FECompositeElement._() { throw new UnsupportedError("Not supported"); }
@@ -1382,7 +1382,7 @@
@SupportedBrowser(SupportedBrowser.IE, '10')
@SupportedBrowser(SupportedBrowser.SAFARI)
@Unstable()
-class FEConvolveMatrixElement extends StyledElement implements FilterPrimitiveStandardAttributes native "SVGFEConvolveMatrixElement" {
+class FEConvolveMatrixElement extends SvgElement implements FilterPrimitiveStandardAttributes native "SVGFEConvolveMatrixElement" {
// To suppress missing implicit constructor warnings.
factory FEConvolveMatrixElement._() { throw new UnsupportedError("Not supported"); }
@@ -1491,7 +1491,7 @@
@SupportedBrowser(SupportedBrowser.IE, '10')
@SupportedBrowser(SupportedBrowser.SAFARI)
@Unstable()
-class FEDiffuseLightingElement extends StyledElement implements FilterPrimitiveStandardAttributes native "SVGFEDiffuseLightingElement" {
+class FEDiffuseLightingElement extends SvgElement implements FilterPrimitiveStandardAttributes native "SVGFEDiffuseLightingElement" {
// To suppress missing implicit constructor warnings.
factory FEDiffuseLightingElement._() { throw new UnsupportedError("Not supported"); }
@@ -1556,7 +1556,7 @@
@SupportedBrowser(SupportedBrowser.IE, '10')
@SupportedBrowser(SupportedBrowser.SAFARI)
@Unstable()
-class FEDisplacementMapElement extends StyledElement implements FilterPrimitiveStandardAttributes native "SVGFEDisplacementMapElement" {
+class FEDisplacementMapElement extends SvgElement implements FilterPrimitiveStandardAttributes native "SVGFEDisplacementMapElement" {
// To suppress missing implicit constructor warnings.
factory FEDisplacementMapElement._() { throw new UnsupportedError("Not supported"); }
@@ -1672,7 +1672,7 @@
@SupportedBrowser(SupportedBrowser.IE, '10')
@SupportedBrowser(SupportedBrowser.SAFARI)
@Unstable()
-class FEFloodElement extends StyledElement implements FilterPrimitiveStandardAttributes native "SVGFEFloodElement" {
+class FEFloodElement extends SvgElement implements FilterPrimitiveStandardAttributes native "SVGFEFloodElement" {
// To suppress missing implicit constructor warnings.
factory FEFloodElement._() { throw new UnsupportedError("Not supported"); }
@@ -1809,7 +1809,7 @@
@SupportedBrowser(SupportedBrowser.IE, '10')
@SupportedBrowser(SupportedBrowser.SAFARI)
@Unstable()
-class FEGaussianBlurElement extends StyledElement implements FilterPrimitiveStandardAttributes native "SVGFEGaussianBlurElement" {
+class FEGaussianBlurElement extends SvgElement implements FilterPrimitiveStandardAttributes native "SVGFEGaussianBlurElement" {
// To suppress missing implicit constructor warnings.
factory FEGaussianBlurElement._() { throw new UnsupportedError("Not supported"); }
@@ -1870,7 +1870,7 @@
@SupportedBrowser(SupportedBrowser.IE, '10')
@SupportedBrowser(SupportedBrowser.SAFARI)
@Unstable()
-class FEImageElement extends StyledElement implements FilterPrimitiveStandardAttributes, UriReference, ExternalResourcesRequired native "SVGFEImageElement" {
+class FEImageElement extends SvgElement implements FilterPrimitiveStandardAttributes, UriReference, ExternalResourcesRequired native "SVGFEImageElement" {
// To suppress missing implicit constructor warnings.
factory FEImageElement._() { throw new UnsupportedError("Not supported"); }
@@ -1931,7 +1931,7 @@
@SupportedBrowser(SupportedBrowser.IE, '10')
@SupportedBrowser(SupportedBrowser.SAFARI)
@Unstable()
-class FEMergeElement extends StyledElement implements FilterPrimitiveStandardAttributes native "SVGFEMergeElement" {
+class FEMergeElement extends SvgElement implements FilterPrimitiveStandardAttributes native "SVGFEMergeElement" {
// To suppress missing implicit constructor warnings.
factory FEMergeElement._() { throw new UnsupportedError("Not supported"); }
@@ -2003,7 +2003,7 @@
@SupportedBrowser(SupportedBrowser.IE, '10')
@SupportedBrowser(SupportedBrowser.SAFARI)
@Unstable()
-class FEMorphologyElement extends StyledElement implements FilterPrimitiveStandardAttributes native "SVGFEMorphologyElement" {
+class FEMorphologyElement extends SvgElement implements FilterPrimitiveStandardAttributes native "SVGFEMorphologyElement" {
// To suppress missing implicit constructor warnings.
factory FEMorphologyElement._() { throw new UnsupportedError("Not supported"); }
@@ -2073,7 +2073,7 @@
@SupportedBrowser(SupportedBrowser.IE, '10')
@SupportedBrowser(SupportedBrowser.SAFARI)
@Unstable()
-class FEOffsetElement extends StyledElement implements FilterPrimitiveStandardAttributes native "SVGFEOffsetElement" {
+class FEOffsetElement extends SvgElement implements FilterPrimitiveStandardAttributes native "SVGFEOffsetElement" {
// To suppress missing implicit constructor warnings.
factory FEOffsetElement._() { throw new UnsupportedError("Not supported"); }
@@ -2165,7 +2165,7 @@
@SupportedBrowser(SupportedBrowser.IE, '10')
@SupportedBrowser(SupportedBrowser.SAFARI)
@Unstable()
-class FESpecularLightingElement extends StyledElement implements FilterPrimitiveStandardAttributes native "SVGFESpecularLightingElement" {
+class FESpecularLightingElement extends SvgElement implements FilterPrimitiveStandardAttributes native "SVGFESpecularLightingElement" {
// To suppress missing implicit constructor warnings.
factory FESpecularLightingElement._() { throw new UnsupportedError("Not supported"); }
@@ -2281,7 +2281,7 @@
@SupportedBrowser(SupportedBrowser.IE, '10')
@SupportedBrowser(SupportedBrowser.SAFARI)
@Unstable()
-class FETileElement extends StyledElement implements FilterPrimitiveStandardAttributes native "SVGFETileElement" {
+class FETileElement extends SvgElement implements FilterPrimitiveStandardAttributes native "SVGFETileElement" {
// To suppress missing implicit constructor warnings.
factory FETileElement._() { throw new UnsupportedError("Not supported"); }
@@ -2330,7 +2330,7 @@
@SupportedBrowser(SupportedBrowser.IE, '10')
@SupportedBrowser(SupportedBrowser.SAFARI)
@Unstable()
-class FETurbulenceElement extends StyledElement implements FilterPrimitiveStandardAttributes native "SVGFETurbulenceElement" {
+class FETurbulenceElement extends SvgElement implements FilterPrimitiveStandardAttributes native "SVGFETurbulenceElement" {
// To suppress missing implicit constructor warnings.
factory FETurbulenceElement._() { throw new UnsupportedError("Not supported"); }
@@ -2423,7 +2423,7 @@
@SupportedBrowser(SupportedBrowser.IE, '10')
@SupportedBrowser(SupportedBrowser.SAFARI)
@Unstable()
-class FilterElement extends StyledElement implements UriReference, ExternalResourcesRequired native "SVGFilterElement" {
+class FilterElement extends SvgElement implements UriReference, ExternalResourcesRequired native "SVGFilterElement" {
// To suppress missing implicit constructor warnings.
factory FilterElement._() { throw new UnsupportedError("Not supported"); }
@@ -2590,7 +2590,7 @@
@DocsEditable()
@DomName('SVGGraphicsElement')
@Experimental() // untriaged
-class GraphicsElement extends StyledElement implements Tests native "SVGGraphicsElement" {
+class GraphicsElement extends SvgElement implements Tests native "SVGGraphicsElement" {
// To suppress missing implicit constructor warnings.
factory GraphicsElement._() { throw new UnsupportedError("Not supported"); }
@@ -2945,7 +2945,7 @@
@DocsEditable()
@DomName('SVGMarkerElement')
@Unstable()
-class MarkerElement extends StyledElement implements FitToViewBox, ExternalResourcesRequired native "SVGMarkerElement" {
+class MarkerElement extends SvgElement implements FitToViewBox, ExternalResourcesRequired native "SVGMarkerElement" {
// To suppress missing implicit constructor warnings.
factory MarkerElement._() { throw new UnsupportedError("Not supported"); }
@@ -3037,7 +3037,7 @@
@DocsEditable()
@DomName('SVGMaskElement')
@Unstable()
-class MaskElement extends StyledElement implements ExternalResourcesRequired, Tests native "SVGMaskElement" {
+class MaskElement extends SvgElement implements ExternalResourcesRequired, Tests native "SVGMaskElement" {
// To suppress missing implicit constructor warnings.
factory MaskElement._() { throw new UnsupportedError("Not supported"); }
@@ -4088,7 +4088,7 @@
@DocsEditable()
@DomName('SVGPatternElement')
@Unstable()
-class PatternElement extends StyledElement implements FitToViewBox, UriReference, ExternalResourcesRequired, Tests native "SVGPatternElement" {
+class PatternElement extends SvgElement implements FitToViewBox, UriReference, ExternalResourcesRequired, Tests native "SVGPatternElement" {
// To suppress missing implicit constructor warnings.
factory PatternElement._() { throw new UnsupportedError("Not supported"); }
@@ -4570,7 +4570,7 @@
@DocsEditable()
@DomName('SVGStopElement')
@Unstable()
-class StopElement extends StyledElement native "SVGStopElement" {
+class StopElement extends SvgElement native "SVGStopElement" {
// To suppress missing implicit constructor warnings.
factory StopElement._() { throw new UnsupportedError("Not supported"); }
@@ -4713,24 +4713,6 @@
@DocsEditable()
-@DomName('SVGStyledElement')
-@Unstable()
-class StyledElement extends SvgElement native "SVGStyledElement" {
- // To suppress missing implicit constructor warnings.
- factory StyledElement._() { throw new UnsupportedError("Not supported"); }
-
- // Shadowing definition.
- AnimatedString get $dom_svgClassName => JS("AnimatedString", "#.className", this);
-
- // Use implementation from Element.
- // final CssStyleDeclaration style;
-}
-// 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.
-
-
-@DocsEditable()
@DomName('SVGDocument')
@Unstable()
class SvgDocument extends Document native "SVGDocument" {
@@ -4857,17 +4839,16 @@
factory SvgElement._() { throw new UnsupportedError("Not supported"); }
// Shadowing definition.
- String get id => JS("String", "#.id", this);
-
- void set id(String value) {
- JS("void", "#.id = #", this, value);
- }
+ AnimatedString get $dom_svgClassName => JS("AnimatedString", "#.className", this);
@JSName('ownerSVGElement')
@DomName('SVGElement.ownerSVGElement')
@DocsEditable()
final SvgSvgElement ownerSvgElement;
+ // Use implementation from Element.
+ // final CssStyleDeclaration style;
+
@DomName('SVGElement.viewportElement')
@DocsEditable()
final SvgElement viewportElement;
@@ -5117,7 +5098,7 @@
@DocsEditable()
@DomName('SVGSymbolElement')
@Unstable()
-class SymbolElement extends StyledElement implements FitToViewBox, ExternalResourcesRequired native "SVGSymbolElement" {
+class SymbolElement extends SvgElement implements FitToViewBox, ExternalResourcesRequired native "SVGSymbolElement" {
// To suppress missing implicit constructor warnings.
factory SymbolElement._() { throw new UnsupportedError("Not supported"); }
@@ -5359,7 +5340,7 @@
@DocsEditable()
@DomName('SVGTitleElement')
@Unstable()
-class TitleElement extends StyledElement native "SVGTitleElement" {
+class TitleElement extends SvgElement native "SVGTitleElement" {
// To suppress missing implicit constructor warnings.
factory TitleElement._() { throw new UnsupportedError("Not supported"); }
@@ -5861,7 +5842,7 @@
@DocsEditable()
@DomName('SVGGradientElement')
@Unstable()
-class _GradientElement extends StyledElement implements UriReference, ExternalResourcesRequired native "SVGGradientElement" {
+class _GradientElement extends SvgElement implements UriReference, ExternalResourcesRequired native "SVGGradientElement" {
// To suppress missing implicit constructor warnings.
factory _GradientElement._() { throw new UnsupportedError("Not supported"); }
@@ -5999,7 +5980,7 @@
@DocsEditable()
@DomName('SVGFEDropShadowElement')
@Experimental() // nonstandard
-abstract class _SVGFEDropShadowElement extends StyledElement implements FilterPrimitiveStandardAttributes native "SVGFEDropShadowElement" {
+abstract class _SVGFEDropShadowElement extends SvgElement implements FilterPrimitiveStandardAttributes native "SVGFEDropShadowElement" {
// To suppress missing implicit constructor warnings.
factory _SVGFEDropShadowElement._() { throw new UnsupportedError("Not supported"); }
@@ -6101,7 +6082,7 @@
@DocsEditable()
@DomName('SVGGlyphRefElement')
@Unstable()
-abstract class _SVGGlyphRefElement extends StyledElement implements UriReference native "SVGGlyphRefElement" {
+abstract class _SVGGlyphRefElement extends SvgElement implements UriReference native "SVGGlyphRefElement" {
// To suppress missing implicit constructor warnings.
factory _SVGGlyphRefElement._() { throw new UnsupportedError("Not supported"); }
@@ -6150,7 +6131,7 @@
@DocsEditable()
@DomName('SVGMissingGlyphElement')
@Unstable()
-abstract class _SVGMissingGlyphElement extends StyledElement native "SVGMissingGlyphElement" {
+abstract class _SVGMissingGlyphElement extends SvgElement native "SVGMissingGlyphElement" {
// To suppress missing implicit constructor warnings.
factory _SVGMissingGlyphElement._() { throw new UnsupportedError("Not supported"); }
}
diff --git a/sdk/lib/svg/dartium/svg_dartium.dart b/sdk/lib/svg/dartium/svg_dartium.dart
index 69dc8ab..1095161 100644
--- a/sdk/lib/svg/dartium/svg_dartium.dart
+++ b/sdk/lib/svg/dartium/svg_dartium.dart
@@ -711,7 +711,7 @@
@DocsEditable()
@DomName('SVGDescElement')
@Unstable()
-class DescElement extends StyledElement {
+class DescElement extends SvgElement {
// To suppress missing implicit constructor warnings.
factory DescElement._() { throw new UnsupportedError("Not supported"); }
@@ -1199,7 +1199,7 @@
@SupportedBrowser(SupportedBrowser.IE, '10')
@SupportedBrowser(SupportedBrowser.SAFARI)
@Unstable()
-class FEBlendElement extends StyledElement implements FilterPrimitiveStandardAttributes {
+class FEBlendElement extends SvgElement implements FilterPrimitiveStandardAttributes {
// To suppress missing implicit constructor warnings.
factory FEBlendElement._() { throw new UnsupportedError("Not supported"); }
@@ -1281,7 +1281,7 @@
@SupportedBrowser(SupportedBrowser.IE, '10')
@SupportedBrowser(SupportedBrowser.SAFARI)
@Unstable()
-class FEColorMatrixElement extends StyledElement implements FilterPrimitiveStandardAttributes {
+class FEColorMatrixElement extends SvgElement implements FilterPrimitiveStandardAttributes {
// To suppress missing implicit constructor warnings.
factory FEColorMatrixElement._() { throw new UnsupportedError("Not supported"); }
@@ -1359,7 +1359,7 @@
@SupportedBrowser(SupportedBrowser.IE, '10')
@SupportedBrowser(SupportedBrowser.SAFARI)
@Unstable()
-class FEComponentTransferElement extends StyledElement implements FilterPrimitiveStandardAttributes {
+class FEComponentTransferElement extends SvgElement implements FilterPrimitiveStandardAttributes {
// To suppress missing implicit constructor warnings.
factory FEComponentTransferElement._() { throw new UnsupportedError("Not supported"); }
@@ -1405,7 +1405,7 @@
@DocsEditable()
@DomName('SVGFECompositeElement')
@Unstable()
-class FECompositeElement extends StyledElement implements FilterPrimitiveStandardAttributes {
+class FECompositeElement extends SvgElement implements FilterPrimitiveStandardAttributes {
// To suppress missing implicit constructor warnings.
factory FECompositeElement._() { throw new UnsupportedError("Not supported"); }
@@ -1500,7 +1500,7 @@
@SupportedBrowser(SupportedBrowser.IE, '10')
@SupportedBrowser(SupportedBrowser.SAFARI)
@Unstable()
-class FEConvolveMatrixElement extends StyledElement implements FilterPrimitiveStandardAttributes {
+class FEConvolveMatrixElement extends SvgElement implements FilterPrimitiveStandardAttributes {
// To suppress missing implicit constructor warnings.
factory FEConvolveMatrixElement._() { throw new UnsupportedError("Not supported"); }
@@ -1610,7 +1610,7 @@
@SupportedBrowser(SupportedBrowser.IE, '10')
@SupportedBrowser(SupportedBrowser.SAFARI)
@Unstable()
-class FEDiffuseLightingElement extends StyledElement implements FilterPrimitiveStandardAttributes {
+class FEDiffuseLightingElement extends SvgElement implements FilterPrimitiveStandardAttributes {
// To suppress missing implicit constructor warnings.
factory FEDiffuseLightingElement._() { throw new UnsupportedError("Not supported"); }
@@ -1676,7 +1676,7 @@
@SupportedBrowser(SupportedBrowser.IE, '10')
@SupportedBrowser(SupportedBrowser.SAFARI)
@Unstable()
-class FEDisplacementMapElement extends StyledElement implements FilterPrimitiveStandardAttributes {
+class FEDisplacementMapElement extends SvgElement implements FilterPrimitiveStandardAttributes {
// To suppress missing implicit constructor warnings.
factory FEDisplacementMapElement._() { throw new UnsupportedError("Not supported"); }
@@ -1796,7 +1796,7 @@
@SupportedBrowser(SupportedBrowser.IE, '10')
@SupportedBrowser(SupportedBrowser.SAFARI)
@Unstable()
-class FEFloodElement extends StyledElement implements FilterPrimitiveStandardAttributes {
+class FEFloodElement extends SvgElement implements FilterPrimitiveStandardAttributes {
// To suppress missing implicit constructor warnings.
factory FEFloodElement._() { throw new UnsupportedError("Not supported"); }
@@ -1946,7 +1946,7 @@
@SupportedBrowser(SupportedBrowser.IE, '10')
@SupportedBrowser(SupportedBrowser.SAFARI)
@Unstable()
-class FEGaussianBlurElement extends StyledElement implements FilterPrimitiveStandardAttributes {
+class FEGaussianBlurElement extends SvgElement implements FilterPrimitiveStandardAttributes {
// To suppress missing implicit constructor warnings.
factory FEGaussianBlurElement._() { throw new UnsupportedError("Not supported"); }
@@ -2008,7 +2008,7 @@
@SupportedBrowser(SupportedBrowser.IE, '10')
@SupportedBrowser(SupportedBrowser.SAFARI)
@Unstable()
-class FEImageElement extends StyledElement implements FilterPrimitiveStandardAttributes, UriReference, ExternalResourcesRequired {
+class FEImageElement extends SvgElement implements FilterPrimitiveStandardAttributes, UriReference, ExternalResourcesRequired {
// To suppress missing implicit constructor warnings.
factory FEImageElement._() { throw new UnsupportedError("Not supported"); }
@@ -2066,7 +2066,7 @@
@SupportedBrowser(SupportedBrowser.IE, '10')
@SupportedBrowser(SupportedBrowser.SAFARI)
@Unstable()
-class FEMergeElement extends StyledElement implements FilterPrimitiveStandardAttributes {
+class FEMergeElement extends SvgElement implements FilterPrimitiveStandardAttributes {
// To suppress missing implicit constructor warnings.
factory FEMergeElement._() { throw new UnsupportedError("Not supported"); }
@@ -2142,7 +2142,7 @@
@SupportedBrowser(SupportedBrowser.IE, '10')
@SupportedBrowser(SupportedBrowser.SAFARI)
@Unstable()
-class FEMorphologyElement extends StyledElement implements FilterPrimitiveStandardAttributes {
+class FEMorphologyElement extends SvgElement implements FilterPrimitiveStandardAttributes {
// To suppress missing implicit constructor warnings.
factory FEMorphologyElement._() { throw new UnsupportedError("Not supported"); }
@@ -2213,7 +2213,7 @@
@SupportedBrowser(SupportedBrowser.IE, '10')
@SupportedBrowser(SupportedBrowser.SAFARI)
@Unstable()
-class FEOffsetElement extends StyledElement implements FilterPrimitiveStandardAttributes {
+class FEOffsetElement extends SvgElement implements FilterPrimitiveStandardAttributes {
// To suppress missing implicit constructor warnings.
factory FEOffsetElement._() { throw new UnsupportedError("Not supported"); }
@@ -2309,7 +2309,7 @@
@SupportedBrowser(SupportedBrowser.IE, '10')
@SupportedBrowser(SupportedBrowser.SAFARI)
@Unstable()
-class FESpecularLightingElement extends StyledElement implements FilterPrimitiveStandardAttributes {
+class FESpecularLightingElement extends SvgElement implements FilterPrimitiveStandardAttributes {
// To suppress missing implicit constructor warnings.
factory FESpecularLightingElement._() { throw new UnsupportedError("Not supported"); }
@@ -2429,7 +2429,7 @@
@SupportedBrowser(SupportedBrowser.IE, '10')
@SupportedBrowser(SupportedBrowser.SAFARI)
@Unstable()
-class FETileElement extends StyledElement implements FilterPrimitiveStandardAttributes {
+class FETileElement extends SvgElement implements FilterPrimitiveStandardAttributes {
// To suppress missing implicit constructor warnings.
factory FETileElement._() { throw new UnsupportedError("Not supported"); }
@@ -2479,7 +2479,7 @@
@SupportedBrowser(SupportedBrowser.IE, '10')
@SupportedBrowser(SupportedBrowser.SAFARI)
@Unstable()
-class FETurbulenceElement extends StyledElement implements FilterPrimitiveStandardAttributes {
+class FETurbulenceElement extends SvgElement implements FilterPrimitiveStandardAttributes {
// To suppress missing implicit constructor warnings.
factory FETurbulenceElement._() { throw new UnsupportedError("Not supported"); }
@@ -2573,7 +2573,7 @@
@SupportedBrowser(SupportedBrowser.IE, '10')
@SupportedBrowser(SupportedBrowser.SAFARI)
@Unstable()
-class FilterElement extends StyledElement implements UriReference, ExternalResourcesRequired {
+class FilterElement extends SvgElement implements UriReference, ExternalResourcesRequired {
// To suppress missing implicit constructor warnings.
factory FilterElement._() { throw new UnsupportedError("Not supported"); }
@@ -2761,7 +2761,7 @@
@DocsEditable()
@DomName('SVGGraphicsElement')
@Experimental() // untriaged
-class GraphicsElement extends StyledElement implements Tests {
+class GraphicsElement extends SvgElement implements Tests {
// To suppress missing implicit constructor warnings.
factory GraphicsElement._() { throw new UnsupportedError("Not supported"); }
@@ -3136,7 +3136,7 @@
@DocsEditable()
@DomName('SVGMarkerElement')
@Unstable()
-class MarkerElement extends StyledElement implements FitToViewBox, ExternalResourcesRequired {
+class MarkerElement extends SvgElement implements FitToViewBox, ExternalResourcesRequired {
// To suppress missing implicit constructor warnings.
factory MarkerElement._() { throw new UnsupportedError("Not supported"); }
@@ -3227,7 +3227,7 @@
@DocsEditable()
@DomName('SVGMaskElement')
@Unstable()
-class MaskElement extends StyledElement implements ExternalResourcesRequired, Tests {
+class MaskElement extends SvgElement implements ExternalResourcesRequired, Tests {
// To suppress missing implicit constructor warnings.
factory MaskElement._() { throw new UnsupportedError("Not supported"); }
@@ -4594,7 +4594,7 @@
@DocsEditable()
@DomName('SVGPatternElement')
@Unstable()
-class PatternElement extends StyledElement implements FitToViewBox, UriReference, ExternalResourcesRequired, Tests {
+class PatternElement extends SvgElement implements FitToViewBox, UriReference, ExternalResourcesRequired, Tests {
// To suppress missing implicit constructor warnings.
factory PatternElement._() { throw new UnsupportedError("Not supported"); }
@@ -5130,7 +5130,7 @@
@DocsEditable()
@DomName('SVGStopElement')
@Unstable()
-class StopElement extends StyledElement {
+class StopElement extends SvgElement {
// To suppress missing implicit constructor warnings.
factory StopElement._() { throw new UnsupportedError("Not supported"); }
@@ -5294,29 +5294,6 @@
@DocsEditable()
-@DomName('SVGStyledElement')
-@Unstable()
-class StyledElement extends SvgElement {
- // To suppress missing implicit constructor warnings.
- factory StyledElement._() { throw new UnsupportedError("Not supported"); }
-
- @DomName('SVGStyledElement.className')
- @DocsEditable()
- AnimatedString get $dom_svgClassName native "SVGStyledElement_className_Getter";
-
- @DomName('SVGStyledElement.style')
- @DocsEditable()
- CssStyleDeclaration get style native "SVGStyledElement_style_Getter";
-
-}
-// 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.
-
-// WARNING: Do not edit - generated code.
-
-
-@DocsEditable()
@DomName('SVGDocument')
@Unstable()
class SvgDocument extends Document {
@@ -5447,18 +5424,20 @@
// To suppress missing implicit constructor warnings.
factory SvgElement._() { throw new UnsupportedError("Not supported"); }
- @DomName('SVGElement.id')
+ @DomName('SVGElement.className')
@DocsEditable()
- String get id native "SVGElement_id_Getter";
-
- @DomName('SVGElement.id')
- @DocsEditable()
- void set id(String value) native "SVGElement_id_Setter";
+ @Experimental() // untriaged
+ AnimatedString get $dom_svgClassName native "SVGElement_className_Getter";
@DomName('SVGElement.ownerSVGElement')
@DocsEditable()
SvgSvgElement get ownerSvgElement native "SVGElement_ownerSVGElement_Getter";
+ @DomName('SVGElement.style')
+ @DocsEditable()
+ @Experimental() // untriaged
+ CssStyleDeclaration get style native "SVGElement_style_Getter";
+
@DomName('SVGElement.viewportElement')
@DocsEditable()
SvgElement get viewportElement native "SVGElement_viewportElement_Getter";
@@ -5723,7 +5702,7 @@
@DocsEditable()
@DomName('SVGSymbolElement')
@Unstable()
-class SymbolElement extends StyledElement implements FitToViewBox, ExternalResourcesRequired {
+class SymbolElement extends SvgElement implements FitToViewBox, ExternalResourcesRequired {
// To suppress missing implicit constructor warnings.
factory SymbolElement._() { throw new UnsupportedError("Not supported"); }
@@ -5986,7 +5965,7 @@
@DocsEditable()
@DomName('SVGTitleElement')
@Unstable()
-class TitleElement extends StyledElement {
+class TitleElement extends SvgElement {
// To suppress missing implicit constructor warnings.
factory TitleElement._() { throw new UnsupportedError("Not supported"); }
@@ -6524,7 +6503,7 @@
@DocsEditable()
@DomName('SVGGradientElement')
@Unstable()
-class _GradientElement extends StyledElement implements UriReference, ExternalResourcesRequired {
+class _GradientElement extends SvgElement implements UriReference, ExternalResourcesRequired {
// To suppress missing implicit constructor warnings.
factory _GradientElement._() { throw new UnsupportedError("Not supported"); }
@@ -6670,7 +6649,7 @@
@DocsEditable()
@DomName('SVGFEDropShadowElement')
@Experimental() // nonstandard
-abstract class _SVGFEDropShadowElement extends StyledElement implements FilterPrimitiveStandardAttributes {
+abstract class _SVGFEDropShadowElement extends SvgElement implements FilterPrimitiveStandardAttributes {
// To suppress missing implicit constructor warnings.
factory _SVGFEDropShadowElement._() { throw new UnsupportedError("Not supported"); }
@@ -6794,7 +6773,7 @@
@DocsEditable()
@DomName('SVGGlyphRefElement')
@Unstable()
-abstract class _SVGGlyphRefElement extends StyledElement implements UriReference {
+abstract class _SVGGlyphRefElement extends SvgElement implements UriReference {
// To suppress missing implicit constructor warnings.
factory _SVGGlyphRefElement._() { throw new UnsupportedError("Not supported"); }
@@ -6846,7 +6825,7 @@
@DocsEditable()
@DomName('SVGMissingGlyphElement')
@Unstable()
-abstract class _SVGMissingGlyphElement extends StyledElement {
+abstract class _SVGMissingGlyphElement extends SvgElement {
// To suppress missing implicit constructor warnings.
factory _SVGMissingGlyphElement._() { throw new UnsupportedError("Not supported"); }
diff --git a/sdk/lib/typed_data/dart2js/typed_data_dart2js.dart b/sdk/lib/typed_data/dart2js/typed_data_dart2js.dart
index a145ff2..c72a299 100644
--- a/sdk/lib/typed_data/dart2js/typed_data_dart2js.dart
+++ b/sdk/lib/typed_data/dart2js/typed_data_dart2js.dart
@@ -934,6 +934,16 @@
/// Extracted w value.
double get w => _storage[3];
+ /// Extract the sign bit from each lane return them in the first 4 bits.
+ int get signMask {
+ var view = new Uint32List.view(_storage.buffer);
+ var mx = (view[0] & 0x80000000) >> 31;
+ var my = (view[1] & 0x80000000) >> 31;
+ var mz = (view[2] & 0x80000000) >> 31;
+ var mw = (view[3] & 0x80000000) >> 31;
+ return mx | my << 1 | mz << 2 | mw << 3;
+ }
+
/// Mask passed to [shuffle].
static const int XXXX = 0x0;
static const int XXXY = 0x40;
@@ -1192,7 +1202,6 @@
static const int WWWZ = 0xBF;
static const int WWWW = 0xFF;
-
/// Shuffle the lane values. [mask] must be one of the 256 shuffle constants.
Float32x4 shuffle(int m) {
if (m < 0 || m > 255) {
@@ -1396,6 +1405,24 @@
return new Uint32x4(_x, _y, _z, _w);
}
+ Uint32x4 operator+(Uint32x4 other) {
+ var r = new Uint32x4(0, 0, 0, 0);
+ r._storage[0] = (_storage[0] + other._storage[0]);
+ r._storage[1] = (_storage[1] + other._storage[1]);
+ r._storage[2] = (_storage[2] + other._storage[2]);
+ r._storage[3] = (_storage[3] + other._storage[3]);
+ return r;
+ }
+
+ Uint32x4 operator-(Uint32x4 other) {
+ var r = new Uint32x4(0, 0, 0, 0);
+ r._storage[0] = (_storage[0] - other._storage[0]);
+ r._storage[1] = (_storage[1] - other._storage[1]);
+ r._storage[2] = (_storage[2] - other._storage[2]);
+ r._storage[3] = (_storage[3] - other._storage[3]);
+ return r;
+ }
+
/// Extract 32-bit mask from x lane.
int get x => _storage[0];
/// Extract 32-bit mask from y lane.
@@ -1405,6 +1432,15 @@
/// Extract 32-bit mask from w lane.
int get w => _storage[3];
+ /// Extract the top bit from each lane return them in the first 4 bits.
+ int get signMask {
+ int mx = (_storage[0] & 0x80000000) >> 31;
+ int my = (_storage[1] & 0x80000000) >> 31;
+ int mz = (_storage[2] & 0x80000000) >> 31;
+ int mw = (_storage[3] & 0x80000000) >> 31;
+ return mx | my << 1 | mz << 2 | mw << 3;
+ }
+
/// Returns a new [Uint32x4] copied from [this] with a new x value.
Uint32x4 withX(int x) {
int _x = x;
diff --git a/sdk/lib/typed_data/typed_data.dart b/sdk/lib/typed_data/typed_data.dart
index 7184e47..71d6a8d 100644
--- a/sdk/lib/typed_data/typed_data.dart
+++ b/sdk/lib/typed_data/typed_data.dart
@@ -876,6 +876,9 @@
/// Extracted w value.
double get w;
+ /// Extract the sign bits from each lane return them in the first 4 bits.
+ int get signMask;
+
/// Mask passed to [shuffle].
static const int XXXX = 0x0;
static const int XXXY = 0x40;
@@ -1201,6 +1204,10 @@
Uint32x4 operator&(Uint32x4 other);
/// The bit-wise xor operator.
Uint32x4 operator^(Uint32x4 other);
+ /// Addition operator.
+ Uint32x4 operator+(Uint32x4 other);
+ /// Subtraction operator.
+ Uint32x4 operator-(Uint32x4 other);
/// Extract 32-bit mask from x lane.
int get x;
@@ -1211,6 +1218,9 @@
/// Extract 32-bit mask from w lane.
int get w;
+ /// Extract the top bit from each lane return them in the first 4 bits.
+ int get signMask;
+
/// Returns a new [Uint32x4] copied from [this] with a new x value.
Uint32x4 withX(int x);
/// Returns a new [Uint32x4] copied from [this] with a new y value.
diff --git a/tests/benchmark_smoke/benchmark_smoke.status b/tests/benchmark_smoke/benchmark_smoke.status
index 0ccd5ca..ed281f3 100644
--- a/tests/benchmark_smoke/benchmark_smoke.status
+++ b/tests/benchmark_smoke/benchmark_smoke.status
@@ -2,12 +2,6 @@
# 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.
-[ $runtime == ie9 && ($system == linux || $system == macos) ]
-*: Skip
-
-[ $runtime == safari && ($system == linux || $system == windows) ]
-*: Skip
-
[ $runtime == vm ]
*: Skip
diff --git a/tests/co19/co19-analyzer.status b/tests/co19/co19-analyzer.status
index cb4f01a..4d9ef03 100644
--- a/tests/co19/co19-analyzer.status
+++ b/tests/co19/co19-analyzer.status
@@ -3,7 +3,6 @@
# BSD-style license that can be found in the LICENSE file.
[ $compiler == dartanalyzer ]
-
# not clear: g([var foo = foo + 10]) is parameter 'foo' in the scope of its own initialzer?
Language/06_Functions/2_Formal_Parameters_A02_t02: fail
@@ -16,13 +15,20 @@
# TBF: _f is private, so does not collide
Language/07_Classes/1_Instance_Methods_A05_t08: fail
+# TBD: should we check that argument for dynamic parameter of constant constructor is not compatible with operation that is performed with it?
+Language/12_Expressions/01_Constants_A16_t03: fail
+
+# TBD: should we report _error_ when constant creation uses arguments with types incompatible with parameters?
+Language/12_Expressions/12_Instance_Creation/2_Const_A09_t02: fail
+Language/12_Expressions/12_Instance_Creation/2_Const_A09_t03: fail
+
+# TBF: infinite look: class A {const A();final m = const A();}
+Language/12_Expressions/01_Constants_A17_t03: fail
+
# co19 issue #380, Strings class has been removed
LibTest/core/RegExp/Pattern_semantics/firstMatch_CharacterClassEscape_A03_t01: fail, OK
LibTest/core/RegExp/Pattern_semantics/firstMatch_CharacterClassEscape_A04_t01: fail, OK
-# co19 issue #389, ceil, floor, truncate and round return integers
-LibTest/core/int/operator_division_A01_t01: fail, OK
-
# co19 issue #397, List.addLast removed
LibTest/core/Iterable/where_A01_t07: fail, OK
@@ -123,69 +129,106 @@
Language/07_Classes/4_Abstract_Instance_Members_A04_t05: fail, OK
Language/07_Classes/4_Abstract_Instance_Members_A04_t06: fail, OK
+# co19 issue #513, rules for finals were loosened, contradiction in spec was fixed
+Language/07_Classes/6_Constructors/1_Generative_Constructors_A21_t01: fail, OK
+
+# co19 issue #514, it is still an error to have both a n initializing formal and an initializer in the constructor's initializer list
+Language/05_Variables/05_Variables_A05_t03: fail, OK
+
+# co19 issue #515, it is a compile-time error if there is more than one entity with the same name declared in the same scope
+Language/07_Classes/3_Setters_A08_t01: fail, OK
+Language/07_Classes/3_Setters_A08_t02: fail, OK
+Language/07_Classes/3_Setters_A08_t03: fail, OK
+Language/07_Classes/3_Setters_A08_t04: fail, OK
+
+# co19 issue #516, it is a compile-time error if a class has both a getter and a method with the same name.
+Language/07_Classes/3_Setters_A08_t05: fail, OK
+
+# co19 issue #438, Static variables are initialized lazily, need not be constants
+Language/12_Expressions/01_Constants_A16_t01: fail, OK
+Language/12_Expressions/01_Constants_A16_t02: fail, OK
+
+# co19 issue #517, +5 is not a valid expression
+Language/12_Expressions/01_Constants_A01_t01: fail, OK
+Language/12_Expressions/03_Numbers_A01_t01: fail, OK
+Language/12_Expressions/03_Numbers_A01_t02: fail, OK
+Language/12_Expressions/03_Numbers_A01_t03: fail, OK
+Language/12_Expressions/03_Numbers_A01_t04: fail, OK
+Language/12_Expressions/03_Numbers_A01_t08: fail, OK
+Language/12_Expressions/03_Numbers_A01_t10: fail, OK
+Language/13_Statements/02_Expression_Statements_A01_t06: fail, OK
+
+# co19 issue #518, It is a compile-time error if evaluation of a compile-time constant would raise an exception
+Language/12_Expressions/01_Constants_A11_t01: fail, OK
+Language/12_Expressions/01_Constants_A12_t01: fail, OK
+Language/12_Expressions/01_Constants_A13_t06: fail, OK
+
+# co19 issue #397, List.addLast being removed
+Language/12_Expressions/06_Lists_A06_t01: fail, OK
+
+# co19 issue #519, ++5 is not assignable
+Language/12_Expressions/07_Maps_A01_t01: fail, OK
+
+# co19 issue #420, "throw" requires expression, "rethrow" should be used instead
+Language/12_Expressions/08_Throw_A05_t01: fail, OK
+Language/12_Expressions/08_Throw_A05_t02: fail, OK
+Language/12_Expressions/08_Throw_A05_t03: fail, OK
+
+# co19 issue #454 (wrongly closed)
+Language/12_Expressions/12_Instance_Creation/1_New_A01_t04: fail, OK
+
+# co19 issue #521, attempt to create instance of not a class
+Language/12_Expressions/12_Instance_Creation/1_New_A02_t01: fail, OK
+Language/12_Expressions/12_Instance_Creation/1_New_A02_t02: fail, OK
+Language/12_Expressions/12_Instance_Creation/1_New_A02_t03: fail, OK
+Language/12_Expressions/12_Instance_Creation/1_New_A02_t05: fail, OK
+Language/12_Expressions/12_Instance_Creation/1_New_A02_t07: fail, OK
+Language/12_Expressions/12_Instance_Creation/1_New_A06_t03: fail, OK
+
+# co19 issue #523, new malbound type
+Language/12_Expressions/12_Instance_Creation/1_New_A05_t01: fail, OK
+Language/12_Expressions/12_Instance_Creation/1_New_A05_t02: fail, OK
+Language/12_Expressions/12_Instance_Creation/1_New_A05_t03: fail, OK
+
+# co19 issue #524, new abstract class
+Language/12_Expressions/12_Instance_Creation/1_New_A06_t01: fail, OK
+Language/12_Expressions/12_Instance_Creation/1_New_A06_t02: fail, OK
+Language/12_Expressions/12_Instance_Creation/1_New_A06_t12: fail, OK
+
+# co19 issue #526, use undefined constructor
+Language/12_Expressions/12_Instance_Creation/1_New_A06_t04: fail, OK
+Language/12_Expressions/12_Instance_Creation/1_New_A06_t05: fail, OK
+Language/12_Expressions/12_Instance_Creation/1_New_A06_t06: fail, OK
+
+# co19 issue #527, not enough or extra positional parameters; no such named paramater
+Language/12_Expressions/12_Instance_Creation/1_New_A06_t07: fail, OK
+Language/12_Expressions/12_Instance_Creation/1_New_A06_t08: fail, OK
+Language/12_Expressions/12_Instance_Creation/1_New_A06_t09: fail, OK
+
+# co19 issue #528, Const: wrong number of type arguments
+Language/12_Expressions/12_Instance_Creation_A01_t02: fail, OK
+Language/12_Expressions/12_Instance_Creation_A01_t05: fail, OK
+Language/12_Expressions/12_Instance_Creation_A01_t06: fail, OK
+
+# co19 issue #529, const instance creation with invalid type arguments
+Language/12_Expressions/12_Instance_Creation_A01_t08: fail, OK
+
+# co19 issue #388 (wrongly closed), StringBuffer methods changed
+Language/12_Expressions/15_Method_Invocation/3_Static_Invocation_A04_t05: fail, OK
+Language/12_Expressions/15_Method_Invocation/4_Super_Invocation_A02_t04: fail, OK
+
+# co19 issue #433 (wrongly closed), missing @static-warning annotation
+Language/12_Expressions/15_Method_Invocation/3_Static_Invocation_A03_t01: fail, OK
+Language/12_Expressions/15_Method_Invocation/3_Static_Invocation_A03_t07: fail, OK
+
+# co19 issue #530, garbage
+Language/12_Expressions/32_Type_Test_A04_t02: fail, OK
+
+# co19 issue #531, void f(void f()) {f();} is error. Gilad: The formal parameter conflicts with the name of the function.
+Language/13_Statements/04_Local_Function_Declaration_A01_t01: fail, OK
+
+
# co19-roll r546 (11.08.2013) caused these failures
-Language/05_Variables/05_Variables_A05_t01: fail # co19-roll r546: Please triage this failure
-Language/05_Variables/05_Variables_A05_t02: fail # co19-roll r546: Please triage this failure
-Language/05_Variables/05_Variables_A05_t03: fail # co19-roll r546: Please triage this failure
-Language/07_Classes/3_Setters_A08_t01: fail # co19-roll r546: Please triage this failure
-Language/07_Classes/3_Setters_A08_t02: fail # co19-roll r546: Please triage this failure
-Language/07_Classes/3_Setters_A08_t03: fail # co19-roll r546: Please triage this failure
-Language/07_Classes/3_Setters_A08_t04: fail # co19-roll r546: Please triage this failure
-Language/07_Classes/3_Setters_A08_t05: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/00_Object_Identity/1_Object_Identity_A04_t01: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/00_Object_Identity/1_Object_Identity_A04_t02: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/01_Constants_A01_t01: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/01_Constants_A11_t01: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/01_Constants_A12_t01: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/01_Constants_A13_t06: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/01_Constants_A16_t01: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/01_Constants_A16_t02: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/01_Constants_A16_t03: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/01_Constants_A17_t03: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/03_Numbers_A01_t01: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/03_Numbers_A01_t02: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/03_Numbers_A01_t03: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/03_Numbers_A01_t04: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/03_Numbers_A01_t08: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/03_Numbers_A01_t10: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/06_Lists_A06_t01: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/07_Maps_A01_t01: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/08_Throw_A05_t01: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/08_Throw_A05_t02: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/08_Throw_A05_t03: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/12_Instance_Creation/1_New_A01_t04: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/12_Instance_Creation/1_New_A02_t01: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/12_Instance_Creation/1_New_A02_t02: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/12_Instance_Creation/1_New_A02_t03: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/12_Instance_Creation/1_New_A02_t05: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/12_Instance_Creation/1_New_A02_t07: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/12_Instance_Creation/1_New_A05_t01: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/12_Instance_Creation/1_New_A05_t02: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/12_Instance_Creation/1_New_A05_t03: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/12_Instance_Creation/1_New_A06_t01: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/12_Instance_Creation/1_New_A06_t02: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/12_Instance_Creation/1_New_A06_t03: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/12_Instance_Creation/1_New_A06_t04: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/12_Instance_Creation/1_New_A06_t05: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/12_Instance_Creation/1_New_A06_t06: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/12_Instance_Creation/1_New_A06_t07: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/12_Instance_Creation/1_New_A06_t08: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/12_Instance_Creation/1_New_A06_t09: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/12_Instance_Creation/1_New_A06_t12: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/12_Instance_Creation/2_Const_A09_t02: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/12_Instance_Creation/2_Const_A09_t03: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/12_Instance_Creation_A01_t02: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/12_Instance_Creation_A01_t05: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/12_Instance_Creation_A01_t06: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/12_Instance_Creation_A01_t08: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/15_Method_Invocation/2_Cascaded_Invocation_A01_t19: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/15_Method_Invocation/3_Static_Invocation_A03_t01: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/15_Method_Invocation/3_Static_Invocation_A03_t07: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/15_Method_Invocation/3_Static_Invocation_A04_t05: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/15_Method_Invocation/4_Super_Invocation_A02_t04: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/32_Type_Test_A04_t02: fail # co19-roll r546: Please triage this failure
-Language/13_Statements/02_Expression_Statements_A01_t06: fail # co19-roll r546: Please triage this failure
-Language/13_Statements/04_Local_Function_Declaration_A01_t01: fail # co19-roll r546: Please triage this failure
Language/13_Statements/11_Return_A07_t01: fail # co19-roll r546: Please triage this failure
Language/13_Statements/11_Try_A02_t03: fail # co19-roll r546: Please triage this failure
Language/13_Statements/11_Try_A03_t03: fail # co19-roll r546: Please triage this failure
diff --git a/tests/co19/co19-co19.status b/tests/co19/co19-co19.status
new file mode 100644
index 0000000..97bece2
--- /dev/null
+++ b/tests/co19/co19-co19.status
@@ -0,0 +1,135 @@
+# 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.
+
+# This file contains the tests that have been identified as broken and have been filed
+# on the co19 issue tracker.
+# In order to qualify here these tests need to fail both on the VM and dart2js.
+
+### GENERAL FAILURES ###
+
+[ $runtime == vm || $compiler == dart2js ]
+Language/07_Classes/6_Constructors_A02_t01: SKIP # co19 issue 415.
+Language/16_Reference/1_Lexical_Rules/2_Comments_A04_t03: FAIL, OK # co19 issue 505
+Language/15_Types/1_Static_Types_A03_t01: FAIL, OK # co19 issue 506
+Language/07_Classes/6_Constructors/3_Constant_Constructors_A05_t01: FAIL, OK # co19 issue 426
+
+LibTest/math/acos_A01_t01: PASS, FAIL, OK # co19 issue 44
+LibTest/math/asin_A01_t01: PASS, FAIL, OK # co19 issue 44
+LibTest/math/atan_A01_t01: PASS, FAIL, OK # co19 issue 44
+LibTest/math/cos_A01_t01: PASS, FAIL, OK # co19 issue 44
+LibTest/math/exp_A01_t01: PASS, FAIL, OK # co19 issue 44
+LibTest/math/max_A01_t03: FAIL, OK # co19 issue 467
+LibTest/math/min_A01_t03: FAIL, OK # co19 issue 467
+LibTest/math/pow_A01_t01: FAIL, OK # co19 issue 44
+LibTest/math/pow_A11_t01: FAIL, OK # co19 issue 512
+LibTest/math/pow_A13_t01: FAIL, OK # co19 issue 507
+LibTest/math/sin_A01_t01: PASS, FAIL, OK # co19 issue 44
+LibTest/math/tan_A01_t01: PASS, FAIL, OK # co19 issue 44
+
+LibTest/collection/Queue/iterator_current_A01_t02: FAIL, OK # co19 issue 475
+LibTest/collection/Queue/iterator_moveNext_A01_t02: FAIL, OK # co19 issue 475
+
+LibTest/core/double/ceil_A01_t03: FAIL, OK # co19 issue 389
+LibTest/core/double/ceil_A01_t04: FAIL, OK # co19 issue 389
+LibTest/core/double/floor_A01_t03: FAIL, OK # co19 issue 389
+LibTest/core/double/floor_A01_t04: FAIL, OK # co19 issue 389
+LibTest/core/double/round_A01_t02: FAIL, OK # co19 issue 389
+LibTest/core/double/round_A01_t04: FAIL, OK # co19 issue 389
+LibTest/core/double/parse_A02_t01: FAIL, OK # co19 issue 418
+LibTest/core/double/truncate_A01_t03: FAIL, OK # co19 issue 389
+LibTest/core/double/truncate_A01_t04: FAIL, OK # co19 issue 389
+
+LibTest/core/int/toStringAsExponential_A02_t01: FAIL, OK # co19 issue 477
+LibTest/core/Iterable/any_A01_t04: FAIL, OK # co19 issue 508.
+LibTest/core/List/skip_A03_t01: FAIL, OK # co19 issue 502
+LibTest/core/List/take_A02_t01: FAIL, OK # co19 issue 502
+LibTest/core/Match/pattern_A01_t01: FAIL, OK # co19 Issue 400, 422
+LibTest/core/RegExp/allMatches_A01_t01: FAIL, OK # co19 Issue 400, 422
+
+LibTest/async/Stream/Stream.periodic_A01_t01: PASS, FAIL, OK # co19 issue 538
+LibTest/async/Stream/Stream.periodic_A03_t01: PASS, FAIL, OK # co19 issue 538
+LibTest/async/Timer/run_A01_t01: PASS, FAIL, OK # co19 issue 538
+LibTest/async/Timer/Timer.periodic_A01_t01: PASS, FAIL, OK # co19 issue 537
+LibTest/async/Timer/Timer.periodic_A02_t01: PASS, FAIL, OK # co19 issue 538
+LibTest/async/Future/Future.delayed_A01_t02: PASS, FAIL, OK # co19 issue 536
+LibTest/core/DateTime/isAtSameMomentAs_A01_t01: FAIL, OK # co19 issue 503
+LibTest/core/DateTime/year_A01_t01: FAIL, OK # co19 issue 504
+LibTest/core/double/parse_A01_t01: FAIL, OK # co19 issue 503
+
+LibTest/isolate/SendPort/send_A02_t02: SKIP # co19 issue 493
+LibTest/isolate/SendPort/send_A02_t03: SKIP # co19 issue 495
+
+Utils/tests/Expect/listEquals_A02_t01: FAIL, OK # co19 issue 499
+Utils/tests/Expect/listEquals_A03_t01: FAIL, OK # co19 issue 500
+Utils/tests/Expect/setEquals_A02_t01: FAIL, OK # co19 issue 499
+
+LibTest/isolate_api/streamSpawnFunction_A02_t02: Pass, Fail # co19 issue 540
+LibTest/isolate_api/streamSpawnFunction_A02_t03: Pass, Fail # co19 issue 540
+
+### CHECKED MODE FAILURES ###
+
+[ ($runtime == vm || $compiler == dart2js) && $checked]
+Language/13_Statements/09_Switch_A05_t01: FAIL, OK # co19 issue 498
+Language/14_Libraries_and_Scripts/1_Imports_A03_t26: FAIL, OK # co19 issue 498
+Language/15_Types/1_Static_Types_A03_t03: FAIL, OK # co19 issue 498
+Language/15_Types/1_Static_Types_A03_t04: FAIL, OK # co19 issue 498
+LibTest/async/EventTransformStream/asBroadcastStream_A01_t01: FAIL, OK # co19 issue 498
+LibTest/async/EventTransformStream/contains_A01_t01: FAIL, OK # co19 issue 498
+LibTest/async/EventTransformStream/contains_A02_t01: FAIL, OK # co19 issue 498
+LibTest/async/EventTransformStream/distinct_A01_t01: FAIL, OK # co19 issue 498
+LibTest/async/EventTransformStream/drain_A01_t01: FAIL, OK # co19 issue 498
+LibTest/async/EventTransformStream/firstWhere_A01_t01: FAIL, OK # co19 issue 498
+LibTest/async/EventTransformStream/firstWhere_A02_t01: FAIL, OK # co19 issue 498
+LibTest/async/EventTransformStream/first_A03_t01: FAIL, OK # co19 issue 498
+LibTest/async/EventTransformStream/fold_A01_t01: FAIL, OK # co19 issue 498
+LibTest/async/EventTransformStream/fold_A01_t02: FAIL, OK # co19 issue 498
+LibTest/async/EventTransformStream/forEach_A01_t01: FAIL, OK # co19 issue 498
+LibTest/async/EventTransformStream/forEach_A02_t02: FAIL, OK # co19 issue 498
+LibTest/async/EventTransformStream/handleError_A02_t01: FAIL, OK # co19 issue 498
+LibTest/async/EventTransformStream/isBroadcast_A01_t02: FAIL, OK # co19 issue 498
+LibTest/async/EventTransformStream/lastWhere_A01_t01: FAIL, OK # co19 issue 498
+LibTest/async/EventTransformStream/lastWhere_A02_t01: FAIL, OK # co19 issue 498
+LibTest/async/EventTransformStream/listen_A01_t01: FAIL, OK # co19 issue 498
+LibTest/async/EventTransformStream/listen_A02_t01: FAIL, OK # co19 issue 498
+LibTest/async/EventTransformStream/listen_A03_t01: FAIL, OK # co19 issue 498
+LibTest/async/EventTransformStream/map_A01_t01: FAIL, OK # co19 issue 498
+LibTest/async/EventTransformStream/reduce_A01_t01: FAIL, OK # co19 issue 498
+LibTest/async/EventTransformStream/reduce_A01_t02: FAIL, OK # co19 issue 498
+LibTest/async/EventTransformStream/singleWhere_A01_t01: FAIL, OK # co19 issue 498
+LibTest/async/EventTransformStream/skip_A01_t01: FAIL, OK # co19 issue 498
+LibTest/async/EventTransformStream/take_A01_t01: FAIL, OK # co19 issue 498
+LibTest/async/EventTransformStream/take_A01_t02: FAIL, OK # co19 issue 498
+LibTest/async/EventTransformStream/toList_A01_t01: FAIL, OK # co19 issue 498
+LibTest/async/EventTransformStream/toSet_A01_t01: FAIL, OK # co19 issue 498
+LibTest/async/EventTransformStream/transform_A01_t01: FAIL, OK # co19 issue 498
+LibTest/async/EventTransformStream/where_A01_t01: FAIL, OK # co19 issue 498
+LibTest/async/EventTransformStream/where_A01_t02: FAIL, OK # co19 issue 498
+LibTest/async/Stream/drain_A01_t01: FAIL, OK # co19 issue 498
+LibTest/async/Stream/firstWhere_A01_t01: FAIL, OK # co19 issue 498
+LibTest/async/Stream/firstWhere_A02_t01: FAIL, OK # co19 issue 498
+LibTest/async/Stream/fold_A01_t01: FAIL, OK # co19 issue 498
+LibTest/async/Stream/fold_A01_t02: FAIL, OK # co19 issue 498
+LibTest/async/Stream/lastWhere_A01_t01: FAIL, OK # co19 issue 498
+LibTest/async/Stream/lastWhere_A02_t01: FAIL, OK # co19 issue 498
+LibTest/async/Stream/reduce_A01_t01: FAIL, OK # co19 issue 498
+LibTest/async/Stream/reduce_A01_t02: FAIL, OK # co19 issue 498
+LibTest/async/Stream/singleWhere_A01_t01: FAIL, OK # co19 issue 498
+LibTest/async/Stream/take_A01_t02: FAIL, OK # co19 issue 498
+LibTest/async/Stream/transform_A01_t01: FAIL, OK # co19 issue 498
+LibTest/async/Stream/where_A01_t01: FAIL, OK # co19 issue 498
+LibTest/async/Stream/where_A01_t02: FAIL, OK # co19 issue 498
+LibTest/async/StreamEventTransformer/bind_A01_t01: FAIL, OK # co19 issue 498
+LibTest/core/DateTime/compareTo_A02_t01: FAIL, OK # co19 issue 498
+LibTest/core/List/join_A01_t01: FAIL, OK # co19 issue 498
+LibTest/core/List/removeAt_A02_t01: FAIL, OK # co19 issue 498
+LibTest/core/TypeError/column_A01_t01: FAIL, OK # co19 issue 510
+LibTest/core/TypeError/dstName_A01_t01: FAIL, OK # co19 issue 510
+LibTest/core/TypeError/dstType_A01_t01: FAIL, OK # co19 issue 510
+LibTest/core/TypeError/failedAssertion_A01_t01: FAIL, OK # co19 issue 510
+LibTest/core/TypeError/line_A01_t01: FAIL, OK # co19 issue 510
+LibTest/core/TypeError/srcType_A01_t01: FAIL, OK # co19 issue 510
+LibTest/core/TypeError/url_A01_t01: FAIL, OK # co19 issue 510
+LibTest/isolate/IsolateStream/last_A01_t01: FAIL, OK # co19 issue 498
+LibTest/isolate/IsolateStream/length_A01_t01: FAIL, OK # co19 issue 498
+LibTest/isolate/IsolateStream/single_A01_t01: FAIL, OK # co19 issue 498
diff --git a/tests/co19/co19-dart2dart.status b/tests/co19/co19-dart2dart.status
index 13a1129..a7ed9ce 100644
--- a/tests/co19/co19-dart2dart.status
+++ b/tests/co19/co19-dart2dart.status
@@ -3,6 +3,7 @@
# BSD-style license that can be found in the LICENSE file.
[ $compiler == dart2dart ]
+LibTest/async/Stream/Stream.periodic_A01_t01: Pass, Fail # Issue 12562.
LibTest/math/max_A01_t03: Fail # co19 issue 467
LibTest/math/min_A01_t03: Fail # co19 issue 467
@@ -132,6 +133,7 @@
LibTest/math/pow_A01_t01: Fail # Inherited from VM.
LibTest/math/pow_A11_t01: Fail # Inherited from VM.
LibTest/math/pow_A13_t01: Fail # Inherited from VM.
+LibTest/math/pow_A18_t01: Fail # Inherited from VM.
LibTest/math/sin_A01_t01: Fail # Inherited from VM.
LibTest/math/tan_A01_t01: Fail # Issue co19 - 44
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index 1cbc686..e373794 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -2,7 +2,7 @@
# 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.
-[ $compiler == dart2js && ($runtime == d8 || $runtime == drt) ]
+[ $compiler == dart2js && $runtime == drt ]
LibTest/core/List/sort_A01_t02: Pass, Fail # v8 bug: Issue 12293
LibTest/core/List/sort_A01_t03: Pass, Fail # v8 bug: Issue 12293
LibTest/core/Map/Map_class_A01_t04: Pass, Fail # v8 bug: Issue 12293
@@ -13,12 +13,12 @@
[ $compiler == dart2js && $checked && $runtime == ie9 ]
LibTest/core/Map/Map_class_A01_t04: Slow, Pass
+LibTest/isolate/isolate_api/spawnUri_A02_t03: Pass, Fail # Issue 8920
+
# Crashes first, please. Then untriaged bugs. There is a section below
# for co19 bugs.
[ $compiler == dart2js ]
-LibTest/math/max_A01_t03: Fail # co19 issue 467
-LibTest/math/min_A01_t03: Fail # co19 issue 467
Language/03_Overview/1_Scoping_A02_t05: Fail # TODO(ahe): Please triage this failure.
Language/03_Overview/1_Scoping_A02_t06: Fail # TODO(ahe): Please triage this failure.
@@ -32,16 +32,9 @@
Language/07_Classes/1_Instance_Methods_A06_t02: Fail # TODO(ahe): Please triage this failure.
Language/07_Classes/6_Constructors/1_Generative_Constructors_A04_t15: Fail # TODO(ahe): Please triage this failure.
Language/07_Classes/6_Constructors/2_Factories_A07_t01: Fail # TODO(ahe): Please triage this failure.
-Language/07_Classes/6_Constructors/3_Constant_Constructors_A05_t01: Fail # TODO(ahe): Please triage this failure.
-LibTest/collection/Queue/iterator_current_A01_t02: Fail # co19 issue 475
-LibTest/collection/Queue/iterator_moveNext_A01_t02: Fail # co19 issue 475
LibTest/core/List/List_A03_t01: Fail # TODO(kasperl): Please triage this failure.
LibTest/core/double/INFINITY_A01_t04: Fail # TODO(ahe): Please triage this failure.
LibTest/core/double/NEGATIVE_INFINITY_A01_t04: Fail # TODO(ahe): Please triage this failure.
-LibTest/core/int/toStringAsExponential_A02_t01: Fail # co19 issue 477.
-LibTest/math/pow_A01_t01: Fail # TODO(ahe): Please triage this failure.
-LibTest/math/pow_A11_t01: Fail # TODO(ahe): Please triage this failure.
-LibTest/math/pow_A13_t01: Fail # TODO(ahe): Please triage this failure.
LibTest/core/List/sort_A01_t04: Pass, Slow # http://dartbug.com/11846
@@ -58,10 +51,6 @@
LibTest/isolate/isolate_api/spawnUri_A02_t03: Fail, Pass # TODO(ahe): Please triage this failure.
-[ $compiler == dart2js && $runtime == jsshell && $system == macos ]
-LibTest/math/cos_A01_t01: Fail # TODO(ahe): Please triage this failure.
-
-
[ $compiler == dart2js ]
LibTest/isolate/ReceivePort/receive_A01_t02: Fail # Issue 6750
@@ -87,14 +76,11 @@
LibTest/core/RegExp/Pattern_semantics/firstMatch_NonEmptyClassRanges_A01_t06: Fail # Issue: 8920
LibTest/core/String/contains_A01_t02: Fail # Issue: 8920
LibTest/isolate/ReceivePort/toSendPort_A01_t02: Pass, Fail # Issue: 8920
-
-
-# These tests are passing with 'runtime == ie9' but are either skipped or fail
-# on other configurations
-[ $compiler == dart2js && ($runtime == ie10 || $runtime == ff || $runtime == chrome || $runtime == chromeOnAndroid || $runtime == drt || $runtime == safari || $runtime == opera || $runtime == d8 || $runtime == jsshell) ]
-LibTest/math/exp_A01_t01: Fail, OK # co19 issue 44
-LibTest/math/sin_A01_t01: Fail # TODO(ahe): Please triage this failure.
-LibTest/math/tan_A01_t01: Fail # TODO(ahe): Please triage this failure.
+LibTest/isolate/ReceivePort/toSendPort_A01_t01: Pass, Fail # Issue: 8920
+LibTest/core/DateTime/timeZoneName_A01_t01: Fail # Issue: 8920
+LibTest/async/Stream/listen_A04_t01: Pass, Timeout # Issue: 8920
+LibTest/async/Completer/completeError_A02_t01: Pass, Fail # Issue 8920
+LibTest/async/DeferredLibrary/DeferredLibrary_A01_t01: Pass, Timeout # Issue 8920
[ $compiler == dart2js && $runtime == jsshell ]
LibTest/core/Map/Map_class_A01_t04: Pass, Slow # Issue 8096
@@ -102,19 +88,10 @@
LibTest/core/int/operator_truncating_division_A01_t01: Fail # TODO(ngeoaffray): Please triage these failure.
LibTest/core/RegExp/Pattern_semantics/firstMatch_CharacterClassEscape_A03_t01: Fail # TODO(ngeoaffray): Please triage these failure.
LibTest/core/RegExp/Pattern_semantics/firstMatch_CharacterClassEscape_A04_t01: Fail # TODO(ngeoaffray): Please triage these failure.
-LibTest/math/acos_A01_t01: Fail # TODO(ngeoaffray): Please triage these failure.
-LibTest/math/asin_A01_t01: Fail # TODO(ngeoaffray): Please triage these failure.
[ $compiler == dart2js && $checked ]
Language/07_Classes/6_Constructors/1_Generative_Constructors_A17_t03: Fail # TODO(ahe): Please triage this failure.
Language/07_Classes/6_Constructors/1_Generative_Constructors_A17_t04: Fail # TODO(ahe): Please triage this failure.
-LibTest/core/TypeError/column_A01_t01: Fail # TODO(ahe): Please triage this failure.
-LibTest/core/TypeError/dstName_A01_t01: Fail # TODO(ahe): Please triage this failure.
-LibTest/core/TypeError/dstType_A01_t01: Fail # TODO(ahe): Please triage this failure.
-LibTest/core/TypeError/failedAssertion_A01_t01: Fail # TODO(ahe): Please triage this failure.
-LibTest/core/TypeError/line_A01_t01: Fail # co19 issue 479
-LibTest/core/TypeError/srcType_A01_t01: Fail # TODO(ahe): Please triage this failure.
-LibTest/core/TypeError/url_A01_t01: Fail # TODO(ahe): Please triage this failure.
[ $compiler == dart2js ]
@@ -130,9 +107,7 @@
Language/07_Classes/1_Instance_Methods_A02_t05: Fail, OK # These tests need to be updated for new optional parameter syntax and semantics, co19 issue 258:
Language/07_Classes/6_Constructors/1_Generative_Constructors_A13_t01: Fail, OK # These tests need to be updated for new optional parameter syntax and semantics, co19 issue 258:
-LibTest/isolate/SendPort/send_A02_t02: Fail, OK # co19 issue 293
-LibTest/isolate/SendPort/send_A02_t03: Fail, OK # co19 issue 293
-LibTest/isolate/SendPort/send_A02_t04: Fail, OK # co19 issue 293
+LibTest/isolate/SendPort/send_A02_t04: Fail, Pass, OK # co19 issue 293 Passes on IE
LibTest/core/RegExp/firstMatch_A01_t01: Fail, OK # co19 issue 294
LibTest/core/RegExp/Pattern_semantics/firstMatch_Term_A04_t01: Fail, OK # co19 issue 294
@@ -148,8 +123,6 @@
Language/06_Functions/2_Formal_Parameters_A03_t06: Fail # TODO(ahe): Enforce optional parameter semantics.
LibTest/isolate/SendPort/send_A02_t01: Fail # Compile-time error: error: not a compile-time constant
-LibTest/isolate/SendPort/send_A02_t02: Fail # Compile-time error: error: not a compile-time constant
-LibTest/isolate/SendPort/send_A02_t03: Fail # Compile-time error: error: not a compile-time constant
LibTest/isolate/isolate_api/spawnUri_A02_t01: Fail # Runtime error: Expect.throws() fails
LibTest/isolate/isolate_api/spawnUri_A01_t01: Fail # Runtime error: UnsupportedError: Currently spawnUri is not supported without web workers.
@@ -195,24 +168,8 @@
Language/03_Overview/2_Privacy_A01_t11: Pass, OK # co19 issue 316
-LibTest/core/double/ceil_A01_t03: Fail # truncate/ceil/floor/round returns ints, issue 389
-LibTest/core/double/ceil_A01_t04: Fail # truncate/ceil/floor/round returns ints, issue 389
-LibTest/core/double/floor_A01_t03: Fail # truncate/ceil/floor/round returns ints, issue 389
-LibTest/core/double/floor_A01_t04: Fail # truncate/ceil/floor/round returns ints, issue 389
-LibTest/core/double/round_A01_t02: Fail # truncate/ceil/floor/round returns ints, issue 389
-LibTest/core/double/round_A01_t04: Fail # truncate/ceil/floor/round returns ints, issue 389
-LibTest/core/double/truncate_A01_t03: Fail # truncate/ceil/floor/round returns ints, issue 389
-LibTest/core/double/truncate_A01_t04: Fail # truncate/ceil/floor/round returns ints, issue 389
-
LibTest/core/Iterable/where_A01_t07: Fail # Issue 397
-LibTest/core/Iterable/any_A01_t04: Fail # setRange now takes end-argument. Issue 402
-
-LibTest/core/double/parse_A02_t01: Fail # Issue 418
-
-LibTest/core/Match/pattern_A01_t01: Fail # co19 Issue 400, 422
-LibTest/core/RegExp/allMatches_A01_t01: Fail # co19 Issue 400, 422
-
LibTest/core/String/indexOf_A01_t02: Fail # Issue 427
LibTest/core/String/lastIndexOf_A01_t02: Fail # Issue 427
@@ -241,10 +198,9 @@
LibTest/core/int/toRadixString_A01_t01: Fail, OK # Bad test: uses Expect.fail, Expect.throws, assumes case of result, and uses unsupported radixes.
LibTest/core/String/contains_A01_t02: Fail, OK # co19 issue 105.
-[ $compiler == dart2js && $system == macos ]
-LibTest/math/acos_A01_t01: Fail, OK # co19 issue 44
-LibTest/math/asin_A01_t01: Fail, OK # co19 issue 44
-LibTest/math/atan_A01_t01: Fail, OK # co19 issue 44
+[ $compiler == dart2js && $runtime == ie9 ]
+LibTest/math/cos_A01_t01: Fail # co19 issue 44
+LibTest/async/EventTransformStream/listen_A04_t01: Pass, Timeout # Issue 12595
#
# The following tests are failing. Please add the error message
@@ -301,7 +257,6 @@
Language/07_Classes/4_Abstract_Instance_Members_A04_t01: Fail # Checks that a compile-time error is produced when the overriding abstract method has fewer named parameters than the instance method being overridden (2 vs 3) and neither have any required parameters.
Language/07_Classes/4_Abstract_Instance_Members_A04_t05: Fail # Checks that a compile-time error is produced when the overriding non-abstract instance method has the same set of named parameters as the abstract method being overriden, but in a different order.
Language/07_Classes/4_Abstract_Instance_Members_A04_t06: Fail # Checks that a compile-time error is produced when the overriding non-abstract instance method has almost the same set of named parameters as the abstract method being overriden, except for one that has a different name.
-Language/07_Classes/6_Constructors_A02_t01: Fail # Checks that a compile-error is produced when a named constructor definition does not begin with the name of its class.
#
# Unexpected compile-time errors.
@@ -453,7 +408,6 @@
Language/14_Libraries_and_Scripts/5_URIs_A01_t21: fail # co19-roll r546: Please triage this failure
Language/14_Libraries_and_Scripts/5_URIs_A01_t24: fail # co19-roll r546: Please triage this failure
Language/14_Libraries_and_Scripts/5_URIs_A01_t25: fail # co19-roll r546: Please triage this failure
-Language/15_Types/1_Static_Types_A03_t01: fail # co19-roll r546: Please triage this failure
Language/15_Types/3_Type_Declarations/1_Typedef_A06_t01: fail # co19-roll r546: Please triage this failure
Language/15_Types/3_Type_Declarations/1_Typedef_A06_t02: fail # co19-roll r546: Please triage this failure
Language/15_Types/3_Type_Declarations/1_Typedef_A06_t03: fail # co19-roll r546: Please triage this failure
@@ -468,21 +422,12 @@
Language/15_Types/4_Interface_Types_A11_t04: fail # co19-roll r546: Please triage this failure
Language/15_Types/4_Interface_Types_A12_t10: fail # co19-roll r546: Please triage this failure
Language/16_Reference/1_Lexical_Rules/1_Reserved_Words_A40_t04: fail # co19-roll r546: Please triage this failure
-Language/16_Reference/1_Lexical_Rules/2_Comments_A04_t03: fail # co19-roll r546: Please triage this failure
Language/16_Reference/1_Lexical_Rules_A02_t06: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/Stream.periodic_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/Stream.periodic_A03_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/Timer/run_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/Timer/Timer.periodic_A02_t01: fail # co19-roll r546: Please triage this failure
LibTest/core/DateTime/DateTime_A01_t03: fail # co19-roll r546: Please triage this failure
-LibTest/core/DateTime/isAtSameMomentAs_A01_t01: fail # co19-roll r546: Please triage this failure
LibTest/core/DateTime/parse_A03_t01: fail # co19-roll r546: Please triage this failure
-LibTest/core/DateTime/year_A01_t01: fail # co19-roll r546: Please triage this failure
LibTest/core/double/parse_A01_t01: fail # co19-roll r546: Please triage this failure
LibTest/core/Duration/operator_div_A01_t01: fail # co19-roll r546: Please triage this failure
LibTest/core/List/List_A02_t01: fail # co19-roll r546: Please triage this failure
-LibTest/core/List/skip_A03_t01: fail # co19-roll r546: Please triage this failure
-LibTest/core/List/take_A02_t01: fail # co19-roll r546: Please triage this failure
LibTest/isolate/isolate_api/spawnFunction_A02_t01: fail # co19-roll r546: Please triage this failure
LibTest/isolate/isolate_api/spawnFunction_A03_t01: fail # co19-roll r546: Please triage this failure
LibTest/isolate/isolate_api/spawnFunction_A04_t01: fail # co19-roll r546: Please triage this failure
@@ -503,9 +448,6 @@
LibTest/isolate/IsolateStream/contains_A02_t01: fail # co19-roll r546: Please triage this failure
LibTest/isolate/SendPort/send_A01_t01: fail # co19-roll r546: Please triage this failure
Utils/tests/Expect/identical_A01_t01: fail # co19-roll r546: Please triage this failure
-Utils/tests/Expect/listEquals_A02_t01: fail # co19-roll r546: Please triage this failure
-Utils/tests/Expect/listEquals_A03_t01: fail # co19-roll r546: Please triage this failure
-Utils/tests/Expect/setEquals_A02_t01: fail # co19-roll r546: Please triage this failure
# co19-roll r546 (11.08.2013) caused these failures
[ $compiler == dart2js && $checked ]
@@ -524,71 +466,14 @@
Language/12_Expressions/20_Logical_Boolean_Expressions_A03_t01: fail # co19-roll r546: Please triage this failure
Language/12_Expressions/27_Unary_Expressions_A02_t03: fail # co19-roll r546: Please triage this failure
Language/13_Statements/06_For/1_For_Loop_A01_t08: fail # co19-roll r546: Please triage this failure
-Language/13_Statements/09_Switch_A05_t01: fail # co19-roll r546: Please triage this failure
-Language/14_Libraries_and_Scripts/1_Imports_A03_t26: fail # co19-roll r546: Please triage this failure
-Language/15_Types/1_Static_Types_A03_t03: fail # co19-roll r546: Please triage this failure
-Language/15_Types/1_Static_Types_A03_t04: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/asBroadcastStream_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/contains_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/contains_A02_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/distinct_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/drain_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/firstWhere_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/firstWhere_A02_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/first_A03_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/fold_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/fold_A01_t02: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/forEach_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/forEach_A02_t02: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/handleError_A02_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/isBroadcast_A01_t02: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/lastWhere_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/lastWhere_A02_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/listen_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/listen_A02_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/listen_A03_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/map_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/reduce_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/reduce_A01_t02: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/singleWhere_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/skip_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/take_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/take_A01_t02: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/toList_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/toSet_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/transform_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/where_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/where_A01_t02: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/drain_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/firstWhere_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/firstWhere_A02_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/fold_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/fold_A01_t02: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/lastWhere_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/lastWhere_A02_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/reduce_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/reduce_A01_t02: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/singleWhere_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/take_A01_t02: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/transform_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/where_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/where_A01_t02: fail # co19-roll r546: Please triage this failure
-LibTest/async/StreamEventTransformer/bind_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/core/DateTime/compareTo_A02_t01: fail # co19-roll r546: Please triage this failure
LibTest/core/List/getRange_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/core/List/join_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/core/List/removeAt_A02_t01: fail # co19-roll r546: Please triage this failure
LibTest/core/Set/intersection_A01_t02: fail # co19-roll r546: Please triage this failure
-LibTest/isolate/IsolateStream/last_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/isolate/IsolateStream/length_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/isolate/IsolateStream/single_A01_t01: fail # co19-roll r546: Please triage this failure
# Could this be dart issue 7728?
# co19-roll r546 (11.08.2013) caused these failures
[ $compiler == dart2js && ($runtime == d8 || $runtime == jsshell) ]
LibTest/async/Future/Future.delayed_A01_t01: Fail # co19-roll r546: Please triage this failure
-LibTest/async/Future/Future.delayed_A01_t02: Fail # co19-roll r546: Please triage this failure
LibTest/async/Future/Future.delayed_A03_t01: fail # co19-roll r546: Please triage this failure
LibTest/async/Stream/first_A01_t01: fail # co19-roll r546: Please triage this failure
LibTest/async/Stream/first_A02_t02: fail # co19-roll r546: Please triage this failure
@@ -598,4 +483,3 @@
LibTest/async/Stream/Stream.periodic_A02_t01: fail # co19-roll r546: Please triage this failure
LibTest/async/Timer/cancel_A01_t01: fail # co19-roll r546: Please triage this failure
LibTest/async/Timer/Timer_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/Timer/Timer.periodic_A01_t01: fail # co19-roll r546: Please triage this failure
diff --git a/tests/co19/co19-runtime.status b/tests/co19/co19-runtime.status
index 96d4ddb..c52aec6 100644
--- a/tests/co19/co19-runtime.status
+++ b/tests/co19/co19-runtime.status
@@ -2,29 +2,16 @@
# 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.
-[ $compiler == none]
-LibTest/math/max_A01_t03: Fail # co19 issue 467
-LibTest/math/min_A01_t03: Fail # co19 issue 467
-
[ $runtime == vm && $system == windows ]
LibTest/core/Stopwatch/elapsed_A01_t01: Pass, Fail # Issue 11382.
LibTest/core/Stopwatch/elapsed_A01_t03: Pass, Fail # Issue 12383.
-[ $runtime == vm ]
-Language/07_Classes/6_Constructors_A02_t01: Skip # co19 issue 415.
-
[ $compiler == none && $runtime == vm ]
# The following tests fail because they contain number literals with a + prefix (co19 issue 428)
LibTest/core/double/floor_A01_t05: Fail # co19 issue 428
LibTest/core/double/ceil_A01_t05: Fail # co19 issue 428
-Language/06_Functions/2_Formal_Parameters/2_Optional_Formals_A03_t04: Fail # Dart issue 5743
-LibTest/collection/Queue/iterator_current_A01_t02: Fail # co19 issue 475
-LibTest/collection/Queue/iterator_moveNext_A01_t02: Fail # co19 issue 475
-LibTest/core/int/toStringAsExponential_A02_t01: Fail # co19 issue 477
-
-LibTest/core/Match/pattern_A01_t01: Fail # co19 issue 422
-LibTest/core/RegExp/allMatches_A01_t01: Fail # co19 issue 422
+Language/06_Functions/2_Formal_Parameters/2_Optional_Formals_A03_t04: Fail # Issue 5743
Language/07_Classes/4_Abstract_Instance_Members_A03_t02: Fail # Dart issue 978
Language/07_Classes/4_Abstract_Instance_Members_A03_t03: Fail # Dart issue 978
@@ -33,35 +20,14 @@
Language/07_Classes/4_Abstract_Instance_Members_A04_t05: Fail # Dart issue 978
Language/07_Classes/4_Abstract_Instance_Members_A04_t06: Fail # Dart issue 978
Language/07_Classes/6_Constructors/1_Generative_Constructors_A04_t15: Fail # Dart issue 6954
-Language/07_Classes/6_Constructors/3_Constant_Constructors_A05_t01: Fail # co19 issue 426
-LibTest/core/double/parse_A02_t01: Fail # co19 issue 418
-LibTest/math/pow_A01_t01: Fail # co19 issue 44
-LibTest/math/pow_A11_t01: Fail # Dart issue 449
-LibTest/math/pow_A13_t01: Fail # Dart issue 449
+LibTest/math/pow_A18_t01: Fail # co19 issue 507
Language/05_Variables/1_Evaluation_of_Implicit_Variable_Getters_A01_t02: Fail # Dart issue 5802
Language/05_Variables/1_Evaluation_of_Implicit_Variable_Getters_A01_t05: Fail # Dart issue 5894
-LibTest/core/double/truncate_A01_t03: Fail # truncate/ceil/floor/round returns ints, co19 issue 389
-LibTest/core/double/truncate_A01_t04: Fail # truncate/ceil/floor/round returns ints, co19 issue 389
-LibTest/core/double/ceil_A01_t03: Fail # truncate/ceil/floor/round returns ints, co19 issue 389
-LibTest/core/double/ceil_A01_t04: Fail # truncate/ceil/floor/round returns ints, co19 issue 389
-LibTest/core/double/floor_A01_t03: Fail # truncate/ceil/floor/round returns ints, co19 issue 389
-LibTest/core/double/floor_A01_t04: Fail # truncate/ceil/floor/round returns ints, co19 issue 389
-LibTest/core/double/round_A01_t02: Fail # truncate/ceil/floor/round returns ints, co19 issue 389
-LibTest/core/double/round_A01_t04: Fail # truncate/ceil/floor/round returns ints, co19 issue 389
Language/06_Functions/2_Formal_Parameters/2_Optional_Formals_A03_t03: Fail # Issue 6085
-LibTest/async/Future/asStream_A01_t01: Fail # Future constructors have changed # co19 issue 408
-LibTest/async/Future/forEach_A03_t01: Fail # Future constructors have changed # co19 issue 408
-LibTest/async/Future/asStream_A01_t02: Fail # Future constructors have changed # co19 issue 408
-LibTest/async/Future/asStream_A02_t01: Fail # Future constructors have changed # co19 issue 408
-
-# Some of these tests are expected to fail for another reason. These are marked as Skip.
-Language/07_Classes/07_Classes_A02_t29: Skip # co19 issue 490
-Language/07_Classes/07_Classes_A02_t31: Skip # co19 issue 490
-
LibTest/core/RegExp/Pattern_semantics/firstMatch_Term_A03_t01: Fail # Issue 12508
LibTest/core/RegExp/Pattern_semantics/firstMatch_Atom_A02_t01: Fail # Issue 12508
LibTest/core/RegExp/Pattern_semantics/firstMatch_DecimalEscape_A01_t02: Fail # Issue 12508
@@ -77,14 +43,8 @@
LibTest/core/double/toRadixString_A01_t01: Fail # co19 issue 491
LibTest/core/int/toRadixString_A01_t01: Fail # co19 issue 492
-LibTest/math/sin_A01_t01: Pass, Fail, OK # co19 issue 44
-
-LibTest/isolate/SendPort/send_A02_t02: Skip # co19 issue 493
-
LibTest/core/String/contains_A01_t02: Fail # Issue 12508
-LibTest/isolate/SendPort/send_A02_t03: Skip # co19 issue 495
-
LibTest/isolate/ReceivePort/receive_A01_t02: Fail # VM triage, check spec.
LibTest/isolate/isolate_api/spawnUri_A02_t02: Fail # VM triage, check spec.
LibTest/isolate/isolate_api/spawnUri_A02_t03: Fail # VM triage, check spec.
@@ -94,12 +54,9 @@
LibTest/core/Iterable/where_A01_t07: Fail # Issue 397
-LibTest/core/List/getRange_A04_t01: Fail # getRange now takes end-argument and returns Iterable. Issue 399
LibTest/core/Set/isSubsetOf_A01_t01: fail # Issue 400
LibTest/core/Set/isSubsetOf_A01_t02: fail # Issue 400
-LibTest/core/Iterable/any_A01_t04: Fail # setRange now takes end-argument. Issue 402
-
LibTest/core/String/indexOf_A01_t02: Fail # Issue 427
LibTest/core/String/lastIndexOf_A01_t02: Fail # Issue 427
@@ -122,31 +79,20 @@
Language/03_Overview/1_Scoping_A02_t28: Fail # Issue 463
Language/03_Overview/2_Privacy_A01_t06: Fail # Issue 463
+LibTest/async/Timer/Timer.periodic_A02_t01: Pass, Fail # co19 issue 537
+
# end [ $compiler == none && $runtime == vm ]
[ $compiler == none && $runtime == vm && $checked ]
LibTest/async/Future/catchError_A01_t01: Fail # Future constructors have changed # issue 408
-LibTest/core/List/every_A01_t01: Fail # insertRange is removed. Issue 403
LibTest/core/List/getRange_A01_t01: Fail # getRange now takes end-argument and returns Iterable. Issue 399
-LibTest/core/Set/intersection_A03_t01: Fail # co19 issue 480
-LibTest/core/TypeError/column_A01_t01: Fail # co19 issue 479
-LibTest/core/TypeError/dstName_A01_t01: Fail # co19 issue 479
-LibTest/core/TypeError/dstType_A01_t01: Fail # co19 issue 479
-LibTest/core/TypeError/failedAssertion_A01_t01: Fail # co19 issue 479
-LibTest/core/TypeError/line_A01_t01: Fail # co19 issue 479
-LibTest/core/TypeError/srcType_A01_t01: Fail # co19 issue 479
-LibTest/core/TypeError/url_A01_t01: Fail # co19 issue 479
-LibTest/core/int/operator_division_A01_t01: Fail # ~/ returns ints, issue 361
+LibTest/core/Set/intersection_A03_t01: Fail # co19 issue 510
+LibTest/core/int/operator_division_A01_t01: Fail # co19 issue 509
LibTest/core/Set/intersection_A01_t01: Fail # issue 390
LibTest/core/Set/intersection_A01_t02: Fail # issue 390
LibTest/core/Set/intersection_A01_t03: Fail # issue 390
-LibTest/collection/Queue/Queue.from_A01_t01: Pass # Issue 400 and 463
-LibTest/collection/Queue/Queue.from_A01_t02: Pass # Issue 400 and 463
-LibTest/core/List/List.from_A01_t01: Pass # Issue 400 and 463
-LibTest/core/List/every_A01_t01: Pass # Issue 400 and 463
-LibTest/core/Match/str_A01_t01: Pass # Issue 400 and 463
# Passing for the wrong reasons:
LibTest/async/Completer/completeError_A03_t02: Pass # No AsyncError anymore. Issue 407 and 463
@@ -159,104 +105,80 @@
[ $compiler == none && $runtime == vm && $mode == debug ]
LibTest/isolate/isolate_api/spawnFunction_A02_t01: Crash
Language/12_Expressions/00_Object_Identity/1_Object_Identity_A04_t02: Crash # co19-roll r546: Please triage this failure
-LibTest/async/Stream/Stream.periodic_A01_t01: Fail # co19-roll r546: Please triage this failure
LibTest/async/Stream/Stream.periodic_A03_t01: Fail # co19-roll r546: Please triage this failure
LibTest/isolate/IsolateStream/contains_A02_t01: Fail # co19-roll r546: Please triage this failure
-[ $compiler == none && $runtime == vm && $system == macos ]
-LibTest/math/exp_A01_t01: Fail, OK # Issue co19 - 44
-LibTest/math/acos_A01_t01: Fail, OK # Issue co19 - 44
-LibTest/math/asin_A01_t01: Fail, OK # Issue co19 - 44
-LibTest/math/atan_A01_t01: Fail, OK # Issue co19 - 44
-LibTest/math/tan_A01_t01: Fail, OK # Issue co19 - 44
-
-[ $compiler == none && $runtime == vm && $system == linux ]
-LibTest/math/exp_A01_t01: Fail
-
-[ $compiler == none && $runtime == vm && $system != windows && $arch != x64 && $arch != arm ]
-LibTest/math/tan_A01_t01: Pass, Fail
-
[ $compiler == none && $runtime == vm && $arch != x64 ]
LibTest/core/int/operator_left_shift_A01_t02: Fail # co19 issue 129
-[ $compiler == none && $runtime == vm && $arch == simarm ]
-LibTest/math/cos_A01_t01: Pass, Fail # Fail on Mac
-
[ $compiler == none && $runtime == vm && $arch == mips ]
-LibTest/math/cos_A01_t01: Pass, Fail # Fail on Mac
LibTest/math/log_A01_t01: Fail
-LibTest/math/asin_A01_t01: Fail
-LibTest/math/acos_A01_t01: Fail
LibTest/core/double/toInt_A01_t01: Fail
-[ $compiler == none && $runtime == vm && $arch == simmips ]
-LibTest/math/cos_A01_t01: Pass, Fail # Fail on Mac
-
# co19-roll r546 (11.08.2013) caused these failures
[ $compiler == none && $runtime == vm ]
-Language/05_Variables/05_Variables_A05_t01: fail # co19-roll r546: Please triage this failure
-Language/05_Variables/05_Variables_A05_t02: fail # co19-roll r546: Please triage this failure
-Language/05_Variables/05_Variables_A05_t03: fail # co19-roll r546: Please triage this failure
-Language/05_Variables/05_Variables_A06_t01: fail # co19-roll r546: Please triage this failure
-Language/05_Variables/05_Variables_A06_t02: fail # co19-roll r546: Please triage this failure
-Language/05_Variables/05_Variables_A06_t03: fail # co19-roll r546: Please triage this failure
-Language/05_Variables/05_Variables_A06_t04: fail # co19-roll r546: Please triage this failure
-Language/05_Variables/05_Variables_A06_t05: fail # co19-roll r546: Please triage this failure
-Language/05_Variables/05_Variables_A06_t06: fail # co19-roll r546: Please triage this failure
-Language/05_Variables/05_Variables_A16_t02: fail # co19-roll r546: Please triage this failure
-Language/07_Classes/07_Classes_A11_t02: fail # co19-roll r546: Please triage this failure
-Language/07_Classes/07_Classes_A11_t04: fail # co19-roll r546: Please triage this failure
-Language/07_Classes/3_Setters_A08_t01: fail # co19-roll r546: Please triage this failure
-Language/07_Classes/3_Setters_A08_t02: fail # co19-roll r546: Please triage this failure
-Language/07_Classes/3_Setters_A08_t03: fail # co19-roll r546: Please triage this failure
-Language/07_Classes/3_Setters_A08_t04: fail # co19-roll r546: Please triage this failure
-Language/07_Classes/3_Setters_A08_t05: fail # co19-roll r546: Please triage this failure
-Language/07_Classes/6_Constructors/1_Generative_Constructors_A09_t01: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/01_Constants_A01_t01: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/01_Constants_A16_t01: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/01_Constants_A16_t02: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/01_Constants_A17_t03: crash # co19-roll r546: Please triage this failure
-Language/12_Expressions/03_Numbers_A01_t01: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/03_Numbers_A01_t02: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/03_Numbers_A01_t03: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/03_Numbers_A01_t04: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/03_Numbers_A01_t08: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/03_Numbers_A01_t10: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/05_Strings/1_String_Interpolation_A03_t02: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/05_Strings/1_String_Interpolation_A04_t02: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/05_Strings_A02_t46: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/05_Strings_A02_t48: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/05_Strings_A20_t01: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/07_Maps_A01_t01: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/12_Instance_Creation/1_New_A06_t12: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/12_Instance_Creation/1_New_A08_t01: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/12_Instance_Creation/1_New_A08_t02: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/12_Instance_Creation/1_New_A08_t03: fail # co19-roll r546: Please triage this failure
+Language/05_Variables/05_Variables_A05_t01: fail # Dart issue 12539
+Language/05_Variables/05_Variables_A05_t02: fail # Dart issue 12539
+Language/05_Variables/05_Variables_A05_t03: fail # Dart issue 12539
+Language/05_Variables/05_Variables_A06_t01: fail # Dart issue 12543
+Language/05_Variables/05_Variables_A06_t02: fail # Dart issue 12543
+Language/05_Variables/05_Variables_A06_t03: fail # Dart issue 12543
+Language/05_Variables/05_Variables_A06_t04: fail # Dart issue 12543
+Language/05_Variables/05_Variables_A06_t05: fail # Dart issue 12543
+Language/05_Variables/05_Variables_A06_t06: fail # Dart issue 12543
+Language/05_Variables/05_Variables_A16_t02: fail # Dart issue 12544
+Language/07_Classes/07_Classes_A11_t02: fail # Dart issue 12545
+Language/07_Classes/07_Classes_A11_t04: fail # Dart issue 12545
+Language/07_Classes/3_Setters_A08_t01: fail # co19 issue 520
+Language/07_Classes/3_Setters_A08_t02: fail # co19 issue 520
+Language/07_Classes/3_Setters_A08_t03: fail # co19 issue 520
+Language/07_Classes/3_Setters_A08_t04: fail # co19 issue 520
+Language/07_Classes/3_Setters_A08_t05: fail # co19 issue 520
+Language/07_Classes/6_Constructors/1_Generative_Constructors_A09_t01: fail # Dart issue 12543
+Language/12_Expressions/01_Constants_A01_t01: fail # co19 issue 522
+Language/12_Expressions/01_Constants_A16_t01: fail # co19 issue 525
+Language/12_Expressions/01_Constants_A16_t02: fail # co19 issue 525
+Language/12_Expressions/03_Numbers_A01_t01: fail # co19 issue 522
+Language/12_Expressions/03_Numbers_A01_t02: fail # co19 issue 522
+Language/12_Expressions/03_Numbers_A01_t03: fail # co19 issue 522
+Language/12_Expressions/03_Numbers_A01_t04: fail # co19 issue 522
+Language/12_Expressions/03_Numbers_A01_t08: fail # co19 issue 522
+Language/12_Expressions/03_Numbers_A01_t10: fail # co19 issue 522
+Language/12_Expressions/05_Strings/1_String_Interpolation_A03_t02: fail # co19 issue 397
+Language/12_Expressions/05_Strings/1_String_Interpolation_A04_t02: fail # co19 issue 397
+Language/12_Expressions/05_Strings_A02_t46: fail # Dart issue 12547
+Language/12_Expressions/05_Strings_A02_t48: fail # Dart issue 12547
+Language/12_Expressions/05_Strings_A20_t01: fail # Dart issue 12518
+Language/12_Expressions/07_Maps_A01_t01: fail # co19 issue 522
+Language/12_Expressions/12_Instance_Creation/1_New_A06_t12: fail # Dart issue 12549
+Language/12_Expressions/12_Instance_Creation/1_New_A08_t01: fail # co19 issue 397
+Language/12_Expressions/12_Instance_Creation/1_New_A08_t02: fail # co19 issue 397
+Language/12_Expressions/12_Instance_Creation/1_New_A08_t03: fail # co19 issue 397
Language/12_Expressions/12_Instance_Creation/1_New_A09_t09: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/12_Instance_Creation/2_Const_A10_t01: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/14_Function_Invocation/4_Function_Expression_Invocation_A01_t02: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/14_Function_Invocation/4_Function_Expression_Invocation_A05_t01: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/15_Method_Invocation/1_Ordinary_Invocation_A05_t02: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/15_Method_Invocation/1_Ordinary_Invocation_A05_t03: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/15_Method_Invocation/3_Static_Invocation_A04_t05: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/15_Method_Invocation/3_Static_Invocation_A04_t09: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/15_Method_Invocation/4_Super_Invocation_A02_t04: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/17_Getter_Invocation_A02_t01: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/18_Assignment_A05_t02: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/18_Assignment_A05_t04: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/18_Assignment_A05_t05: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/18_Assignment_A08_t04: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/30_Identifier_Reference_A05_t02: fail # co19-roll r546: Please triage this failure
+Language/12_Expressions/12_Instance_Creation/2_Const_A10_t01: fail # co19 issue 525
+Language/12_Expressions/14_Function_Invocation/4_Function_Expression_Invocation_A01_t02: fail # co19 issue 532
+Language/12_Expressions/14_Function_Invocation/4_Function_Expression_Invocation_A05_t01: fail # Dart issue 12550
+Language/12_Expressions/15_Method_Invocation/1_Ordinary_Invocation_A05_t02: fail # co19 issue 532
+Language/12_Expressions/15_Method_Invocation/1_Ordinary_Invocation_A05_t03: fail # co19 issue 532
+Language/12_Expressions/15_Method_Invocation/3_Static_Invocation_A04_t05: fail # co19 issue 533
+Language/12_Expressions/15_Method_Invocation/3_Static_Invocation_A04_t09: fail # Dart issue 12549
+Language/12_Expressions/15_Method_Invocation/4_Super_Invocation_A02_t04: fail # Dart issue 12549
+Language/12_Expressions/17_Getter_Invocation_A02_t01: fail # co19 issue 532
+Language/12_Expressions/18_Assignment_A05_t02: fail # co19 issue 532
+Language/12_Expressions/18_Assignment_A05_t04: fail # co19 issue 532
+Language/12_Expressions/18_Assignment_A05_t05: fail # co19 issue 532
+Language/12_Expressions/18_Assignment_A08_t04: fail # co19 issue 532
+Language/12_Expressions/30_Identifier_Reference_A05_t02: fail # Dart issue 12551
Language/12_Expressions/30_Identifier_Reference_A08_t02: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/32_Type_Test_A04_t02: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/32_Type_Test_A04_t03: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/32_Type_Test_A04_t04: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/33_Type_Cast_A03_t02: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/33_Type_Cast_A03_t03: fail # co19-roll r546: Please triage this failure
-Language/13_Statements/02_Expression_Statements_A01_t06: fail # co19-roll r546: Please triage this failure
-Language/13_Statements/03_Variable_Declaration_A04_t07: fail # co19-roll r546: Please triage this failure
-Language/13_Statements/03_Variable_Declaration_A04_t08: fail # co19-roll r546: Please triage this failure
-Language/13_Statements/06_For_A01_t11: fail # co19-roll r546: Please triage this failure
+Language/12_Expressions/32_Type_Test_A04_t02: fail # co19 issue 503
+Language/12_Expressions/32_Type_Test_A04_t03: fail # co19 issue 534
+Language/12_Expressions/32_Type_Test_A04_t04: fail # co19 issue 534
+Language/12_Expressions/33_Type_Cast_A03_t02: fail # co19 issue 534
+Language/12_Expressions/33_Type_Cast_A03_t03: fail # co19 issue 534
+Language/13_Statements/02_Expression_Statements_A01_t06: fail # co19 issue 517
+Language/13_Statements/03_Variable_Declaration_A04_t07: fail # co19 issue 535
+Language/13_Statements/03_Variable_Declaration_A04_t08: fail # co19 issue 535
+Language/13_Statements/06_For_A01_t11: fail # Dart issue 5675
Language/13_Statements/09_Switch_A01_t02: fail # co19-roll r546: Please triage this failure
Language/13_Statements/09_Switch_A02_t01: fail # co19-roll r546: Please triage this failure
Language/13_Statements/09_Switch_A02_t02: fail # co19-roll r546: Please triage this failure
@@ -286,116 +208,40 @@
Language/14_Libraries_and_Scripts/2_Exports_A04_t02: fail # co19-roll r546: Please triage this failure
Language/14_Libraries_and_Scripts/2_Exports_A04_t03: fail # co19-roll r546: Please triage this failure
Language/14_Libraries_and_Scripts/2_Exports_A05_t01: fail # co19-roll r546: Please triage this failure
-Language/14_Libraries_and_Scripts/5_URIs_A01_t01: fail # co19-roll r546: Please triage this failure
-Language/14_Libraries_and_Scripts/5_URIs_A01_t04: fail # co19-roll r546: Please triage this failure
-Language/14_Libraries_and_Scripts/5_URIs_A01_t05: fail # co19-roll r546: Please triage this failure
-Language/14_Libraries_and_Scripts/5_URIs_A01_t11: fail # co19-roll r546: Please triage this failure
-Language/14_Libraries_and_Scripts/5_URIs_A01_t14: fail # co19-roll r546: Please triage this failure
-Language/14_Libraries_and_Scripts/5_URIs_A01_t15: fail # co19-roll r546: Please triage this failure
-Language/14_Libraries_and_Scripts/5_URIs_A01_t21: fail # co19-roll r546: Please triage this failure
-Language/15_Types/1_Static_Types_A03_t01: fail # co19-roll r546: Please triage this failure
-Language/16_Reference/1_Lexical_Rules/2_Comments_A04_t03: fail # co19-roll r546: Please triage this failure
-LibTest/async/Future/asStream_A01_t01: pass # co19-roll r546: Please triage this failure
-LibTest/async/Future/asStream_A01_t02: pass # co19-roll r546: Please triage this failure
-LibTest/async/Future/asStream_A02_t01: pass # co19-roll r546: Please triage this failure
-LibTest/async/Future/forEach_A03_t01: pass # co19-roll r546: Please triage this failure
-LibTest/async/StreamSink/close_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/Stream.periodic_A01_t01: fail, pass # co19-roll r546: Please triage this failure
-LibTest/async/Stream/Stream.periodic_A03_t01: fail, pass # co19-roll r546: Please triage this failure
-LibTest/async/Timer/run_A01_t01: fail, pass # co19-roll r546: Please triage this failure
-LibTest/async/Timer/Timer_A02_t01: fail, pass # co19-roll r546: Please triage this failure
-LibTest/async/Timer/Timer_A02_t01: fail, pass # co19-roll r546: Please triage this failure
-LibTest/async/Timer/Timer.periodic_A02_t01: fail, pass # co19-roll r546: Please triage this failure
-LibTest/core/DateTime/isAtSameMomentAs_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/core/DateTime/parse_A03_t01: fail # co19-roll r546: Please triage this failure
-LibTest/core/DateTime/year_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/core/double/parse_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/core/List/getRange_A04_t01: pass # co19-roll r546: Please triage this failure
-LibTest/core/List/skip_A03_t01: fail # co19-roll r546: Please triage this failure
-LibTest/core/List/take_A02_t01: fail # co19-roll r546: Please triage this failure
+Language/14_Libraries_and_Scripts/5_URIs_A01_t01: fail # Issue 12521
+Language/14_Libraries_and_Scripts/5_URIs_A01_t04: fail # Issue 12521
+Language/14_Libraries_and_Scripts/5_URIs_A01_t05: fail # Issue 12521
+Language/14_Libraries_and_Scripts/5_URIs_A01_t11: fail # Issue 12521
+Language/14_Libraries_and_Scripts/5_URIs_A01_t14: fail # Issue 12521
+Language/14_Libraries_and_Scripts/5_URIs_A01_t15: fail # Issue 12521
+Language/14_Libraries_and_Scripts/5_URIs_A01_t21: fail # Issue 12518
+LibTest/async/StreamSink/close_A01_t01: fail # co19 503
+
+LibTest/async/Timer/Timer_A02_t01: fail, pass # co19 issue 538
+LibTest/core/DateTime/parse_A03_t01: fail # Issue 12514
LibTest/isolate/isolate_api/spawnFunction_A04_t01: fail # co19-roll r546: Please triage this failure
LibTest/isolate/isolate_api/streamSpawnFunction_A02_t01: fail # co19-roll r546: Please triage this failure
LibTest/isolate/IsolateSink/addError_A01_t01: fail # co19-roll r546: Please triage this failure
LibTest/isolate/IsolateSink/addError_A01_t02: fail # co19-roll r546: Please triage this failure
LibTest/isolate/IsolateStream/any_A02_t01: fail # co19-roll r546: Please triage this failure
LibTest/isolate/IsolateStream/contains_A02_t01: fail, pass # co19-roll r546: Please triage this failure
+LibTest/isolate/isolate_api/streamSpawnFunction_A02_t03: fail, pass # co19-roll r546: Please triage this failure
LibTest/isolate/SendPort/send_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/isolate/SendPort/send_A02_t04: fail # co19-roll r546: Please triage this failure
-Utils/tests/Expect/listEquals_A02_t01: fail # co19-roll r546: Please triage this failure
-Utils/tests/Expect/listEquals_A03_t01: fail # co19-roll r546: Please triage this failure
-Utils/tests/Expect/setEquals_A02_t01: fail # co19-roll r546: Please triage this failure
+LibTest/isolate/SendPort/send_A02_t04: fail # co19 issue 501
-
-# co19-roll r546 (11.08.2013) caused these failures
[ $compiler == none && $runtime == vm && $checked ]
-Language/12_Expressions/12_Instance_Creation_A01_t08: fail # co19-roll r546: Please triage this failure
-Language/13_Statements/09_Switch_A05_t01: fail # co19-roll r546: Please triage this failure
-Language/14_Libraries_and_Scripts/1_Imports_A03_t26: fail # co19-roll r546: Please triage this failure
-Language/15_Types/1_Static_Types_A03_t03: fail # co19-roll r546: Please triage this failure
-Language/15_Types/1_Static_Types_A03_t04: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/asBroadcastStream_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/contains_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/contains_A02_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/distinct_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/drain_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/firstWhere_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/firstWhere_A02_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/first_A03_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/fold_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/fold_A01_t02: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/forEach_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/forEach_A02_t02: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/handleError_A02_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/isBroadcast_A01_t02: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/lastWhere_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/lastWhere_A02_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/listen_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/listen_A02_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/listen_A03_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/map_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/reduce_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/reduce_A01_t02: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/singleWhere_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/skip_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/take_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/take_A01_t02: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/toList_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/toSet_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/transform_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/where_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/where_A01_t02: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/drain_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/firstWhere_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/firstWhere_A02_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/fold_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/fold_A01_t02: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/lastWhere_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/lastWhere_A02_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/reduce_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/reduce_A01_t02: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/singleWhere_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/take_A01_t02: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/transform_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/where_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/where_A01_t02: fail # co19-roll r546: Please triage this failure
-LibTest/async/StreamEventTransformer/bind_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/core/DateTime/compareTo_A02_t01: fail # co19-roll r546: Please triage this failure
-LibTest/core/List/join_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/core/List/removeAt_A02_t01: fail # co19-roll r546: Please triage this failure
+Language/12_Expressions/12_Instance_Creation_A01_t08: FAIL, OK # co19 issue 498
LibTest/core/Set/intersection_A01_t01: pass # co19-roll r546: Please triage this failure
LibTest/core/Set/intersection_A01_t03: pass # co19-roll r546: Please triage this failure
LibTest/core/Set/intersection_A03_t01: pass # co19-roll r546: Please triage this failure
-LibTest/core/int/ceilToDouble_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/core/int/floorToDouble_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/core/int/roundToDouble_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/core/int/truncateToDouble_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/isolate/IsolateStream/last_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/isolate/IsolateStream/length_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/isolate/IsolateStream/single_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/isolate/isolate_api/spawnFunction_A03_t01: fail # co19-roll r546: Please triage this failure
+LibTest/core/int/ceilToDouble_A01_t01: fail # co19 issue 498
+LibTest/core/int/floorToDouble_A01_t01: fail # co19 issue 498
+LibTest/core/int/roundToDouble_A01_t01: fail # co19 issue 498
+LibTest/core/int/truncateToDouble_A01_t01: fail # co19 issue 498
+LibTest/isolate/isolate_api/spawnFunction_A03_t01: fail # co19 issue 497
# co19-roll r546 (11.08.2013) caused these failures
[ $compiler == none && $runtime == vm && $unchecked ]
-Language/12_Expressions/12_Instance_Creation/2_Const_A09_t02: Fail # co19-roll r546: Please triage this failure
+Language/12_Expressions/12_Instance_Creation/2_Const_A09_t02: Fail # co19 issue 496
diff --git a/tests/co19/test_config.dart b/tests/co19/test_config.dart
index ec8cc08..5756107 100644
--- a/tests/co19/test_config.dart
+++ b/tests/co19/test_config.dart
@@ -14,7 +14,8 @@
: super(configuration,
"co19",
new Path("tests/co19/src"),
- ["tests/co19/co19-analyzer.status",
+ ["tests/co19/co19-co19.status",
+ "tests/co19/co19-analyzer.status",
"tests/co19/co19-analyzer2.status",
"tests/co19/co19-runtime.status",
"tests/co19/co19-dart2dart.status",
diff --git a/tests/compiler/dart2js/import_test.dart b/tests/compiler/dart2js/import_test.dart
new file mode 100644
index 0000000..54748c4
--- /dev/null
+++ b/tests/compiler/dart2js/import_test.dart
@@ -0,0 +1,49 @@
+// 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.
+
+// Test that the compiler can handle missing files used in imports, exports,
+// part tags or as the main source file.
+
+library dart2js.test.import;
+
+import 'package:expect/expect.dart';
+import 'memory_compiler.dart';
+
+const MEMORY_SOURCE_FILES = const {
+ 'main.dart': '''
+
+library main;
+
+import 'dart:thisLibraryShouldNotExist';
+import 'package:thisPackageShouldNotExist/thisPackageShouldNotExist.dart';
+export 'foo.dart';
+
+part 'bar.dart';
+
+main() {
+ int i = "";
+}
+''',
+};
+
+testMissingImports() {
+ var collector = new DiagnosticCollector();
+ var compiler = compilerFor(MEMORY_SOURCE_FILES, diagnosticHandler: collector);
+ compiler.run(Uri.parse('memory:main.dart'));
+ Expect.equals(4, collector.errors.length);
+ Expect.equals(1, collector.warnings.length);
+}
+
+testMissingMain() {
+ var collector = new DiagnosticCollector();
+ var compiler = compilerFor({}, diagnosticHandler: collector);
+ compiler.run(Uri.parse('memory:missing.dart'));
+ Expect.equals(1, collector.errors.length);
+ Expect.equals(0, collector.warnings.length);
+}
+
+void main() {
+ testMissingImports();
+ testMissingMain();
+}
diff --git a/tests/compiler/dart2js/library_load_test.dart b/tests/compiler/dart2js/library_load_test.dart
new file mode 100644
index 0000000..36c9adf
--- /dev/null
+++ b/tests/compiler/dart2js/library_load_test.dart
@@ -0,0 +1,34 @@
+// 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 'mock_compiler.dart';
+
+class ScanMockCompiler extends MockCompiler {
+ ScanMockCompiler() {
+ isolateHelperLibrary = null;
+ foreignLibrary = null;
+ }
+
+ LibraryElement scanBuiltinLibrary(String filename) {
+ return createLibrary(filename, "main(){}");
+ }
+}
+
+void main() {
+ Compiler compiler = new ScanMockCompiler();
+ Expect.equals(null, compiler.isolateHelperLibrary);
+ Expect.equals(null, compiler.foreignLibrary);
+ compiler.onLibraryLoaded(mockLibrary(compiler, "mock"),
+ new Uri(scheme: 'dart', path: '_isolate_helper'));
+ Expect.isTrue(compiler.isolateHelperLibrary != null);
+ compiler.onLibraryLoaded(mockLibrary(compiler, "mock"),
+ new Uri(scheme: 'dart', path: '_foreign_helper'));
+ Expect.isTrue(compiler.isolateHelperLibrary != null);
+ Expect.equals(new Uri(scheme: 'dart', path: '_isolate_helper'),
+ compiler.isolateHelperLibrary.canonicalUri);
+ Expect.isTrue(compiler.foreignLibrary != null);
+ Expect.equals(new Uri(scheme: 'dart', path: '_foreign_helper'),
+ compiler.foreignLibrary.canonicalUri);
+}
diff --git a/tests/compiler/dart2js/memory_compiler.dart b/tests/compiler/dart2js/memory_compiler.dart
index 5418963..04a95df 100644
--- a/tests/compiler/dart2js/memory_compiler.dart
+++ b/tests/compiler/dart2js/memory_compiler.dart
@@ -11,35 +11,91 @@
show NullSink;
import '../../../sdk/lib/_internal/compiler/compiler.dart'
- show DiagnosticHandler;
+ show Diagnostic, DiagnosticHandler;
import 'dart:async';
import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart';
import '../../../sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart';
+class DiagnosticMessage {
+ final Uri uri;
+ final int begin;
+ final int end;
+ final String message;
+ final Diagnostic kind;
+
+ DiagnosticMessage(this.uri, this.begin, this.end, this.message, this.kind);
+}
+
+class DiagnosticCollector {
+ List<DiagnosticMessage> messages = <DiagnosticMessage>[];
+
+ void call(Uri uri, int begin, int end, String message,
+ Diagnostic kind) {
+ messages.add(new DiagnosticMessage(uri, begin, end, message, kind));
+ }
+
+ Iterable<DiagnosticMessage> filterMessagesByKind(Diagnostic kind) {
+ return messages.where(
+ (DiagnosticMessage message) => message.kind == kind);
+ }
+
+ Iterable<DiagnosticMessage> get errors {
+ return filterMessagesByKind(Diagnostic.ERROR);
+ }
+
+ Iterable<DiagnosticMessage> get warnings {
+ return filterMessagesByKind(Diagnostic.WARNING);
+ }
+
+ Iterable<DiagnosticMessage> get hints {
+ return filterMessagesByKind(Diagnostic.HINT);
+ }
+}
+
+DiagnosticHandler createDiagnosticHandler(DiagnosticHandler diagnosticHandler,
+ SourceFileProvider provider,
+ bool showDiagnostics) {
+ var handler = diagnosticHandler;
+ if (showDiagnostics) {
+ if (diagnosticHandler == null) {
+ handler = new FormattingDiagnosticHandler(provider);
+ } else {
+ var formattingHandler = new FormattingDiagnosticHandler(provider);
+ handler = (Uri uri, int begin, int end, String message, Diagnostic kind) {
+ diagnosticHandler(uri, begin, end, message, kind);
+ formattingHandler(uri, begin, end, message, kind);
+ };
+ }
+ } else if (diagnosticHandler == null) {
+ handler = (Uri uri, int begin, int end, String message, Diagnostic kind) {};
+ }
+ return handler;
+}
+
Compiler compilerFor(Map<String,String> memorySourceFiles,
{DiagnosticHandler diagnosticHandler,
List<String> options: const [],
- Compiler cachedCompiler}) {
+ Compiler cachedCompiler,
+ bool showDiagnostics: true}) {
Uri script = currentDirectory.resolve(nativeToUriPath(Platform.script));
Uri libraryRoot = script.resolve('../../../sdk/');
Uri packageRoot = script.resolve('./packages/');
MemorySourceFileProvider.MEMORY_SOURCE_FILES = memorySourceFiles;
var provider = new MemorySourceFileProvider();
- if (diagnosticHandler == null) {
- diagnosticHandler = new FormattingDiagnosticHandler(provider);
- }
+ var handler =
+ createDiagnosticHandler(diagnosticHandler, provider, showDiagnostics);
EventSink<String> outputProvider(String name, String extension) {
if (name != '') throw 'Attempt to output file "$name.$extension"';
return new NullSink('$name.$extension');
}
- Compiler compiler = new Compiler(provider.readStringFromUri,
+ Compiler compiler = new Compiler(provider,
outputProvider,
- diagnosticHandler,
+ handler,
libraryRoot,
packageRoot,
options);
@@ -49,7 +105,7 @@
cachedCompiler.libraries.forEach((String uri, library) {
if (library.isPlatformLibrary) {
compiler.libraries[uri] = library;
- compiler.onLibraryScanned(library, library.canonicalUri);
+ compiler.onLibraryLoaded(library, library.canonicalUri);
}
});
@@ -79,16 +135,16 @@
Future<MirrorSystem> mirrorSystemFor(Map<String,String> memorySourceFiles,
{DiagnosticHandler diagnosticHandler,
- List<String> options: const []}) {
+ List<String> options: const [],
+ bool showDiagnostics: true}) {
Uri script = currentDirectory.resolve(nativeToUriPath(Platform.script));
Uri libraryRoot = script.resolve('../../../sdk/');
Uri packageRoot = script.resolve('./packages/');
MemorySourceFileProvider.MEMORY_SOURCE_FILES = memorySourceFiles;
var provider = new MemorySourceFileProvider();
- if (diagnosticHandler == null) {
- diagnosticHandler = new FormattingDiagnosticHandler(provider);
- }
+ var handler =
+ createDiagnosticHandler(diagnosticHandler, provider, showDiagnostics);
List<Uri> libraries = <Uri>[];
memorySourceFiles.forEach((String path, _) {
@@ -96,5 +152,5 @@
});
return analyze(libraries, libraryRoot, packageRoot,
- provider, diagnosticHandler, options);
+ provider, handler, options);
}
diff --git a/tests/compiler/dart2js/memory_source_file_helper.dart b/tests/compiler/dart2js/memory_source_file_helper.dart
index 987fff7..f8ecb27 100644
--- a/tests/compiler/dart2js/memory_source_file_helper.dart
+++ b/tests/compiler/dart2js/memory_source_file_helper.dart
@@ -21,7 +21,7 @@
show SourceFileProvider;
export '../../../sdk/lib/_internal/compiler/implementation/source_file_provider.dart'
- show FormattingDiagnosticHandler;
+ show SourceFileProvider, FormattingDiagnosticHandler;
class MemorySourceFileProvider extends SourceFileProvider {
static Map MEMORY_SOURCE_FILES;
diff --git a/tests/compiler/dart2js/message_kind_helper.dart b/tests/compiler/dart2js/message_kind_helper.dart
index f972a96..6302bf1 100644
--- a/tests/compiler/dart2js/message_kind_helper.dart
+++ b/tests/compiler/dart2js/message_kind_helper.dart
@@ -14,8 +14,13 @@
const String ESCAPE_REGEXP = r'[[\]{}()*+?.\\^$|]';
-Compiler check(MessageKind kind, Compiler cachedCompiler) {
- Expect.isNotNull(kind.howToFix);
+Compiler check(MessageKind kind, Compiler cachedCompiler,
+ {bool expectNoHowToFix: false}) {
+ if (expectNoHowToFix) {
+ Expect.isNull(kind.howToFix);
+ } else {
+ Expect.isNotNull(kind.howToFix);
+ }
Expect.isFalse(kind.examples.isEmpty);
for (String example in kind.examples) {
@@ -37,7 +42,9 @@
Expect.isFalse(messages.isEmpty, 'No messages in """$example"""');
- String pattern = '${kind.template}\n${kind.howToFix}'.replaceAllMapped(
+ String expectedText = kind.howToFix == null
+ ? kind.template : '${kind.template}\n${kind.howToFix}';
+ String pattern = expectedText.replaceAllMapped(
new RegExp(ESCAPE_REGEXP), (m) => '\\${m[0]}');
pattern = pattern.replaceAll(new RegExp(r'#\\\{[^}]*\\\}'), '.*');
diff --git a/tests/compiler/dart2js/message_kind_test.dart b/tests/compiler/dart2js/message_kind_test.dart
index 55f9bed..6a2e641 100644
--- a/tests/compiler/dart2js/message_kind_test.dart
+++ b/tests/compiler/dart2js/message_kind_test.dart
@@ -27,9 +27,15 @@
}
});
List<String> names = kinds.keys.toList()..sort();
- List<String> examples = <String>[];
+ Map<String, bool> examples = <String, bool>{};
for (String name in names) {
MessageKind kind = kinds[name];
+ bool expectNoHowToFix = false;
+ if (name == 'READ_SCRIPT_ERROR') {
+ // For this we can give no how-to-fix since the underlying error is
+ // unknown.
+ expectNoHowToFix = true;
+ }
if (name == 'GENERIC' // Shouldn't be used.
// We can't provoke a crash.
|| name == 'COMPILER_CRASHED'
@@ -37,16 +43,17 @@
// We cannot provide examples for patch errors.
|| name.startsWith('PATCH_')) continue;
if (kind.examples != null) {
- examples.add(name);
+ examples[name] = expectNoHowToFix;
} else {
print("No example in '$name'");
}
};
var cachedCompiler;
- for (String name in examples) {
+ examples.forEach((String name, bool expectNoHowToFix) {
Stopwatch sw = new Stopwatch()..start();
- cachedCompiler = check(kinds[name], cachedCompiler);
+ cachedCompiler = check(kinds[name], cachedCompiler,
+ expectNoHowToFix: expectNoHowToFix);
sw.stop();
print("Checked '$name' in ${sw.elapsedMilliseconds}ms.");
- }
+ });
}
diff --git a/tests/compiler/dart2js/mirror_helper_unique_minification_test.dart b/tests/compiler/dart2js/mirror_helper_unique_minification_test.dart
new file mode 100644
index 0000000..35885cd
--- /dev/null
+++ b/tests/compiler/dart2js/mirror_helper_unique_minification_test.dart
@@ -0,0 +1,63 @@
+// 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 'memory_compiler.dart' show compilerFor;
+import '../../../sdk/lib/_internal/compiler/implementation/apiimpl.dart' show
+ Compiler;
+import
+ '../../../sdk/lib/_internal/compiler/implementation/dart_backend/dart_backend.dart'
+show
+ DartBackend;
+
+main() {
+ testUniqueMinification();
+ testNoUniqueMinification();
+}
+
+Compiler runCompiler({useMirrorHelperLibrary: false, minify: false}) {
+ List<String> options = ['--output-type=dart'];
+ if (minify) {
+ options.add('--minify');
+ }
+ Compiler compiler = compilerFor(MEMORY_SOURCE_FILES, options: options);
+ DartBackend backend = compiler.backend;
+ backend.useMirrorHelperLibrary = useMirrorHelperLibrary;
+ compiler.runCompiler(Uri.parse('memory:main.dart'));
+ return compiler;
+}
+
+void testUniqueMinification() {
+ Compiler compiler = runCompiler(useMirrorHelperLibrary: true, minify: true);
+ DartBackend backend = compiler.backend;
+ Map<Node, String> renames = backend.renames;
+
+ //'Foo' appears twice, so toSet() reduces the length by 1.
+ Expect.equals(renames.values.toSet().length, renames.values.length - 1);
+}
+
+void testNoUniqueMinification() {
+ Compiler compiler = runCompiler(useMirrorHelperLibrary: false, minify: true);
+ DartBackend backend = compiler.backend;
+ Map<Node, String> renames = backend.renames;
+
+ //'Foo' appears twice and now 'invocation' and 'hest' can get the same 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(const Symbol('hest'));
+ }
+}
+
+main() {
+ new Foo().fisk();
+ var hest;
+}
+"""};
diff --git a/tests/compiler/dart2js/mock_compiler.dart b/tests/compiler/dart2js/mock_compiler.dart
index 2d72fc5..688f4bc 100644
--- a/tests/compiler/dart2js/mock_compiler.dart
+++ b/tests/compiler/dart2js/mock_compiler.dart
@@ -154,6 +154,8 @@
class JSNull extends Interceptor {
bool operator==(other) => identical(null, other);
get hashCode => throw "JSNull.hashCode not implemented.";
+ String toString() => 'Null';
+ Type get runtimeType => null;
}
class JSBool extends Interceptor implements bool {
}
diff --git a/tests/compiler/dart2js/simple_inferrer_test.dart b/tests/compiler/dart2js/simple_inferrer_test.dart
index 74194b5..5eb96d2 100644
--- a/tests/compiler/dart2js/simple_inferrer_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_test.dart
@@ -426,6 +426,29 @@
return a;
}
+testSpecialization1() {
+ var a = topLevelGetter();
+ a - 42;
+ return a;
+}
+
+testSpecialization2() {
+ var a = topLevelGetter();
+ // Make [a] a captured variable. This should disable receiver
+ // specialization on [a].
+ (() => a.toString())();
+ a - 42;
+ return a;
+}
+
+testSpecialization3() {
+ var a = returnDynamic() ? null : 42;
+ a.toString();
+ // Test that calling an [Object] method on [a] will not lead to
+ // infer that [a] is not null;
+ return a;
+}
+
testReturnInvokeDynamicGetter() => new A().myFactory();
var topLevelConstList = const [42];
@@ -565,6 +588,9 @@
testReturnInvokeDynamicGetter();
testCascade1();
testCascade2();
+ testSpecialization1();
+ testSpecialization2();
+ testSpecialization3();
}
""";
@@ -687,4 +713,7 @@
checkReturn('testCascade1', typesTask.growableListType);
checkReturn('testCascade2', new TypeMask.nonNullExact(
typesTask.rawTypeOf(findElement(compiler, 'CascadeHelper'))));
+ checkReturn('testSpecialization1', typesTask.numType);
+ checkReturn('testSpecialization2', typesTask.dynamicType);
+ checkReturn('testSpecialization3', typesTask.intType.nullable());
}
diff --git a/tests/compiler/dart2js_extra/dart2js_extra.status b/tests/compiler/dart2js_extra/dart2js_extra.status
index 3824d9e..4e70d58 100644
--- a/tests/compiler/dart2js_extra/dart2js_extra.status
+++ b/tests/compiler/dart2js_extra/dart2js_extra.status
@@ -15,7 +15,6 @@
deferred/deferred_class_test: Pass, Crash # Issue 9158
[ $compiler == dart2js && $checked ]
-parameter_bailout_test: Fail, OK
variable_type_test/03: Fail, OK
variable_type_test/01: Fail, OK
diff --git a/tests/corelib/corelib.status b/tests/corelib/corelib.status
index d2fd801..ecd14b0 100644
--- a/tests/corelib/corelib.status
+++ b/tests/corelib/corelib.status
@@ -4,14 +4,13 @@
reg_exp_unicode_2_test: Fail # Bug 6592
-[ $compiler == dart2js && ($runtime == d8 || $runtime == drt) ]
+[ $compiler == dart2js && $runtime == drt ]
hash_set_test: Pass, Fail # v8 bug: Issue 12293
list_test: Pass, Fail # v8 bug: Issue 12293
[ $compiler == none ]
unicode_test: Fail # Bug 6706
-*dartc_test: Skip
compare_to2_test: Fail # Bug 4018
symbol_test/01: Fail, Pass # bug 11669
@@ -42,12 +41,6 @@
date_time7_test: Fail
unicode_test: Fail
-[ $runtime == ie9 && ($system == linux || $system == macos) ]
-*: Skip
-
-[ $runtime == safari && ($system == linux || $system == windows) ]
-*: Skip
-
[ $runtime == vm ]
string_trim_unicode_test: Fail # Bug 6569
diff --git a/tests/html/async_test.dart b/tests/html/async_test.dart
index 1d7768f..616258c 100644
--- a/tests/html/async_test.dart
+++ b/tests/html/async_test.dart
@@ -40,10 +40,8 @@
cancellingIsolate() {
port.receive((msg, replyTo) {
expect(msg, 'START');
- final oneshot = new Timer(const Duration(milliseconds: 30), () {
- fail('Should never be invoked');
- });
bool shot = false;
+ var oneshot;
var periodic;
periodic = new Timer.periodic(const Duration(milliseconds: 10), (timer) {
expect(shot, isFalse);
@@ -57,6 +55,13 @@
replyTo.send('DONE');
});
});
+ // We launch the oneshot timer after the periodic timer. Otherwise a
+ // (very long) context switch could make this test flaky: assume the
+ // oneshot timer is created first and then there is a 30ms context switch.
+ // when the periodic timer is scheduled it would execute after the oneshot.
+ oneshot = new Timer(const Duration(milliseconds: 30), () {
+ fail('Should never be invoked');
+ });
});
}
diff --git a/tests/html/custom/attribute_changed_callback_test.dart b/tests/html/custom/attribute_changed_callback_test.dart
new file mode 100644
index 0000000..3e78587
--- /dev/null
+++ b/tests/html/custom/attribute_changed_callback_test.dart
@@ -0,0 +1,76 @@
+// 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 attribute_changed_callback_test;
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
+import 'dart:html';
+
+class A extends HtmlElement {
+ static final tag = 'x-a';
+ factory A() => new Element.tag(tag);
+
+ static var attributeChangedInvocations = 0;
+
+ void onAttributeChanged(name, oldValue, newValue) {
+ attributeChangedInvocations++;
+ }
+}
+
+class B extends HtmlElement {
+ static final tag = 'x-b';
+ factory B() => new Element.tag(tag);
+
+ static var invocations = [];
+
+ void onCreated() {
+ invocations.add('created');
+ }
+
+ void onAttributeChanged(name, oldValue, newValue) {
+ invocations.add('$name: $oldValue => $newValue');
+ }
+}
+
+main() {
+ useHtmlConfiguration();
+
+ // Adapted from Blink's fast/dom/custom/attribute-changed-callback test.
+
+ test('transfer attribute changed callback', () {
+ document.register(A.tag, A);
+ var element = new A();
+
+ element.attributes['a'] = 'b';
+ expect(A.attributeChangedInvocations, 1);
+ });
+
+ test('add, change and remove an attribute', () {
+ document.register(B.tag, B);
+ var b = new B();
+ b.id = 'x';
+ expect(B.invocations, ['created', 'id: null => x']);
+
+ B.invocations = [];
+ b.attributes.remove('id');
+ expect(B.invocations, ['id: x => null']);
+
+ B.invocations = [];
+ b.attributes['data-s'] = 't';
+ expect(B.invocations, ['data-s: null => t']);
+
+ B.invocations = [];
+ b.classList.toggle('u');
+ expect(B.invocations, ['class: null => u']);
+
+ b.attributes['data-v'] = 'w';
+ B.invocations = [];
+ b.attributes['data-v'] = 'x';
+ expect(B.invocations, ['data-v: w => x']);
+
+ B.invocations = [];
+ b.attributes['data-v'] = 'x';
+ expect(B.invocations, []);
+ });
+}
diff --git a/tests/html/custom/constructor_calls_created_synchronously_test.dart b/tests/html/custom/constructor_calls_created_synchronously_test.dart
new file mode 100644
index 0000000..ae11d86
--- /dev/null
+++ b/tests/html/custom/constructor_calls_created_synchronously_test.dart
@@ -0,0 +1,32 @@
+// 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 constructor_calls_created_synchronously_test;
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
+import 'dart:html';
+
+class A extends HtmlElement {
+ static final tag = 'x-a';
+ factory A() => new Element.tag(tag);
+
+ static int ncallbacks = 0;
+
+ void onCreated() {
+ ncallbacks++;
+ }
+}
+
+main() {
+ useHtmlConfiguration();
+
+ // Adapted from Blink's
+ // fast/dom/custom/constructor-calls-created-synchronously test.
+
+ test('createdCallback', () {
+ document.register(A.tag, A);
+ var x = new A();
+ expect(A.ncallbacks, 1);
+ });
+}
diff --git a/tests/html/custom/created_callback_test.dart b/tests/html/custom/created_callback_test.dart
new file mode 100644
index 0000000..2f3cd51
--- /dev/null
+++ b/tests/html/custom/created_callback_test.dart
@@ -0,0 +1,87 @@
+// 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 created_callback_test;
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
+import 'dart:html';
+
+class A extends HtmlElement {
+ static final tag = 'x-a';
+ factory A() => new Element.tag(tag);
+
+ static int createdInvocations = 0;
+
+ void onCreated() {
+ createdInvocations++;
+ }
+}
+
+class B extends HtmlElement {
+ static final tag = 'x-b';
+ factory B() => new Element.tag(tag);
+}
+
+class C extends HtmlElement {
+ static final tag = 'x-c';
+ factory C() => new Element.tag(tag);
+
+ static int createdInvocations = 0;
+ static var div;
+
+ void onCreated() {
+ createdInvocations++;
+
+ if (this.id != 'u') {
+ return;
+ }
+
+ var t = div.query('#t');
+ var v = div.query('#v');
+ var w = div.query('#w');
+
+ expect(query('x-b:not(:unresolved)'), this);
+ expect(queryAll(':unresolved'), [v, w]);
+
+ // As per:
+ // http://www.w3.org/TR/2013/WD-custom-elements-20130514/#serializing-and-parsing
+ // creation order is t, u, v, w (postorder).
+ expect(t is C, isTrue);
+ // Note, this is different from JavaScript where this would be false.
+ expect(v is C, isTrue);
+ }
+}
+
+main() {
+ useHtmlConfiguration();
+
+ // Adapted from Blink's
+ // fast/dom/custom/created-callback test.
+
+ test('transfer created callback', () {
+ document.register(A.tag, A);
+ var x = new A();
+ expect(A.createdInvocations, 1);
+ });
+
+ test(':unresolved and created callback timing', () {
+ document.register(B.tag, B);
+ document.register(C.tag, C);
+
+ var div = new DivElement();
+ C.div = div;
+ div.innerHtml = """
+<x-c id="t"></x-c>
+<x-b id="u"></x-b>
+<x-c id="v"></x-c>
+<x-b id="w"></x-b>
+""";
+
+ expect(C.createdInvocations, 2);
+ expect(div.query('#w') is B, isTrue);
+ });
+
+ // TODO(vsm): Port additional test from upstream here:
+ // http://src.chromium.org/viewvc/blink/trunk/LayoutTests/fast/dom/custom/created-callback.html?r1=156141&r2=156185
+}
diff --git a/tests/html/custom/document_register_basic_test.dart b/tests/html/custom/document_register_basic_test.dart
new file mode 100644
index 0000000..718358a
--- /dev/null
+++ b/tests/html/custom/document_register_basic_test.dart
@@ -0,0 +1,131 @@
+// 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 document_register_basic_test;
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
+import 'dart:html';
+
+class Foo extends HtmlElement {
+ static final tag = 'x-foo';
+ factory Foo() => new Element.tag(tag);
+
+ get thisIsACustomClass => true;
+}
+
+class Bar extends HtmlElement {
+ static final tag = 'x-bar';
+ factory Bar() => new Element.tag(tag);
+
+ get thisIsACustomClass => true;
+}
+
+class Baz extends Foo {
+ static final tag = 'x-baz';
+ factory Baz() => new Element.tag(tag);
+
+ get thisIsAlsoACustomClass => true;
+}
+
+class BadB {
+}
+
+class BadE implements HtmlElement {
+ static final tag = 'x-tag-e';
+ factory BadE() => new Element.tag(tag);
+}
+
+main() {
+ useHtmlConfiguration();
+
+ // Adapted from Blink's fast/dom/custom/document-register-basic test.
+
+ test('Testing document.register() basic behaviors', () {
+ document.register(Foo.tag, Foo);
+
+ // Cannot register an existing dart:html type.
+ expect(() => document.register('x-bad-a', HtmlElement), throws);
+
+ // Invalid user type. Doesn't inherit from HtmlElement.
+ expect(() => document.register('x-bad-b', BadB), throws);
+
+ // Not a type.
+ expect(() => document.register('x-bad-c', null), throws);
+
+ // Cannot register system type.
+ expect(() => document.register('x-bad-d', Object), throws);
+
+ // Must extend HtmlElement, not just implement it.
+ expect(() => document.register(BadE.tag, BadE), throws);
+
+ // Constructor initiated instantiation
+ var createdFoo = new Foo();
+ expect(createdFoo.thisIsACustomClass, isTrue);
+
+ // Dart type correctness
+ expect(createdFoo is HtmlElement, isTrue);
+ expect(createdFoo is Foo, isTrue);
+ expect(createdFoo.runtimeType, Foo);
+
+ // Native getter
+ expect(createdFoo.tagName, "X-FOO");
+
+ // Native setter
+ createdFoo.innerHtml = "Hello";
+ expect(createdFoo.text, "Hello");
+
+ // Native method
+ var childDiv = new DivElement();
+ createdFoo.append(childDiv);
+ expect(createdFoo.lastChild, childDiv);
+
+ // Parser initiated instantiation
+ var container = new DivElement()..id = "container";
+ document.body.append(container);
+ container.innerHtml = "<x-foo></x-foo>";
+ var parsedFoo = container.firstChild;
+
+ expect(parsedFoo is Foo, isTrue);
+ expect(parsedFoo.tagName, "X-FOO");
+
+ // Ensuring the wrapper is retained
+ var someProperty = new Expando();
+ someProperty[parsedFoo] = "hello";
+ expect(container.firstChild, parsedFoo);
+ expect(someProperty[container.firstChild], someProperty[parsedFoo]);
+
+ // Having another constructor
+ document.register(Bar.tag, Bar);
+ var createdBar = new Bar();
+ expect(createdBar is Bar, isTrue);
+ expect(createdBar is Foo, isFalse);
+ expect(createdBar.tagName, "X-BAR");
+
+ // Having a subclass
+ document.register(Baz.tag, Baz);
+ var createdBaz = new Baz();
+ expect(createdBaz.tagName, "X-BAZ");
+ expect(createdBaz.thisIsACustomClass, isTrue);
+ expect(createdBaz.thisIsAlsoACustomClass, isTrue);
+
+ // With irregular cases
+ var createdUpperBar = new Element.tag("X-BAR");
+ var createdMixedBar = new Element.tag("X-Bar");
+ expect(createdUpperBar is Bar, isTrue);
+ expect(createdUpperBar.tagName, "X-BAR");
+ expect(createdMixedBar is Bar, isTrue);
+ expect(createdMixedBar.tagName, "X-BAR");
+
+ container.innerHtml = "<X-BAR></X-BAR><X-Bar></X-Bar>";
+ expect(container.firstChild is Bar, isTrue);
+ expect(container.firstChild.tagName, "X-BAR");
+ expect(container.lastChild is Bar, isTrue);
+ expect(container.lastChild.tagName, "X-BAR");
+
+ // Constructors shouldn't interfere with each other
+ expect((new Foo()).tagName, "X-FOO");
+ expect((new Bar()).tagName, "X-BAR");
+ expect((new Baz()).tagName, "X-BAZ");
+ });
+}
diff --git a/tests/html/custom/document_register_type_extensions_test.dart b/tests/html/custom/document_register_type_extensions_test.dart
new file mode 100644
index 0000000..cacb251
--- /dev/null
+++ b/tests/html/custom/document_register_type_extensions_test.dart
@@ -0,0 +1,197 @@
+// 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 document_register_type_extensions_test;
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
+import 'dart:html';
+
+class Foo extends HtmlElement {
+ static final tag = 'x-foo';
+ factory Foo() => new Element.tag(tag);
+}
+
+class Bar extends InputElement {
+ static final tag = 'x-bar';
+ factory Bar() => document.$dom_createElement('input', tag);
+}
+
+class Baz extends Foo {
+ static final tag = 'x-baz';
+ factory Baz() => new Element.tag(tag);
+}
+
+class Qux extends Bar {
+ static final tag = 'x-qux';
+ factory Qux() => document.$dom_createElement('input', tag);
+}
+
+class FooBad extends DivElement {
+ static final tag = 'x-foo';
+ factory FooBad() => document.$dom_createElement('div', tag);
+}
+
+main() {
+ useHtmlConfiguration();
+
+ // Adapted from Blink's fast/dom/custom/document-register-type-extension test.
+
+ var testForm = new FormElement()..id = 'testForm';
+ document.body.append(testForm);
+
+ var isFormControl = (element) {
+ testForm.append(element);
+ return element.form == testForm;
+ };
+
+ test('construction', () {
+ document.register(Foo.tag, Foo);
+ document.register(Bar.tag, Bar);
+ document.register(Baz.tag, Baz);
+ document.register(Qux.tag, Qux);
+
+ expect(() => document.register(FooBad.tag, Foo), throws);
+
+ // Constructors
+
+ var fooNewed = new Foo();
+ var fooOuterHtml = "<x-foo></x-foo>";
+ expect(fooNewed.outerHtml, fooOuterHtml);
+ expect(fooNewed is Foo, isTrue);
+ expect(fooNewed is HtmlElement, isTrue);
+ expect(fooNewed is UnknownElement, isFalse);
+
+ var barNewed = new Bar();
+ var barOuterHtml = '<input is="x-bar">';
+ expect(barNewed.outerHtml, barOuterHtml);
+ expect(barNewed is Bar, isTrue);
+ expect(barNewed is InputElement, isTrue);
+ expect(isFormControl(barNewed), isTrue);
+
+ var bazNewed = new Baz();
+ var bazOuterHtml = "<x-baz></x-baz>";
+ expect(bazNewed.outerHtml, bazOuterHtml);
+ expect(bazNewed is Baz, isTrue);
+ expect(bazNewed is HtmlElement, isTrue);
+ expect(bazNewed is UnknownElement, isFalse);
+
+ var quxNewed = new Qux();
+ var quxOuterHtml = '<input is="x-qux">';
+ expect(quxNewed.outerHtml, quxOuterHtml);
+ expect(quxNewed is Qux, isTrue);
+ expect(quxNewed is InputElement, isTrue);
+ expect(isFormControl(quxNewed), isTrue);
+
+ // new Element.tag
+
+ var fooCreated = new Element.tag('x-foo');
+ expect(fooCreated.outerHtml, fooOuterHtml);
+ expect(fooCreated is Foo, isTrue);
+
+ var barCreated = new Element.tag('x-bar');
+ expect(barCreated.outerHtml, "<x-bar></x-bar>");
+ expect(barCreated is Bar, isFalse);
+ expect(barCreated is UnknownElement, isFalse);
+ expect(barCreated is HtmlElement, isTrue);
+
+ var bazCreated = new Element.tag('x-baz');
+ expect(bazCreated.outerHtml, bazOuterHtml);
+ expect(bazCreated is Baz, isTrue);
+ expect(bazCreated is UnknownElement, isFalse);
+
+ var quxCreated = new Element.tag('x-qux');
+ expect(quxCreated.outerHtml, "<x-qux></x-qux>");
+ expect(quxCreated is Qux, isFalse);
+ expect(quxCreated is UnknownElement, isFalse);
+ expect(quxCreated is HtmlElement, isTrue);
+
+ // create with type extensions
+ // TODO(vsm): How should we expose this?
+
+ var divFooCreated = document.$dom_createElement("div", Foo.tag);
+ expect(divFooCreated.outerHtml, '<div is="x-foo"></div>');
+ expect(divFooCreated is Foo, isFalse);
+ expect(divFooCreated is DivElement, isTrue);
+
+ var inputBarCreated =
+ document.$dom_createElement("input", Bar.tag);
+ expect(inputBarCreated.outerHtml, barOuterHtml);
+ expect(inputBarCreated is Bar, isTrue);
+ expect(inputBarCreated is UnknownElement, isFalse);
+ expect(isFormControl(inputBarCreated), isTrue);
+
+ var divBarCreated = document.$dom_createElement("div", Bar.tag);
+ expect(divBarCreated.outerHtml, '<div is="x-bar"></div>');
+ expect(divBarCreated is Bar, isFalse);
+ expect(divBarCreated is DivElement, isTrue);
+
+ var fooBarCreated =
+ document.$dom_createElement(Foo.tag, Bar.tag);
+ expect(fooBarCreated.outerHtml, '<x-foo is="x-bar"></x-foo>');
+ expect(fooBarCreated is Foo, isTrue);
+
+ var barFooCreated = document.$dom_createElement(Bar.tag,
+ Foo.tag);
+ expect(barFooCreated.outerHtml, '<x-bar is="x-foo"></x-bar>');
+ expect(barFooCreated is UnknownElement, isFalse);
+ expect(barFooCreated is HtmlElement, isTrue);
+
+ var fooCreatedNull = document.$dom_createElement(Foo.tag, null);
+ expect(fooCreatedNull.outerHtml, fooOuterHtml);
+ expect(fooCreatedNull is Foo, isTrue);
+
+ var fooCreatedEmpty = document.$dom_createElement(Foo.tag, "");
+ expect(fooCreatedEmpty.outerHtml, fooOuterHtml);
+ expect(fooCreatedEmpty is Foo, isTrue);
+
+ expect(() => document.$dom_createElement('@invalid', 'x-bar'), throws);
+
+ // Create NS with type extensions
+
+ var fooCreatedNS =
+ document.$dom_createElementNS("http://www.w3.org/1999/xhtml",
+ Foo.tag, null);
+ expect(fooCreatedNS.outerHtml, fooOuterHtml);
+ expect(fooCreatedNS is Foo, isTrue);
+
+ var barCreatedNS =
+ document.$dom_createElementNS("http://www.w3.org/1999/xhtml", "input",
+ Bar.tag);
+ expect(barCreatedNS.outerHtml, barOuterHtml);
+ expect(barCreatedNS is Bar, isTrue);
+ expect(isFormControl(barCreatedNS), isTrue);
+
+ expect(() =>
+ document.$dom_createElementNS(
+ 'http://example.com/2013/no-such-namespace',
+ 'xml:lang', 'x-bar'), throws);
+
+ // Parser
+
+ createElementFromHtml(html) {
+ var container = new DivElement()..innerHtml = html;
+ return container.firstChild;
+ }
+
+ var fooParsed = createElementFromHtml('<x-foo>');
+ expect(fooParsed is Foo, isTrue);
+
+ var barParsed = createElementFromHtml('<input is=x-bar>');
+ expect(barParsed is Bar, isTrue);
+ expect(isFormControl(barParsed), isTrue);
+
+ var divFooParsed = createElementFromHtml('<div is=x-foo>');
+ expect(divFooParsed is Foo, isFalse);
+ expect(divFooParsed is DivElement, isTrue);
+
+ var namedBarParsed = createElementFromHtml('<x-bar>');
+ expect(namedBarParsed is Bar, isFalse);
+ expect(namedBarParsed is UnknownElement, isFalse);
+ expect(namedBarParsed is HtmlElement, isTrue);
+
+ var divBarParsed = createElementFromHtml('<div is=x-bar>');
+ expect(divBarParsed is Bar, isFalse);
+ expect(divBarParsed is DivElement, isTrue);
+ });
+}
diff --git a/tests/html/custom_elements_test.dart b/tests/html/custom_elements_test.dart
index a78892b..8f627e7 100644
--- a/tests/html/custom_elements_test.dart
+++ b/tests/html/custom_elements_test.dart
@@ -3,9 +3,10 @@
// BSD-style license that can be found in the LICENSE file.
library custom_elements_test;
-import '../../pkg/unittest/lib/unittest.dart';
-import '../../pkg/unittest/lib/html_individual_config.dart';
+import 'dart:async';
import 'dart:html';
+import 'package:unittest/html_individual_config.dart';
+import 'package:unittest/unittest.dart';
class CustomMixin {
var mixinMethodCalled;
@@ -35,9 +36,23 @@
class NotAnElement {}
+loadPolyfills() {
+ if (!document.supportsRegister) {
+ // Cache blocker is a workaround for:
+ // https://code.google.com/p/dart/issues/detail?id=11834
+ var cacheBlocker = new DateTime.now().millisecondsSinceEpoch;
+ return HttpRequest.getString('/root_dart/pkg/custom_element/lib/'
+ 'custom-elements.debug.js?cacheBlock=$cacheBlocker').then((code) {
+ document.head.children.add(new ScriptElement()..text = code);
+ });
+ }
+}
+
main() {
useHtmlIndividualConfiguration();
+ setUp(loadPolyfills);
+
group('register', () {
test('register', () {
var tag = nextTag;
@@ -83,11 +98,14 @@
});
});
+ // TODO(vsm): Modify this test once we agree on the proper semantics.
+ /*
group('preregister', () {
- // TODO(vsm): Modify this test once we agree on the proper semantics.
+
test('pre-registration construction', () {
var tag = nextTag;
var dom = new Element.html('<div><$tag></$tag></div>');
+
var preElement = dom.children[0];
expect(preElement, isNotNull);
expect(preElement is HtmlElement, isTrue);
@@ -98,6 +116,7 @@
});
document.register(tag, CustomType);
+ Platform.upgradeCustomElements(dom);
var postElement = dom.children[0];
expect(postElement, isNotNull);
@@ -118,7 +137,7 @@
expect(firedOnPre, isTrue);
expect(firedOnPost, isTrue);
});
- });
+ });*/
group('innerHtml', () {
test('query', () {
diff --git a/tests/html/html.status b/tests/html/html.status
index 8cdf46d..7c00a70 100644
--- a/tests/html/html.status
+++ b/tests/html/html.status
@@ -2,12 +2,20 @@
# 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.
+# Skipped for in-progress Dartium rull on 8-16-2013
+node_test/iterating: Fail
+websocket_test: skip
+
async_window_test: Skip #TODO(gram): investigating
event_test: Skip # Issue 1996
interactive_test: Skip # Must be run manually.
[ $compiler == dart2js && $runtime != drt ]
-custom_elements_test: Skip
+custom/*: Skip
+
+[ $compiler == dart2js && $browser ]
+# Issue 9325 failures
+custom/attribute_changed_callback_test: Fail
[ $compiler == none && ($runtime == drt || $runtime == dartium) && $mode == debug && $system == macos]
audiobuffersourcenode_test: Pass, Fail, Crash # http://crbug.com/256601
@@ -15,15 +23,14 @@
[ $compiler == none && ($runtime == drt || $runtime == dartium) ]
# postMessage in dartium always transfers the typed array buffer, never a view
postmessage_structured_test/typed_arrays: Fail
-events_test: Pass, Fail # Issue 12489
custom_elements_test/lifecycle: Fail # Issue 9326 - Implement "extends Element" in dartium
+# Issue 9326 failures
+custom/attribute_changed_callback_test: Fail
+custom/created_callback_test: Fail
[ $compiler == none && $runtime == drt && $system == windows ]
worker_test/functional: Pass, Crash # Issue 9929.
-[ $compiler == dart2js && $checked ]
-template_element_test: Fail # BUG(11480): Triage.
-
[ $compiler == dart2js && ($runtime == ie9 || $runtime == ie10 || $runtime == safari || $runtime == ff || $runtime == chrome || $runtime == chromeOnAndroid || $runtime == opera || $runtime == drt || $runtime == dartium)]
dom_isolates_test: Skip # Need to migrate to new spawnDomFunction.
@@ -41,10 +48,11 @@
[ $compiler == dart2js && $browser && $checked ]
postmessage_structured_test/typed_arrays: Fail # Issue 10097
postmessage_structured_test/primitives: Fail # Issue 10097
-
-# Layout tests are only supported on DRT.
-[ $runtime == ie9 || $runtime == ie10 || $runtime == safari || $runtime == ff || $runtime == chrome || $runtime == opera ]
-*layout_test: Skip
+# Issue 9325 failures
+custom/constructor_calls_created_synchronously_test: Fail
+custom/created_callback_test: Fail
+custom/document_register_basic_test: Fail
+custom/document_register_type_extensions_test: Fail
[ $runtime == chrome ]
canvasrenderingcontext2d_test/drawImage_video_element: Pass,Fail # Issue 11836
@@ -55,6 +63,8 @@
xhr_test: Pass, Fail # Issue 11884
xhr_cross_origin_test: Pass, Fail # Issue 11884
+fileapi_test/directoryReader: Fail # Issue 12573
+
[ $runtime == chrome || $runtime == chromeOnAndroid || $runtime == drt || $runtime == safari ]
audiocontext_test: Skip # Issue 9322
@@ -277,7 +287,6 @@
blob_constructor_test: Fail
canvas_test: Fail
canvas_test: Pass,Fail
-canvas_using_html_test: Fail
cssstyledeclaration_test: Fail
document_test/document: Fail # Issue: 7413
element_add_test: Fail
@@ -288,7 +297,6 @@
element_test/eventListening: Crash
element_test/eventListening: Fail # Issue: 7413
element_test/queryAll: Fail
-element_webkit_test: Fail
fileapi_test: Skip # Timeout.
form_data_test: Fail # Issue: 7413
htmlelement_test: Fail
@@ -342,7 +350,7 @@
input_element_test/supported_datetime-local: Fail
input_element_test/supported_month: Fail
input_element_test/supported_number: Fail
-input_element_test/supported_range: Fail
+input_element_test/supported_range: Fail, Pass # FF 23 is introducing support.
input_element_test/supported_time: Fail
input_element_test/supported_week: Fail
media_stream_test/supported_MediaStreamEvent: Fail
@@ -361,12 +369,6 @@
[ $runtime == ff && $system == linux ]
rtc_test/functionality: Fail # Issue: 12109.
-[ $runtime == ie9 && ($system == linux || $system == macos) ]
-*: Skip
-
-[ $runtime == safari && ($system == linux || $system == windows) ]
-*: Skip
-
# 'html' tests import the HTML library, so they only make sense in
# a browser environment.
[ $runtime == vm ]
@@ -387,4 +389,3 @@
js_test: Skip # Test cannot run under CSP restrictions (times out).
postmessage_structured_test: Skip # Test cannot run under CSP restrictions (times out).
safe_dom_test: Skip # Test cannot run under CSP restrictions (times out).
-shadow_dom_layout_test: Fail, OK # Test cannot run under CSP restrictions.
diff --git a/tests/isolate/isolate.status b/tests/isolate/isolate.status
index 73c3a5c..3655cf9 100644
--- a/tests/isolate/isolate.status
+++ b/tests/isolate/isolate.status
@@ -62,23 +62,8 @@
[ $runtime == safari ]
cross_isolate_message_test: Skip # Depends on 32/64 bit Safari. See Issue 1120
-mixed_test: Pass,Fail # Depends on 32/64 bit Safari. See Issue 1120
-mixed2_test: Pass,Fail # Depends on 32/64 bit Safari. See Issue 1120
message_test: Skip
-# TODO(ager): Update these.
-[ $runtime == ie9 && $system == windows ]
-v2*: Skip
-
-[ $runtime == safari && $system == macos ]
-v2*: Skip
-
-[ $runtime == ie9 && ($system == linux || $system == macos) ]
-*: Skip
-
-[ $runtime == safari && ($system == linux || $system == windows) ]
-*: Skip
-
[ $runtime == opera ]
isolate2_negative_test: Skip # Timeout.
unresolved_ports_negative_test: Skip # See Issue 6839
@@ -125,3 +110,8 @@
[ $arch == simmips ]
*: Skip
+
+[ $compiler == none && ($runtime == drt || $runtime == dartium) ]
+# Skipped for in-progress Dartium rull on 8-16-2013
+isolate_stress_test: Skip
+
diff --git a/tests/json/json.status b/tests/json/json.status
index 0d01775..ebf041d 100644
--- a/tests/json/json.status
+++ b/tests/json/json.status
@@ -2,12 +2,6 @@
# 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.
-[ $runtime == ie9 && ($system == linux || $system == macos) ]
-*: Skip
-
-[ $runtime == safari && ($system == linux || $system == windows) ]
-*: Skip
-
[ $runtime == vm ]
*: Skip
diff --git a/tests/language/compile_time_constant10_test.dart b/tests/language/compile_time_constant10_test.dart
index a2d1a02..a29cb8a 100644
--- a/tests/language/compile_time_constant10_test.dart
+++ b/tests/language/compile_time_constant10_test.dart
@@ -34,7 +34,7 @@
class CT {
final x1;
final x2;
- bool id;
+ final bool id;
const CT(var x1, var x2)
: this.x1 = x1, this.x2 = x2, this.id = identical(x1, x2);
void test(void expect(a,b), name) {
diff --git a/tests/language/dynamic_prefix_core_test.dart b/tests/language/dynamic_prefix_core_test.dart
new file mode 100644
index 0000000..1aba87f
--- /dev/null
+++ b/tests/language/dynamic_prefix_core_test.dart
@@ -0,0 +1,17 @@
+// 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.
+// Test explicit import of dart:core in the source code..
+
+library DynamicPrefixCoreTest.dart;
+import "package:expect/expect.dart";
+import "dart:core" as mycore;
+
+void main() {
+ // Should still be available because it is not a member of dart:core.
+ Expect.isTrue(dynamic is Type);
+
+ Expect.throws(() => mycore.dynamic is Type,
+ (e) => e is NoSuchMethodError,
+ 'dynamic is not a member of dart:core');
+}
diff --git a/tests/language/f_bounded_quantification4_test.dart b/tests/language/f_bounded_quantification4_test.dart
new file mode 100644
index 0000000..922e225
--- /dev/null
+++ b/tests/language/f_bounded_quantification4_test.dart
@@ -0,0 +1,16 @@
+// 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.
+
+// Test for F-Bounded Quantification.
+
+import "package:expect/expect.dart";
+
+class A<T extends B<T>> { }
+
+class B<T> extends A<T> { }
+
+main() {
+ Expect.equals("B<B>", new B<B>().runtimeType.toString());
+}
+
diff --git a/tests/language/field_override3_test.dart b/tests/language/field_override3_test.dart
new file mode 100644
index 0000000..fff5fd0
--- /dev/null
+++ b/tests/language/field_override3_test.dart
@@ -0,0 +1,23 @@
+// 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.
+
+// Test that we report a compile-time error when a static field conflicts with
+// an inherited instance member of the same name.
+
+import "package:expect/expect.dart";
+
+class A {
+ var foo = 42; /// 00: compile-time error
+ get foo => 42; /// 01: compile-time error
+ foo() => 42; /// 02: compile-time error
+ set foo(value) { } /// 03: compile-time error
+}
+
+class B extends A {
+ static var foo = 42;
+}
+
+main() {
+ Expect.equals(42, B.foo);
+}
diff --git a/tests/language/field_override4_test.dart b/tests/language/field_override4_test.dart
new file mode 100644
index 0000000..46e6c73
--- /dev/null
+++ b/tests/language/field_override4_test.dart
@@ -0,0 +1,23 @@
+// 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.
+
+// Test that we report a compile-time error when an instance field conflicts
+// with an inherited instance method of the same name.
+
+import "package:expect/expect.dart";
+
+class A {
+ var foo = 42; /// 00: ok
+ get foo => 42; /// 01: ok
+ foo() => 42; /// 02: compile-time error
+ set foo(value) { } /// 03: ok
+}
+
+class B extends A {
+ var foo = 42;
+}
+
+main() {
+ Expect.equals(42, new B().foo);
+}
diff --git a/tests/language/getter_override2_test.dart b/tests/language/getter_override2_test.dart
new file mode 100644
index 0000000..ec162de
--- /dev/null
+++ b/tests/language/getter_override2_test.dart
@@ -0,0 +1,23 @@
+// 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.
+
+// Test that we report a compile-time error when an instance getter conflicts
+// with an inherited instance method of the same name.
+
+import "package:expect/expect.dart";
+
+class A {
+ var foo = 42; /// 00: ok
+ get foo => 42; /// 01: ok
+ foo() => 42; /// 02: compile-time error
+ set foo(value) { } /// 03: ok
+}
+
+class B extends A {
+ get foo => 42;
+}
+
+main() {
+ Expect.equals(42, new B().foo);
+}
diff --git a/tests/language/getter_override_test.dart b/tests/language/getter_override_test.dart
new file mode 100644
index 0000000..e61ecd7
--- /dev/null
+++ b/tests/language/getter_override_test.dart
@@ -0,0 +1,23 @@
+// 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.
+
+// Test that we report a compile-time error when a static getter conflicts with
+// an inherited instance member of the same name.
+
+import "package:expect/expect.dart";
+
+class A {
+ var foo = 42; /// 00: compile-time error
+ get foo => 42; /// 01: compile-time error
+ foo() => 42; /// 02: compile-time error
+ set foo(value) { } /// 03: static type warning
+}
+
+class B extends A {
+ static get foo => 42;
+}
+
+main() {
+ Expect.equals(42, B.foo);
+}
diff --git a/tests/language/inference_captured_variable2_test.dart b/tests/language/inference_captured_variable2_test.dart
new file mode 100644
index 0000000..ddc3162
--- /dev/null
+++ b/tests/language/inference_captured_variable2_test.dart
@@ -0,0 +1,20 @@
+// 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.
+
+// Ensure that dart2js's receiver specialization optimization works
+// with captured variables.
+
+import "package:expect/expect.dart";
+
+var list = [new Object(), 31];
+
+main() {
+ Expect.throws(() => foo()() + 42, (e) => e is NoSuchMethodError);
+}
+
+foo() {
+ var a = list[0];
+ var closure = (() => a - 42);
+ return () => a + 54;
+}
diff --git a/tests/language/inference_captured_variable_test.dart b/tests/language/inference_captured_variable_test.dart
new file mode 100644
index 0000000..cdb8931
--- /dev/null
+++ b/tests/language/inference_captured_variable_test.dart
@@ -0,0 +1,24 @@
+// 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.
+
+// Ensure that dart2js's receiver specialization optimization works
+// with captured variables.
+
+import "package:expect/expect.dart";
+
+var list = [new Object(), 31];
+
+main() {
+ Expect.throws(() => foo()() + 42, (e) => e is NoSuchMethodError);
+}
+
+foo() {
+ var a = list[0];
+ var closure = (() => a + 42);
+ if (list[1] == 0) {
+ a.toInt();
+ return closure;
+ }
+ return closure;
+}
diff --git a/tests/language/language.status b/tests/language/language.status
index a16ddfb..cdac989 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -5,16 +5,6 @@
# This directory contains tests that are intended to show the
# current state of the language.
-# In order to maintain maximum test coverage for all builds,
-# please use the following procedure to mark a test
-# failed on architectures other than the one you are working on.
-#
-# 1) Copy the old version of the test to
-# tests/language/src/test_name_[dartc|vm]_test.dart.
-# to maintain coverage.
-# 2) File a bug on each architecture for the failure due to the language change.
-# 3) Update the language/src directory with the updated test.
-
[ $compiler == dart2js && ($runtime == ie9 || $runtime == ie10) ]
licm2_test: Skip # Issue: 12298
@@ -29,7 +19,6 @@
mixin_super_constructor_positionals_test: Fail
built_in_identifier_prefix_test: Fail # http://dartbug.com/6970
library_juxtaposition_test: Fail # Issue 6877
-pseudo_kw_illegal_test/14: Fail # Issue 356
switch_int_double_test/01: Fail # Issue 7307
switch_int_double_test/02: Fail # Issue 7307
@@ -42,26 +31,16 @@
closure_in_initializer_test: Fail # Issue 6422
# Regular bugs which should be fixed.
-const_init6_negative_test: Fail # Issue 811
super_first_constructor_test: Fail # Issue 1372.
parameter_initializer6_negative_test: Fail # Issue 3502
named_parameters_aggregated_test/05: Fail # Compile-time error reported instead of static type warning.
-lazy_static3_test: Fail # Issue 3558
-
-# DartC specific tests that should not be run by the VM
-*dartc_test: Skip
-*dartc_negative_test: Skip
-
-compile_time_constant10_test/none: Fail # issue 5214
+lazy_static3_test: Fail # Issue 12593
export_cyclic_test: Fail, Crash # issue 6060
duplicate_export_negative_test: Fail # issue 6134
-type_annotation_test/04: Fail # Issue 6970
-type_annotation_test/06: Fail # Issue 6973
-type_annotation_test/09: Fail # Issue 6973
on_catch_malformed_type_test: Fail # Issue 8601
@@ -106,17 +85,12 @@
[ $runtime == vm || ($runtime == drt && $compiler == none) ]
first_class_types_literals_test: Fail # issue 11761
-call_test: Fail # Issue 1604
+call_test: Fail # Issue 12602
+dynamic_prefix_core_test: Fail # Issue 12478
[ $runtime == chrome ]
-[ $runtime == ie9 && ($system == linux || $system == macos) ]
-*: Skip
-
-[ $runtime == safari && ($system == linux || $system == windows) ]
-*: Skip
-
[ $browser ]
@@ -147,8 +121,6 @@
import_core_prefix_test: Fail
prefix16_test: Fail
prefix22_test: Fail
-type_annotation_test/04: Fail
-type_annotation_test/06: Fail
# Calling unresolved class constructor:
call_nonexistent_constructor_test: Fail
@@ -157,6 +129,20 @@
bad_override_test/02: Fail # Issue 11496
bad_override_test/06: Fail # Issue 11496
class_override_test/00: Fail # Issue 11496
+field_override3_test/00: Fail # Issue 11496
+field_override3_test/01: Fail # Issue 11496
+field_override3_test/02: Fail # Issue 11496
+field_override3_test/03: Fail # Issue 11496
+getter_override_test/00: Fail # Issue 11496
+getter_override_test/01: Fail # Issue 11496
+getter_override_test/02: Fail # Issue 11496
+method_override7_test/00: Fail # Issue 11496
+method_override7_test/01: Fail # Issue 11496
+method_override7_test/02: Fail # Issue 11496
+method_override8_test/03: Fail # Issue 11496
+setter_override_test/00: Fail # Issue 11496
+setter_override_test/03: Fail # Issue 11496
+setter_override2_test/02: Fail # Issue 11496
# Missing compile-time error when modifying final local variables
final_variable_assignment_test/01: Fail
@@ -205,17 +191,15 @@
# chokes on things like typedef(x) => "typedef $x" and alike.
abstract_syntax_test/01: Fail
abstract_syntax_test/02: Fail
-pseudo_kw_illegal_test/14: Fail
pseudo_kw_test: Fail
# external keyword is not yet supported by dart2js/dart2dart.
external_test/*: Skip
-lazy_static3_test: Fail, OK # Issue 3558
+lazy_static3_test: Fail # Issue 12593
# dart2js frontend doesn't even analyse problematic classes.
duplicate_implements_test/01: Fail
duplicate_implements_test/02: Fail
duplicate_implements_test/03: Fail
duplicate_implements_test/04: Fail
-interface_factory_constructor_negative_test: Fail
method_override4_test: Fail
method_override5_test: Fail
operator1_negative_test: Fail
@@ -269,8 +253,6 @@
get_set_syntax_test/14: Fail # Fixed by https://chromiumcodereview.appspot.com/10915111
get_set_syntax_test/15: Fail # Fixed by https://chromiumcodereview.appspot.com/10915111
-compile_time_constant10_test/none: Fail # Triage this.
-
# Only checked mode reports an error on type assignment
# problems in compile time constants.
compile_time_constant_checked_test/02: Fail, OK
@@ -291,6 +273,7 @@
[ $compiler == dart2dart && $minified ]
super_getter_setter_test: Fail # Issue 11065.
+f_bounded_quantification4_test: Fail # Issue 12605.
# TODO(tball): Assign proper bug numbers.
class_literal_test: Fail
@@ -305,6 +288,3 @@
[ $compiler == dart2js ]
null_test/none: Fail # Issue 12482
-
-[ $compiler == dartanalyzer ]
-null_test/03: Fail # Issue 12484
diff --git a/tests/language/language_analyzer.status b/tests/language/language_analyzer.status
index 9368478..34b721d 100644
--- a/tests/language/language_analyzer.status
+++ b/tests/language/language_analyzer.status
@@ -37,9 +37,10 @@
number_identifier_negative_test: fail
# TBF: we should check conflicts not only for methods, but for accessors too
-override_field_test/01: fail
override_field_test/02: fail
override_field_test/03: fail
+method_override7_test/03: Fail # Issue 11496
+method_override8_test/03: Fail # Issue 11496
# TBF: prefix T hidden by type variable T in 'new T.Class()'
prefix10_negative_test: fail
@@ -132,9 +133,6 @@
# test issue 11581, it is not warning to call dynamic
call_through_getter_test: fail
-# test issue 11582, non-final field with 'const' constructor
-compile_time_constant10_test/none: fail
-
# test issue 11583, int is valid key for constant map literal
compile_time_constant_c_test/01: fail
@@ -175,9 +173,6 @@
# test issue 11595, It is static warning to create instance (new) of the malformed type
instantiate_type_variable_negative_test: fail
-# test issue 11596. e is Unknown is not a compile time error
-is_not_class2_negative_test: fail
-
# test issue 11598, Any use of a malbounded type gives rise to a static warning
mixin_type_parameters_errors_test/01: fail
mixin_type_parameters_errors_test/02: fail
@@ -205,12 +200,8 @@
# test issue 11964, Any use of a malformed type gives rise to a static warning.
prefix8_negative_test: fail
-prefix9_negative_test: fail
prefix11_negative_test: fail
-# test issue 11965, 'source' is not built-in identifier anymore
-pseudo_kw_illegal_test/14: fail
-
# test issue 12156, fails only at runtime
static_call_wrong_argument_count_negative_test: fail
@@ -244,7 +235,7 @@
# test issue 12184, It is static warning, not error, to assign to a constant variable.
static_final_field2_negative_test: fail
-# test issue 12191, ambuguous import is always warning now
+# test issue 12191, ambiguous import is always warning now
prefix3_negative_test: fail
library_ambiguous_test/00: fail
library_ambiguous_test/01: fail
@@ -261,6 +252,17 @@
# test issue 12397; it is static warning, not error to use variable before declaration (or hidden)
scope_negative_test: fail
+# test issue 12539, rules for finals were loosened, contradiction in spec was fixed
+const_syntax_test/09: fail
+
+# test issue 12541; there shouldn't be a static warning
+static_field_test/01: fail
+static_field_test/02: fail
+static_field_test/03: fail
+static_field_test/04: fail
+
+null_test/03: Fail # Issue 12484
+
[ $compiler == dartanalyzer && $checked ]
factory1_test/00: fail
factory1_test/01: fail
diff --git a/tests/language/language_analyzer2.status b/tests/language/language_analyzer2.status
index 5acf485..6a18173 100644
--- a/tests/language/language_analyzer2.status
+++ b/tests/language/language_analyzer2.status
@@ -21,7 +21,6 @@
# TBF: It is a compile-time error if the superclass of a class C appears in the implements clause of C.
const_constructor_super_test/01: fail
-compile_time_constant10_test/none: fail
compile_time_constant_c_test/01: fail
# TBF: m([int p = 'String']) and call 'const' instance creation
@@ -182,9 +181,6 @@
# test issue 11581, it is not warning to call dynamic
call_through_getter_test: fail
-# test issue 11582, non-final field with 'const' constructor
-compile_time_constant10_test/none: fail
-
# test issue 11583, int is valid key for constant map literal
compile_time_constant_c_test/01: fail
@@ -225,9 +221,6 @@
# test issue 11595, It is static warning to create instance (new) of the malformed type
instantiate_type_variable_negative_test: fail
-# test issue 11596. e is Unknown is not a compile time error
-is_not_class2_negative_test: fail
-
# test issue 11598, Any use of a malbounded type gives rise to a static warning
mixin_type_parameters_errors_test/01: fail
mixin_type_parameters_errors_test/02: fail
@@ -255,12 +248,8 @@
# test issue 11964, Any use of a malformed type gives rise to a static warning.
prefix8_negative_test: fail
-prefix9_negative_test: fail
prefix11_negative_test: fail
-# test issue 11965, 'source' is not built-in identifier anymore
-pseudo_kw_illegal_test/14: fail
-
# test issue 12156, fails only at runtime
static_call_wrong_argument_count_negative_test: fail
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index f560c23..a3223eb 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -38,15 +38,14 @@
malformed_test/06: Fail
# Fails due to inlining. Not all expected frames are in the trace.
-full_stacktrace1_test: Pass, Fail # issue 9895
-full_stacktrace2_test: Pass, Fail # issue 9895
-full_stacktrace3_test: Pass, Fail # issue 9895
+full_stacktrace1_test: Pass, Fail
+full_stacktrace2_test: Pass, Fail
+full_stacktrace3_test: Pass, Fail
# Stack traces may or may not end in a newline depending on the JS enging.
stacktrace_test: Pass, Fail # Assumes stack trace string ends in newline.
# VM specific tests that should not be run by dart2js.
*vm_test: Skip
-*vm_negative_test: Skip
[ $compiler == dart2js && $checked ]
checked_setter2_test: Fail # dartbug.com/11273
@@ -63,7 +62,6 @@
f_bounded_quantification_test/01: Fail
f_bounded_quantification_test/02: Fail
closure_type_test: Fail # does not detect type error in checked mode.
-type_annotation_test/09: Fail # Named constructors interpreted as a type.
function_subtype_setter0_test: Fail # dartbug.com/11273
[ $compiler == dart2js && $unchecked ]
@@ -92,16 +90,19 @@
compile_time_constant_checked3_test/05: Fail, OK
compile_time_constant_checked3_test/06: Fail, OK
+[ $compiler == dart2js && $minified ]
+f_bounded_quantification4_test: Fail # Issue 12605.
+
[ $compiler == dart2js ]
function_type_alias6_test/00: Crash # dartbug.com/9792
function_type_alias9_test/00: Crash # dartbug.com/9792
branch_canonicalization_test: Fail # Issue 638.
div_with_power_of_two_test: Fail # Issue 8301.
class_literal_test: Fail # Issue 7626.
-identical_closure2_test: Fail # Issues 563, 1533
+identical_closure2_test: Fail # Issue 1533, Issue 12596
invocation_mirror_test: Fail
built_in_identifier_prefix_test: Fail # http://dartbug.com/6972
-number_identity2_test: Fail # Issue 563: identity of NaN
+number_identity2_test: Fail # Issue 12596: identity of NaN
new_expression_type_args_test/00: Fail # Wrongly reports compile-time error.
new_expression_type_args_test/01: Fail # Wrongly reports compile-time error.
double_int_to_string_test: Fail # Issue 1533 (double/integer distinction)
@@ -117,11 +118,26 @@
bad_override_test/02: Fail # Issue 11496
bad_override_test/06: Fail # Issue 11496
class_override_test/00: Fail # Issue 11496
+field_override3_test/00: Fail # Issue 11496
+field_override3_test/01: Fail # Issue 11496
+field_override3_test/02: Fail # Issue 11496
+field_override3_test/03: Fail # Issue 11496
+getter_override_test/00: Fail # Issue 11496
+getter_override_test/01: Fail # Issue 11496
+getter_override_test/02: Fail # Issue 11496
+method_override7_test/00: Fail # Issue 11496
+method_override7_test/01: Fail # Issue 11496
+method_override7_test/02: Fail # Issue 11496
+method_override8_test/03: Fail # Issue 11496
+setter_override_test/00: Fail # Issue 11496
+setter_override_test/03: Fail # Issue 11496
+setter_override2_test/02: Fail # Issue 11496
call_nonexistent_constructor_test: Fail
constructor_named_arguments_test/01: Fail # http://dartbug.com/5519
getter_no_setter_test/01: Fail # http://dartbug.com/5519
not_enough_positional_arguments_test/01: Fail # http://dartbug.com/5519
dynamic_test: Fail # http://dartbug.com/12398
+dynamic_prefix_core_test: Fail # http://dartbug.com/12398
constructor_negative_test: Pass # Wrong reason: the expression 'C()' is valid with class literals.
@@ -193,7 +209,6 @@
list_literal4_test: Fail # Illegal argument(s): 0 -- checked mode test.
map_literal4_test: Fail # Attempt to modify an immutable object -- checked mode test.
named_parameters_type_test: Fail # Expect.equals(expected: <111>, actual: <0>) fails. -- checked mode test.
-type_dartc_test: Fail # Expect.equals(expected: <1>, actual: <0>) -- checked mode test.
class_cycle_negative_test: Fail, OK # Bad test: assumes eager loading.
external_test/16: Fail, OK # Bad test: assumes eager loading.
@@ -204,13 +219,9 @@
#
# The following tests are all negative tests that should be fixed.
#
-abstract_static_negative_test: Fail # Negative language test.
abstract_syntax_test/01: Fail # Negative language test.
abstract_syntax_test/02: Fail # Negative language test.
const_constructor_syntax_test/04: Fail # Negative language test.
-const_field_negative_test: Fail # Negative language test.
-const_init4_negative_test: Fail # Negative language test.
-const_init_negative_test: Fail # Negative language test.
const_syntax_test/04: Fail # Negative language test.
constructor2_negative_test: Fail # Negative language test.
constructor_return_negative_test: Fail # Negative language test.
@@ -224,15 +235,10 @@
field3_negative_test: Fail # Negative language test.
final_for_in_variable_test/01: Fail # Negative language test
instantiate_type_variable_negative_test: Pass # For the wrong reason.
-interface_factory3_negative_test: Fail # Negative language test.
-interface_factory_constructor_negative_test: Fail # Negative language test.
list_literal1_negative_test: Fail # Negative language test.
map_literal1_negative_test: Fail # Negative language test.
number_identifier_negative_test: Fail # Negative language test.
operator1_negative_test: Fail # Negative language test.
-prefix23_negative_test: Fail # Negative language test.
-pseudo_kw_illegal_test/03: Fail # Negative language test.
-pseudo_kw_illegal_test/14: Fail # Negative language test.
scope_negative_test: Fail # Negative language test.
static_final_field_negative_test: Fail # Negative language test.
static_top_level_test/00: Fail # Negative language test.
@@ -243,7 +249,6 @@
static_top_level_test/05: Fail # Negative language test.
static_top_level_test/06: Fail # Negative language test.
static_top_level_test/07: Fail # Negative language test.
-string_interpolation7_negative_test: Fail # Negative language test.
throw7_negative_test: Fail # Negative language test.
numbers_test: Fail, OK # (unintended?) VM specific test.
@@ -292,8 +297,6 @@
[ $compiler == dart2js && $runtime == safari ]
-null_pointer_exception_test: Fail # Uncaught error: Instance of 'TypeError'
-string_interpolate_npe_test: Fail # Uncaught error: Instance of 'TypeError'
arithmetic_test: Fail # Issue: 7414
@@ -304,9 +307,7 @@
closure3_test: Fail
execute_finally3_test: Fail
method_invocation_test: Fail
-null_pointer_exception_test: Fail
stack_overflow_test: Fail
stack_overflow_stacktrace_test: Fail
-string_interpolate_npe_test: Fail
closure_call_wrong_argument_count_negative_test: Skip
label_test: Skip
diff --git a/tests/language/method_override7_test.dart b/tests/language/method_override7_test.dart
new file mode 100644
index 0000000..5290609
--- /dev/null
+++ b/tests/language/method_override7_test.dart
@@ -0,0 +1,23 @@
+// 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.
+
+// Test that we report a compile-time error when a static function conflicts
+// with an inherited instance member of the same name.
+
+import "package:expect/expect.dart";
+
+class A {
+ var foo = 42; /// 00: compile-time error
+ get foo => 42; /// 01: compile-time error
+ foo() => 42; /// 02: compile-time error
+ set foo(value) { } /// 03: static type warning
+}
+
+class B extends A {
+ static foo() => 42;
+}
+
+main() {
+ Expect.equals(42, B.foo());
+}
diff --git a/tests/language/method_override8_test.dart b/tests/language/method_override8_test.dart
new file mode 100644
index 0000000..4255160
--- /dev/null
+++ b/tests/language/method_override8_test.dart
@@ -0,0 +1,23 @@
+// 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.
+
+// Test that we report a compile-time error when an instance method conflicts
+// with an inherited instance field or getter of the same name.
+
+import "package:expect/expect.dart";
+
+class A {
+ var foo = 42; /// 00: compile-time error
+ get foo => 42; /// 01: compile-time error
+ foo() => 42; /// 02: ok
+ set foo(value) { } /// 03: static type warning
+}
+
+class B extends A {
+ foo() => 42;
+}
+
+main() {
+ Expect.equals(42, new B().foo());
+}
diff --git a/tests/language/pseudo_kw_illegal_test.dart b/tests/language/pseudo_kw_illegal_test.dart
index fcaf3c5..32d8041 100644
--- a/tests/language/pseudo_kw_illegal_test.dart
+++ b/tests/language/pseudo_kw_illegal_test.dart
@@ -16,7 +16,6 @@
class operator { } /// 12: compile-time error
class part { } /// 18: compile-time error
class set { } /// 13: compile-time error
-class source { } /// 14: compile-time error
class static { } /// 15: compile-time error
class typedef { } /// 16: compile-time error
diff --git a/tests/language/refine_receiver_null_test.dart b/tests/language/refine_receiver_null_test.dart
new file mode 100644
index 0000000..c65afa8
--- /dev/null
+++ b/tests/language/refine_receiver_null_test.dart
@@ -0,0 +1,22 @@
+// 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.
+
+// Regression test for dart2js that used to infer that code following
+// a dynamic call could assume the receiver is not null. This does not
+// work for Object methods.
+
+import "package:expect/expect.dart";
+import "compiler_annotations.dart";
+
+main() {
+ var a = true ? null : 42;
+ a.toString();
+ foo(a);
+}
+
+@DontInline()
+foo(a) {
+ var f = () => 42;
+ Expect.throws(() => a + 42, (e) => e is NoSuchMethodError);
+}
diff --git a/tests/language/setter_override2_test.dart b/tests/language/setter_override2_test.dart
new file mode 100644
index 0000000..e5ac9d0
--- /dev/null
+++ b/tests/language/setter_override2_test.dart
@@ -0,0 +1,27 @@
+// 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.
+
+// Test that we do not report a compile-time error when an instance setter named
+// foo= is declared in a class inheriting an instance method, field, or getter
+// named foo, or an instance setter named foo=.
+
+import "package:expect/expect.dart";
+
+class A {
+ var foo = 42; /// 00: ok
+ get foo => 42; /// 01: ok
+ foo() => 42; /// 02: ok
+ set foo(value) { } /// 03: ok
+}
+
+class B extends A {
+ var foo_;
+ set foo(value) { foo_ = value; }
+}
+
+main() {
+ var b = new B();
+ b.foo = 42;
+ Expect.equals(42, b.foo_);
+}
diff --git a/tests/language/setter_override_test.dart b/tests/language/setter_override_test.dart
new file mode 100644
index 0000000..577fbc1
--- /dev/null
+++ b/tests/language/setter_override_test.dart
@@ -0,0 +1,27 @@
+// 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.
+
+// Test that we do not report a compile-time error when a static setter named
+// foo= is declared in a class inheriting an instance method or getter named
+// foo, and that we do report an error if an instance setter named foo= or
+// instance field name foo is inherited.
+
+import "package:expect/expect.dart";
+
+class A {
+ var foo = 42; /// 00: compile-time error
+ get foo => 42; /// 01: static type warning
+ foo() => 42; /// 02: static type warning
+ set foo(value) { } /// 03: compile-time error
+}
+
+class B extends A {
+ static var foo_;
+ static set foo(value) { foo_ = value; }
+}
+
+main() {
+ B.foo = 42;
+ Expect.equals(42, B.foo_);
+}
diff --git a/tests/lib/analyzer/analyze_tests.status b/tests/lib/analyzer/analyze_tests.status
index de9d41a..b1e51479 100644
--- a/tests/lib/analyzer/analyze_tests.status
+++ b/tests/lib/analyzer/analyze_tests.status
@@ -2,13 +2,18 @@
# 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 testing infrastructure is using the dart:io Path and LineTransformer
+# classes.
+standalone/io/skipping_dart2js_compilations_test: Skip # http/dartbug.com/12449
+standalone/io/dependency_graph_test: Skip # http/dartbug.com/12449
+standalone/io/status_file_parser_test: Skip # http/dartbug.com/12449
+
[ $compiler == dartanalyzer ]
javascript_int_overflow_literal_test/01: fail, ok
# https://code.google.com/p/dart/issues/detail?id=11665
standalone/io/directory_invalid_arguments_test: fail
standalone/io/file_constructor_test: fail
-standalone/io/file_fuzz_test: fail
standalone/io/http_cookie_date_test: fail
standalone/io/http_headers_test: fail
standalone/io/http_parser_test: fail
diff --git a/tests/lib/convert/unicode_tests.dart b/tests/lib/convert/unicode_tests.dart
index 1f90b7b..52a7b09 100644
--- a/tests/lib/convert/unicode_tests.dart
+++ b/tests/lib/convert/unicode_tests.dart
@@ -45,6 +45,24 @@
0x79, 0x7A ];
const ASCII_STRING = "abcdefghijklmnopqrstuvwxyz";
+const BIGGEST_ASCII_BYTES = const [ 0x7F ];
+const BIGGEST_ASCII_STRING = "\x7F";
+
+const SMALLEST_2_UTF8_UNIT_BYTES = const [ 0xC2, 0x80 ];
+const SMALLEST_2_UTF8_UNIT_STRING = "\u{80}";
+
+const BIGGEST_2_UTF8_UNIT_BYTES = const [ 0xDF, 0xBF ];
+const BIGGEST_2_UTF8_UNIT_STRING = "\u{7FF}";
+
+const SMALLEST_3_UTF8_UNIT_BYTES = const [ 0xE0, 0xA0, 0x80 ];
+const SMALLEST_3_UTF8_UNIT_STRING = "\u{800}";
+
+const BIGGEST_3_UTF8_UNIT_BYTES = const [ 0xEF, 0xBF, 0xBF ];
+const BIGGEST_3_UTF8_UNIT_STRING = "\u{FFFF}";
+
+const SMALLEST_4_UTF8_UNIT_BYTES = const [ 0xF0, 0x90, 0x80, 0x80 ];
+const SMALLEST_4_UTF8_UNIT_STRING = "\u{10000}";
+
const _TEST_PAIRS = const [
const [ const [], "" ],
const [ INTER_BYTES, INTER_STRING ],
@@ -53,7 +71,14 @@
const [ SIVA_BYTES2, SIVA_STRING2 ],
const [ BEE_BYTES, BEE_STRING ],
const [ DIGIT_BYTES, DIGIT_STRING ],
- const [ ASCII_BYTES, ASCII_STRING ]];
+ const [ ASCII_BYTES, ASCII_STRING ],
+ const [ BIGGEST_ASCII_BYTES, BIGGEST_ASCII_STRING ],
+ const [ SMALLEST_2_UTF8_UNIT_BYTES, SMALLEST_2_UTF8_UNIT_STRING ],
+ const [ BIGGEST_2_UTF8_UNIT_BYTES, BIGGEST_2_UTF8_UNIT_STRING ],
+ const [ SMALLEST_3_UTF8_UNIT_BYTES, SMALLEST_3_UTF8_UNIT_STRING ],
+ const [ BIGGEST_3_UTF8_UNIT_BYTES, BIGGEST_3_UTF8_UNIT_STRING ],
+ const [ SMALLEST_4_UTF8_UNIT_BYTES, SMALLEST_4_UTF8_UNIT_STRING ],
+ ];
List<List> _expandTestPairs() {
assert(2 == BEE_STRING.length);
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index 97c4189..49dda71 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -2,12 +2,14 @@
# 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.
-[ $compiler == dart2js && ($runtime == d8 || $runtime == drt) ]
+[ $compiler == dart2js && $runtime == drt ]
convert/chunked_conversion_utf87_test: Pass, Fail # v8 bug: Issue 12293
typed_data/byte_data_test: Pass, Fail # v8 bug: Issue 12293
[ $compiler == dart2js ]
-math/*: Skip
+math/double_pow_test: Fail
+math/low_test: Fail
+math/random_test: Fail
mirrors/invoke_test: Fail # Issue 11954
mirrors/class_mirror_type_variables_test: Fail # Issue 12087
mirrors/invoke_private_test: Fail # Issue 12164
@@ -21,6 +23,7 @@
mirrors/null_test : Fail # Issue 12129
mirrors/library_metadata_test: Fail # Issue 10905
mirrors/library_uri_io_test: Skip # Not intended for dart2js as it uses dart:io.
+mirrors/reflected_type_test: Fail # Issue 12607
mirrors/unnamed_library_test: Fail # Issue 10580
async/run_async3_test: Fail # _enqueueImmediate runs after Timer. http://dartbug.com/9002
async/run_async4_test: Pass, Fail # no global exception handler in isolates. http://dartbug.com/9012
@@ -28,12 +31,13 @@
async/stream_controller_async_test: Fail, Pass # http://dartbug.com/11953
-[ $compiler == dart2js && ($runtime == d8) ]
-typed_data/byte_data_test: Fail, OK # d8 doesn't support DataView
-
[ $csp ]
mirrors/*: Skip # Issue 6490
+[ $compiler == dart2js && $runtime != jsshell && $runtime != safari && $runtime != ff && $runtime != ie9 && $runtime != ie10]
+math/math_test: Fail
+math/math2_test: Fail
+
[ $compiler == dart2js && $jscl ]
async/future_test: Fail # Timer interface not supported; dartbug.com/7728.
async/slow_consumer2_test: Fail # Timer interface not supported; dartbug.com/7728.
@@ -82,7 +86,10 @@
[ $runtime == ie9 ]
# IE9 doesn't support typed arrays.
typed_data/*: Fail # Issue 11971
-convert/chunked_conversion_utf88_test: Pass, Slow # Issue 12029
+convert/chunked_conversion_utf88_test: Pass, Slow, Timeout # Issue 12029
+convert/streamed_conversion_utf8_encode_test: Pass, Timeout # Issue 12029
+convert/streamed_conversion_json_utf8_decode_test: Pass, Timeout # Issue 12029
+async/deferred/deferred_api_test: Pass, Timeout # Issue 12029
[ $runtime == opera ]
async/multiple_timer_test: Pass, Fail
@@ -99,7 +106,6 @@
[ $runtime == vm || ($compiler == none && $runtime == drt) ]
async/run_async3_test: Fail # _enqueueImmediate runs after Timer. http://dartbug.com/9001.
-mirrors/operator_test: Fail # http://dartbug.com/11944
mirrors/mixin_test: Fail # TODO(ahe): This test is slightly broken. http://dartbug.com/12464
mirrors/hierarchy_test: Fail # TODO(ahe): This test is slightly broken. http://dartbug.com/12464
@@ -118,3 +124,7 @@
[ $arch == simmips || $arch == mips ]
convert/chunked_conversion_utf88_test: Pass, Slow # Issue 12025.
convert/streamed_conversion_json_utf8_decode_test: Pass, Slow
+
+[ $arch == simarm || $arch == arm ]
+typed_data/uint32x4_arithmetic_test: Crash # Unimplemented
+
diff --git a/tests/lib/math/double_pow_test.dart b/tests/lib/math/double_pow_test.dart
new file mode 100644
index 0000000..c3ce04c
--- /dev/null
+++ b/tests/lib/math/double_pow_test.dart
@@ -0,0 +1,158 @@
+// Copyright (c) 2011, 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 math_test;
+import "package:expect/expect.dart";
+import 'dart:math';
+
+void checkVeryClose(double a, double b) {
+ // We find a ulp (unit in the last place) by shifting the original number
+ // to the right. This only works if we are not too close to infinity or if
+ // we work with denormals.
+ // We special case or 0.0, but not for infinity.
+ if (a == 0.0) {
+ final minimalDouble = 4.9406564584124654e-324;
+ Expect.equals(true, b.abs() <= minimalDouble);
+ return;
+ }
+ if (b == 0.0) {
+ // No need to look if they are close. Otherwise the check for 'a' above
+ // whould have triggered.
+ Expect.equals(a, b);
+ }
+ final double shiftRightBy52 = 2.220446049250313080847263336181640625e-16;
+ final double shiftedA = (a * shiftRightBy52).abs();
+ // Compared to 'a', 'shiftedA' is now ~1-2 ulp.
+
+ final double limitLow = a - shiftedA;
+ final double limitHigh = a + shiftedA;
+ Expect.equals(false, a == limitLow);
+ Expect.equals(false, a == limitHigh);
+ Expect.equals(true, limitLow <= b);
+ Expect.equals(true, b <= limitHigh);
+}
+
+const NaN = double.NAN;
+const Infinity = double.INFINITY;
+
+var samples = [
+ NaN,
+ -Infinity,
+ -3.0, // Odd integer
+ -2.0, // Even integer
+ -1.5, // Non-integer, magnitude > 1
+ -1.0, // Unit
+ -0.5, // Non-integer, magnitude < 1.
+ -0.0,
+ 0.5, // Non-integer, magnitude < 1.
+ 1.0, // Unit
+ 1.5, // Non-integer, magnitude > 1
+ 2.0, // Even integer
+ 3.0, // Odd integer
+ Infinity
+];
+
+main() {
+ // Tests of pow(x, y):
+ for (var d in samples) {
+ // if `y` is zero (0.0 or -0.0), the result is always 1.0.
+ Expect.identical(1.0, pow(d, 0.0), "$d");
+ Expect.identical(1.0, pow(d, -0.0), "$d");
+ }
+ for (var d in samples) {
+ // if `x` is 1.0, the result is always 1.0.
+ Expect.identical(1.0, pow(1.0, d), "$d");
+ }
+ for (var d in samples) {
+ // otherwise, if either `x` or `y` is NaN then the result is NaN.
+ if (d != 0.0) Expect.identical(NaN, pow(NaN, d), "$d");
+ if (d != 1.0) Expect.identical(NaN, pow(d, NaN), "$d");
+ }
+
+ for (var d in samples) {
+ // if `x` is a finite and strictly negative and `y` is a finite non-integer,
+ // the result is NaN.
+ if (d < 0 && !d.isInfinite) {
+ Expect.identical(NaN, pow(d, 0.5), "$d");
+ Expect.identical(NaN, pow(d, -0.5), "$d");
+ Expect.identical(NaN, pow(d, 1.5), "$d");
+ Expect.identical(NaN, pow(d, -1.5), "$d");
+ }
+ }
+
+ for (var d in samples) {
+ if (d < 0) {
+ // if `x` is Infinity and `y` is strictly negative, the result is 0.0.
+ Expect.identical(0.0, pow(Infinity, d), "$d");
+ }
+ if (d > 0) {
+ // if `x` is Infinity and `y` is strictly positive, the result is Infinity.
+ Expect.identical(Infinity, pow(Infinity, d), "$d");
+ }
+ }
+
+ for (var d in samples) {
+ if (d < 0) {
+ // if `x` is 0.0 and `y` is strictly negative, the result is Infinity.
+ Expect.identical(Infinity, pow(0.0, d), "$d");
+ }
+ if (d > 0) {
+ // if `x` is 0.0 and `y` is strictly positive, the result is 0.0.
+ Expect.identical(0.0, pow(0.0, d), "$d");
+ }
+ }
+
+ for (var d in samples) {
+ if (!d.isInfinite && !d.isNaN) {
+ var dint = d.toInt();
+ if (d == dint && dint.isOdd) {
+ // if `x` is -Infinity or -0.0 and `y` is an odd integer, then the
+ // result is`-pow(-x ,y)`.
+ Expect.identical(-pow(Infinity, d), pow(-Infinity, d));
+ Expect.identical(-pow(0.0, d), pow(-0.0, d));
+ continue;
+ }
+ }
+ // if `x` is -Infinity or -0.0 and `y` is not an odd integer, then the
+ // result is the same as `pow(-x , y)`.
+ Expect.identical(pow(Infinity, d), pow(-Infinity, d));
+ Expect.identical(pow(0.0, d), pow(-0.0, d));
+ }
+
+ for (var d in samples) {
+
+ if (d.abs() < 1) {
+ // if `y` is Infinity and the absolute value of `x` is less than 1, the
+ // result is 0.0.
+ Expect.identical(0.0, pow(d, Infinity));
+ } else if (d.abs() > 1) {
+ // if `y` is Infinity and the absolute value of `x` is greater than 1,
+ // the result is Infinity.
+ Expect.identical(Infinity, pow(d, Infinity));
+ } else if (d == -1) {
+ // if `y` is Infinity and `x` is -1, the result is 1.0.
+ Expect.identical(1.0, pow(d, Infinity));
+ }
+ // if `y` is -Infinity, the result is `1/pow(x, Infinity)`.
+ Expect.identical(1/pow(d, Infinity), pow(d, -Infinity));
+ }
+
+ // Some non-exceptional values.
+ checkVeryClose(16.0, pow(4.0, 2.0));
+ checkVeryClose(SQRT2, pow(2.0, 0.5));
+ checkVeryClose(SQRT1_2, pow(0.5, 0.5));
+ // Denormal result.
+ Expect.identical(5e-324, pow(2.0, -1074.0));
+ // Overflow.
+ Expect.identical(Infinity, pow(10.0, 309.0));
+ // Underflow.
+ Expect.identical(0.0, pow(10.0, -325.0));
+
+ // Conversion to double.
+
+ // The second argument is an odd integer as int, but not when converted
+ // to double.
+ Expect.identical(Infinity, pow(-0.0, -9223372036854775809));
+}
+
diff --git a/tests/lib/math/math_test.dart b/tests/lib/math/math_test.dart
index 04a5022..b911e0a 100644
--- a/tests/lib/math/math_test.dart
+++ b/tests/lib/math/math_test.dart
@@ -146,12 +146,6 @@
checkVeryClose(LN2, log(2.0));
}
- static void testPow() {
- checkVeryClose(16.0, pow(4.0, 2.0));
- checkVeryClose(SQRT2, pow(2.0, 0.5));
- checkVeryClose(SQRT1_2, pow(0.5, 0.5));
- }
-
static bool parseIntThrowsFormatException(str) {
try {
int.parse(str);
@@ -251,7 +245,6 @@
testSqrt();
testLog();
testExp();
- testPow();
testParseInt();
}
}
diff --git a/tests/lib/mirrors/reflected_type_test.dart b/tests/lib/mirrors/reflected_type_test.dart
new file mode 100644
index 0000000..df4e578
--- /dev/null
+++ b/tests/lib/mirrors/reflected_type_test.dart
@@ -0,0 +1,69 @@
+// 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 test.reflected_type_test;
+
+import 'dart:mirrors';
+
+import 'package:expect/expect.dart';
+
+class A<T> {}
+class B extends A {} // Same as class B extends A<dynamic>.
+class C extends A<num, int> {} // Same as class C extends A<dynamic>.
+class D extends A<int> {}
+class E<S> extends A<S> {}
+class F<R> extends A<int> {}
+class G {}
+class H<A,B,C> {}
+
+expectReflectedType(classMirror, expectedType) {
+ if (expectedType == null) {
+ Expect.isFalse(classMirror.hasReflectedType);
+ Expect.throws(() => classMirror.reflectedType,
+ (e) => e is UnsupportedError,
+ "Should not have a reflected type");
+ } else {
+ Expect.isTrue(classMirror.hasReflectedType);
+ Expect.equals(expectedType, classMirror.reflectedType);
+ }
+}
+
+main() {
+ // Declarations.
+ expectReflectedType(reflectClass(A), null);
+ expectReflectedType(reflectClass(B), B);
+ expectReflectedType(reflectClass(C), C);
+ expectReflectedType(reflectClass(D), D);
+ expectReflectedType(reflectClass(E), null);
+ expectReflectedType(reflectClass(F), null);
+ expectReflectedType(reflectClass(G), G);
+ expectReflectedType(reflectClass(H), null);
+
+ // Instantiations.
+ expectReflectedType(reflect(new A()).type, new A().runtimeType);
+ expectReflectedType(reflect(new B()).type, new B().runtimeType);
+ expectReflectedType(reflect(new C()).type, new C().runtimeType);
+ expectReflectedType(reflect(new D()).type, new D().runtimeType);
+ expectReflectedType(reflect(new E()).type, new E().runtimeType);
+ expectReflectedType(reflect(new F()).type, new F().runtimeType);
+ expectReflectedType(reflect(new G()).type, new G().runtimeType);
+ expectReflectedType(reflect(new H()).type, new H().runtimeType);
+
+ expectReflectedType(reflect(new A<num>()).type, new A<num>().runtimeType);
+ expectReflectedType(reflect(new B<num>()).type.superclass,
+ new A<dynamic>().runtimeType);
+ expectReflectedType(reflect(new C<num>()).type.superclass,
+ new A<dynamic>().runtimeType);
+ expectReflectedType(reflect(new D<num>()).type.superclass,
+ new A<int>().runtimeType);
+ expectReflectedType(reflect(new E<num>()).type, new E<num>().runtimeType);
+ // TODO(rmacnak): This requires some work to compute.
+ // expectReflectedType(reflect(new E<num>()).type.superclass,
+ // new A<num>().runtimeType);
+ expectReflectedType(reflect(new F<num>()).type.superclass,
+ new A<int>().runtimeType);
+ expectReflectedType(reflect(new F<num>()).type, new F<num>().runtimeType);
+ expectReflectedType(reflect(new H<num, num, num>()).type,
+ new H<num, num, num>().runtimeType);
+}
diff --git a/tests/lib/typed_data/float32x4_sign_mask_test.dart b/tests/lib/typed_data/float32x4_sign_mask_test.dart
new file mode 100644
index 0000000..95825d4
--- /dev/null
+++ b/tests/lib/typed_data/float32x4_sign_mask_test.dart
@@ -0,0 +1,62 @@
+// 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.
+// VMOptions=--optimization-counter-threshold=10
+
+// Library tag to be able to run in html test framework.
+library float32x4_sign_mask;
+
+import 'dart:typed_data';
+import 'package:expect/expect.dart';
+
+void testImmediates() {
+ var f = new Float32x4(1.0, 2.0, 3.0, 4.0);
+ var m = f.signMask;
+ Expect.equals(0x0, m);
+ f = new Float32x4(-1.0, -2.0, -3.0, -0.0);
+ m = f.signMask;
+ Expect.equals(0xf, m);
+ f = new Float32x4(-1.0, 2.0, 3.0, 4.0);
+ m = f.signMask;
+ Expect.equals(0x1, m);
+ f = new Float32x4(1.0, -2.0, 3.0, 4.0);
+ m = f.signMask;
+ Expect.equals(0x2, m);
+ f = new Float32x4(1.0, 2.0, -3.0, 4.0);
+ m = f.signMask;
+ Expect.equals(0x4, m);
+ f = new Float32x4(1.0, 2.0, 3.0, -4.0);
+ m = f.signMask;
+ Expect.equals(0x8, m);
+}
+
+void testZero() {
+ var f = new Float32x4(0.0, 0.0, 0.0, 0.0);
+ var m = f.signMask;
+ Expect.equals(0x0, m);
+ f = new Float32x4(-0.0, -0.0, -0.0, -0.0);
+ m = f.signMask;
+ Expect.equals(0xf, m);
+}
+
+void testArithmetic() {
+ var a = new Float32x4(1.0, 1.0, 1.0, 1.0);
+ var b = new Float32x4(2.0, 2.0, 2.0, 2.0);
+ var c = new Float32x4(-1.0, -1.0, -1.0, -1.0);
+ var m1 = (a - b).signMask;
+ Expect.equals(0xf, m1);
+ var m2 = (b - a).signMask;
+ Expect.equals(0x0, m2);
+ var m3 = (c * c).signMask;
+ Expect.equals(0x0, m3);
+ var m4 = (a * c).signMask;
+ Expect.equals(0xf, m4);
+}
+
+main() {
+ for (int i = 0; i < 2000; i++) {
+ testImmediates();
+ testZero();
+ testArithmetic();
+ }
+}
diff --git a/tests/lib/typed_data/uint32x4_arithmetic_test.dart b/tests/lib/typed_data/uint32x4_arithmetic_test.dart
new file mode 100644
index 0000000..a702082
--- /dev/null
+++ b/tests/lib/typed_data/uint32x4_arithmetic_test.dart
@@ -0,0 +1,99 @@
+// 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.
+// VMOptions=--deoptimization_counter_threshold=1000 --optimization-counter-threshold=10
+
+// Library tag to be able to run in html test framework.
+library uint32x4_arithmetic_test;
+
+import "package:expect/expect.dart";
+import 'dart:typed_data';
+
+testAdd() {
+ var m = new Uint32x4(0, 0, 0, 0);
+ var n = new Uint32x4(-1, -1, -1, -1);
+ var o = m + n;
+ Expect.equals(4294967295, o.x);
+ Expect.equals(4294967295, o.y);
+ Expect.equals(4294967295, o.z);
+ Expect.equals(4294967295, o.w);
+
+ m = new Uint32x4(0, 0, 0, 0);
+ n = new Uint32x4(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);
+ o = m + n;
+ Expect.equals(4294967295, o.x);
+ Expect.equals(4294967295, o.y);
+ Expect.equals(4294967295, o.z);
+ Expect.equals(4294967295, o.w);
+
+ n = new Uint32x4(1, 1, 1, 1);
+ m = new Uint32x4(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);
+ o = m + n;
+ Expect.equals(0, o.x);
+ Expect.equals(0, o.y);
+ Expect.equals(0, o.z);
+ Expect.equals(0, o.w);
+
+ n = new Uint32x4(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);
+ m = new Uint32x4(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);
+ o = m + n;
+ Expect.equals(4294967294, o.x);
+ Expect.equals(4294967294, o.y);
+ Expect.equals(4294967294, o.z);
+ Expect.equals(4294967294, o.w);
+
+ n = new Uint32x4(1, 0, 0, 0);
+ m = new Uint32x4(2, 0, 0, 0);
+ o = n + m;
+ Expect.equals(3, o.x);
+ Expect.equals(0, o.y);
+ Expect.equals(0, o.z);
+ Expect.equals(0, o.w);
+
+ n = new Uint32x4(1, 3, 0, 0);
+ m = new Uint32x4(2, 4, 0, 0);
+ o = n + m;
+ Expect.equals(3, o.x);
+ Expect.equals(7, o.y);
+ Expect.equals(0, o.z);
+ Expect.equals(0, o.w);
+
+ n = new Uint32x4(1, 3, 5, 0);
+ m = new Uint32x4(2, 4, 6, 0);
+ o = n + m;
+ Expect.equals(3, o.x);
+ Expect.equals(7, o.y);
+ Expect.equals(11, o.z);
+ Expect.equals(0, o.w);
+
+ n = new Uint32x4(1, 3, 5, 7);
+ m = new Uint32x4(2, 4, 6, 8);
+ o = n + m;
+ Expect.equals(3, o.x);
+ Expect.equals(7, o.y);
+ Expect.equals(11, o.z);
+ Expect.equals(15, o.w);
+}
+
+testSub() {
+ var m = new Uint32x4(0, 0, 0, 0);
+ var n = new Uint32x4(1, 1, 1, 1);
+ var o = m - n;
+ Expect.equals(4294967295, o.x);
+ Expect.equals(4294967295, o.y);
+ Expect.equals(4294967295, o.z);
+ Expect.equals(4294967295, o.w);
+
+ o = n - m;
+ Expect.equals(1, o.x);
+ Expect.equals(1, o.y);
+ Expect.equals(1, o.z);
+ Expect.equals(1, o.w);
+}
+
+main() {
+ for (int i = 0; i < 20; i++) {
+ testAdd();
+ testSub();
+ }
+}
diff --git a/tests/lib/typed_data/uint32x4_sign_mask_test.dart b/tests/lib/typed_data/uint32x4_sign_mask_test.dart
new file mode 100644
index 0000000..052d0bf
--- /dev/null
+++ b/tests/lib/typed_data/uint32x4_sign_mask_test.dart
@@ -0,0 +1,62 @@
+// 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.
+// VMOptions=--optimization-counter-threshold=10
+
+// Library tag to be able to run in html test framework.
+library uint32x4_sign_mask;
+
+import 'dart:typed_data';
+import 'package:expect/expect.dart';
+
+void testImmediates() {
+ var f = new Uint32x4(1, 2, 3, 4);
+ var m = f.signMask;
+ Expect.equals(0x0, m);
+ f = new Uint32x4(-1, -2, -3, -4);
+ m = f.signMask;
+ Expect.equals(0xf, m);
+ f = new Uint32x4.bool(true, false, false, false);
+ m = f.signMask;
+ Expect.equals(0x1, m);
+ f = new Uint32x4.bool(false, true, false, false);
+ m = f.signMask;
+ Expect.equals(0x2, m);
+ f = new Uint32x4.bool(false, false, true, false);
+ m = f.signMask;
+ Expect.equals(0x4, m);
+ f = new Uint32x4.bool(false, false, false, true);
+ m = f.signMask;
+ Expect.equals(0x8, m);
+}
+
+void testZero() {
+ var f = new Uint32x4(0, 0, 0, 0);
+ var m = f.signMask;
+ Expect.equals(0x0, m);
+ f = new Uint32x4(-0, -0, -0, -0);
+ m = f.signMask;
+ Expect.equals(0x0, m);
+}
+
+void testLogic() {
+ var a = new Uint32x4(0x80000000, 0x80000000, 0x80000000, 0x80000000);
+ var b = new Uint32x4(0x70000000, 0x70000000, 0x70000000, 0x70000000);
+ var c = new Uint32x4(0xf0000000, 0xf0000000, 0xf0000000, 0xf0000000);
+ var m1 = (a & c).signMask;
+ Expect.equals(0xf, m1);
+ var m2 = (a & b).signMask;
+ Expect.equals(0x0, m2);
+ var m3 = (b ^ a).signMask;
+ Expect.equals(0xf, m3);
+ var m4 = (b | c).signMask;
+ Expect.equals(0xf, m4);
+}
+
+main() {
+ for (int i = 0; i < 2000; i++) {
+ testImmediates();
+ testZero();
+ testLogic();
+ }
+}
diff --git a/tests/standalone/coverage_test.dart b/tests/standalone/coverage_test.dart
index ef5e42d..ecf92ea 100644
--- a/tests/standalone/coverage_test.dart
+++ b/tests/standalone/coverage_test.dart
@@ -7,8 +7,10 @@
// This test is mainly here to ensure that the coverage tool compiles and
// runs.
-import "dart:io";
import "dart:async";
+import "dart:convert";
+import "dart:io";
+
import "package:path/path.dart";
// Coverage tool script relative to the path of this test.
@@ -64,11 +66,11 @@
coverageToolProcess.stdin.close();
var stdoutStringStream = coverageToolProcess.stdout
.transform(new StringDecoder())
- .transform(new LineTransformer());
+ .transform(new LineSplitter());
var stderrStringStream = coverageToolProcess.stderr
.transform(new StringDecoder())
- .transform(new LineTransformer());
+ .transform(new LineSplitter());
// Wait for 3 future events: stdout and stderr streams of the coverage
// tool process closed, and coverage tool process terminated.
diff --git a/tests/standalone/debugger/debug_lib.dart b/tests/standalone/debugger/debug_lib.dart
index 79161c7..7be6854 100644
--- a/tests/standalone/debugger/debug_lib.dart
+++ b/tests/standalone/debugger/debug_lib.dart
@@ -7,6 +7,7 @@
library DartDebugger;
import "dart:async";
+import "dart:convert";
import "dart:io";
import "dart:math";
import "dart:utf";
@@ -393,7 +394,7 @@
Debugger(this.targetProcess, this.script) {
var stdoutStringStream = targetProcess.stdout
.transform(new StringDecoder())
- .transform(new LineTransformer());
+ .transform(new LineSplitter());
stdoutStringStream.listen((line) {
print("TARG: $line");
if (line.startsWith("Debugger listening")) {
@@ -406,7 +407,7 @@
var stderrStringStream = targetProcess.stderr
.transform(new StringDecoder())
- .transform(new LineTransformer());
+ .transform(new LineSplitter());
stderrStringStream.listen((line) {
print("TARG: $line");
});
diff --git a/tests/standalone/io/file_input_stream_test.dart b/tests/standalone/io/file_input_stream_test.dart
index d57c014..021e19e 100644
--- a/tests/standalone/io/file_input_stream_test.dart
+++ b/tests/standalone/io/file_input_stream_test.dart
@@ -3,23 +3,25 @@
// BSD-style license that can be found in the LICENSE file.
// Testing file input stream, VM-only, standalone test.
-import "package:expect/expect.dart";
+import "dart:convert";
import "dart:io";
import "dart:isolate";
+import "package:expect/expect.dart";
+
// Helper method to be able to run the test from the runtime
// directory, or the top directory.
String getFilename(String path) =>
new File(path).existsSync() ? path : '../$path';
-void testStringLineTransformer() {
+void testStringLineSplitter() {
String fileName = getFilename("tests/standalone/io/readuntil_test.dat");
// File contains "Hello Dart\nwassup!\n"
File file = new File(fileName);
int linesRead = 0;
var lineStream = file.openRead()
.transform(new StringDecoder())
- .transform(new LineTransformer());
+ .transform(new LineSplitter());
lineStream.listen((line) {
linesRead++;
if (linesRead == 1) {
@@ -224,14 +226,14 @@
}
-void testStringLineTransformerEnding(String name, int length) {
+void testStringLineSplitterEnding(String name, int length) {
String fileName = getFilename("tests/standalone/io/$name");
// File contains 10 lines.
File file = new File(fileName);
Expect.equals(length, file.openSync().lengthSync());
var lineStream = file.openRead()
.transform(new StringDecoder())
- .transform(new LineTransformer());
+ .transform(new LineSplitter());
int lineCount = 0;
lineStream.listen(
(line) {
@@ -248,7 +250,7 @@
main() {
- testStringLineTransformer();
+ testStringLineSplitter();
testOpenStreamAsync();
testInputStreamTruncate();
testInputStreamDelete();
@@ -258,6 +260,6 @@
// Check the length of these files as both are text files where one
// is without a terminating line separator which can easily be added
// back if accidentally opened in a text editor.
- testStringLineTransformerEnding("readline_test1.dat", 111);
- testStringLineTransformerEnding("readline_test2.dat", 114);
+ testStringLineSplitterEnding("readline_test1.dat", 111);
+ testStringLineSplitterEnding("readline_test2.dat", 114);
}
diff --git a/tests/standalone/io/http_server_idle_timeout_test.dart b/tests/standalone/io/http_server_idle_timeout_test.dart
new file mode 100644
index 0000000..5673bfc
--- /dev/null
+++ b/tests/standalone/io/http_server_idle_timeout_test.dart
@@ -0,0 +1,57 @@
+// 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.
+//
+// VMOptions=
+// VMOptions=--short_socket_read
+// VMOptions=--short_socket_write
+// VMOptions=--short_socket_read --short_socket_write
+
+import "dart:async";
+import "dart:io";
+import "dart:isolate";
+
+
+void testTimeoutAfterRequest() {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
+ server.idleTimeout = null;
+
+ server.listen((request) {
+ server.idleTimeout = const Duration(milliseconds: 100);
+ request.response.close();
+ });
+
+ Socket.connect("127.0.0.1", server.port).then((socket) {
+ var data = "GET / HTTP/1.1\r\nContent-Length: 0\r\n\r\n";
+ socket.write(data);
+ socket.listen(
+ null,
+ onDone: () {
+ socket.close();
+ server.close();
+ });
+ });
+ });
+}
+
+void testTimeoutBeforeRequest() {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
+ server.idleTimeout = const Duration(milliseconds: 100);
+
+ server.listen((request) => request.response.close());
+
+ Socket.connect("127.0.0.1", server.port).then((socket) {
+ socket.listen(
+ null,
+ onDone: () {
+ socket.close();
+ server.close();
+ });
+ });
+ });
+}
+
+void main() {
+ testTimeoutAfterRequest();
+ testTimeoutBeforeRequest();
+}
diff --git a/tests/standalone/io/platform_test.dart b/tests/standalone/io/platform_test.dart
index 1677e67a..1fdad2b 100644
--- a/tests/standalone/io/platform_test.dart
+++ b/tests/standalone/io/platform_test.dart
@@ -25,6 +25,11 @@
Expect.isTrue(Platform.executable.contains('dart'));
Expect.isTrue(Platform.script.replaceAll('\\', '/').
endsWith('tests/standalone/io/platform_test.dart'));
+ Directory packageRoot = new Directory(Platform.packageRoot);
+ Expect.isTrue(packageRoot.existsSync());
+ Expect.isTrue(new Directory("${packageRoot.path}/expect").existsSync());
+ Expect.isTrue(Platform.executableArguments.any(
+ (arg) => arg.contains(Platform.packageRoot)));
}
void f() {
@@ -35,6 +40,12 @@
if (msg == "Platform.script") {
reply.send(Platform.script);
}
+ if (msg == "Platform.packageRoot") {
+ reply.send(Platform.packageRoot);
+ }
+ if (msg == "Platform.executableArguments") {
+ reply.send(Platform.executableArguments);
+ }
if (msg == "new Options().executable") {
reply.send(new Options().executable);
}
@@ -53,15 +64,19 @@
var sendPort = spawnFunction(f);
Future.wait([sendPort.call("Platform.executable"),
sendPort.call("Platform.script"),
+ sendPort.call("Platform.packageRoot"),
+ sendPort.call("Platform.executableArguments"),
sendPort.call("new Options().executable"),
sendPort.call("new Options().script")])
.then((results) {
Expect.equals(Platform.executable, results[0]);
- Expect.equals(Platform.executable, results[2]);
+ Expect.equals(Platform.executable, results[4]);
Uri uri = Uri.parse(results[1]);
- Expect.equals(uri, Uri.parse(results[3]));
+ Expect.equals(uri, Uri.parse(results[5]));
Expect.equals("file", uri.scheme);
Expect.isTrue(uri.path.endsWith('tests/standalone/io/platform_test.dart'));
+ Expect.equals(Platform.packageRoot, results[2]);
+ Expect.listEquals(Platform.executableArguments, results[3]);
sendPort.call("close").then((_) => port.close());
});
}
diff --git a/tests/standalone/io/process_stdin_transform_unsubscribe_script.dart b/tests/standalone/io/process_stdin_transform_unsubscribe_script.dart
index 0711124..06b42d8 100644
--- a/tests/standalone/io/process_stdin_transform_unsubscribe_script.dart
+++ b/tests/standalone/io/process_stdin_transform_unsubscribe_script.dart
@@ -4,13 +4,14 @@
//
// Utility script to echo stdin to stdout or stderr or both.
+import "dart:convert";
import "dart:io";
main() {
var subscription;
subscription = stdin
.transform(new StringDecoder())
- .transform(new LineTransformer())
+ .transform(new LineSplitter())
.listen((String line) {
// Unsubscribe after the first line.
subscription.cancel();
diff --git a/tests/standalone/io/secure_socket_renegotiate_client.dart b/tests/standalone/io/secure_socket_renegotiate_client.dart
index 9ac2192..49d9c99 100644
--- a/tests/standalone/io/secure_socket_renegotiate_client.dart
+++ b/tests/standalone/io/secure_socket_renegotiate_client.dart
@@ -8,6 +8,7 @@
// a client certificate to be sent.
import "dart:async";
+import "dart:convert";
import "dart:io";
const HOST_NAME = "localhost";
@@ -44,7 +45,7 @@
expectEquals('CN=myauthority', certificate.issuer);
StreamIterator<String> input = new StreamIterator(socket
.transform(new StringDecoder())
- .transform(new LineTransformer()));
+ .transform(new LineSplitter()));
socket.writeln('first');
input.moveNext()
.then((success) {
diff --git a/tests/standalone/io/secure_socket_renegotiate_test.dart b/tests/standalone/io/secure_socket_renegotiate_test.dart
index b938244..54736a8 100644
--- a/tests/standalone/io/secure_socket_renegotiate_test.dart
+++ b/tests/standalone/io/secure_socket_renegotiate_test.dart
@@ -6,10 +6,12 @@
// are in separate processes, and that connection renegotiation works, and
// can request a client certificate to be sent.
+import "dart:async";
+import "dart:convert";
+import "dart:io";
+
import "package:expect/expect.dart";
import "package:path/path.dart";
-import "dart:async";
-import "dart:io";
const HOST_NAME = "localhost";
const CERTIFICATE = "localhost_cert";
@@ -29,7 +31,7 @@
StreamIterator<String> input =
new StreamIterator(socket.transform(new StringDecoder())
- .transform(new LineTransformer()));
+ .transform(new LineSplitter()));
input.moveNext().then((success) {
Expect.isTrue(success);
Expect.equals('first', input.current);
diff --git a/tests/standalone/io/stdin_sync_test.dart b/tests/standalone/io/stdin_sync_test.dart
index f687837..0ac4e9d 100644
--- a/tests/standalone/io/stdin_sync_test.dart
+++ b/tests/standalone/io/stdin_sync_test.dart
@@ -2,10 +2,12 @@
// 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:path/path.dart";
+import "dart:convert";
import "dart:io";
import "dart:json";
+import "package:path/path.dart";
+
void testReadByte() {
void test(String line, List<String> expected) {
var script = join(dirname(Platform.script), "stdin_sync_script.dart");
@@ -16,14 +18,14 @@
process.stdin.close();
process.stderr
.transform(new StringDecoder())
- .transform(new LineTransformer())
+ .transform(new LineSplitter())
.fold(new StringBuffer(), (b, d) => b..write(d))
.then((data) {
if (data.toString() != '') throw "Bad output: '$data'";
});
process.stdout
.transform(new StringDecoder())
- .transform(new LineTransformer())
+ .transform(new LineSplitter())
.fold(new StringBuffer(), (b, d) => b..write(d))
.then((data) {
if (data.toString() != 'true') throw "Bad output: '$data'";
diff --git a/tests/standalone/io/string_transformer_test.dart b/tests/standalone/io/string_transformer_test.dart
index 054f973..eb6d168 100644
--- a/tests/standalone/io/string_transformer_test.dart
+++ b/tests/standalone/io/string_transformer_test.dart
@@ -2,12 +2,14 @@
// 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 "dart:convert";
import "dart:io";
import "dart:isolate";
import "dart:utf";
+import "package:expect/expect.dart";
+
void main() {
testUtf8();
testLatin1();
@@ -101,7 +103,7 @@
var controller = new StreamController(sync: true);
var stream = controller.stream
.transform(new StringDecoder())
- .transform(new LineTransformer());
+ .transform(new LineSplitter());
var stage = 0;
@@ -130,7 +132,7 @@
var stream = controller.stream
.transform(new StringDecoder())
- .transform(new LineTransformer());
+ .transform(new LineSplitter());
var expectedLines = ['Line1', 'Line2','Line3', 'Line4',
'', '', '', '', '', '',
@@ -161,7 +163,7 @@
var errors = 0;
var stream = controller.stream
.transform(new StringDecoder())
- .transform(new LineTransformer());
+ .transform(new LineSplitter());
stream.listen(
(_) {},
onDone: () {
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index e15eaf5..b50b03f 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -7,9 +7,11 @@
# listed in tests/lib/analyzer/analyze_tests.status without the "standalone"
# prefix.
-# The testing infrastructure is using the dart:io Path class.
+# The testing infrastructure is using the dart:io Path and LineTransformer
+# classes.
io/skipping_dart2js_compilations_test: Skip # http/dartbug.com/12449
io/dependency_graph_test: Skip # http/dartbug.com/12449
+io/status_file_parser_test: Skip # http/dartbug.com/12449
package/invalid_uri_test: Fail, OK # Fails intentionally
@@ -29,11 +31,6 @@
io/directory_fuzz_test: Skip
[ $runtime == vm && $system == macos ]
-# These tests fail intermittently on MacOS due to an https request that
-# fails not completing the future it returns: Issue 12451
-io/https_unauthorized_test: Pass, Fail
-io/https_bad_certificate_test: Pass, Fail
-
# This test fails with "Too many open files" on the Mac OS buildbot.
# This is expected as MacOS by default runs with a very low number
# of allowed open files ('ulimit -n' says something like 256).
@@ -130,7 +127,6 @@
[ $compiler == dart2js && $jscl ]
assert_test: Fail, OK # Assumes unspecified fields on the AssertionError.
-byte_array_test: Fail, OK # ByteArray
deoptimization_test: Fail, OK # Requires bigint.
out_of_memory_test: Fail, OK # d8 handles much larger arrays than Dart VM.
io/options_test: Fail, OK # Cannot pass options to d8.
diff --git a/tests/standalone/vmservice/test_helper.dart b/tests/standalone/vmservice/test_helper.dart
index e3f51c5..d199d05 100644
--- a/tests/standalone/vmservice/test_helper.dart
+++ b/tests/standalone/vmservice/test_helper.dart
@@ -5,6 +5,7 @@
library vmservice_test_helper;
import 'dart:async';
+import 'dart:convert';
import 'dart:io';
import 'dart:json' as JSON;
import 'dart:utf' as UTF;
@@ -97,7 +98,7 @@
var blank;
var first = true;
process.stdout.transform(new StringDecoder())
- .transform(new LineTransformer()).listen((line) {
+ .transform(new LineSplitter()).listen((line) {
if (line.startsWith('VmService listening on port ')) {
RegExp portExp = new RegExp(r"\d+");
var port = portExp.stringMatch(line);
@@ -116,7 +117,7 @@
print(line);
});
process.stderr.transform(new StringDecoder())
- .transform(new LineTransformer()).listen((line) {
+ .transform(new LineSplitter()).listen((line) {
print(line);
});
process.exitCode.then((code) {
diff --git a/tests/utils/utils.status b/tests/utils/utils.status
index 6fdf0e2..7bc1414 100644
--- a/tests/utils/utils.status
+++ b/tests/utils/utils.status
@@ -11,9 +11,6 @@
dart2js_test: Skip # Uses dart:io.
txt_layout_test: Skip # Might just go away.
-[ $compiler == none && $runtime == drt && $mode == debug ]
-recursive_import_test: Fail # 12501
-
[ $compiler == dart2js && $browser ]
*: Skip
diff --git a/tools/VERSION b/tools/VERSION
index 01d318f..e7ae0f4 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -1,4 +1,4 @@
MAJOR 0
MINOR 6
-BUILD 19
+BUILD 20
PATCH 0
diff --git a/tools/bots/bot.py b/tools/bots/bot.py
index 993ff4f..f9fcd0d 100644
--- a/tools/bots/bot.py
+++ b/tools/bots/bot.py
@@ -36,11 +36,13 @@
- total_shards: The total number of shards, None when not specified.
- is_buildbot: True if we are on a buildbot (or emulating it).
- test_set: Specification of a non standard test set or None.
+ - csp: This is using csp when running
+ - arch: The architecture to build on.
"""
def __init__(self, compiler, runtime, mode, system, checked=False,
host_checked=False, minified=False, shard_index=None,
total_shards=None, is_buildbot=False, test_set=None,
- csp=None):
+ csp=None, arch=None):
self.compiler = compiler
self.runtime = runtime
self.mode = mode
@@ -53,6 +55,10 @@
self.is_buildbot = is_buildbot
self.test_set = test_set
self.csp = csp
+ if (arch == None):
+ self.arch = 'ia32'
+ else:
+ self.arch = arch
def PrintBuildInfo(self):
shard_description = ""
@@ -60,10 +66,11 @@
shard_description = " shard %s of %s" % (self.shard_index,
self.total_shards)
print ("compiler: %s, runtime: %s mode: %s, system: %s,"
- " checked: %s, host-checked: %s, minified: %s, test-set: %s%s"
+ " checked: %s, host-checked: %s, minified: %s, test-set: %s"
+ " arch: %s%s"
) % (self.compiler, self.runtime, self.mode, self.system,
self.checked, self.host_checked, self.minified, self.test_set,
- shard_description)
+ self.arch, shard_description)
class BuildStep(object):
@@ -102,7 +109,7 @@
"""
with BuildStep('Build SDK'):
args = [sys.executable, './tools/build.py', '--mode=' + build_info.mode,
- 'create_sdk']
+ '--arch=' + build_info.arch, 'create_sdk']
print 'Building SDK: %s' % (' '.join(args))
RunProcess(args)
@@ -205,6 +212,7 @@
'--mode=' + build_info.mode,
'--compiler=' + build_info.compiler,
'--runtime=' + build_info.runtime,
+ '--arch=' + build_info.arch,
'--progress=buildbot',
'-v', '--time', '--use-sdk', '--report'
]
diff --git a/tools/bots/compiler.py b/tools/bots/compiler.py
index 79e538c..e469d6a 100644
--- a/tools/bots/compiler.py
+++ b/tools/bots/compiler.py
@@ -21,7 +21,7 @@
import bot
DART2JS_BUILDER = (
- r'dart2js-(linux|mac|windows)(-(jsshell))?-(debug|release)(-(checked|host-checked))?(-(host-checked))?(-(minified))?-?(\d*)-?(\d*)')
+ r'dart2js-(linux|mac|windows)(-(jsshell))?-(debug|release)(-(checked|host-checked))?(-(host-checked))?(-(minified))?(-(x64))?-?(\d*)-?(\d*)')
WEB_BUILDER = (
r'dart2js-(ie9|ie10|ff|safari|chrome|chromeOnAndroid|opera|drt)-(win7|win8|mac10\.8|mac10\.7|linux)(-(all|html))?(-(csp))?(-(\d+)-(\d+))?')
@@ -41,6 +41,7 @@
total_shards = None
test_set = None
csp = None
+ arch = None
dart2js_pattern = re.match(DART2JS_BUILDER, builder_name)
web_pattern = re.match(WEB_BUILDER, builder_name)
@@ -59,6 +60,7 @@
compiler = 'dart2js'
system = dart2js_pattern.group(1)
runtime = 'd8'
+ arch = 'ia32'
if dart2js_pattern.group(3) == 'jsshell':
runtime = 'jsshell'
mode = dart2js_pattern.group(4)
@@ -75,8 +77,10 @@
host_checked = True
if dart2js_pattern.group(10) == 'minified':
minified = True
- shard_index = dart2js_pattern.group(11)
- total_shards = dart2js_pattern.group(12)
+ if dart2js_pattern.group(12) == 'x64':
+ arch = 'x64'
+ shard_index = dart2js_pattern.group(13)
+ total_shards = dart2js_pattern.group(14)
else :
return None
@@ -96,7 +100,7 @@
return None
return bot.BuildInfo(compiler, runtime, mode, system, checked, host_checked,
minified, shard_index, total_shards, is_buildbot,
- test_set, csp)
+ test_set, csp, arch)
def NeedsXterm(compiler, runtime):
@@ -135,7 +139,7 @@
IsFirstTestStepCall = True
-def TestStep(name, mode, system, compiler, runtime, targets, flags):
+def TestStep(name, mode, system, compiler, runtime, targets, flags, arch):
step_name = TestStepName(name, flags)
with bot.BuildStep(step_name, swallow_error=True):
sys.stdout.flush()
@@ -152,6 +156,7 @@
'--mode=' + mode,
'--compiler=' + compiler,
'--runtime=' + runtime,
+ '--arch=' + arch,
'--time',
'--use-sdk',
'--report',
@@ -181,7 +186,7 @@
bot.RunProcess(cmd)
-def TestCompiler(runtime, mode, system, flags, is_buildbot, test_set):
+def TestCompiler(runtime, mode, system, flags, is_buildbot, test_set, arch):
""" test the compiler.
Args:
- runtime: either 'd8', 'jsshell', or one of the browsers, see GetBuildInfo
@@ -191,6 +196,7 @@
- is_buildbot: true if we are running on a real buildbot instead of
emulating one.
- test_set: Specification of a non standard test set, default None
+ - arch: The architecture to run on.
"""
def GetPath(runtime):
@@ -239,13 +245,13 @@
# Run the unit tests in checked mode (the VM's checked mode).
unit_test_flags.append('--checked')
TestStep("dart2js_unit", mode, system, 'none', 'vm', ['dart2js'],
- unit_test_flags)
+ unit_test_flags, arch)
if system == 'windows' and runtime == 'ie10':
- TestStep("dart2js", mode, system, 'dart2js', runtime, ['html'], flags)
+ TestStep("dart2js", mode, system, 'dart2js', runtime, ['html'], flags, arch)
else:
# Run the default set of test suites.
- TestStep("dart2js", mode, system, 'dart2js', runtime, [], flags)
+ TestStep("dart2js", mode, system, 'dart2js', runtime, [], flags, arch)
# TODO(kasperl): Consider running peg and css tests too.
extras = ['dart2js_extra', 'dart2js_native', 'dart2js_foreign']
@@ -257,7 +263,7 @@
# Other systems have less resources and tend to time out.
extras_flags = extras_flags + ['--host-checked']
TestStep("dart2js_extra", mode, system, 'dart2js', runtime, extras,
- extras_flags)
+ extras_flags, arch)
def _DeleteTempWebdriverProfiles(directory):
@@ -356,13 +362,14 @@
AddAndroidToolsToPath()
TestCompiler(build_info.runtime, build_info.mode, build_info.system,
- list(test_flags), build_info.is_buildbot, build_info.test_set)
+ list(test_flags), build_info.is_buildbot, build_info.test_set,
+ build_info.arch)
# See comment in GetHasHardCodedCheckedMode, this is a hack.
if (GetHasHardCodedCheckedMode(build_info)):
TestCompiler(build_info.runtime, build_info.mode, build_info.system,
test_flags + ['--checked'], build_info.is_buildbot,
- build_info.test_set)
+ build_info.test_set, build_info.arch)
if build_info.runtime != 'd8':
CleanUpTemporaryFiles(build_info.system, build_info.runtime)
@@ -377,7 +384,7 @@
"""
with bot.BuildStep('Build SDK and d8'):
args = [sys.executable, './tools/build.py', '--mode=' + build_info.mode,
- 'dart2js_bot']
+ '--arch=' + build_info.arch, 'dart2js_bot']
print 'Build SDK and d8: %s' % (' '.join(args))
bot.RunProcess(args)
diff --git a/tools/coverage.dart b/tools/coverage.dart
index 20811d1..350019d 100644
--- a/tools/coverage.dart
+++ b/tools/coverage.dart
@@ -13,6 +13,7 @@
// --verbose see the stdout and stderr output of the debug
// target process.
+import "dart:convert";
import "dart:io";
import "dart:utf";
import "dart:json" as JSON;
@@ -214,7 +215,7 @@
Debugger(this.targetProcess) {
var stdoutStringStream = targetProcess.stdout
.transform(new StringDecoder())
- .transform(new LineTransformer());
+ .transform(new LineSplitter());
stdoutStringStream.listen((line) {
if (showDebuggeeOutput) {
print("TARG: $line");
@@ -231,7 +232,7 @@
var stderrStringStream = targetProcess.stderr
.transform(new StringDecoder())
- .transform(new LineTransformer());
+ .transform(new LineSplitter());
stderrStringStream.listen((line) {
if (showDebuggeeOutput) {
print("TARG: $line");
diff --git a/tools/ddbg.dart b/tools/ddbg.dart
index f1079e0..18673a6 100644
--- a/tools/ddbg.dart
+++ b/tools/ddbg.dart
@@ -38,6 +38,7 @@
sbp [<file>] <line> Set breakpoint
rbp <id> Remove breakpoint with given id
po <id> Print object info for given id
+ eval <id> <expr> Evaluate expr on object id
pl <id> <idx> [<len>] Print list element/slice
pc <id> Print class info for given id
ll List loaded libraries
@@ -126,6 +127,14 @@
"params": { "isolateId" : isolate_id,
"libraryId": int.parse(args[1]) } };
sendCmd(cmd).then((result) => handleGetScriptsResponse(result));
+ } else if (command == "eval" && args.length > 2) {
+ var expr = args.getRange(2, args.length).join(" ");
+ var cmd = { "id": seqNum,
+ "command": "evaluateExpr",
+ "params": { "isolateId": isolate_id,
+ "objectId": int.parse(args[1]),
+ "expression": expr } };
+ sendCmd(cmd).then((result) => handleEvalResponse(result));
} else if (command == "po" && args.length == 2) {
var cmd = { "id": seqNum,
"command": "getObjectProperties",
@@ -368,6 +377,12 @@
}
+void handleEvalResponse(response) {
+ Map result = response["result"];
+ print(remoteObject(result));
+}
+
+
void handleSetBpResponse(response) {
Map result = response["result"];
var id = result["breakpointId"];
diff --git a/tools/dom/dom.json b/tools/dom/dom.json
index d56916c..d9a9dec 100644
--- a/tools/dom/dom.json
+++ b/tools/dom/dom.json
@@ -675,8 +675,14 @@
"comment": "http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#path-objects",
"support_level": "experimental"
},
+ "drawCustomFocusRing": {
+ "support_level": "untriaged"
+ },
"drawImage": {},
"drawImageFromRect": {},
+ "drawSystemFocusRing": {
+ "support_level": "untriaged"
+ },
"fill": {},
"fillRect": {},
"fillStyle": {},
@@ -690,6 +696,9 @@
"getLineDash": {},
"globalAlpha": {},
"globalCompositeOperation": {},
+ "imageSmoothingEnabled": {
+ "support_level": "untriaged"
+ },
"isPointInPath": {},
"isPointInStroke": {},
"lineCap": {},
@@ -1897,6 +1906,9 @@
},
"getBoundingClientRect": {},
"getClientRects": {},
+ "getDestinationInsertionPoints": {
+ "support_level": "untriaged"
+ },
"getElementsByClassName": {},
"getElementsByTagName": {},
"getElementsByTagNameNS": {
@@ -1924,6 +1936,9 @@
"dart_action": "stable",
"support_level": "nonstandard"
},
+ "inputMethodContext": {
+ "support_level": "untriaged"
+ },
"isContentEditable": {
"comment": "http://www.whatwg.org/specs/web-apps/2007-10-26/multipage/section-elements.html#htmlelement",
"dart_action": "stable",
@@ -2252,6 +2267,12 @@
"comment": "http://www.whatwg.org/specs/web-apps/current-work/multipage/workers.html#errorevent",
"dart_action": "unstable",
"members": {
+ "colno": {
+ "support_level": "untriaged"
+ },
+ "error": {
+ "support_level": "untriaged"
+ },
"filename": {},
"lineno": {},
"message": {}
@@ -3142,6 +3163,9 @@
"dart_action": "suppress",
"support_level": "nonstandard"
},
+ "inputMethodContext": {
+ "support_level": "untriaged"
+ },
"insertAdjacentElement": {
"support_level": "nonstandard"
},
@@ -4961,12 +4985,27 @@
"KeyboardEvent": {
"comment": "http://www.w3.org/TR/DOM-Level-3-Events/#events-KeyboardEvent",
"members": {
+ "DOM_KEY_LOCATION_LEFT": {
+ "support_level": "untriaged"
+ },
+ "DOM_KEY_LOCATION_NUMPAD": {
+ "support_level": "untriaged"
+ },
+ "DOM_KEY_LOCATION_RIGHT": {
+ "support_level": "untriaged"
+ },
+ "DOM_KEY_LOCATION_STANDARD": {
+ "support_level": "untriaged"
+ },
"altGraphKey": {
"dart_action": "experimental",
"support_level": "nonstandard"
},
"altKey": {},
"ctrlKey": {},
+ "getModifierState": {
+ "support_level": "untriaged"
+ },
"initKeyboardEvent": {},
"keyIdentifier": {
"dart_action": "experimental",
@@ -4976,6 +5015,9 @@
"dart_action": "experimental",
"support_level": "nonstandard"
},
+ "location": {
+ "support_level": "untriaged"
+ },
"metaKey": {},
"shiftKey": {}
},
@@ -6133,6 +6175,9 @@
"Performance": {
"comment": "http://www.w3.org/TR/navigation-timing/#performance",
"members": {
+ "addEventListener": {
+ "support_level": "untriaged"
+ },
"clearMarks": {
"comment": "https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/UserTiming/Overview.html#extensions-performance-interface",
"support_level": "experimental"
@@ -6141,6 +6186,9 @@
"comment": "https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/UserTiming/Overview.html#extensions-performance-interface",
"support_level": "experimental"
},
+ "dispatchEvent": {
+ "support_level": "untriaged"
+ },
"getEntries": {
"comment": "http://www.w3.org/TR/performance-timeline/#sec-window.performance-attribute",
"support_level": "experimental"
@@ -6173,6 +6221,9 @@
"comment": "http://www.w3c-test.org/webperf/specs/ResourceTiming/#performanceresourcetiming-methods",
"support_level": "experimental"
},
+ "removeEventListener": {
+ "support_level": "untriaged"
+ },
"timing": {},
"webkitClearResourceTimings": {
"comment": "http://www.w3c-test.org/webperf/specs/ResourceTiming/#extensions-performance-interface",
@@ -6443,11 +6494,29 @@
"bufferedAmount": {},
"close": {},
"dispatchEvent": {},
+ "id": {
+ "support_level": "untriaged"
+ },
"label": {},
+ "maxRetransmitTime": {
+ "support_level": "untriaged"
+ },
+ "maxRetransmits": {
+ "support_level": "untriaged"
+ },
+ "negotiated": {
+ "support_level": "untriaged"
+ },
"onclose": {},
"onerror": {},
"onmessage": {},
"onopen": {},
+ "ordered": {
+ "support_level": "untriaged"
+ },
+ "protocol": {
+ "support_level": "untriaged"
+ },
"readyState": {},
"reliable": {},
"removeEventListener": {},
@@ -6691,6 +6760,25 @@
},
"support_level": "experimental"
},
+ "RsaKeyGenParams": {
+ "members": {
+ "modulusLength": {
+ "support_level": "untriaged"
+ },
+ "publicExponent": {
+ "support_level": "untriaged"
+ }
+ },
+ "support_level": "untriaged"
+ },
+ "RsaSsaParams": {
+ "members": {
+ "hash": {
+ "support_level": "untriaged"
+ }
+ },
+ "support_level": "untriaged"
+ },
"SQLError": {
"comment": "http://www.w3.org/TR/webdatabase/#sqlerror",
"dart_action": "experimental",
@@ -7301,8 +7389,17 @@
"comment": "http://www.w3.org/TR/SVG/types.html#InterfaceSVGElement",
"dart_action": "unstable",
"members": {
+ "className": {
+ "support_level": "untriaged"
+ },
+ "getPresentationAttribute": {
+ "support_level": "untriaged"
+ },
"id": {},
"ownerSVGElement": {},
+ "style": {
+ "support_level": "untriaged"
+ },
"viewportElement": {},
"xmlbase": {},
"xmllang": {
@@ -10055,10 +10152,19 @@
"appendBufferView": {
"support_level": "untriaged"
},
+ "appendWindowEnd": {
+ "support_level": "untriaged"
+ },
+ "appendWindowStart": {
+ "support_level": "untriaged"
+ },
"buffered": {},
"dispatchEvent": {
"support_level": "untriaged"
},
+ "remove": {
+ "support_level": "untriaged"
+ },
"removeEventListener": {
"support_level": "untriaged"
},
@@ -10400,6 +10506,9 @@
"encrypt": {
"support_level": "untriaged"
},
+ "generateKey": {
+ "support_level": "untriaged"
+ },
"importKey": {
"support_level": "untriaged"
},
@@ -10416,6 +10525,9 @@
"comment": "http://dom.spec.whatwg.org/#interface-text",
"members": {
"Text": {},
+ "getDestinationInsertionPoints": {
+ "support_level": "untriaged"
+ },
"replaceWholeText": {
"comment": "http://dom.spec.whatwg.org/#dom-text-replacewholetext",
"dart_action": "suppress",
diff --git a/tools/dom/idl/dart/dart.idl b/tools/dom/idl/dart/dart.idl
index e7be42c..7b1639a 100644
--- a/tools/dom/idl/dart/dart.idl
+++ b/tools/dom/idl/dart/dart.idl
@@ -67,6 +67,8 @@
[Supplemental]
interface CanvasRenderingContext2D {
[DartName=createImageDataFromImageData] ImageData createImageData(ImageData imagedata);
+
+ [Suppressed] attribute boolean webkitImageSmoothingEnabled;
};
[Supplemental]
@@ -334,6 +336,26 @@
[CustomSetter] attribute DOMString hash;
};
+// TODO(jacobr): reenable these new Blink features.
+[Suppressed]
+interface ImageBitmapFactories {};
+
+// See https://chromiumcodereview.appspot.com/15901002 for the V8 implementation of
+// TextEncoder/TextDecoder
+[Suppressed]
+interface TextEncoder {};
+
+[Suppressed]
+interface TextDecoder {};
+
+// TODO(jacobr): renable these as part of fixing dartbug.com/12537
+// We need to apply changes analogous to https://chromiumcodereview.appspot.com/21274004
+// to the Dart bindings so that we can reenable NodeIterator and TreeWalker
+[Suppressed]
+interface NodeIterator {};
+
+[Suppressed]
+interface TreeWalker {};
[Supplemental]
interface Window : EventTarget {};
diff --git a/tools/dom/scripts/dartmetadata.py b/tools/dom/scripts/dartmetadata.py
index ecbc261..40b9713 100644
--- a/tools/dom/scripts/dartmetadata.py
+++ b/tools/dom/scripts/dartmetadata.py
@@ -83,6 +83,10 @@
"@Creates('Null')",
],
+ "ErrorEvent.error": [
+ "@Creates('Null')", # Only returns values created elsewhere.
+ ],
+
# To be in callback with the browser-created Event, we had to have called
# addEventListener on the target, so we avoid
'Event.currentTarget': [
diff --git a/tools/dom/scripts/generator.py b/tools/dom/scripts/generator.py
index 396b7b3..5889566 100644
--- a/tools/dom/scripts/generator.py
+++ b/tools/dom/scripts/generator.py
@@ -18,6 +18,7 @@
'DOMStringMap',
'ChildNode',
'EventListener',
+ 'EventHandler',
'MediaQueryListListener',
'MutationCallback',
'ParentNode',
@@ -783,6 +784,12 @@
super(CallbackIDLTypeInfo, self).__init__(idl_type, data)
+def array_type(data_type):
+ matched = re.match(r'([\w\d_\s]+)\[\]', data_type)
+ if not matched:
+ return None
+ return matched.group(1)
+
class SequenceIDLTypeInfo(IDLTypeInfo):
def __init__(self, idl_type, data, item_info):
super(SequenceIDLTypeInfo, self).__init__(idl_type, data)
@@ -807,7 +814,11 @@
return '%s', 'Vector< RefPtr<%s> >' % item_native_type, 'DartUtilities', 'toNativeVector< RefPtr<%s> >' % item_native_type
def parameter_type(self):
- return self.native_type()
+ native_type = self.native_type()
+ if array_type(native_type):
+ return 'const Vector<RefPtr<%s> > &' % array_type(native_type)
+
+ return native_type
def pass_native_by_ref(self): return True
@@ -1030,6 +1041,7 @@
'Element': TypeData(clazz='Interface', merged_interface='HTMLElement',
custom_to_dart=True),
'EventListener': TypeData(clazz='Interface', custom_to_native=True),
+ 'EventHandler': TypeData(clazz='Interface', custom_to_native=True),
'EventTarget': TypeData(clazz='Interface', custom_to_native=True),
'HTMLElement': TypeData(clazz='Interface', merged_into='Element',
custom_to_dart=True),
@@ -1142,7 +1154,7 @@
item_info = self.TypeInfo(match.group(1) or match.group(2))
# TODO(vsm): Generalize this code.
if 'SourceInfo' in type_name:
- type_data.native_type = 'Vector<RefPtr<SourceInfo> >'
+ type_data.native_type = 'const Vector<RefPtr<SourceInfo> >& '
return SequenceIDLTypeInfo(type_name, type_data, item_info)
if not type_name in _idl_type_registry:
@@ -1179,8 +1191,7 @@
type_name, type_data, dart_interface_name, self)
if type_data.clazz == 'TypedList':
- dart_interface_name = self._renamer.RenameInterface(
- self._database.GetInterface(type_name))
+ dart_interface_name = self._renamer.RenameInterfaceId(type_name)
return TypedListIDLTypeInfo(
type_name, type_data, dart_interface_name, self)
@@ -1188,8 +1199,7 @@
if type_name == 'ArrayBuffer':
dart_interface_name = 'ByteBuffer'
else:
- dart_interface_name = self._renamer.RenameInterface(
- self._database.GetInterface(type_name))
+ dart_interface_name = self._renamer.RenameInterfaceId(type_name)
return BasicTypedListIDLTypeInfo(
type_name, type_data, dart_interface_name, self)
diff --git a/tools/dom/scripts/htmldartgenerator.py b/tools/dom/scripts/htmldartgenerator.py
index 0692740..34911cf 100644
--- a/tools/dom/scripts/htmldartgenerator.py
+++ b/tools/dom/scripts/htmldartgenerator.py
@@ -72,7 +72,7 @@
self.AddConstant(const)
for attr in sorted(interface.attributes, ConstantOutputOrder):
- if attr.type.id != 'EventListener':
+ if attr.type.id != 'EventHandler' and attr.type.id != 'EventListener':
self.AddAttribute(attr, declare_only)
# The implementation should define an indexer if the interface directly
@@ -117,7 +117,7 @@
continue
for attr in sorted(parent_interface.attributes, ConstantOutputOrder):
if not FindMatchingAttribute(interface, attr):
- if attr.type.id != 'EventListener':
+ if attr.type.id != 'EventHandler':
self.SecondaryContext(parent_interface)
self.AddAttribute(attr)
diff --git a/tools/dom/scripts/htmleventgenerator.py b/tools/dom/scripts/htmleventgenerator.py
index eee08c6..4f38941 100644
--- a/tools/dom/scripts/htmleventgenerator.py
+++ b/tools/dom/scripts/htmleventgenerator.py
@@ -328,7 +328,8 @@
for super_interface in all_interfaces:
events = events.union(
set([attr.id for attr in super_interface.attributes
- if attr.type.id == 'EventListener']))
+ if (attr.type.id == 'EventHandler'
+ or attr.type.id == 'EventListener')]))
return events
def _GetEvents(self, interface, custom_events):
diff --git a/tools/dom/scripts/htmlrenamer.py b/tools/dom/scripts/htmlrenamer.py
index c58b21b..ceee9ba 100644
--- a/tools/dom/scripts/htmlrenamer.py
+++ b/tools/dom/scripts/htmlrenamer.py
@@ -375,6 +375,18 @@
'transactionList',
'IDBDatabase.transaction(DOMString storeName, DOMString mode)':
'transactionStore',
+ 'ImageBitmapFactories.createImageBitmap(HTMLImageElement image)' : 'createImageBitmap0',
+ 'ImageBitmapFactories.createImageBitmap(HTMLImageElement image, long sx, long sy, long sw, long sh)' : 'createImageBitmap1',
+ 'ImageBitmapFactories.createImageBitmap(HTMLVideoElement video)' : 'createImageBitmap2',
+ 'ImageBitmapFactories.createImageBitmap(HTMLVideoElement video, long sx, long sy, long sw, long sh)' : 'createImageBitmap3',
+ 'ImageBitmapFactories.createImageBitmap(CanvasRenderingContext2D context)' : 'createImageBitmap4',
+ 'ImageBitmapFactories.createImageBitmap(CanvasRenderingContext2D context, long sx, long sy, long sw, long sh)' : 'createImageBitmap5',
+ 'ImageBitmapFactories.createImageBitmap(HTMLCanvasElement canvas)' : 'createImageBitmap6',
+ 'ImageBitmapFactories.createImageBitmap(HTMLCanvasElement canvas, long sx, long sy, long sw, long sh)' : 'createImageBitmap7',
+ 'ImageBitmapFactories.createImageBitmap(ImageData data)' : 'createImageBitmap8',
+ 'ImageBitmapFactories.createImageBitmap(ImageData data, long sx, long sy, long sw, long sh)' : 'createImageBitmap9',
+ 'ImageBitmapFactories.createImageBitmap(ImageBitmap bitmap)' : 'createImageBitmap10',
+ 'ImageBitmapFactories.createImageBitmap(ImageBitmap bitmap, long sx, long sy, long sw, long sh)' : 'createImageBitmap11',
'RTCDataChannel.send(ArrayBuffer data)': 'sendByteBuffer',
'RTCDataChannel.send(ArrayBufferView data)': 'sendTypedData',
'RTCDataChannel.send(Blob data)': 'sendBlob',
@@ -713,6 +725,7 @@
'Performance.webkitMark',
'Performance.webkitMeasure',
'ShadowRoot.getElementsByTagNameNS',
+ 'SVGElement.getPresentationAttribute',
'SVGStyledElement.getPresentationAttribute',
'WheelEvent.wheelDelta',
'WorkerGlobalScope.webkitIndexedDB',
@@ -738,14 +751,20 @@
if interface.id in _removed_html_interfaces:
return None
- if interface.id in html_interface_renames:
- return html_interface_renames[interface.id]
- elif interface.id.startswith('HTML'):
+ candidate = self.RenameInterfaceId(interface.id)
+ if candidate:
+ return candidate
+
+ if interface.id.startswith('HTML'):
if any(interface.id in ['Element', 'Document']
for interface in self._database.Hierarchy(interface)):
return interface.id[len('HTML'):]
return self._DartifyName(interface.javascript_binding_name)
+ def RenameInterfaceId(self, interface_id):
+ if interface_id in html_interface_renames:
+ return html_interface_renames[interface_id]
+ return None;
def RenameMember(self, interface_name, member_node, member, member_prefix='',
diff --git a/tools/dom/scripts/systemhtml.py b/tools/dom/scripts/systemhtml.py
index 5133ef6..9770a59 100644
--- a/tools/dom/scripts/systemhtml.py
+++ b/tools/dom/scripts/systemhtml.py
@@ -49,6 +49,7 @@
'WebKitCSSKeyframesRule.insertRule',
'CSSStyleDeclaration.setProperty',
'Element.createShadowRoot',
+ 'Element.innerHTML',
'Element.insertAdjacentElement',
'Element.insertAdjacentHTML',
'Element.insertAdjacentText',
diff --git a/tools/dom/scripts/systemnative.py b/tools/dom/scripts/systemnative.py
index f9809eb..9a6436e 100644
--- a/tools/dom/scripts/systemnative.py
+++ b/tools/dom/scripts/systemnative.py
@@ -93,6 +93,12 @@
else:
return set([])
+def array_type(data_type):
+ matched = re.match(r'([\w\d_\s]+)\[\]', data_type)
+ if not matched:
+ return None
+ return matched.group(1)
+
def _GetCPPTypeName(interface_name, callback_name, cpp_name):
# TODO(vsm): We need to track the original IDL file name in order to recover
# the proper CPP name.
@@ -714,6 +720,9 @@
requires_script_execution_context = (ext_attrs.get('CallWith') == 'ScriptExecutionContext' or
ext_attrs.get('ConstructorCallWith') == 'ScriptExecutionContext')
+
+ requires_document = ext_attrs.get('ConstructorCallWith') == 'Document'
+
if requires_script_execution_context:
raises_exceptions = True
cpp_arguments = ['context']
@@ -725,7 +734,7 @@
cpp_arguments = ['&state']
requires_dom_window = 'NamedConstructor' in ext_attrs
- if requires_dom_window:
+ if requires_dom_window or requires_document:
raises_exceptions = True
cpp_arguments = ['document']
@@ -810,7 +819,7 @@
' }\n'
' ScriptState& state = *currentState;\n\n')
- if requires_dom_window:
+ if requires_dom_window or requires_document:
self._cpp_impl_includes.add('"DOMWindow.h"')
body_emitter.Emit(
' DOMWindow* domWindow = DartUtilities::domWindowForCurrentIsolate();\n'
@@ -967,7 +976,7 @@
# Generate to Dart conversion of C++ value.
if return_type_info.dart_type() == 'bool':
set_return_value = 'Dart_SetBooleanReturnValue(args, %s)' % (value_expression)
- elif return_type_info.dart_type() == 'int':
+ elif return_type_info.dart_type() == 'int' and return_type_info.native_type() == 'int':
set_return_value = 'Dart_SetIntegerReturnValue(args, %s)' % (value_expression)
elif return_type_info.dart_type() == 'double':
set_return_value = 'Dart_SetDoubleReturnValue(args, %s)' % (value_expression)
diff --git a/tools/dom/src/dart2js_CustomElementSupport.dart b/tools/dom/src/dart2js_CustomElementSupport.dart
index a40e81c..e601ef0 100644
--- a/tools/dom/src/dart2js_CustomElementSupport.dart
+++ b/tools/dom/src/dart2js_CustomElementSupport.dart
@@ -45,9 +45,6 @@
if (baseClassName == 'Element') baseClassName = 'HTMLElement';
var baseConstructor = JS('=Object', '#[#]', context, baseClassName);
- if (JS('bool', "typeof(#) != 'function'", baseConstructor)) {
- throw new ArgumentError(type);
- }
var properties = JS('=Object', '{}');
diff --git a/tools/dom/src/dart2js_Platform.dart b/tools/dom/src/dart2js_Platform.dart
index 5988011..ea50a6a 100644
--- a/tools/dom/src/dart2js_Platform.dart
+++ b/tools/dom/src/dart2js_Platform.dart
@@ -18,4 +18,17 @@
* error.
*/
static final supportsSimd = false;
+
+ /**
+ * Upgrade all custom elements in the subtree which have not been upgraded.
+ *
+ * This is needed to cover timing scenarios which the custom element polyfill
+ * does not cover.
+ */
+ static void upgradeCustomElements(Node node) {
+ if (JS('bool', '(#.CustomElements && #.CustomElements.upgradeAll)',
+ window, window)) {
+ JS('', '#.CustomElements.upgradeAll(#)', window, node);
+ }
+ }
}
diff --git a/tools/dom/src/dartium_Platform.dart b/tools/dom/src/dartium_Platform.dart
index a851cca..48f3238 100644
--- a/tools/dom/src/dartium_Platform.dart
+++ b/tools/dom/src/dartium_Platform.dart
@@ -18,4 +18,14 @@
* error.
*/
static final supportsSimd = true;
+
+ /**
+ * Upgrade all custom elements in the subtree which have not been upgraded.
+ *
+ * This is needed to cover timing scenarios which the custom element polyfill
+ * does not cover.
+ */
+ void upgradeCustomElements(Node node) {
+ // no-op, provided for dart2js polyfill.
+ }
}
diff --git a/tools/dom/src/native_DOMImplementation.dart b/tools/dom/src/native_DOMImplementation.dart
index a7c0e97..80676b0 100644
--- a/tools/dom/src/native_DOMImplementation.dart
+++ b/tools/dom/src/native_DOMImplementation.dart
@@ -195,15 +195,20 @@
// DOM node rather than just a class that extends Node.
static bool isNode(obj) => obj is Node;
+ static bool _isBuiltinType(ClassMirror cls) {
+ // TODO(vsm): Find a less hackish way to do this.
+ LibraryMirror lib = cls.owner;
+ String libName = lib.uri.toString();
+ return libName.startsWith('dart:');
+ }
+
static void register(String tag, Type type) {
// TODO(vsm): Move these checks into native code.
if (type == null) {
throw new UnsupportedError("Invalid null type.");
}
ClassMirror cls = reflectClass(type);
- LibraryMirror lib = cls.owner;
- String libName = lib.uri.toString();
- if (libName.startsWith('dart:')) {
+ if (_isBuiltinType(cls)) {
throw new UnsupportedError("Invalid custom element from $libName.");
}
ClassMirror superClass = cls.superclass;
@@ -216,17 +221,21 @@
bool isElement(ClassMirror cls) =>
cls != null && cls.qualifiedName == elementName;
+ ClassMirror nativeClass = _isBuiltinType(superClass) ? superClass : null;
while(!isRoot(superClass) && !isElement(superClass)) {
superClass = superClass.superclass;
+ if (nativeClass == null && _isBuiltinType(superClass)) {
+ nativeClass = superClass;
+ }
}
if (isRoot(superClass)) {
throw new UnsupportedError("Invalid custom element doesn't inherit from HtmlElement.");
}
- _register(tag, type);
+ _register(tag, type, nativeClass.reflectedType);
}
- static void _register(String tag, Type type) native "Utils_register";
+ static void _register(String tag, Type customType, Type nativeType) native "Utils_register";
}
class _NPObject extends NativeFieldWrapperClass1 {
diff --git a/tools/dom/templates/html/impl/impl_Document.darttemplate b/tools/dom/templates/html/impl/impl_Document.darttemplate
index f0fdc7b..e095026 100644
--- a/tools/dom/templates/html/impl/impl_Document.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Document.darttemplate
@@ -35,4 +35,13 @@
ElementList queryAll(String selectors) {
return new _FrozenElementList._wrap($dom_querySelectorAll(selectors));
}
+
+ /// Checks if [register] is supported on the current platform.
+ bool get supportsRegister {
+$if DART2JS
+ return JS('bool', '("register" in #)', this);
+$else
+ return true;
+$endif
+ }
}
diff --git a/tools/dom/templates/html/impl/impl_Element.darttemplate b/tools/dom/templates/html/impl/impl_Element.darttemplate
index cbea8c1..acf6abb 100644
--- a/tools/dom/templates/html/impl/impl_Element.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Element.darttemplate
@@ -244,7 +244,7 @@
*/
@Experimental()
CssRect get marginEdge;
-$!STREAM_GETTER_SIGNATURES
+$!STREAM_GETTER_SIGNATURES
}
// TODO(jacobr): this is an inefficient implementation but it is hard to see
@@ -1170,6 +1170,20 @@
Point p = Element._offsetToHelper(parentOffset, parent);
return new Point(p.x + current.offsetLeft, p.y + current.offsetTop);
}
+
+$if DART2JS
+ @JSName('innerHTML')
+ @DomName('HTMLElement.innerHTML')
+ String get innerHtml => JS('String', '#.innerHTML', this);
+
+ void set innerHtml(String value) {
+ JS('', '#.innerHTML = #', this, value);
+ // Polyfill relies on mutation observers for upgrading, but we want it
+ // immediate.
+ Platform.upgradeCustomElements(this);
+ }
+$endif
+
$!MEMBERS
}
diff --git a/tools/test.dart b/tools/test.dart
index e0a1617..154d0ee 100755
--- a/tools/test.dart
+++ b/tools/test.dart
@@ -9,7 +9,7 @@
*
* 1. the dart vm
* 2. the dart2js compiler
- * 3. the dartc static analyzer
+ * 3. the static analyzer
* 4. the dart core library
* 5. other standard dart libraries (DOM bindings, ui libraries,
* io libraries etc.)
@@ -37,7 +37,6 @@
import "testing/dart/utils.dart";
import "../runtime/tests/vm/test_config.dart";
-import "../samples/tests/dartc/test_config.dart";
import "../tests/co19/test_config.dart";
import "../tests/lib/analyzer/test_config.dart";
diff --git a/tools/testing/dart/multitest.dart b/tools/testing/dart/multitest.dart
index 1159a8a..da61f9d 100644
--- a/tools/testing/dart/multitest.dart
+++ b/tools/testing/dart/multitest.dart
@@ -14,9 +14,9 @@
//
// For each key in the file, a new test file is made containing all
// the normal lines of the file, and all of the multitest lines containing
-// that key, in the same order as in the source file. The new test
-// is expected to fail if there is a non-empty error type listed, of
-// type 'compile-time error', 'runtime error', 'static type warning', or
+// that key, in the same order as in the source file. The new test is expected
+// to pass if the error type listed is 'ok', or to fail if there is an error
+// type of type 'compile-time error', 'runtime error', 'static type warning', or
// 'dynamic type error'. The type error tests fail only in checked mode.
// There is also a test created from only the untagged lines of the file,
// with key "none", which is expected to pass. This library extracts these
@@ -29,29 +29,35 @@
// bbb /// 02: runtime error
// ccc /// 02: continued
// ddd /// 07: static type warning
-// eee
+// eee /// 10: ok
+// fff
//
-// should create three tests:
+// should create four tests:
// I_am_a_multitest_none.dart
// aaa
-// eee
+// fff
//
// I_am_a_multitest_02.dart
// aaa
// bbb /// 02: runtime error
// ccc /// 02: continued
-// eee
+// fff
//
-// and I_am_a_multitest_07.dart
+// I_am_a_multitest_07.dart
// aaa
// ddd /// 07: static type warning
-// eee
+// fff
+//
+// and I_am_a_multitest_10.dart
+// aaa
+// eee /// 10: ok
+// fff
//
// Note that it is possible to indicate more than one acceptable outcome
// in the case of dynamic and static type warnings
// aaa
// ddd /// 07: static type warning, dynamic type error
-// eee
+// fff
void ExtractTestsFromMultitest(Path filePath,
Map<String, String> tests,
@@ -71,7 +77,7 @@
bytes = null;
contents = null;
Set<String> validMultitestOutcomes = new Set<String>.from(
- ['compile-time error', 'runtime error',
+ ['ok', 'compile-time error', 'runtime error',
'static type warning', 'dynamic type error']);
List<String> testTemplate = new List<String>();
diff --git a/tools/testing/dart/status_file_parser.dart b/tools/testing/dart/status_file_parser.dart
index dc3d5fe..36dd839 100644
--- a/tools/testing/dart/status_file_parser.dart
+++ b/tools/testing/dart/status_file_parser.dart
@@ -24,9 +24,11 @@
*/
const SLOW = "slow";
-final RegExp StripComment = new RegExp("^[^#]*");
+final RegExp SplitComment = new RegExp("^([^#]*)(#.*)?\$");
final RegExp HeaderPattern = new RegExp(r"^\[([^\]]+)\]");
final RegExp RulePattern = new RegExp(r"\s*([^: ]*)\s*:(.*)");
+final RegExp IssueNumberPattern =
+ new RegExp("Issue ([0-9]+)|dartbug.com/([0-9]+)", caseSensitive: false);
// TODO(whesse): Implement configuration_info library that contains data
// structures for test configuration, including Section.
@@ -39,6 +41,10 @@
bool isEnabled(environment) =>
condition == null || condition.evaluate(environment);
+
+ String toString() {
+ return "Section: $condition";
+ }
}
void ReadTestExpectationsInto(TestExpectations expectations,
@@ -75,11 +81,14 @@
sections.add(current);
lines.listen((String line) {
- Match match = StripComment.firstMatch(line);
- line = (match == null) ? "" : match[0];
+ Match match = SplitComment.firstMatch(line);
+ line = (match == null) ? "" : match[1];
line = line.trim();
if (line.isEmpty) return;
+ // Extract the comment to get the issue number if needed.
+ String comment = (match == null || match[2] == null) ? "" : match[2];
+
match = HeaderPattern.firstMatch(line);
if (match != null) {
String condition_string = match[1].trim();
@@ -98,7 +107,16 @@
List<String> tokens = new Tokenizer(expression_string).tokenize();
SetExpression expression =
new ExpressionParser(new Scanner(tokens)).parseSetExpression();
- current.testRules.add(new TestRule(name, expression));
+
+ // Look for issue number in comment.
+ String issueString = null;
+ match = IssueNumberPattern.firstMatch(comment);
+ if (match != null) {
+ issueString = match[1];
+ if (issueString == null) issueString = match[2];
+ }
+ int issue = issueString != null ? int.parse(issueString) : null;
+ current.testRules.add(new TestRule(name, expression, issue));
return;
}
@@ -111,10 +129,13 @@
class TestRule {
String name;
SetExpression expression;
+ int issue;
- TestRule(this.name, this.expression);
+ TestRule(this.name, this.expression, this.issue);
- String toString() => 'TestRule($name, $expression)';
+ bool get hasIssue => issue != null;
+
+ String toString() => 'TestRule($name, $expression, $issue)';
}