| Index: compiler/java/com/google/dart/compiler/backend/js/Normalizer.java
|
| diff --git a/compiler/java/com/google/dart/compiler/backend/js/Normalizer.java b/compiler/java/com/google/dart/compiler/backend/js/Normalizer.java
|
| deleted file mode 100644
|
| index 5813042645d61fcc3be4302184d5b1b213a7c45c..0000000000000000000000000000000000000000
|
| --- a/compiler/java/com/google/dart/compiler/backend/js/Normalizer.java
|
| +++ /dev/null
|
| @@ -1,1034 +0,0 @@
|
| -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
| -// for details. All rights reserved. Use of this source code is governed by a
|
| -// BSD-style license that can be found in the LICENSE file.
|
| -
|
| -package com.google.dart.compiler.backend.js;
|
| -
|
| -import com.google.common.collect.Lists;
|
| -import com.google.dart.compiler.InternalCompilerException;
|
| -import com.google.dart.compiler.ast.DartArrayAccess;
|
| -import com.google.dart.compiler.ast.DartBinaryExpression;
|
| -import com.google.dart.compiler.ast.DartBlock;
|
| -import com.google.dart.compiler.ast.DartCase;
|
| -import com.google.dart.compiler.ast.DartClass;
|
| -import com.google.dart.compiler.ast.DartClassMember;
|
| -import com.google.dart.compiler.ast.DartContext;
|
| -import com.google.dart.compiler.ast.DartDefault;
|
| -import com.google.dart.compiler.ast.DartDoWhileStatement;
|
| -import com.google.dart.compiler.ast.DartExprStmt;
|
| -import com.google.dart.compiler.ast.DartExpression;
|
| -import com.google.dart.compiler.ast.DartForInStatement;
|
| -import com.google.dart.compiler.ast.DartForStatement;
|
| -import com.google.dart.compiler.ast.DartFunction;
|
| -import com.google.dart.compiler.ast.DartFunctionExpression;
|
| -import com.google.dart.compiler.ast.DartFunctionObjectInvocation;
|
| -import com.google.dart.compiler.ast.DartIdentifier;
|
| -import com.google.dart.compiler.ast.DartIfStatement;
|
| -import com.google.dart.compiler.ast.DartInitializer;
|
| -import com.google.dart.compiler.ast.DartIntegerLiteral;
|
| -import com.google.dart.compiler.ast.DartLabel;
|
| -import com.google.dart.compiler.ast.DartMethodDefinition;
|
| -import com.google.dart.compiler.ast.DartMethodInvocation;
|
| -import com.google.dart.compiler.ast.DartModVisitor;
|
| -import com.google.dart.compiler.ast.DartNewExpression;
|
| -import com.google.dart.compiler.ast.DartNode;
|
| -import com.google.dart.compiler.ast.DartNodeTraverser;
|
| -import com.google.dart.compiler.ast.DartParameter;
|
| -import com.google.dart.compiler.ast.DartParenthesizedExpression;
|
| -import com.google.dart.compiler.ast.DartPropertyAccess;
|
| -import com.google.dart.compiler.ast.DartRedirectConstructorInvocation;
|
| -import com.google.dart.compiler.ast.DartReturnStatement;
|
| -import com.google.dart.compiler.ast.DartStatement;
|
| -import com.google.dart.compiler.ast.DartSuperConstructorInvocation;
|
| -import com.google.dart.compiler.ast.DartSwitchMember;
|
| -import com.google.dart.compiler.ast.DartSwitchStatement;
|
| -import com.google.dart.compiler.ast.DartThrowStatement;
|
| -import com.google.dart.compiler.ast.DartTypeNode;
|
| -import com.google.dart.compiler.ast.DartUnaryExpression;
|
| -import com.google.dart.compiler.ast.DartUnit;
|
| -import com.google.dart.compiler.ast.DartVariable;
|
| -import com.google.dart.compiler.ast.DartVariableStatement;
|
| -import com.google.dart.compiler.ast.DartWhileStatement;
|
| -import com.google.dart.compiler.ast.Modifiers;
|
| -import com.google.dart.compiler.parser.Token;
|
| -import com.google.dart.compiler.resolver.ClassElement;
|
| -import com.google.dart.compiler.resolver.ConstructorElement;
|
| -import com.google.dart.compiler.resolver.CoreTypeProvider;
|
| -import com.google.dart.compiler.resolver.Element;
|
| -import com.google.dart.compiler.resolver.ElementKind;
|
| -import com.google.dart.compiler.resolver.Elements;
|
| -import com.google.dart.compiler.resolver.EnclosingElement;
|
| -import com.google.dart.compiler.resolver.FieldElement;
|
| -import com.google.dart.compiler.resolver.LabelElement;
|
| -import com.google.dart.compiler.resolver.MethodElement;
|
| -import com.google.dart.compiler.resolver.SyntheticDefaultConstructorElement;
|
| -import com.google.dart.compiler.resolver.VariableElement;
|
| -import com.google.dart.compiler.type.InterfaceType;
|
| -import com.google.dart.compiler.type.Types;
|
| -
|
| -import java.util.ArrayList;
|
| -import java.util.Arrays;
|
| -import java.util.Collections;
|
| -import java.util.HashSet;
|
| -import java.util.List;
|
| -import java.util.Set;
|
| -
|
| -/**
|
| - * Normalization phase of Dart compiler. Rewrites the AST to simplify later
|
| - * phases.
|
| - * <ul>
|
| - * <li>Split 'type' declarations such as "int a = 0, b = 0"
|
| - * <li>Introduce block statements for control structures such as IF, WHILE, and
|
| - * FOR
|
| - * <li>normalize case statements, including adding FallThroughError throws
|
| - * <li>pull initializers out of FOR loops
|
| - * <li>remove useless statement labels
|
| - * <li>remove parenthesized expression nodes
|
| - * </ul>
|
| - */
|
| -public class Normalizer {
|
| -
|
| - public DartUnit exec(DartUnit unit, CoreTypeProvider typeProvider) {
|
| - new ParenNormalizer().accept(unit);
|
| - new BlockNormalizer(typeProvider).accept(unit);
|
| - new ForLoopInitNormalizer().accept(unit);
|
| - // Now that the have been inserted and the For VAR has been
|
| - // pulled out. It is easy to split up the VAR declarations.
|
| - new VarNormalizer().accept(unit);
|
| - unit.accept(new NormalizerVisitor());
|
| - // debugPrint(unit);
|
| - return unit;
|
| - }
|
| -
|
| - @SuppressWarnings("unused")
|
| - private void debugPrint(DartUnit unit) {
|
| - DartNodeTraverser<Void> debugPrinter = new DartNodeTraverser<Void>() {
|
| - @Override
|
| - public Void visitClassMember(DartClassMember<?> node) {
|
| - System.err.println(node);
|
| - return super.visitClassMember(node);
|
| - }
|
| -
|
| - @Override
|
| - public Void visitNode(DartNode node) {
|
| - DartNode normalizedNode = node.getNormalizedNode();
|
| - if (node != normalizedNode) {
|
| - System.err.println("orig: " + node);
|
| - System.err.println("norm: " + normalizedNode);
|
| - System.err.println();
|
| - }
|
| - return super.visitNode(node);
|
| - }
|
| - };
|
| - unit.accept(debugPrinter);
|
| - }
|
| -
|
| - /**
|
| - * Minimize the complexity of adding statements to the AST by inserting BLOCK
|
| - * nodes where there can be statements, after this pass there are only
|
| - * three statement holders: BLOCK, FOR, and LABEL.
|
| - * <p>
|
| - * This also simplifies scope handling.
|
| - * <p>
|
| - * The complexity of dealing with LABEL statements is reduced by minimizing
|
| - * the number of places that a label can be used to four statement types:
|
| - * BLOCK, FOR, WHILE, and DO-WHILE.
|
| - * BLOCK could also be removed by using "label:do { statement } while (false);"
|
| - * should we choose to.
|
| - */
|
| - private static class BlockNormalizer extends DartModVisitor {
|
| -
|
| - private final ConstructorElement fallThroughError;
|
| -
|
| - private static ConstructorElement getFallThroughError(
|
| - CoreTypeProvider typeProvider) {
|
| - ClassElement element = typeProvider.getFallThroughError().getElement();
|
| - // TODO(fabiomfv): remove local resolution once we settle on the approach.
|
| - ConstructorElement constructor = element.lookupConstructor("");
|
| - if (constructor == null) {
|
| - throw new InternalCompilerException("FallThroughError does not have unnamed constructor.");
|
| - }
|
| - return constructor;
|
| - }
|
| -
|
| - public BlockNormalizer(CoreTypeProvider typeProvider) {
|
| - fallThroughError = getFallThroughError(typeProvider);
|
| - }
|
| -
|
| - @Override
|
| - public void endVisit(DartLabel x, DartContext ctx) {
|
| - DartStatement body = x.getStatement();
|
| - if (body instanceof DartVariableStatement) {
|
| - // TODO(johnlenz): I'm assuming labelled statements don't introduce
|
| - // a new scope.
|
| - // Don't push a single VAR into a BLOCK, the label can't be referenced
|
| - // so drop it entirely.
|
| - ctx.replaceMe(body);
|
| - } else if (!(body instanceof DartBlock) && !canContinueControlStructure(body)) {
|
| - DartIdentifier label = x.getLabel();
|
| - DartLabel replacement = new DartLabel(label, maybeAddBlock(body));
|
| - LabelElement element = (LabelElement) x.getSymbol();
|
| - element.setNode(replacement);
|
| - replacement.setSymbol(element);
|
| - replacement.setSourceInfo(x);
|
| - ctx.replaceMe(replacement);
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * @return Whether this is a control structure that can be used
|
| - * with a named "continue" statement.
|
| - */
|
| - private boolean canContinueControlStructure(DartStatement stmt) {
|
| - if (stmt instanceof DartForStatement
|
| - || stmt instanceof DartWhileStatement
|
| - || stmt instanceof DartDoWhileStatement) {
|
| - return true;
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public void endVisit(DartForStatement x, DartContext ctx) {
|
| - DartStatement body = x.getBody();
|
| - if (!(body instanceof DartBlock)) {
|
| - DartStatement init = x.getInit();
|
| - DartExpression condition = x.getCondition();
|
| - DartExpression increment = x.getIncrement();
|
| -
|
| - DartStatement replacement = new DartForStatement(
|
| - init, condition, increment, maybeAddBlock(body));
|
| - replacement.setSourceInfo(x);
|
| - ctx.replaceMe(replacement);
|
| - }
|
| - }
|
| -
|
| - @Override
|
| - public void endVisit(DartIfStatement x, DartContext ctx) {
|
| - DartStatement thenStmt = x.getThenStatement();
|
| - DartStatement elseStmt = x.getElseStatement();
|
| - if (!(thenStmt instanceof DartBlock) || !(elseStmt instanceof DartBlock)) {
|
| - DartExpression condition = x.getCondition();
|
| -
|
| - // TODO(johnlenz): Preserve source location?
|
| - DartIfStatement replacement = new DartIfStatement(
|
| - condition,
|
| - maybeAddBlock(thenStmt),
|
| - (elseStmt != null) ? maybeAddBlock(elseStmt) : null);
|
| - replacement.setSourceInfo(x);
|
| - ctx.replaceMe(replacement);
|
| - }
|
| - }
|
| -
|
| - @Override
|
| - public void endVisit(DartWhileStatement x, DartContext ctx) {
|
| - DartStatement body = x.getBody();
|
| - if (!(body instanceof DartBlock)) {
|
| - DartExpression condition = x.getCondition();
|
| -
|
| - // TODO(johnlenz): Preserve source location?
|
| - DartWhileStatement replacement = new DartWhileStatement(
|
| - condition, maybeAddBlock(body));
|
| - replacement.setSourceInfo(x);
|
| - ctx.replaceMe(replacement);
|
| - }
|
| - }
|
| -
|
| - @Override
|
| - public void endVisit(DartDoWhileStatement x, DartContext ctx) {
|
| - DartStatement body = x.getBody();
|
| - if (!(body instanceof DartBlock)) {
|
| - DartExpression condition = x.getCondition();
|
| -
|
| - // TODO(johnlenz): Preserve source location?
|
| - DartDoWhileStatement replacement = new DartDoWhileStatement(
|
| - condition, maybeAddBlock(body));
|
| - replacement.setSourceInfo(x);
|
| - ctx.replaceMe(replacement);
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Normalize case statements. There are two main things to be accomplished:
|
| - * <ol>
|
| - * <li>add throw new FallThroughError at the end of non-empty cases which
|
| - * may fall through to the next block
|
| - * <li>wrap individual statements or empty cases in blocks
|
| - * </ol>
|
| - *
|
| - * For example:
|
| - * <pre>
|
| - * case 1:
|
| - * case 2: ...
|
| - * </pre>
|
| - * becomes
|
| - * <pre>
|
| - * case 1: {}
|
| - * case 2: ...
|
| - * </pre>
|
| - * while this:
|
| - * <pre>
|
| - * case 1: {}
|
| - * case 2: ...
|
| - * </pre>
|
| - * becomes
|
| - * <pre>
|
| - * case 1: { throw new FallThroughError(); }
|
| - * case 2: ...
|
| - * </pre>
|
| - * The last case (and any empty labels that fall through into it) does not get
|
| - * a throw added, but does get changed to an empty block.
|
| - *
|
| - * @param caseStmt the "case: stmt;*" block being normalized
|
| - * @param ctx {@link DartContext}
|
| - */
|
| - @Override
|
| - public void endVisit(DartCase caseStmt, DartContext ctx) {
|
| - List<DartStatement> stmts = caseStmt.getStatements();
|
| - if (stmts.size() == 0) {
|
| - replaceWithBlock(stmts, Lists.newArrayList(stmts));
|
| - return;
|
| - }
|
| -
|
| - // unpack an outer block if present
|
| - List<DartStatement> innerStatements = stmts;
|
| - if (stmts.get(0) instanceof DartBlock) {
|
| - innerStatements = ((DartBlock) stmts.get(0)).getStatements();
|
| - }
|
| -
|
| - // check if we need to add a throw
|
| - boolean needsThrow = !isLastSwitchMember(caseStmt);
|
| - if (needsThrow) {
|
| - // TODO(jat): should we only look at the last statement?
|
| - // DartParser.parseCaseStatemets seems to stop as soon as it hits an
|
| - // AbruptCompletingStatement.
|
| - for (DartStatement stmt : innerStatements) {
|
| - if (stmt.isAbruptCompletingStatement()) {
|
| - needsThrow = false;
|
| - break;
|
| - }
|
| - }
|
| - }
|
| -
|
| - // if we don't need to modify the block, nothing to do
|
| - if (!needsThrow && stmts.get(0) instanceof DartBlock) {
|
| - return;
|
| - }
|
| -
|
| - // copy the list of statements and add a throw
|
| - List<DartStatement> newStmts = Lists.newArrayList(innerStatements);
|
| - if (needsThrow) {
|
| - newStmts.add(buildThrow(fallThroughError));
|
| - }
|
| - caseStmt.setNormalizedNode(new DartCase(caseStmt.getExpr(), caseStmt.getLabel(), newStmts));
|
| - replaceWithBlock(stmts, newStmts);
|
| - }
|
| -
|
| - /**
|
| - * Check to see if the supplied switch member is the last one in the switch
|
| - * statement, or is allowed to fall through to the last one.
|
| - *
|
| - * @param member
|
| - * @return true if the specified member is the last one in the switch
|
| - * statement or is allowed to fall through to the l
|
| - */
|
| - private boolean isLastSwitchMember(DartSwitchMember member) {
|
| - /*
|
| - * We are replacing empty switch members with empty blocks as we go, but
|
| - * that is ok because we start from the end here.
|
| - */
|
| - DartSwitchStatement switchStmt = (DartSwitchStatement) member.getParent();
|
| - List<DartSwitchMember> members = switchStmt.getMembers();
|
| - int i = members.size() - 1;
|
| - if (members.get(i) == member) {
|
| - // last switch member
|
| - return true;
|
| - }
|
| - // now we only want ones that are empty and have no non-empty switch members
|
| - // between them and the last member
|
| - while (i >= 0) {
|
| - DartSwitchMember curMember = members.get(i);
|
| - if (curMember.getStatements().size() > 0) {
|
| - // non-empty, so no earlier members can fall through
|
| - return false;
|
| - }
|
| - if (curMember == member) {
|
| - return true;
|
| - }
|
| - i--;
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - /**
|
| - * Create a throw new ExceptionCtor() statement.
|
| - *
|
| - * @param exceptionCtor constructor to use to create exception instance
|
| - * @param args zero or more arguments for the supplied constructor
|
| - * @return a {@link DartStatement} representing a throw of the supplied
|
| - * exception
|
| - */
|
| - private static DartStatement buildThrow(ConstructorElement exceptionCtor,
|
| - DartExpression... args) {
|
| - // Create AST nodes representing 'throw new FallThroughException();'.
|
| - DartNewExpression newExpr = new DartNewExpression(new DartTypeNode(new DartIdentifier(
|
| - exceptionCtor.getName())), Arrays.asList(args), false);
|
| - newExpr.setSymbol(exceptionCtor);
|
| - return new DartThrowStatement(newExpr);
|
| - }
|
| -
|
| - /**
|
| - * @param stmts
|
| - * @param newStmts
|
| - */
|
| - private void replaceWithBlock(List<DartStatement> stmts, List<DartStatement> newStmts) {
|
| - DartBlock block = new DartBlock(newStmts);
|
| - stmts.clear();
|
| - stmts.add(block);
|
| - }
|
| -
|
| - @Override
|
| - public void endVisit(DartDefault member, DartContext ctx) {
|
| - // default labels must be last, so they do not need to throw FallThroughErrors
|
| - // So, all we need to do is make sure they are blocks
|
| - List<DartStatement> stmts = member.getStatements();
|
| - if (stmts.size() == 0 || !(stmts.get(0) instanceof DartBlock)) {
|
| - replaceWithBlock(stmts, Lists.newArrayList(stmts));
|
| - }
|
| - }
|
| -
|
| - private DartBlock maybeAddBlock(DartStatement statement) {
|
| - if (statement instanceof DartBlock) {
|
| - return (DartBlock)statement;
|
| - }
|
| - return new DartBlock(Lists.newArrayList(statement));
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Extract the any initializer statements out of the FOR loop. This is done
|
| - * to minimize the amount of code that needs to be special cased for handling
|
| - * expressions in a FOR loop.
|
| - */
|
| - private static class ForLoopInitNormalizer extends DartModVisitor {
|
| - @Override
|
| - public boolean visit(DartLabel x, DartContext ctx) {
|
| - // Pulled any FOR loop initializer expressions up above the label,
|
| - // we do this in the visit to allow the DartForStatement to handle
|
| - // the unlabelled case.
|
| -
|
| - LabeledForVisitor labelVisitor = new LabeledForVisitor();
|
| - labelVisitor.accept(x);
|
| - if (labelVisitor.forInit != null) {
|
| - // FOR loop initializer need to be scoped, put them in a block.
|
| - List<DartStatement> stmts = Lists.newArrayList(labelVisitor.forInit, x);
|
| - DartBlock replacement = new DartBlock(stmts);
|
| - ctx.replaceMe(replacement);
|
| -
|
| - // The removed expression hasn't be visited yet, do it now so it isn't
|
| - // skipped.
|
| - accept(replacement);
|
| - }
|
| - return true;
|
| - }
|
| -
|
| - @Override
|
| - public void endVisit(DartForStatement x, DartContext ctx) {
|
| - DartStatement init = x.getInit();
|
| - if (init != null) {
|
| - DartStatement body = x.getBody();
|
| - DartExpression condition = x.getCondition();
|
| - DartExpression increment = x.getIncrement();
|
| -
|
| - DartStatement newFor = new DartForStatement(
|
| - null, condition, increment, body);
|
| - newFor.setSourceInfo(x);
|
| -
|
| - // FOR loop initializer need to be scoped, put them in a block.
|
| - DartStatement replacementBlock = new DartBlock(
|
| - Lists.newArrayList(init, newFor));
|
| -
|
| - ctx.replaceMe(replacementBlock);
|
| - }
|
| - }
|
| -
|
| - private static class LabeledForVisitor extends DartModVisitor {
|
| - DartStatement forInit = null;
|
| -
|
| - @Override
|
| - public boolean visit(DartForStatement x, DartContext ctx) {
|
| - if (x.getInit() != null) {
|
| - DartStatement init = x.getInit();
|
| - if (init != null) {
|
| - DartStatement body = x.getBody();
|
| - DartExpression condition = x.getCondition();
|
| - DartExpression increment = x.getIncrement();
|
| -
|
| - // TODO(johnlenz): Preserve source location?
|
| - DartStatement newFor = new DartForStatement(
|
| - null, condition, increment, body);
|
| - newFor.setSourceInfo(x);
|
| - ctx.replaceMe(newFor);
|
| - }
|
| - forInit = init;
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(DartLabel x, DartContext ctx) {
|
| - DartStatement stmt = x.getStatement();
|
| - return (stmt instanceof DartLabel) || (stmt instanceof DartForStatement);
|
| - }
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Remove parenthesized expression nodes. This simplifies all of the rest of
|
| - * the normalizers by not requiring them to deal with this special case.
|
| - */
|
| - private static class ParenNormalizer extends DartModVisitor {
|
| - @Override
|
| - public void endVisit(DartParenthesizedExpression x, DartContext ctx) {
|
| - ctx.replaceMe(x.getExpression());
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Split VAR declarations so that there is only one VAR declaration per
|
| - * statement. This simplifies rewriting of VAR statements.
|
| - */
|
| - private static class VarNormalizer extends DartModVisitor {
|
| - @Override
|
| - public void endVisit(DartVariableStatement x, DartContext ctx) {
|
| - List<DartVariable> vars = x.getVariables();
|
| - if (vars.size() > 1) {
|
| - for (DartVariable v : vars) {
|
| - DartVariableStatement stmt = new DartVariableStatement(
|
| - Lists.newArrayList(v), x.getTypeNode());
|
| - stmt.setSourceInfo(v);
|
| - ctx.insertBefore(stmt);
|
| - }
|
| - ctx.removeMe();
|
| - }
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * The actual normalization.
|
| - */
|
| - private static class NormalizerVisitor extends DartNodeTraverser<DartNode> {
|
| - // Collects names to avoid conflicts with synthesized variables.
|
| - private final Set<String> usedNames = new HashSet<String>();
|
| -
|
| - @Override
|
| - public DartNode visitClassMember(DartClassMember<?> node) {
|
| - usedNames.clear();
|
| - return super.visitClassMember(node);
|
| - }
|
| -
|
| - @Override
|
| - public DartNode visitForInStatement(DartForInStatement node) {
|
| - node.visitChildren(this);
|
| -
|
| - // Normalize for (var? name in expression) { ... } into:
|
| - // {
|
| - // var i = expression.iterator();
|
| - // while (i.hasNext()) {
|
| - // var? name = i.next();
|
| - // ...
|
| - // }
|
| - // }
|
| - List<DartStatement> topLevelStatements = new ArrayList<DartStatement>();
|
| -
|
| - // Generate the call to expression.iterator().
|
| - DartMethodInvocation iteratorCall = call(node.getIterable(), "iterator");
|
| -
|
| - // Create and add the iterator variable to the statements.
|
| - DartVariableStatement iteratorVariable = makeTempVariable(0, iteratorCall);
|
| - topLevelStatements.add(iteratorVariable);
|
| -
|
| - // Generate the call to i.hasNext();
|
| - DartIdentifier iterator = ref(iteratorVariable);
|
| - DartMethodInvocation hasNext = call(iterator, "hasNext");
|
| -
|
| - // Generate the call to i.next();
|
| - iterator = ref(iteratorVariable);
|
| - DartMethodInvocation next = call(iterator, "next");
|
| -
|
| - DartStatement setup = normalizeForInSetup(node, next);
|
| - DartWhileStatement whileStatement = whileStmt(hasNext, setup, node.getBody());
|
| - topLevelStatements.add(whileStatement);
|
| -
|
| - DartBlock newBlock = new DartBlock(topLevelStatements);
|
| - node.setNormalizedNode(newBlock);
|
| - return node;
|
| - }
|
| -
|
| - private DartStatement normalizeForInSetup(DartForInStatement node, DartExpression next) {
|
| - if (node.introducesVariable()) {
|
| - // Since we're going to change the variable to have an initializer expression,
|
| - // we have to create a new variable statement around it too. Make sure it has
|
| - // the right type and modifiers.
|
| - DartVariableStatement variableStatement = node.getVariableStatement();
|
| - DartVariable oldVariable = variableStatement.getVariables().get(0);
|
| - DartVariable newVariable = new DartVariable(oldVariable.getName(), next);
|
| - newVariable.setSymbol(oldVariable.getSymbol());
|
| - return new DartVariableStatement(Lists.newArrayList(newVariable),
|
| - variableStatement.getTypeNode(), variableStatement.getModifiers());
|
| - } else {
|
| - return exprStmt(assign(node.getIdentifier(), next));
|
| - }
|
| - }
|
| -
|
| - @Override
|
| - public DartNode visitClass(DartClass node) {
|
| - final ClassElement classElement = node.getSymbol();
|
| - // Ensure implicit default constructor with method.
|
| - if (Elements.needsImplicitDefaultConstructor(classElement)) {
|
| - DartMethodDefinition method = createImplicitDefaultConstructor(classElement);
|
| - // TODO - We should really normalize the class itself.
|
| - node.getMembers().add(method);
|
| - }
|
| - return super.visitClass(node);
|
| - }
|
| -
|
| - private DartMethodDefinition createImplicitDefaultConstructor(final ClassElement classElement) {
|
| - assert (Elements.needsImplicitDefaultConstructor(classElement));
|
| - DartFunction function = new DartFunction(Collections.<DartParameter>emptyList(),
|
| - new DartBlock(Collections.<DartStatement>emptyList()), null);
|
| - final DartMethodDefinition method =
|
| - DartMethodDefinition.create(new DartIdentifier(""), function, Modifiers.NONE, null);
|
| - method.setSymbol(new SyntheticDefaultConstructorElement(method, classElement, null));
|
| - return method;
|
| - }
|
| -
|
| - @Override
|
| - public DartExpression visitBinaryExpression(DartBinaryExpression node) {
|
| - node.visitChildren(this);
|
| - Token operator = node.getOperator();
|
| - if (operator.isAssignmentOperator() && operator != Token.ASSIGN) {
|
| - node.setNormalizedNode(normalizeCompoundAssignment(mapAssignableOp(operator), false,
|
| - node.getArg1().getNormalizedNode(),
|
| - node.getArg2().getNormalizedNode()));
|
| - }
|
| - return node;
|
| - }
|
| -
|
| - @Override
|
| - public DartExpression visitUnaryExpression(DartUnaryExpression node) {
|
| - node.visitChildren(this);
|
| - Token operator = node.getOperator();
|
| - if (operator.isCountOperator()) {
|
| - DartExpression lhs = node.getArg().getNormalizedNode();
|
| - DartIntegerLiteral rhs = DartIntegerLiteral.one();
|
| - node.setNormalizedNode(normalizeCompoundAssignment(mapAssignableOp(operator),
|
| - !node.isPrefix(), lhs, rhs));
|
| - }
|
| - return node;
|
| - }
|
| -
|
| - static class NeedsImplicitSuperInvocationDeterminant extends DartNodeTraverser<Void> {
|
| - private boolean needsSuperInvocation = true;
|
| -
|
| - @Override
|
| - public Void visitSuperConstructorInvocation(DartSuperConstructorInvocation node) {
|
| - needsSuperInvocation = false;
|
| - return super.visitSuperConstructorInvocation(node);
|
| - }
|
| -
|
| - @Override
|
| - public Void visitRedirectConstructorInvocation(DartRedirectConstructorInvocation node) {
|
| - needsSuperInvocation = false;
|
| - return super.visitRedirectConstructorInvocation(node);
|
| - }
|
| -
|
| - @Override
|
| - public Void visitMethodDefinition(DartMethodDefinition node) {
|
| - // Ignore everything except the initializers
|
| - for (DartInitializer initializer : node.getInitializers()) {
|
| - initializer.accept(this);
|
| - }
|
| - return null;
|
| - }
|
| - }
|
| -
|
| - @Override
|
| - public DartMethodDefinition visitMethodDefinition(DartMethodDefinition node) {
|
| - super.visitMethodDefinition(node);
|
| - if (Elements.isNonFactoryConstructor(node.getSymbol())) {
|
| - normalizeParameterInitializer(node);
|
| - }
|
| -
|
| - return node;
|
| - }
|
| -
|
| - @Override
|
| - public DartNode visitNewExpression(DartNewExpression node) {
|
| - ConstructorElement symbol = node.getSymbol();
|
| - if (symbol == null) {
|
| - InterfaceType constructorType = Types.constructorType(node);
|
| - if (!constructorType.getElement().isDynamic() && node.getArgs().isEmpty()) {
|
| - // HACK use proper normalized node
|
| - ClassElement classToInstantiate = constructorType.getElement();
|
| - if (classToInstantiate.getDefaultClass() != null) {
|
| - classToInstantiate = classToInstantiate.getDefaultClass().getElement();
|
| - }
|
| -
|
| - if (classToInstantiate != null
|
| - && Elements.needsImplicitDefaultConstructor(classToInstantiate)) {
|
| - DartMethodDefinition implicitDefaultConstructor =
|
| - createImplicitDefaultConstructor(classToInstantiate);
|
| - node.setSymbol(implicitDefaultConstructor.getSymbol());
|
| - }
|
| - }
|
| - }
|
| -
|
| - return super.visitNewExpression(node);
|
| - }
|
| -
|
| - @Override
|
| - public DartNode visitSwitchStatement(DartSwitchStatement node) {
|
| - node.getExpression().accept(this);
|
| - for (DartNode member : node.getMembers()) {
|
| - member.accept(this);
|
| - }
|
| - return node;
|
| - }
|
| -
|
| - // Normalize parameter initializer.
|
| - // transforms: class A { A(this.x) { } }
|
| - // into: class A { A(this.x) : this.x = x { }
|
| - private void normalizeParameterInitializer(DartMethodDefinition node) {
|
| - List<DartInitializer> nInit = new ArrayList<DartInitializer>();
|
| - for (DartParameter param : node.getFunction().getParams()) {
|
| - FieldElement fieldElement = param.getSymbol().getParameterInitializerElement();
|
| - if (fieldElement != null) {
|
| - DartIdentifier left = new DartIdentifier(param.getParameterName());
|
| - left.setSymbol(fieldElement);
|
| - left.setSourceInfo(param);
|
| - Element ve = Elements.makeVariable(param.getParameterName());
|
| - DartParameter nParam = new DartParameter(param.getName(), param.getTypeNode(),
|
| - param.getFunctionParameters(), param.getDefaultExpr(), param.getModifiers());
|
| - nParam.setSymbol(ve);
|
| - param.setNormalizedNode(nParam);
|
| - DartIdentifier right = new DartIdentifier(param.getParameterName());
|
| - right.setSymbol(ve);
|
| - right.setSourceInfo(param);
|
| - DartInitializer di = new DartInitializer(left, right);
|
| - di.setSourceInfo(param);
|
| - nInit.add(di);
|
| - }
|
| - }
|
| -
|
| - EnclosingElement enclosingElement = node.getSymbol().getEnclosingElement();
|
| - if (ElementKind.of(enclosingElement) == ElementKind.CLASS) {
|
| - ClassElement classElement = (ClassElement) enclosingElement;
|
| - if (!classElement.isObject()) {
|
| - NeedsImplicitSuperInvocationDeterminant superLocator = new NeedsImplicitSuperInvocationDeterminant();
|
| - node.accept(superLocator);
|
| - if (superLocator.needsSuperInvocation) {
|
| - DartSuperConstructorInvocation superInvocation = new DartSuperConstructorInvocation(
|
| - new DartIdentifier(""), Collections.<DartExpression>emptyList());
|
| - // Set constructor element - actual constructor with all named parameters or synthetic.
|
| - ConstructorElement superConstructorElement = null;
|
| - {
|
| - ClassElement superTypeElement = classElement.getSupertype().getElement();
|
| - List<ConstructorElement> constructors = superTypeElement.getConstructors();
|
| - for (ConstructorElement constructor : constructors) {
|
| - if (hasOnlyNamedParameters(constructor)) {
|
| - superConstructorElement = constructor;
|
| - break;
|
| - }
|
| - }
|
| - if (superConstructorElement == null) {
|
| - superConstructorElement =
|
| - new SyntheticDefaultConstructorElement(null, superTypeElement, null);
|
| - }
|
| - superInvocation.setSymbol(superConstructorElement);
|
| - }
|
| - // Add implicit "super" invocation.
|
| - nInit.add(new DartInitializer(null, superInvocation));
|
| - }
|
| - }
|
| - }
|
| -
|
| - if (!nInit.isEmpty()) {
|
| - if (!node.getInitializers().isEmpty()) {
|
| - nInit.addAll(0, node.getInitializers());
|
| - }
|
| -
|
| - DartMethodDefinition nConstructor = DartMethodDefinition.create(
|
| - node.getName(), node.getFunction(), node.getModifiers(), nInit);
|
| - nConstructor.setSymbol(node.getSymbol());
|
| - nConstructor.setSourceInfo(node.getSourceInfo());
|
| - node.setNormalizedNode(nConstructor);
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * @return <code>true</code> if given constructor has only named (i.e. optional) parameters.
|
| - */
|
| - private static boolean hasOnlyNamedParameters(ConstructorElement constructor) {
|
| - for (VariableElement parameter : constructor.getParameters()) {
|
| - if (!parameter.isNamed()) {
|
| - return false;
|
| - }
|
| - }
|
| - return true;
|
| - }
|
| -
|
| - private DartExpression normalizeCompoundAssignment(Token operator,
|
| - boolean isPostfix,
|
| - DartExpression operand1,
|
| - DartExpression operand2) {
|
| - return operand1.accept(new CompoundAssignmentNormalizer(operator, isPostfix, operand2));
|
| - }
|
| -
|
| - private String makeTempName(int i) {
|
| - String name;
|
| - do {
|
| - name = "$" + i;
|
| - i++;
|
| - } while (usedNames.contains(name));
|
| - usedNames.add(name);
|
| - return name;
|
| - }
|
| -
|
| - private DartVariableStatement makeTempVariable(int i, DartExpression init) {
|
| - String variableName = makeTempName(i);
|
| - DartIdentifier variableIdentifier = new DartIdentifier(variableName);
|
| - DartVariable variable = new DartVariable(variableIdentifier, init);
|
| - VariableElement element = Elements.variableElement(variable,
|
| - variableName,
|
| - Modifiers.NONE);
|
| - variable.setSymbol(element);
|
| - return new DartVariableStatement(Lists.newArrayList(variable), null);
|
| - }
|
| -
|
| - private class Let {
|
| - private final List<DartExpression> arguments;
|
| - final DartParameter[] parameters;
|
| -
|
| - Let(DartExpression... arguments) {
|
| - this.arguments = Arrays.asList(arguments);
|
| - parameters = new DartParameter[arguments.length];
|
| - for (int i = 0; i < arguments.length; i++) {
|
| - parameters[i] = makeTempParameter(i);
|
| - }
|
| - }
|
| -
|
| - DartExpression expression() {
|
| - DartBlock body = new DartBlock(Arrays.<DartStatement>asList(body()));
|
| - return call(makeFunctionExpression(body), arguments);
|
| - }
|
| -
|
| - private DartFunctionExpression makeFunctionExpression(DartBlock body) {
|
| - DartFunction function = new DartFunction(Arrays.asList(parameters), body , null);
|
| - DartFunctionExpression expression = new DartFunctionExpression(null, function, false);
|
| - MethodElement element =
|
| - Elements.methodFromFunctionExpression(expression, Modifiers.NONE.makeInlinable());
|
| - expression.setSymbol(element);
|
| - for (DartParameter parameter : parameters) {
|
| - Elements.addParameter(element, parameter.getSymbol());
|
| - }
|
| - return expression;
|
| - }
|
| -
|
| - DartExpression p(int i) {
|
| - return ref(parameters[i]);
|
| - }
|
| -
|
| - DartStatement[] body() {
|
| - return new DartStatement[0];
|
| - }
|
| -
|
| - private DartParameter makeTempParameter(int i) {
|
| - String name = makeTempName(i);
|
| - DartIdentifier identifier = new DartIdentifier(name);
|
| - DartParameter parameter = new DartParameter(identifier, null, null, null, Modifiers.NONE);
|
| - VariableElement element = Elements.parameterElement(parameter, name, Modifiers.NONE);
|
| - parameter.setSymbol(element);
|
| - return parameter;
|
| - }
|
| - }
|
| -
|
| - private class CompoundAssignmentNormalizer extends DartNodeTraverser<DartExpression> {
|
| - final Token operator;
|
| - final boolean isPostfix;
|
| - final DartExpression rhs;
|
| -
|
| - CompoundAssignmentNormalizer(Token operator, boolean isPostfix,
|
| - DartExpression rhs) {
|
| - this.operator = operator;
|
| - this.isPostfix = isPostfix;
|
| - this.rhs = rhs;
|
| - }
|
| -
|
| - @Override
|
| - public DartExpression visitNode(DartNode lhs) {
|
| - throw new AssertionError(lhs);
|
| - }
|
| -
|
| - @Override
|
| - public DartExpression visitIdentifier(DartIdentifier id) {
|
| - return rewriteExpression(id);
|
| - }
|
| -
|
| - private DartExpression rewriteExpression(final DartExpression lhs) {
|
| - if (!isPostfix) {
|
| - // Turns: lhs += rhs
|
| - // Into: lhs = lhs + rhs
|
| - // Turns: ++lhs
|
| - // Into: lhs = lhs + 1
|
| - return assign(lhs, bin(operator, lhs, rhs));
|
| - } else {
|
| - // Turns: lhs++
|
| - // Into: function($2) { id = $2 + 1; return $2; }(lhs)
|
| - return new Let(lhs) {
|
| - @Override DartStatement[] body() {
|
| - return statements(exprStmt(assign(lhs, bin(operator, p(0), rhs))),
|
| - retrn(p(0)));
|
| - }
|
| - }.expression();
|
| - }
|
| - }
|
| -
|
| - @Override
|
| - public DartExpression visitPropertyAccess(DartPropertyAccess access) {
|
| - Element element = access.getTargetSymbol();
|
| - if (element != null && element.getModifiers().isStatic()) {
|
| - return rewriteExpression(access);
|
| - }
|
| - final DartIdentifier name = access.getName();
|
| - return new RewriteAccess((DartExpression) access.getQualifier()) {
|
| - @Override
|
| - DartExpression operand1() {
|
| - return access(p(0), name);
|
| - }
|
| - }.expression();
|
| - }
|
| -
|
| - @Override
|
| - public DartExpression visitArrayAccess(DartArrayAccess access) {
|
| - DartExpression target = access.getTarget();
|
| - DartExpression key = access.getKey();
|
| - // TODO(5408710): Evaluation order of target vs. key? (order passed to constructor)
|
| - return new RewriteAccess(target, key) {
|
| - @Override
|
| - DartExpression operand1() {
|
| - return arrayAccess(p(0), p(1));
|
| - }
|
| - }.expression();
|
| - }
|
| -
|
| - private abstract class RewriteAccess extends Let {
|
| - public RewriteAccess(DartExpression... arguments) {
|
| - super(arguments);
|
| - }
|
| -
|
| - abstract DartExpression operand1();
|
| -
|
| - @Override
|
| - DartStatement[] body() {
|
| - final DartExpression operand1 = operand1();
|
| - if (isPostfix) {
|
| - // Turns: this[0.0]--
|
| - // Into: function($0, $1) {
|
| - // return function($2) { $0[$1] = $2 - 1; return $2; }($0[$1]);
|
| - // }(this, 0.0)
|
| - Let let = new Let(operand1) {
|
| - @Override DartStatement[] body() {
|
| - return statements(exprStmt(assign(operand1, bin(operator, p(0), rhs))),
|
| - retrn(p(0)));
|
| - }
|
| - };
|
| - return statements(retrn(let.expression()));
|
| - } else {
|
| - // Turns: this[0.0] += $0
|
| - // Into: function($3, $4) { return $3[$4] = $3[$4] + $0; }(this, 0.0)
|
| - // Turns: ++this[0.0]
|
| - // Into: function($3, $4) { return $3[$4] = $3[$4] + 1; }(this, 0.0)
|
| - return statements(retrn(assign(operand1, bin(operator, operand1, rhs))));
|
| - }
|
| - }
|
| - }
|
| - }
|
| -
|
| - private DartStatement[] statements(DartStatement... statements) {
|
| - return statements;
|
| - }
|
| -
|
| - private DartWhileStatement whileStmt(DartExpression condition, DartStatement... statements) {
|
| - return new DartWhileStatement(condition, new DartBlock(Arrays.asList(statements)));
|
| - }
|
| -
|
| - private DartExpression call(DartFunctionExpression function, List<DartExpression> args) {
|
| - return new DartFunctionObjectInvocation(function, args);
|
| - }
|
| -
|
| - private DartMethodInvocation call(DartExpression receiver, String name) {
|
| - return new DartMethodInvocation(receiver,
|
| - new DartIdentifier(name),
|
| - Collections.<DartExpression>emptyList());
|
| - }
|
| -
|
| - private DartArrayAccess arrayAccess(DartExpression target, DartExpression key) {
|
| - return new DartArrayAccess(target, key);
|
| - }
|
| -
|
| - private DartReturnStatement retrn(DartExpression value) {
|
| - return new DartReturnStatement(value);
|
| - }
|
| -
|
| - private DartBinaryExpression bin(Token operator, DartExpression lhs, DartExpression rhs) {
|
| - return new DartBinaryExpression(operator, lhs, rhs);
|
| - }
|
| -
|
| - private DartBinaryExpression assign(DartExpression lhs, DartExpression rhs) {
|
| - return bin(Token.ASSIGN, lhs, rhs);
|
| - }
|
| -
|
| - private DartExprStmt exprStmt(DartExpression expression) {
|
| - return new DartExprStmt(expression);
|
| - }
|
| -
|
| - private DartPropertyAccess access(DartExpression qualifier, DartIdentifier name) {
|
| - return new DartPropertyAccess(qualifier, name);
|
| - }
|
| -
|
| - private DartExpression ref(DartParameter parameter) {
|
| - DartIdentifier identifier = new DartIdentifier(parameter.getParameterName());
|
| - identifier.setSymbol(parameter.getSymbol());
|
| - return identifier;
|
| - }
|
| -
|
| - private DartIdentifier ref(DartVariableStatement variableStatement) {
|
| - DartVariable variable = variableStatement.getVariables().get(0);
|
| - DartIdentifier identifier = new DartIdentifier(variable.getVariableName());
|
| - identifier.setSymbol(variable.getSymbol());
|
| - return identifier;
|
| - }
|
| -
|
| - private Token mapAssignableOp(Token operator) {
|
| - switch (operator) {
|
| - case ASSIGN_BIT_OR: return Token.BIT_OR;
|
| - case ASSIGN_BIT_XOR: return Token.BIT_XOR;
|
| - case ASSIGN_BIT_AND: return Token.BIT_AND;
|
| - case ASSIGN_SHL: return Token.SHL;
|
| - case ASSIGN_SAR: return Token.SAR;
|
| - case ASSIGN_ADD: return Token.ADD;
|
| - case ASSIGN_SUB: return Token.SUB;
|
| - case ASSIGN_MUL: return Token.MUL;
|
| - case ASSIGN_DIV: return Token.DIV;
|
| - case ASSIGN_MOD: return Token.MOD;
|
| - case ASSIGN_TRUNC: return Token.TRUNC;
|
| - case INC: return Token.ADD;
|
| - case DEC: return Token.SUB;
|
| -
|
| - default:
|
| - throw new InternalCompilerException("Invalid assignment operator");
|
| - }
|
| - }
|
| - }
|
| -}
|
|
|