inits = toReturn.getPropertyInitializers();
-
- int size = x.getPropertyInitializers().size();
- while (size-- > 0) {
- /*
- * JsPropertyInitializers are the only non-JsExpression objects that we
- * care about, so we just go ahead and create the objects in the loop,
- * rather than expecting it to be on the stack and having to perform
- * narrowing casts at all stack.pop() invocations.
- */
- JsPropertyInitializer newInit = new JsPropertyInitializer();
- newInit.setValueExpr(stack.pop());
- newInit.setLabelExpr(stack.pop());
-
- inits.add(0, newInit);
- }
- stack.push(toReturn);
- }
-
- @Override
- public void endVisit(JsPostfixOperation x, JsContext ctx) {
- JsPostfixOperation toReturn = new JsPostfixOperation(x.getOperator());
- toReturn.setArg(stack.pop());
- stack.push(toReturn);
- }
-
- @Override
- public void endVisit(JsPrefixOperation x, JsContext ctx) {
- JsPrefixOperation toReturn = new JsPrefixOperation(x.getOperator());
- toReturn.setArg(stack.pop());
- stack.push(toReturn);
- }
-
- @Override
- public void endVisit(JsRegExp x, JsContext ctx) {
- stack.push(x);
- }
-
- @Override
- public void endVisit(JsStringLiteral x, JsContext ctx) {
- stack.push(x);
- }
-
- @Override
- public void endVisit(JsThisRef x, JsContext ctx) {
- stack.push(new JsThisRef());
- }
-
- public JsExpression getExpression() {
- return (successful && checkStack()) ? stack.peek() : null;
- }
-
- private boolean checkStack() {
- if (stack.size() > 1) {
- throw new InternalCompilerException("Too many expressions on stack");
- }
-
- return stack.size() == 1;
- }
-}
-
diff --git a/compiler/java/com/google/dart/compiler/backend/js/DartMangler.java b/compiler/java/com/google/dart/compiler/backend/js/DartMangler.java
deleted file mode 100644
index 3848cd9fa32..00000000000
--- a/compiler/java/com/google/dart/compiler/backend/js/DartMangler.java
+++ /dev/null
@@ -1,143 +0,0 @@
-// 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.
-
-package com.google.dart.compiler.backend.js;
-
-import com.google.dart.compiler.parser.Token;
-import com.google.dart.compiler.resolver.ClassElement;
-import com.google.dart.compiler.resolver.Element;
-import com.google.dart.compiler.resolver.FieldElement;
-import com.google.dart.compiler.resolver.LibraryElement;
-import com.google.dart.compiler.resolver.MethodElement;
-
-/**
- * Mangles dart identifiers so that they don't conflict with JavaScript identifiers.
- * This complements the JsScope infrastructure. The JsScope infrastructure deals with obfuscatable
- * identifiers, whereas the DartMangler deals with non-obfuscatable identifiers.
- */
-public interface DartMangler {
- public static final String NEGATE_OPERATOR_NAME = "negate";
-
- /**
- * Mangles the given className, so that it does not clash with any global variable or other
- * mangled identifiers.
- * @return a String that identifies the class, and does not clash with any global variable.
- */
- public String mangleClassName(ClassElement classElement);
- @Deprecated
- public String mangleClassNameHack(LibraryElement library, String str);
-
- /**
- * Mangles the given constructor, so that it does not clash with any built-in JS property,
- * initializers, factories or other mangled fields.
- * The given LibraryElement is used if the constructor is library private.
- * @return a String that identifies the constructor, and does not clash with any global variable.
- */
- public String mangleConstructor(String constructorName, LibraryElement currentLibrary);
-
- /**
- * Returns a mangled identifier for the given method.
- */
- public String mangleNativeMethod(MethodElement methodElement);
-
- /**
- * Mangles the given initializer, so that it does not clash with any built-in JS property,
- * factories, constructors or other mangled fields.
- * The given LibraryElement is used if the initializer is library private.
- * @return a String that identifies the initializer, and does not clash with any global variable.
- */
- public String createInitializerSyntax(String constructorName, LibraryElement currentLibrary);
-
- /**
- * Mangles the given factory, so that it does not clash with any built-in JS property,
- * constructors, initializers or other mangled fields.
- * Note that factories may be unrelated to the containing class. A class A can
- * have a factory method returning an instance of class B. In this case
- * className equals B.
- * The given LibraryElement is used if the factory is library private.
- *
- * @return a String that identifies the factory, and does not clash with any global variable.
- */
- public String createFactorySyntax(String className, String constructorName,
- LibraryElement currentlibrary);
-
-
- /**
- * Returns a name for the given closure. The returned name does not
- * clash with any global variable or other mangled identifiers.
- * The closure is identified by the closureIdentifier. Manglers are allowed to discard the
- * closureName completely.
- *
- * @param closureIdentifier must be a valid identifier of the form [a-zA-Z]+[0-9]*
- * @param closureName the closures short readable name. May be null.
- * @return a String that identifies the hoisted closure, and does not clash with any global
- * variable.
- */
- public String createHoistedFunctionName(Element holder,
- Element classMemberElement,
- String closureIdentifier,
- String closureName);
-
- /**
- * Mangles the given field, so that it does not clash with any built-in JS property or other
- * mangled fields or methods.
- * The given LibraryElement is used if the field is library private.
- * @return a String that identifies the member, and does not clash with built-in JS properties.
- */
- public String mangleField(FieldElement field, LibraryElement currentLibrary);
-
- /**
- * Mangles the given method, so that it does not clash with any built-in JS property or other
- * mangled fields or methods.
- * The given LibraryElement is used if the method is library private.
- * @return a String that identifies the member, and does not clash with built-in JS properties.
- */
- public String mangleMethod(MethodElement method, LibraryElement currentLibrary);
- public String mangleMethod(String methodName, LibraryElement currentLibrary);
-
- /**
- * Mangles the given method to its $named form.
- * @return a String that identifies the named form of the member.
- */
- public String mangleNamedMethod(MethodElement method, LibraryElement currentLibrary);
- public String mangleNamedMethod(String methodName, LibraryElement currentLibrary);
-
- /**
- * Mangles the given method to its _$lookupRTT form.
- * @return a String that identifies the named form of the member.
- */
- public String mangleRttLookupMethod(MethodElement method, LibraryElement currentLibrary);
- public String mangleRttLookupMethod(String methodName, LibraryElement currentLibrary);
-
- /**
- * Mangles the given method, so that it does not clash with any built-in JS property or other
- * mangled fields or methods. This method is different than mangleMethod, as it returns
- * the fully qualified mangled name.
- * @return a String that identifies the entry, and does not clash with built-in JS properties.
- */
- public String mangleEntryPoint(MethodElement method, LibraryElement library);
-
- /**
- * @return the JavaScript property identifier for the given operation.
- */
- public String createOperatorSyntax(Token token);
-
- /**
- * @return the JavaScript property identifier for the given operation.
- */
- public String createOperatorSyntax(String operation);
-
- /**
- * @return the JavaScript getter property for the given member.
- */
- public String createGetterSyntax(String member, LibraryElement currentLibrary);
- public String createGetterSyntax(FieldElement member, LibraryElement currentLibrary);
- public String createGetterSyntax(MethodElement member, LibraryElement currentLibrary);
-
- /**
- * @return the JavaScript setter property for the given member.
- */
- public String createSetterSyntax(String member, LibraryElement currentLibrary);
- public String createSetterSyntax(FieldElement member, LibraryElement currentLibrary);
-}
diff --git a/compiler/java/com/google/dart/compiler/backend/js/DollarMangler.java b/compiler/java/com/google/dart/compiler/backend/js/DollarMangler.java
deleted file mode 100644
index 648a0d75d74..00000000000
--- a/compiler/java/com/google/dart/compiler/backend/js/DollarMangler.java
+++ /dev/null
@@ -1,424 +0,0 @@
-// 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.
-
-package com.google.dart.compiler.backend.js;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.dart.compiler.InternalCompilerException;
-import com.google.dart.compiler.ast.LibraryUnit;
-import com.google.dart.compiler.parser.Token;
-import com.google.dart.compiler.resolver.ClassElement;
-import com.google.dart.compiler.resolver.Element;
-import com.google.dart.compiler.resolver.ElementKind;
-import com.google.dart.compiler.resolver.FieldElement;
-import com.google.dart.compiler.resolver.LibraryElement;
-import com.google.dart.compiler.resolver.MethodElement;
-
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.Set;
-
-/**
- * Mangles classes and members (including constructors and operators).
- * These must be accessible from outside the compilation unit and must therefore have a
- * predictable mangling.
- *
- * Functions, constructors and initializers to become top-level functions. They
- * cannot conflict with other members, but must not conflict with predefined JavaScript globals.
- *
- *
Other members (fields, operators, methods) are always accessed through an object. The mangler
- * only needs to guard against conflicts with predefined JavaScript properties (like "prototype"
- * and "__proto__").
- */
-public class DollarMangler implements DartMangler {
- // TODO(floitsch): get rid of the blacklisted libraries.
- // Libraries, where class-names must not include the library-name.
- private static final Set BLACKLISTED_LIBRARIES = ImmutableSet.of("corelib",
- "corelib_impl", "dom");
-
- // Helpers for getters/setters/operator name mangling.
- private static final String OPERATOR_SUFFIX = "$operator";
- private static final String GETTER_SUFFIX = "$getter";
- private static final String SETTER_SUFFIX = "$setter";
- private static final String FIELD_SUFFIX = "$field";
- private static final String METHOD_SUFFIX = "$member";
- private static final String NAMED_SUFFIX = "$named";
- private static final String CONSTRUCTOR_SUFFIX = "$Constructor";
- private static final String FACTORY_SUFFIX = "$Factory";
- private static final String INITIALIZER_SUFFIX = "$Initializer";
-
- private static final String CLASS_SUFFIX = "$Dart";
- private static final String HOISTED_METHOD_SUFFIX = "$Hoisted";
- private static final String HOISTED_OPERATOR_SUFFIX = "$HoistedOperator";
- private static final String HOISTED_CONSTRUCTOR_SUFFIX = "$HoistedConstructor";
- private static final String HOISTED_STATIC_SUFFIX = "$HoistedStatic";
- private static final String DYNAMIC_CLASS_NAME = "$_Dynamic_";
- private static final String RTT_LOOKUP_NAME = "_$lookupRTT";
-
- private static final String NATIVE_PREFIX = "native_";
-
- private boolean isLibraryPrivate(String id) {
- return (id.length() > 0) && (id.charAt(0) == '_');
- }
-
- private String attachSuffix(String name, String suffix,
- boolean isLibraryPrivate, LibraryElement currentLibrary) {
- if (isLibraryPrivate) {
- return name + '$' + mangleLibraryName(currentLibrary) + suffix + '_';
- }
- return name + suffix;
- }
-
- private String attachSuffix(String name, String suffix, LibraryElement currentLibrary) {
- return attachSuffix(name, suffix, isLibraryPrivate(name), currentLibrary);
- }
-
- private String mangleLibraryName(LibraryElement element) {
- LibraryUnit library = element.getLibraryUnit();
- if (isInBlacklist(library)) {
- return "";
- }
-
- // TODO(floitsch): Replace this libraryName + md5(source) with something more enhanced.
-
- String libName = library.getName();
- if (libName == null || libName.isEmpty()) {
- libName = "unnamed";
- }
-
- // If the libraryName is a path, cut off everything before the last slash.
- int nameStart = libName.lastIndexOf('/') + 1;
-
- // add space for md5 + trailing '$' (and possible leading 'l').
- StringBuilder sb = new StringBuilder(libName.length() + 8);
-
- // see if we have a leading number, in which case need to prepend an alpha char
- final char startChar = libName.charAt(nameStart);
- if ('0' <= startChar && startChar <= '9') {
- sb.append('l');
- }
- sb.append(libName.substring(nameStart));
-
- // Replace all non-word chars ([^a-z_A-Z0-9]) with "_".
- replaceNonWordChars(sb);
-
- MessageDigest md;
- try {
- md = MessageDigest.getInstance("MD5");
- } catch (NoSuchAlgorithmException e) {
- throw new AssertionError("Could not find MD5 digest");
- }
- byte[] md5 = md.digest(library.getSource().getUri().toString().getBytes());
- // Only use the first 6 hex characters of the md5.
- for (int i = 0; i < 3; i++) {
- sb.append(Integer.toHexString((md5[i] & 0xf0) >> 4));
- sb.append(Integer.toHexString(md5[i] & 0xf));
- }
-
- sb.append("$");
-
- return sb.toString();
- }
-
- /*
- * Replace all non-word characters with an underscore
- */
- private void replaceNonWordChars(StringBuilder sb) {
- /*
- * This code is implemented as a more efficient implementation than using
- * String.replaceAll("\\W", "_")
- */
- final int len = sb.length();
- for (int idx = 0; idx < len; idx++) {
- final char ch = sb.charAt(idx);
- if (!((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9'))) {
- sb.setCharAt(idx, '_');
- }
- }
- }
-
- @Override
- public String mangleClassName(ClassElement classElement) {
- String className = !classElement.isDynamic() ? classElement.getName() : DYNAMIC_CLASS_NAME;
- return mangleClassNameHack(classElement.getLibrary(), className);
- }
-
- @Override
- @Deprecated
- public String mangleClassNameHack(LibraryElement library, String className) {
- String libraryToken = library == null ? "" : mangleLibraryName(library);
- return libraryToken + className + CLASS_SUFFIX;
- }
-
- private boolean isInBlacklist(LibraryUnit libraryUnit) {
- if (libraryUnit.getName() == null) {
- return false;
- }
- if (BLACKLISTED_LIBRARIES.contains(libraryUnit.getName())) {
- return true;
- }
-
- // Libraries that use the new syntax (with no name) will have a URI for a name, e.g.:
- // file://blah/blah/coreimpl.dart
- for (String name : BLACKLISTED_LIBRARIES) {
- if (libraryUnit.getName().endsWith(name)) {
- return true;
- }
- }
- return false;
- }
-
- @Override
- public String mangleConstructor(String constructorName, LibraryElement currentLibrary) {
- return attachSuffix(constructorName, CONSTRUCTOR_SUFFIX, currentLibrary);
- }
-
- @Override
- public String createInitializerSyntax(String constructorName, LibraryElement currentLibrary) {
- return attachSuffix(constructorName, INITIALIZER_SUFFIX, currentLibrary);
- }
-
- @Override
- public String createFactorySyntax(String className, String constructor,
- LibraryElement currentLibrary) {
- // We can't just return the constructor + suffix.
- // A class might have factories for different classes.
- String factoryName;
- className = className.equals("") ? DYNAMIC_CLASS_NAME : className;
- if (constructor.equals("")) {
- factoryName = className + "$";
- } else {
- factoryName = className + "$" + constructor + "$" + className.length();
- }
-
- return attachSuffix(factoryName, FACTORY_SUFFIX, isLibraryPrivate(constructor), currentLibrary);
- }
-
- private boolean containsDollar(String str) {
- return str.indexOf('$') >= 0;
- }
-
- private String createHoistedFunctionName(String holderName,
- String elementName,
- String closureIdentifier,
- String closureName,
- String suffix) {
- assert closureIdentifier.indexOf('$') == -1;
- boolean containsDollar = containsDollar(holderName)
- || containsDollar(elementName)
- || (closureName != null && containsDollar(closureName));
- String result;
- if (closureName != null) {
- // Return a mangled id of the form:
- // class$method$id$closure$$Hoisted, or
- // class$method$id$closure$12_23_45$Hoisted (if any of the strings contains dollars).
- result = holderName + "$" + elementName + "$" + closureIdentifier + "$" + closureName + "$";
- if (containsDollar) {
- result += holderName.length() + "_" + elementName.length() + "_"
- + closureIdentifier.length();
- }
- } else {
- // Return a mangled id of the form:
- // class$method$id$$Hoisted, or
- // class$method$id$12_23$Hoisted (if any of the strings contains dollars).
- result = holderName + "$" + elementName + "$" + closureIdentifier + "$";
- if (containsDollar) {
- result += holderName.length() + "_" + holderName.length();
- }
- }
- return result + suffix;
- }
-
- @Override
- public String createHoistedFunctionName(Element holder,
- Element element,
- String closureIdentifier,
- String closureName) {
- String holderName = "";
- switch (ElementKind.of(holder)) {
- case CLASS:
- holderName = mangleClassName((ClassElement) holder);
- break;
-
- case LIBRARY:
- holderName = mangleLibraryName((LibraryElement) holder);
- break;
- }
-
- String name = element.getName();
- String suffix;
- switch (ElementKind.of(element)) {
- case METHOD:
- if (element.getModifiers().isOperator()) {
- suffix = HOISTED_OPERATOR_SUFFIX;
- if (!name.equals(NEGATE_OPERATOR_NAME)) {
- name = Token.lookup(name).name();
- }
- } else {
- suffix = HOISTED_METHOD_SUFFIX;
- }
- break;
-
- case CONSTRUCTOR:
- suffix = HOISTED_CONSTRUCTOR_SUFFIX;
- break;
-
- default:
- // Otherwise we are in a static initializer.
- suffix = HOISTED_STATIC_SUFFIX;
- }
- return createHoistedFunctionName(holderName, name, closureIdentifier, closureName,
- suffix);
- }
-
- private String createFieldOrMethodBaseName(Element field, boolean accessor) {
- String prefix = "";
- Element enclosing = field.getEnclosingElement();
- if (ElementKind.of(enclosing).equals(ElementKind.LIBRARY)) {
- prefix = mangleLibraryName((LibraryElement) enclosing);
- } else if (!accessor && field.getModifiers().isStatic()) {
- prefix = mangleClassName((ClassElement) enclosing);
- }
- return prefix + field.getName();
- }
-
- @Override
- public String mangleField(FieldElement field, LibraryElement currentLibrary) {
- return attachSuffix(createFieldOrMethodBaseName(field, false), FIELD_SUFFIX,
- isLibraryPrivate(field.getName()), currentLibrary);
- }
-
- @Override
- public String mangleMethod(MethodElement method, LibraryElement currentLibrary) {
- String methodName = method.getName();
- if (method.getModifiers().isOperator()) {
- methodName = createOperatorSyntax(methodName);
- } else if (method.getModifiers().isGetter()) {
- methodName = createGetterSyntax(methodName, currentLibrary);
- } else if (method.getModifiers().isSetter()) {
- methodName = createSetterSyntax(methodName, currentLibrary);
- } else {
- methodName = attachSuffix(methodName, METHOD_SUFFIX, currentLibrary);
- }
-
- String prefix = "";
- if (ElementKind.of(method.getEnclosingElement()).equals(ElementKind.LIBRARY)) {
- prefix = mangleLibraryName((LibraryElement) method.getEnclosingElement());
- }
- return prefix + methodName;
- }
-
- @Override
- public String mangleNamedMethod(MethodElement method, LibraryElement currentLibrary) {
- // There can be no named shims for operators, getters, or setters.
- String methodName = method.getName();
- methodName = attachSuffix(methodName, NAMED_SUFFIX, currentLibrary);
-
- String prefix = "";
- if (ElementKind.of(method.getEnclosingElement()).equals(ElementKind.LIBRARY)) {
- prefix = mangleLibraryName((LibraryElement) method.getEnclosingElement());
- }
- return prefix + methodName;
- }
-
- @Override
- public String mangleNamedMethod(String methodName, LibraryElement currentLibrary) {
- return attachSuffix(methodName, NAMED_SUFFIX, currentLibrary);
- }
-
- @Override
- public String mangleEntryPoint(MethodElement method, LibraryElement library) {
- Element holder = method.getEnclosingElement();
- switch (ElementKind.of(holder)) {
- case CLASS:
- String mangledClassName = mangleClassName((ClassElement) holder);
- return mangledClassName + "." + mangleMethod(method.getName(), library);
-
- case LIBRARY:
- return mangleMethod(method, library);
- }
- throw new InternalCompilerException("Unknown entry point kind" + method);
- }
-
- @Override
- public String createGetterSyntax(FieldElement field, LibraryElement currentLibrary) {
- return attachSuffix(createFieldOrMethodBaseName(field, true), GETTER_SUFFIX,
- isLibraryPrivate(field.getName()), currentLibrary);
- }
-
- @Override
- public String createGetterSyntax(MethodElement field, LibraryElement currentLibrary) {
- return attachSuffix(createFieldOrMethodBaseName(field, true), GETTER_SUFFIX,
- isLibraryPrivate(field.getName()), currentLibrary);
- }
-
- @Override
- public String createSetterSyntax(FieldElement field, LibraryElement currentLibrary) {
- return attachSuffix(createFieldOrMethodBaseName(field, true), SETTER_SUFFIX,
- isLibraryPrivate(field.getName()), currentLibrary);
- }
-
- @Override
- public String mangleMethod(String methodName, LibraryElement currentLibrary) {
- return attachSuffix(methodName, METHOD_SUFFIX, currentLibrary);
- }
-
- private static String getNegateOperator() {
- return NEGATE_OPERATOR_NAME + OPERATOR_SUFFIX;
- }
-
- @Override
- public String createOperatorSyntax(Token token) {
- return token.name() + OPERATOR_SUFFIX;
- }
-
- @Override
- public String createOperatorSyntax(String operation) {
- if (operation.equals(NEGATE_OPERATOR_NAME)) {
- return getNegateOperator();
- }
- return Token.lookup(operation).name() + OPERATOR_SUFFIX;
- }
-
- @Override
- public String createGetterSyntax(String member, LibraryElement currentLibrary) {
- return attachSuffix(member, GETTER_SUFFIX, currentLibrary);
- }
-
- @Override
- public String createSetterSyntax(String member, LibraryElement currentLibrary) {
- return attachSuffix(member, SETTER_SUFFIX, currentLibrary);
- }
-
- @Override
- public String mangleNativeMethod(MethodElement element) {
- String elementName = element.getName();
- String encodedName = null;
- if (element.getModifiers().isOperator()) {
- if ("negate".equals(elementName)) {
- encodedName = elementName;
- } else {
- encodedName = Token.lookup(elementName).name();
- }
- } else if (element.getModifiers().isGetter()) {
- encodedName = "get$" + elementName;
- } else if (element.getModifiers().isSetter()) {
- encodedName = "set$" + elementName;
- } else {
- encodedName = elementName;
- }
- String holderName = element.getEnclosingElement().getName();
- return NATIVE_PREFIX + holderName + "_" + encodedName;
- }
-
- @Override
- public String mangleRttLookupMethod(MethodElement method, LibraryElement currentLibrary) {
- return mangleNamedMethod(method, currentLibrary) + RTT_LOOKUP_NAME;
- }
-
- @Override
- public String mangleRttLookupMethod(String methodName, LibraryElement currentLibrary) {
- return mangleNamedMethod(methodName, currentLibrary) + RTT_LOOKUP_NAME;
- }
-}
diff --git a/compiler/java/com/google/dart/compiler/backend/js/GenerateJavascriptAST.java b/compiler/java/com/google/dart/compiler/backend/js/GenerateJavascriptAST.java
deleted file mode 100644
index 2942b740588..00000000000
--- a/compiler/java/com/google/dart/compiler/backend/js/GenerateJavascriptAST.java
+++ /dev/null
@@ -1,3877 +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.DartCompilationError;
-import com.google.dart.compiler.DartCompilerContext;
-import com.google.dart.compiler.InternalCompilerException;
-import com.google.dart.compiler.ast.DartArrayAccess;
-import com.google.dart.compiler.ast.DartArrayLiteral;
-import com.google.dart.compiler.ast.DartAssertion;
-import com.google.dart.compiler.ast.DartBinaryExpression;
-import com.google.dart.compiler.ast.DartBlock;
-import com.google.dart.compiler.ast.DartBooleanLiteral;
-import com.google.dart.compiler.ast.DartBreakStatement;
-import com.google.dart.compiler.ast.DartCase;
-import com.google.dart.compiler.ast.DartCatchBlock;
-import com.google.dart.compiler.ast.DartClass;
-import com.google.dart.compiler.ast.DartClassMember;
-import com.google.dart.compiler.ast.DartConditional;
-import com.google.dart.compiler.ast.DartContinueStatement;
-import com.google.dart.compiler.ast.DartDefault;
-import com.google.dart.compiler.ast.DartDoWhileStatement;
-import com.google.dart.compiler.ast.DartDoubleLiteral;
-import com.google.dart.compiler.ast.DartEmptyStatement;
-import com.google.dart.compiler.ast.DartExprStmt;
-import com.google.dart.compiler.ast.DartExpression;
-import com.google.dart.compiler.ast.DartField;
-import com.google.dart.compiler.ast.DartFieldDefinition;
-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.DartFunctionTypeAlias;
-import com.google.dart.compiler.ast.DartIdentifier;
-import com.google.dart.compiler.ast.DartIfStatement;
-import com.google.dart.compiler.ast.DartImportDirective;
-import com.google.dart.compiler.ast.DartInitializer;
-import com.google.dart.compiler.ast.DartIntegerLiteral;
-import com.google.dart.compiler.ast.DartInvocation;
-import com.google.dart.compiler.ast.DartLabel;
-import com.google.dart.compiler.ast.DartLibraryDirective;
-import com.google.dart.compiler.ast.DartMapLiteral;
-import com.google.dart.compiler.ast.DartMapLiteralEntry;
-import com.google.dart.compiler.ast.DartMethodDefinition;
-import com.google.dart.compiler.ast.DartMethodInvocation;
-import com.google.dart.compiler.ast.DartNamedExpression;
-import com.google.dart.compiler.ast.DartNativeBlock;
-import com.google.dart.compiler.ast.DartNativeDirective;
-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.DartNullLiteral;
-import com.google.dart.compiler.ast.DartParameter;
-import com.google.dart.compiler.ast.DartParameterizedTypeNode;
-import com.google.dart.compiler.ast.DartParenthesizedExpression;
-import com.google.dart.compiler.ast.DartPlainVisitor;
-import com.google.dart.compiler.ast.DartPropertyAccess;
-import com.google.dart.compiler.ast.DartRedirectConstructorInvocation;
-import com.google.dart.compiler.ast.DartResourceDirective;
-import com.google.dart.compiler.ast.DartReturnStatement;
-import com.google.dart.compiler.ast.DartSourceDirective;
-import com.google.dart.compiler.ast.DartStatement;
-import com.google.dart.compiler.ast.DartStringInterpolation;
-import com.google.dart.compiler.ast.DartStringLiteral;
-import com.google.dart.compiler.ast.DartSuperConstructorInvocation;
-import com.google.dart.compiler.ast.DartSuperExpression;
-import com.google.dart.compiler.ast.DartSwitchStatement;
-import com.google.dart.compiler.ast.DartSyntheticErrorExpression;
-import com.google.dart.compiler.ast.DartSyntheticErrorStatement;
-import com.google.dart.compiler.ast.DartThisExpression;
-import com.google.dart.compiler.ast.DartThrowStatement;
-import com.google.dart.compiler.ast.DartTryStatement;
-import com.google.dart.compiler.ast.DartTypeExpression;
-import com.google.dart.compiler.ast.DartTypeNode;
-import com.google.dart.compiler.ast.DartTypeParameter;
-import com.google.dart.compiler.ast.DartUnaryExpression;
-import com.google.dart.compiler.ast.DartUnit;
-import com.google.dart.compiler.ast.DartUnqualifiedInvocation;
-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.backend.js.ScopeRootInfo.DartScope;
-import com.google.dart.compiler.backend.js.ast.JsArrayLiteral;
-import com.google.dart.compiler.backend.js.ast.JsBinaryOperation;
-import com.google.dart.compiler.backend.js.ast.JsBinaryOperator;
-import com.google.dart.compiler.backend.js.ast.JsBlock;
-import com.google.dart.compiler.backend.js.ast.JsBreak;
-import com.google.dart.compiler.backend.js.ast.JsCase;
-import com.google.dart.compiler.backend.js.ast.JsCatch;
-import com.google.dart.compiler.backend.js.ast.JsConditional;
-import com.google.dart.compiler.backend.js.ast.JsContinue;
-import com.google.dart.compiler.backend.js.ast.JsDefault;
-import com.google.dart.compiler.backend.js.ast.JsDoWhile;
-import com.google.dart.compiler.backend.js.ast.JsEmpty;
-import com.google.dart.compiler.backend.js.ast.JsExprStmt;
-import com.google.dart.compiler.backend.js.ast.JsExpression;
-import com.google.dart.compiler.backend.js.ast.JsFor;
-import com.google.dart.compiler.backend.js.ast.JsFunction;
-import com.google.dart.compiler.backend.js.ast.JsIf;
-import com.google.dart.compiler.backend.js.ast.JsInvocation;
-import com.google.dart.compiler.backend.js.ast.JsLabel;
-import com.google.dart.compiler.backend.js.ast.JsLiteral;
-import com.google.dart.compiler.backend.js.ast.JsName;
-import com.google.dart.compiler.backend.js.ast.JsNameRef;
-import com.google.dart.compiler.backend.js.ast.JsNew;
-import com.google.dart.compiler.backend.js.ast.JsNode;
-import com.google.dart.compiler.backend.js.ast.JsNullLiteral;
-import com.google.dart.compiler.backend.js.ast.JsNumberLiteral;
-import com.google.dart.compiler.backend.js.ast.JsObjectLiteral;
-import com.google.dart.compiler.backend.js.ast.JsParameter;
-import com.google.dart.compiler.backend.js.ast.JsPostfixOperation;
-import com.google.dart.compiler.backend.js.ast.JsPrefixOperation;
-import com.google.dart.compiler.backend.js.ast.JsProgram;
-import com.google.dart.compiler.backend.js.ast.JsPropertyInitializer;
-import com.google.dart.compiler.backend.js.ast.JsReturn;
-import com.google.dart.compiler.backend.js.ast.JsScope;
-import com.google.dart.compiler.backend.js.ast.JsStatement;
-import com.google.dart.compiler.backend.js.ast.JsStringLiteral;
-import com.google.dart.compiler.backend.js.ast.JsSwitch;
-import com.google.dart.compiler.backend.js.ast.JsSwitchMember;
-import com.google.dart.compiler.backend.js.ast.JsThisRef;
-import com.google.dart.compiler.backend.js.ast.JsThrow;
-import com.google.dart.compiler.backend.js.ast.JsTry;
-import com.google.dart.compiler.backend.js.ast.JsUnaryOperator;
-import com.google.dart.compiler.backend.js.ast.JsValueLiteral;
-import com.google.dart.compiler.backend.js.ast.JsVars;
-import com.google.dart.compiler.backend.js.ast.JsVars.JsVar;
-import com.google.dart.compiler.backend.js.ast.JsWhile;
-import com.google.dart.compiler.common.SourceInfo;
-import com.google.dart.compiler.common.Symbol;
-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.LibraryElement;
-import com.google.dart.compiler.resolver.MethodElement;
-import com.google.dart.compiler.resolver.SuperElement;
-import com.google.dart.compiler.resolver.VariableElement;
-import com.google.dart.compiler.type.InterfaceType;
-import com.google.dart.compiler.type.Type;
-import com.google.dart.compiler.type.TypeKind;
-import com.google.dart.compiler.type.Types;
-import com.google.dart.compiler.util.AstUtil;
-
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Deque;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.Stack;
-import java.util.concurrent.Callable;
-
-/**
- * Visitor that generates a Javascript AST from an existing Dart AST.
- */
-public class GenerateJavascriptAST {
- private final DartCompilerContext context;
- private final DartUnit unit;
- private final CoreTypeProvider typeProvider;
-
- /**
- * Generates the Javascript AST using the names created in {@link GenerateNamesAndScopes}.
- */
- static class GenerateJavascriptVisitor
- implements DartPlainVisitor, TraversalContextProvider {
-
- private static boolean isSuperCall(Symbol symbol) {
- return ElementKind.of(symbol).equals(ElementKind.SUPER);
- }
-
- /**
- * Returns true for members that are static or should be treated
- * as if the user had declared them as static.
- */
- private static boolean isDeclaredAsStaticOrImplicitlyStatic(Element element) {
- Modifiers modifiers = element.getModifiers();
- if (modifiers.isStatic()) {
- // Member was actually declared static
- return true;
- }
-
- if (Elements.isTopLevel(element)) {
- // Top level fields and methods are implicitly static
- ElementKind elementKind = ElementKind.of(element);
- return elementKind == ElementKind.FIELD || elementKind == ElementKind.METHOD;
- }
-
- return false;
- }
-
- /**
- * The name of the javascript function used to intern compile time constants
- */
- private static final String INTERN_CONST_FUNCTION = "$intern";
-
- /**
- * The name of the function used to lookup a id for a constant object
- */
- private static final String DART_CONST_ID_JS_FUNC = "$dart_const_id";
-
- /**
- * The name of the method use to generate the id for an constant object
- */
- private static final String CONST_ID_JS_METHOD_NAME = "$const_id";
-
- private static final String STATIC_UNINITIALIZED = "static$uninitialized";
- private static final String STATIC_INITIALIZING = "static$initializing";
- private static final String ISOLATE_CURRENT = "isolate$current";
- private static final String ISOLATE_INITS = "isolate$inits";
- private static final String ISOLATE_DEFAULT_FACTORY = "default$factory";
- static final int MAX_SPECIALIZED_BIND_SCOPES = 3;
- static final int MAX_SPECIALIZED_BIND_ARGS = 5;
- private static final String ISOLATE_ISOLATE_FACTORY = "isolateFactory";
- private static final String ISOLATE_ISOLATE_FACTORY_GETTER = "getIsolateFactory";
-
- private final JsScope globalScope;
- private final JsBlock globalBlock;
- private final List staticInit = Lists.newArrayList();
- private final Deque functionStack = new LinkedList();
- private final Deque> jsNewDeclarationsStack = new LinkedList>();
- private Element currentHolder;
- private boolean inFactory = false;
- private boolean inFactoryOrStaticContext = false;
- private ScopeRootInfo currentScopeInfo;
- private JsName traceCounter;
- private final RuntimeTypeInjector rtt;
-
- private final TranslationContext translationContext;
- private final DartCompilerContext context;
- private final LibraryElement unitLibrary;
- private final DartMangler mangler;
- private final CoreTypeProvider typeProvider;
- private final Types typeUtils;
-
- private final Deque catchVarStack = new ArrayDeque();
-
- public GenerateJavascriptVisitor(DartUnit unit, DartCompilerContext context,
- TranslationContext translationContext,
- CoreTypeProvider typeProvider) {
- this.context = context;
- this.translationContext = translationContext;
- this.typeProvider = typeProvider;
- this.typeUtils = Types.getInstance(typeProvider);
- this.unitLibrary = unit.getLibrary().getElement();
-
- // Cache the mangler in a field since it is used frequently
- mangler = translationContext.getMangler();
-
- JsProgram program = translationContext.getProgram();
- globalScope = program.getScope();
- globalBlock = program.getGlobalBlock();
- // setup the global scope.
- jsNewDeclarationsStack.push(new HashSet());
- currentHolder = unit.getLibrary().getElement();
- rtt = new RuntimeTypeInjector(this, typeProvider, translationContext,
- context.getCompilerConfiguration().developerModeChecks(), mangler, unitLibrary);
- }
-
- /**
- * @param block The global block to add the static init statements too.
- */
- public void addStaticInitsToBlock(JsBlock block) {
- if (staticInit.isEmpty()) return;
- JsFunction init = new JsFunction(globalScope);
- JsBlock body = new JsBlock();
- body.getStatements().addAll(staticInit);
- init.setBody(body);
- staticInit.clear();
-
- // All the static variable initialization code belonging to the
- // current compilation unit is appended to the initialization
- // list (isolate$inits) through Array.prototype.push.
- JsNameRef pushRef = AstUtil.newNameRef(new JsNameRef(ISOLATE_INITS), "push");
- JsInvocation invokePush = AstUtil.newInvocation(pushRef);
- invokePush.getArguments().add(init);
- block.getStatements().add(new JsExprStmt(invokePush));
- }
-
- /**
- * @return the JsScope that is used to create temporary Js-variables in the current scope.
- */
- private JsScope getCurrentFunctionScope() {
- return translationContext.getMethods().get(functionStack.peek()).getScope();
- }
-
- /**
- * Adds the given name to the declarations-array. All names in the array will be declared at
- * the beginning of the function. The same name can be registered multiple times.
- * @param name
- */
- private void registerForDeclaration(JsName name) {
- jsNewDeclarationsStack.peek().add(name);
- }
-
-
- /**
- * Creates a temporary variable but does not register it for var-declaration.
- * @return the JsName of the temporary.
- */
- private JsName createNonVarTempory() {
- JsScope scope;
- if (!functionStack.isEmpty()) {
- scope = getCurrentFunctionScope();
- } else {
- scope = globalScope;
- }
- return scope.declareTemporary();
- }
-
- /**
- * Creates a temporary variable and registers it, so that an declaration statement is
- * emitted.
- * @return the JsName of the temporary.
- */
- @Override
- public JsName createTemporary() {
- JsName temp = createNonVarTempory();
- registerForDeclaration(temp);
- return temp;
- }
-
- /**
- * Returns the JsName for the given element. If the element is global and
- * hasn't been declared yet, it is done now.
- */
- private JsName getJsName(Symbol symbol) {
- return translationContext.getNames().getName(symbol);
- }
-
- /**
- * Creates a JS function with JS calling conventions and a deterministic name
- * so that it can be invoked from JS. The function will then forward
- * the call to the given method (with Dart calling conventions).
- */
- private void generateJsExportedFunction(MethodElement element, JsName name) {
- JsFunction fn = new JsFunction(globalScope);
-
- JsNameRef dartTarget = makeMethodJsReference(element, name);
- JsInvocation callIntoDart = AstUtil.newInvocation(dartTarget);
-
- List parameters = fn.getParameters();
- List arguments = callIntoDart.getArguments();
- for (VariableElement p : element.getParameters()) {
- JsName parameter = fn.getScope().declareFreshName(p.getName());
- parameters.add(new JsParameter(parameter));
- arguments.add(parameter.makeRef());
- }
- JsBlock jsBlock = new JsBlock();
- jsBlock.getStatements().add(new JsReturn(callIntoDart));
- jsBlock.setSourceRef(element.getNode());
-
- fn.setBody(jsBlock);
-
- String exportedFunctionName = mangler.mangleNativeMethod(element);
- JsName exportedFunctionJsName = globalScope.declareName(exportedFunctionName,
- exportedFunctionName,
- exportedFunctionName);
- fn.setName(exportedFunctionJsName);
- fn.setSourceRef(element.getNode());
- globalBlock.getStatements().add(fn.makeStmt());
- }
-
- /**
- * Makes the default-constructor accessible under a deterministic name and
- * with JavaScript calling conventions so that it can be invoked from JS.
- */
- private void generateIsolateDefaultFactoryMember(MethodElement element, JsName funcName) {
- JsName className = getJsName(element.getEnclosingElement());
- JsNameRef unmangledName = AstUtil.newNameRef(className.makeRef(), ISOLATE_DEFAULT_FACTORY);
- JsNameRef factoryName = AstUtil.newNameRef(className.makeRef(), funcName);
- JsBinaryOperation defaultAsg = AstUtil.newAssignment(unmangledName, factoryName);
- defaultAsg.setSourceRef(element.getNode());
- globalBlock.getStatements().add(defaultAsg.makeStmt());
- }
-
- @Override
- public JsNode visitClass(DartClass x) {
- assert ElementKind.of(currentHolder).equals(ElementKind.LIBRARY)
- : "Nested classes should be impossible";
- Element previousHolder = currentHolder;
- currentHolder = x.getSymbol();
-
- ClassElement classElement = x.getSymbol();
- JsName classJsName = getJsName(classElement);
-
- // If there is already a native class we must not create the JS function.
- if (classElement.getNativeName() == null) {
- JsFunction jsClass = new JsFunction(globalScope, classJsName).setSourceRef(x);
- jsClass.setIsConstructor(true);
- jsClass.setBody(new JsBlock());
- globalBlock.getStatements().add(jsClass.makeStmt());
- }
-
- if (classElement.isInterface()) {
- rtt.generateRuntimeTypeInfo(x);
-
- // Emit only static final fields for interfaces.
- for (Element member : classElement.getMembers()) {
- if (ElementKind.of(member).equals(ElementKind.FIELD)) {
- Modifiers modifiers = member.getModifiers();
- if (modifiers.isStatic() && !modifiers.isAbstractField()) {
- assert modifiers.isFinal();
- generateField((FieldElement) member);
- }
- }
- }
- } else {
- // Inherits.
- if (x.getSuperSymbol() != null) {
- JsNameRef superRef = getJsName(x.getSuperSymbol()).makeRef();
- JsInvocation inherits = AstUtil.newInvocation(
- new JsNameRef("$inherits"),
- classJsName.makeRef(),
- superRef);
- inherits.setSourceRef(x);
- globalBlock.getStatements().add(inherits.makeStmt());
- }
-
- maybeInjectIsolateMethods(classElement);
- rtt.generateRuntimeTypeInfo(x);
-
- List classMembers = new ArrayList();
- classMembers.addAll(classElement.getConstructors());
- for (Element element : classElement.getMembers()) {
- classMembers.add(element);
- }
-
- if (Elements.needsImplicitDefaultConstructor(classElement)) {
- addImplicitDefaultConstructor(x, classElement, classMembers);
- }
-
- for (Element member : classMembers) {
- switch(ElementKind.of(member)) {
- case METHOD: {
- MethodElement methodElement = (MethodElement) member;
- generateMethodDefinition(methodElement);
- if (!methodElement.getModifiers().isOperator()) {
- generateMethodGetter(methodElement);
- }
- break;
- }
-
- case CONSTRUCTOR:
- generateMethodDefinition((MethodElement) member);
- break;
-
- case FIELD:
- generateField((FieldElement) member);
- break;
-
- default:
- throw new AssertionError("Invalid member " + member);
- }
- }
-
- // TODO(johnlenz): should we create a stub method to catch
- // class without const constructors? As is, the a non-const
- // class with get the id of an "const Object".
- if (hasConstConstructor(classElement)) {
- makeConstIdMethod(classElement);
- }
-
- // Add temporary variable declarations, if any.
- // TODO(johnlenz): This isn't always correct: an incremental compile
- // might reuse temps, which we don't want. However, static initializations
- // (where the temps would be used) aren't quite right either yet. Double
- // check this when its done.
- Set temps = jsNewDeclarationsStack.peek();
- declareTempsInBlock(globalBlock, temps);
-
- // Clear the set for the next class.
- temps.clear();
- }
-
- assert currentHolder == x.getSymbol() : "Unbalanced class visitation";
- currentHolder = previousHolder;
-
- return null;
- }
-
- private void addImplicitDefaultConstructor(DartClass x, ClassElement classElement,
- List classElementMembers) {
- for (DartNode member : x.getMembers()) {
- if (member instanceof DartMethodDefinition) {
- DartMethodDefinition method = (DartMethodDefinition) member;
- MethodElement symbol = method.getSymbol();
- if (symbol.isConstructor() && "".equals(symbol.getName())) {
- classElementMembers.add(symbol);
- }
- }
- }
- }
-
- /**
- * @param classElement
- *
- */
- private void maybeInjectIsolateMethods(ClassElement classElement) {
- if (isIsolateClass(classElement)) {
- // In order to construct an isolate in another worker, it must be
- // referrable by name, this requires a top level method.
- generateIsolateFactory(classElement);
-
- // ... and a way to get the factory from a isolate instance
- generateIsolateFactoryGetter(classElement);
- }
- }
-
- private JsName getIsolateFactoryFunctionName(ClassElement classElement) {
- String fnNameStr = getJsName(classElement).getShortIdent() + "$" + ISOLATE_ISOLATE_FACTORY;
- return globalScope.declareName(fnNameStr);
- }
-
- private JsNameRef getIsolateFactoryGetterName(ClassElement classElement) {
- return AstUtil.newNameRef(
- AstUtil.newPrototypeNameRef(getJsName(classElement).makeRef()),
- ISOLATE_ISOLATE_FACTORY_GETTER);
- }
-
- private void generateIsolateFactory(ClassElement classElement) {
- // Create static factory function:
- // function Foo$IsolateFactory() {
- // return Foo.default$Factory();
- // }
-
- // Build the function
- JsName fnName = getIsolateFactoryFunctionName(classElement);
-
- JsNameRef defaultFactory = AstUtil.newNameRef(
- getJsName(classElement).makeRef(), ISOLATE_DEFAULT_FACTORY);
- JsInvocation invokeFactory = AstUtil.newInvocation(defaultFactory);
-
- // TODO(johnlenz): Add runtime type information if necessary.
- JsFunction factoryFn = AstUtil.newFunction(globalScope, fnName, null,
- new JsReturn(invokeFactory));
-
- globalBlock.getStatements().add(factoryFn.makeStmt());
- }
-
- private void generateIsolateFactoryGetter(ClassElement classElement) {
- // Create static factory function:
- // function Foo.prototype.getFactory() {
- // return Foo$IsolateFactory;
- // }
-
- // Build the function
- JsName fnName = getIsolateFactoryFunctionName(classElement);
- JsFunction getterFn = AstUtil.newFunction(globalScope, null, null,
- new JsReturn(fnName.makeRef()));
-
- // Declare it.
- JsExpression declStmt = AstUtil.newAssignment(
- getIsolateFactoryGetterName(classElement), getterFn);
- globalBlock.getStatements().add(declStmt.makeStmt());
- }
-
- private boolean isIsolateClass(ClassElement classElement) {
- return false;
- }
-
- /**
- * Creates a $getter for a method of a class, returning $method as a closure
- * bound to the current instance if it is an instance method.
- */
- private void generateMethodGetter(MethodElement methodElement) {
- // Generate a getter for method binding to a variable
- boolean isTopLevel = Elements.isTopLevel(methodElement);
- if (methodElement.getModifiers().isGetter() || methodElement.getModifiers().isSetter()) {
- return;
- }
- JsNameRef classJsNameRef = isTopLevel ? null :
- getJsName(methodElement.getEnclosingElement()).makeRef();
- String getterName = mangler.createGetterSyntax(methodElement, unitLibrary);
- String methodName = methodElement.getName();
- JsName getterJsName = globalScope.declareName(getterName, getterName, methodName);
- getterJsName.setObfuscatable(false);
- String mangledMethodName = mangler.mangleNamedMethod(methodElement, unitLibrary);
- JsNameRef mangledRttMethod = rtt.getRTTLookupMethodNameRef(methodElement);
- JsFunction func = new JsFunction(globalScope);
- JsNameRef getterJsNameRef;
- if (isTopLevel || methodElement.getModifiers().isStatic()) {
- // function() {
- // var ret = $named;
- // ret.$lookupRTT = $named_$lookupRTT;
- // return ret;
- // }
- func.setBody(new JsBlock());
- List stmts = func.getBody().getStatements();
- JsName returnVar = func.getScope().declareFreshName("ret");
- getterJsNameRef = AstUtil.newNameRef(classJsNameRef, getterJsName);
- stmts.add(AstUtil.newVar(null, returnVar,
- AstUtil.newNameRef(classJsNameRef, mangledMethodName)));
- JsBinaryOperation varLookup = AstUtil.newAssignment(
- AstUtil.newNameRef(returnVar.makeRef(), "$lookupRTT"),
- mangledRttMethod);
- stmts.add(varLookup.makeStmt());
- stmts.add(new JsReturn(returnVar.makeRef()));
- } else {
- // function() { return $bind(.prototype.$named,
- // $bind(.prototype.$named_$lookupRTT, this); }
- JsNameRef prototypeRef = AstUtil.newPrototypeNameRef(classJsNameRef);
- getterJsNameRef = AstUtil.newNameRef(prototypeRef, getterJsName);
- JsExpression bindMethodCall = AstUtil.newInvocation(new JsNameRef("$bind"),
- AstUtil.newNameRef(prototypeRef, mangledMethodName),
- mangledRttMethod, new JsThisRef());
- func.setBody(AstUtil.newBlock(new JsReturn(bindMethodCall)));
- }
-
- JsExpression asg;
- if (isTopLevel) {
- func.setName(getterJsNameRef.getName());
- asg = func;
- } else {
- func.setSourceRef(methodElement.getNode());
- asg = AstUtil.newAssignment(getterJsNameRef, func);
- }
- asg.setSourceRef(methodElement.getNode());
- globalBlock.getStatements().add(asg.makeStmt());
- }
-
- private boolean hasConstConstructor(ClassElement element) {
- for (ConstructorElement ctr : element.getConstructors()) {
- if (ctr.getModifiers().isConstant()) {
- return true;
- }
- }
- return false;
- }
-
- private void makeConstIdMethod(ClassElement classElement) {
- JsNameRef methodRef = makeConstIdMethodRef(classElement);
- JsStatement decl = AstUtil.newAssignment(methodRef,
- makeConstIdMethodFunction(classElement)).makeStmt();
- this.globalBlock.getStatements().add(decl);
- }
-
- private JsNameRef makeConstIdMethodRef(ClassElement classElement) {
- // Instance methods hang from the prototype.
- JsNameRef qualifier = AstUtil.newPrototypeNameRef(getJsName(classElement).makeRef());
- JsNameRef methodRef = AstUtil.newNameRef(qualifier, CONST_ID_JS_METHOD_NAME);
- return methodRef;
- }
-
- private JsFunction makeConstIdMethodFunction(ClassElement classElement) {
- JsFunction func = new JsFunction(this.globalScope);
- // Make an id like:
- // :field1:field2:...-:field1:field2:...
- JsExpression idExpr = rtt.getRTTClassId(classElement);
- for (Element member : classElement.getMembers()) {
- if (member.getKind() == ElementKind.FIELD) {
- if (!member.getModifiers().isStatic()) {
- idExpr = addConstIdFieldExpr((FieldElement) member, idExpr);
- }
- }
- }
- idExpr = addConstIdSuperExpr(classElement, idExpr);
- func.setBody(AstUtil.newBlock(new JsReturn(idExpr)));
- return func;
- }
-
- private JsExpression addConstIdFieldExpr(
- FieldElement element, JsExpression prevPart) {
- JsExpression qualifier = getGetterSetterQualifier(element);
- JsName fieldJsName = getJsName(element);
- JsNameRef ref = AstUtil.newNameRef(qualifier, fieldJsName);
-
- // example: prevPart + ":" + $const_id(this.field)
- return add(prevPart, add(string(":"),
- AstUtil.newInvocation(new JsNameRef(DART_CONST_ID_JS_FUNC), ref)));
- }
-
- private JsExpression addConstIdSuperExpr(ClassElement element, JsExpression prevPart) {
- InterfaceType superType = element.getSupertype();
- if (superType == null || superType.getElement().isObject()) {
- // The root object doesn't add anything.
- return prevPart;
- }
- JsNameRef superConstIdRef = makeConstIdMethodRef(superType.getElement());
- JsNameRef callRef = AstUtil.newNameRef(superConstIdRef, "call");
- JsInvocation superCall = AstUtil.newInvocation(callRef, new JsThisRef());
-
- // example: prevPart + "-" + super.prototype.$const_id.call(this);
- return add(prevPart, add(string("-"), superCall));
- }
-
- private JsExpression add(JsExpression first, JsExpression second) {
- return new JsBinaryOperation(JsBinaryOperator.ADD, first, second);
- }
-
- private void generateField(FieldElement element) {
- generate(element.getNode());
- }
-
- private void generateMethodDefinition(MethodElement element) {
- JsFunction func = (JsFunction) generate(element.getNode());
-
- // makeMethod clears the name of the function.
- JsName funcName = func.getName();
- makeMethod(element, func);
-
- // If the method is the default factory we add the same method under an unmangled name.
- // This is necessary for the isolate code.
- if (Elements.isNonFactoryConstructor(element)
- && "".equals(element.getName())
- && func.getParameters().size() == 0
- && isIsolateClass((ClassElement)element.getEnclosingElement())) {
- generateIsolateDefaultFactoryMember(element, funcName);
- }
-
- // If the function is exported to JavaScript make it accessible under its
- // (more or less) unmangled name.
- DartMethodDefinition method = (DartMethodDefinition) element.getNode();
- DartBlock body = method.getFunction().getBody();
- if (element.getModifiers().isNative() && !(body instanceof DartNativeBlock)) {
- generateJsExportedFunction(element, funcName);
- }
- }
-
- private void createInlinedClassConstructor(DartClass x) {
- ClassElement classElement = x.getSymbol();
- assert classElement.getNativeName() == null;
- JsName classJsName = getJsName(classElement);
- JsFunction jsClass = new JsFunction(globalScope, classJsName).setSourceRef(x);
- jsClass.setIsConstructor(true);
- JsBlock block = new JsBlock();
- JsScope scope = new JsScope(globalScope, "temp");
- for (FieldElement fieldElement : getFieldsInClassHierarchy(classElement)) {
- String fieldName = translationContext.getMangler().mangleField(fieldElement, unitLibrary);
- JsNameRef fieldRef = AstUtil.newNameRef(new JsThisRef(), fieldName);
- JsName paramName = scope.declareName("p$" + fieldName);
- jsClass.getParameters().add(new JsParameter(paramName));
- JsBinaryOperation asg = AstUtil.newAssignment(fieldRef, new JsNameRef(paramName));
- block.getStatements().add(asg.makeStmt());
- }
- jsClass.setBody(block);
- globalBlock.getStatements().add(jsClass.makeStmt());
- }
-
- private List getFieldsInClassHierarchy(ClassElement classElement) {
- InterfaceType current = classElement.getType();
- Stack classes = new Stack();
- while ((current != null) && !current.getElement().isObject()) {
- classElement = current.getElement();
- classes.push(classElement);
- current = classElement.getSupertype();
- }
- List fields = Lists.newArrayList();
- while (!classes.isEmpty()) {
- classElement = classes.pop();
- for (Element elem : classElement.getMembers()) {
- Modifiers modifiers = elem.getModifiers();
- if (ElementKind.of(elem).equals(ElementKind.FIELD) && !modifiers.isStatic()
- && !modifiers.isAbstractField()) {
- fields.add((FieldElement) elem);
- }
- }
- }
- return fields;
- }
-
- private void generateAbstractField(FieldElement fieldElement) {
- if (fieldElement.getGetter() != null) {
- generateMethodDefinition(fieldElement.getGetter());
- }
- if (fieldElement.getSetter() != null) {
- generateMethodDefinition(fieldElement.getSetter());
- }
- }
-
- private void declareTempsInBlock(JsBlock block, Collection tempCollection) {
- // Add temporary variable declarations, if any.
- Iterator temps = tempCollection.iterator();
- if (temps.hasNext()) {
- JsVars jsVars = new JsVars();
- while (temps.hasNext()) {
- JsName name = temps.next();
- JsVars.JsVar jsVar = new JsVars.JsVar(name);
- jsVars.insert(jsVar);
- }
- block.getStatements().add(0, jsVars);
- }
- }
-
- private List getInlineFieldInitializers(ConstructorElement element) {
- List fieldInitializers = new ArrayList();
- Iterable classMembers = element.getEnclosingElement().getMembers();
- for (Element member : classMembers) {
- Modifiers modifiers = member.getModifiers();
- if (!modifiers.isStatic()
- && !modifiers.isAbstractField()
- && ElementKind.of(member).equals(ElementKind.FIELD)) {
- DartField field = (DartField) member.getNode();
- if (field.getValue() != null) {
- fieldInitializers.add(field);
- }
- }
- }
- return fieldInitializers;
- }
-
- private JsExpression generateInlineFieldInitializer(DartField field) {
- JsNameRef fieldName = AstUtil.newNameRef(new JsThisRef(), getJsName(field.getSymbol()));
- JsExpression initExpr = (JsExpression) generate(field.getValue());
- return AstUtil.newAssignment(fieldName, initExpr);
- }
-
- /**
- * For a constructor B whose super is A we generate:
- *
- * FactoryB() {
- * var tmp = new B;
- * InitB(tmp);
- * BodyB(tmp);
- * }
- *
- * BodyB() {
- * BodyA();
- * }
- *
- * InitB() {
- * InitA();
- * }
- *
- * This method creates the InitB method and adds the BodyA call in the BodyB method.
- */
- private void addInitializers(DartMethodDefinition constructor,
- JsFunction factory,
- JsName tempVar) {
- ConstructorElement element = (ConstructorElement) constructor.getSymbol();
- JsScope classMemberScope = translationContext.getMemberScopes().get(element.getEnclosingElement());
- JsName curClassJsName = getJsName(element.getEnclosingElement());
-
- // Create the initializer function.
- String constructorName = element.getName();
- String initName = mangler.createInitializerSyntax(constructorName, unitLibrary);
- JsName initJsName = classMemberScope.declareName(initName, initName, constructorName);
- // Initializers are called from other class (as part of the super initialization).
- initJsName.setObfuscatable(false);
- JsFunction initFunction = new JsFunction(globalScope, initJsName).setSourceRef(constructor);
- initFunction.setBody(new JsBlock());
-
- // Add the initializer as a member of the current class.
- makeMethod(element, initFunction);
-
- // Add the parameters to the initializer function.
- List params = constructor.getFunction().getParams();
- for (DartParameter p : params) {
- initFunction.getParameters().add(
- new JsParameter(getJsName(p.getNormalizedNode().getSymbol())));
- }
-
- // If there are initializers, or inline field initializers, populate the
- // initializer function.
- List initializers = constructor.getInitializers();
- List fieldInitializers = getInlineFieldInitializers(element);
-
- if (!initializers.isEmpty() || !fieldInitializers.isEmpty()) {
- // TODO(johnlenz): move this block shares the some of the same setup
- // and tear down as the visitFunction method.
-
- // Give the initializer expressions access to the function parameters
- functionStack.push(constructor.getFunction());
- jsNewDeclarationsStack.push(new HashSet());
-
- // Do the field inline initializers first. If there are any assignments in the initializer
- // list, they will be the last assignments.
- List jsInitializers = initFunction.getBody().getStatements();
- Iterator fieldIterator = fieldInitializers.iterator();
- while (fieldIterator.hasNext()) {
- jsInitializers.add(generateInlineFieldInitializer(fieldIterator.next()).makeStmt());
- }
-
- DartInvocation initInvocation = null;
- Iterator iterator = initializers.iterator();
- while (iterator.hasNext()) {
- DartInitializer initializer = iterator.next();
- if (!initializer.isInvocation()) {
- jsInitializers.add((JsStatement) generate(initializer));
- } else {
- initInvocation = (DartInvocation) initializer.getValue();
- }
- }
-
- JsInvocation constructorInvocation = maybeGenerateSuperOrRedirectCall(constructor);
- if (constructorInvocation != null) {
- // Call the super initializer function in the initializer.
- // Compute the super constructor initializer to call.
- ConstructorElement superElement = (ConstructorElement) initInvocation.getSymbol();
- // TODO(floitsch): it would be better if we had a js-name and not just a string.
- // This way the debugging information would be better.
- // We need to generate the JsName (for the initializer/factory) once only and store it
- // in some hashtable. Then instead of reusing the mangler, we should reuse those JsNames.
- // The debugging information would then contain a link from the property-access to the
- // constructor. Without JsName the debugger just assumes we access some random property.
- String mangledSuperConstructorName =
- mangler.createInitializerSyntax(superElement.getName(), unitLibrary);
- Element superClassElement = superElement.getEnclosingElement();
- JsNameRef superInitRef = AstUtil.newNameRef(getJsName(superClassElement).makeRef(),
- mangledSuperConstructorName);
- JsNameRef callRef = AstUtil.newNameRef(superInitRef, "call");
- JsInvocation superInitCall = AstUtil.newInvocation(callRef);
- initFunction.getBody().getStatements().add(0, superInitCall.makeStmt());
- // TODO(floitsch): don't copy the arguments from the super call for the initializer call.
- // This will evaluate side-effects twice, and we are reusing nodes (thereby creating a
- // DAG instead of a tree).
- superInitCall.getArguments().addAll(constructorInvocation.getArguments());
- }
-
- // Call the initializer in the factory. This must be executed
- // before calling the super constructor: .$Initializer.call(this, ...)
- JsNameRef initRef = AstUtil.newNameRef(curClassJsName.makeRef(), initJsName);
- JsNameRef initCallRef = AstUtil.newNameRef(initRef, "call");
- JsInvocation initCall = AstUtil.newInvocation(initCallRef, tempVar.makeRef());
- for (DartParameter p : params) {
- initCall.getArguments().add(getJsName(p.getNormalizedNode().getSymbol()).makeRef());
- }
-
- factory.getBody().getStatements().add(0, initCall.makeStmt());
-
- // Dart does not have an implicit call to a super constructor.
-
- // Add temporary variable declarations, if any.
- declareTempsInBlock(initFunction.getBody(), jsNewDeclarationsStack.pop());
-
- // setup the scope alias for the init function
- maybeAddFunctionScopeAlias(
- currentScopeInfo.getScope(constructor.getFunction()), initFunction);
-
- // Remove the containing function scope.
- functionStack.pop();
- }
- }
-
- private void addSuperOrRedirectConstructorCall(DartMethodDefinition constructor) {
- JsInvocation superCall = maybeGenerateSuperOrRedirectCall(constructor);
- if (superCall != null) {
- // If we have a super constructor call, add it as the first statement
- // in the constructor body.
- // .$Constructor.call(this, ...).
- JsFunction constructorFunction = translationContext.getMethods().get(constructor.getFunction());
- constructorFunction.getBody().getStatements().add(0, superCall.makeStmt());
- }
- }
-
- private JsInvocation maybeGenerateSuperOrRedirectCall(DartMethodDefinition constructor) {
- // If there are initializers, populate the initializer function.
- List initializers = constructor.getInitializers();
- if (!initializers.isEmpty()) {
- for (DartInitializer init : initializers) {
- if (init.isInvocation()) {
- JsExprStmt statement = (JsExprStmt) generate(init);
- if (statement != null) {
- return (JsInvocation) statement.getExpression();
- }
- }
- }
- }
- return null;
- }
-
- private JsNode generateConstructorDefinition(DartMethodDefinition x) {
- assert currentScopeInfo == null : "Nesting a constructor in a method should be impossible";
- currentScopeInfo = ScopeRootInfo.makeScopeInfo(x, !shouldGenerateDeveloperModeChecks());
- ConstructorElement element = (ConstructorElement) x.getSymbol();
- ClassElement classElement = (ClassElement) element.getEnclosingElement();
- JsScope classMemberScope = translationContext.getMemberScopes().get(classElement);
- String constructorName = element.getName();
- JsName curClassJsName = getJsName(classElement);
-
- JsFunction dartCtor = (JsFunction) generate(x.getFunction());
-
- // Add the constructor as a member of the current class.
- makeMethod(element, dartCtor);
-
- // Create the static factory function that allocates the object
- // and calls the constructor.
- // .ConstructorName$Factory = function (args ...) {
- // var tmp = new ();
- // tmp.$typeInfo = runtimeType;
- // .ConstructorName$Constructor.call(tmp, args ...);
- // return tmp;
- // }
- // Attaching the factory to is done outside this method. We just provide the
- // factory-name ("ConstructorName$Factory" here).
-
- // The factory becomes a member of and should therefore be declared in the same
- // scope as all other members.
- String className = element.getConstructorType().getName();
- String factoryName = mangler.createFactorySyntax(className, constructorName, unitLibrary);
- JsName factoryJsName =
- classMemberScope.declareName(factoryName, factoryName, constructorName);
- // Factories are globally accessible.
- factoryJsName.setObfuscatable(false);
-
- JsFunction factoryFunction = new JsFunction(globalScope, factoryJsName).setSourceRef(x);
- JsScope factoryScope = factoryFunction.getScope();
-
- // We do the constructor invocation before we declare the temporary variable. This is
- // necessary to ensure that the created temporary does not conflict with the parameters.
- JsInvocation constructorInvocation = new JsInvocation();
- JsName constructorJsName = getJsName(element);
- JsNameRef constructorRef = AstUtil.newNameRef(curClassJsName.makeRef(), constructorJsName);
- constructorInvocation.setQualifier(AstUtil.newNameRef(constructorRef, "call"));
-
- // Add the arguments to the constructor invocation. Note that the constructor call is still
- // missing the 'tmp' variable. We will add it later.
- List params = x.getFunction().getParams();
- List jsArgNames = new ArrayList();
- for (DartParameter p : params) {
- // TODO(ngeoffray): We should actually copy the arguments. See b/4424659.
- JsName argName = getJsName(p.getNormalizedNode().getSymbol());
- jsArgNames.add(argName);
- constructorInvocation.getArguments().add(argName.makeRef());
- }
-
- JsName tempVar = factoryScope.declareTemporary();
- // Add the 'tmp' var to the constructor call.
- constructorInvocation.getArguments().add(0, tempVar.makeRef());
-
- factoryFunction.setBody(AstUtil.newBlock(
- constructorInvocation.makeStmt(),
- new JsReturn(tempVar.makeRef())));
-
- addInitializers(x, factoryFunction, tempVar);
- rtt.maybeAddClassRuntimeTypeToConstructor(classElement, factoryFunction, tempVar.makeRef());
- JsNew jsNew = new JsNew(curClassJsName.makeRef());
- if (classElement.getNativeName() != null && x.getFunction().getBody() == null) {
- /*
- * For native classes with bodyless constructors, we pass the user-declared arguments of
- * the factory method to the native "new" expression.
- */
- List newArguments = jsNew.getArguments();
- for (JsName jsArgName : jsArgNames) {
- newArguments.add(jsArgName.makeRef());
- }
- }
- factoryFunction.getBody().getStatements().add(0, AstUtil.newVar(x, tempVar, jsNew));
-
- generateAll(x.getFunction().getParams(), factoryFunction.getParameters(), JsParameter.class);
-
- assert currentScopeInfo != null;
- inFactory = false;
- inFactoryOrStaticContext = false;
- currentScopeInfo = null;
-
- return factoryFunction;
- }
-
- private void generateInitializersInlined(DartMethodDefinition x, JsFunction factoryFunction,
- JsScope factoryScope, JsName tempVar) {
- ConstructorElement element = (ConstructorElement) x.getSymbol();
- JsName curClassJsName = getJsName(element.getEnclosingElement());
- Map initMap = new HashMap();
- JsExpression superInvocation = null;
- for (DartInitializer init : x.getInitializers()) {
- JsExpression initValue = (JsExpression) generate(init.getValue());
- if (init.isInvocation()) {
- superInvocation = initValue;
- continue;
- } else {
- assert ElementKind.of(init.getName().getTargetSymbol()).equals(ElementKind.FIELD);
- FieldElement fieldElement = (FieldElement) init.getName().getTargetSymbol();
- initMap.put(fieldElement, initValue);
- }
- }
- List stmts = Lists.newArrayList();
- JsNew jsNew = new JsNew(curClassJsName.makeRef());
- ClassElement classElement = (ClassElement) element.getEnclosingElement();
- for (FieldElement fieldElement : getFieldsInClassHierarchy(classElement)) {
- String fieldName = translationContext.getMangler().mangleField(fieldElement, unitLibrary);
- JsName tmp = factoryScope.declareName("init$" + fieldName);
- JsExpression initValue = initMap.get(fieldElement);
- if (initValue == null) {
- DartField fieldNode = (DartField) fieldElement.getNode();
- if (fieldNode.getValue() != null) {
- initValue = (JsExpression) generate(fieldNode.getValue());
- } else {
- initValue = undefined();
- }
- }
- stmts.add(AstUtil.newVar(x, tmp, initValue));
- jsNew.getArguments().add(new JsNameRef(tmp));
- }
- if (superInvocation != null) {
- factoryFunction.getBody().getStatements().add(0, new JsExprStmt(superInvocation));
- }
- stmts.add(AstUtil.newVar(x, tempVar, jsNew));
- factoryFunction.getBody().getStatements().addAll(0, stmts);
- }
-
- @Override
- public JsNode visitMethodDefinition(DartMethodDefinition x) {
- assert x == x.getNormalizedNode();
- if (Elements.isNonFactoryConstructor(x.getSymbol())) {
- return generateConstructorDefinition(x);
- }
-
- assert currentScopeInfo == null : "Nested methods should be impossible";
- inFactory = x.getModifiers().isFactory();
- inFactoryOrStaticContext = isFactoryOrStaticContext(x.getModifiers());
- currentScopeInfo = ScopeRootInfo.makeScopeInfo(x, !shouldGenerateDeveloperModeChecks());
-
- JsFunction func = (JsFunction) generate(x.getFunction());
- assert currentScopeInfo != null;
- inFactory = false;
- inFactoryOrStaticContext = false;
- currentScopeInfo = null;
-
- if (Elements.isTopLevel(x.getSymbol())) {
- JsFunction tramp = generateNamedParameterMethodTrampoline(x, func.getName().makeRef());
- String mangled = mangler.mangleNamedMethod(x.getSymbol(), unitLibrary);
- JsName trampName = globalScope.declareName(mangled);
- tramp.setName(trampName);
-
- globalBlock.getStatements().add(func.makeStmt());
- globalBlock.getStatements().add(tramp.makeStmt());
-
- // special case for top level methods
- rtt.generateRuntimeTypeInfo(x);
- generateMethodGetter(x.getSymbol());
- }
-
- return func;
- }
-
- private JsFunction generateNamedParameterMethodTrampoline(DartMethodDefinition method,
- JsNameRef origJsName) {
- boolean preserveThis = !(method.getModifiers().isStatic() ||
- method.getModifiers().isFactory() ||
- Elements.isTopLevel(method.getSymbol()));
-
- return generateNamedParameterTrampoline(method.getFunction(), origJsName, 0, preserveThis);
- }
-
- private JsFunction generateNamedParameterTrampoline(DartFunction func,
- JsNameRef origJsName, int numClosureScopes, boolean preserveThis) {
- // function([$s0, $s1, ...], $n, $o, P0, P1, P2, P3, ...) {
- JsFunction tramp = new JsFunction(globalScope);
- JsScope scope = tramp.getScope();
-
- // Create fresh parameters for the explicit and synthetic parameters.
- boolean hasNamedParams = false;
- List explicitJsParams = new ArrayList();
- for (DartParameter dartParam : func.getParams()) {
- String paramName = ((DartIdentifier) dartParam.getName()).getTargetName();
- JsParameter param = new JsParameter(scope.declareName(paramName));
- explicitJsParams.add(param);
- if (dartParam.getModifiers().isNamed()) {
- hasNamedParams = true;
- }
- }
-
- List closureScopeParams = new ArrayList();
- for (int i = 0; i < numClosureScopes; ++i) {
- JsParameter param = new JsParameter(scope.declareFreshName("$s" + i));
- closureScopeParams.add(param);
- }
- JsParameter countParam = new JsParameter(scope.declareFreshName("$n"));
- JsParameter namedParam = new JsParameter(scope.declareFreshName("$o"));
-
- // Declare parameters in the proper order.
- for (int i = 0; i < numClosureScopes; ++i) {
- tramp.getParameters().add(closureScopeParams.get(i));
- }
- tramp.getParameters().add(countParam);
- tramp.getParameters().add(namedParam);
- for (int i = 0; i < explicitJsParams.size(); ++i) {
- tramp.getParameters().add(explicitJsParams.get(i));
- }
-
- JsBlock body = new JsBlock();
- tramp.setBody(body);
- List stmts = body.getStatements();
-
- if (hasNamedParams) {
- // var seen = 0, def = 0;
- JsName seen = scope.declareFreshName("seen");
- JsName def = scope.declareFreshName("def");
- stmts.add(AstUtil.newVar(null, seen, number(0)));
- stmts.add(AstUtil.newVar(null, def, number(0)));
-
- // switch ($n) {
- // case 1: P0 = $o.P0 ? (++seen, $o.P0) : null; // no default value
- // case 2: P1 = $o.P1 ? (++seen, $o.P1) : (++def, DEFAULT); // explicit default value
- // ...
- // }
- JsSwitch jsSwitch = new JsSwitch();
- jsSwitch.setExpr(countParam.getName().makeRef());
- for (int i = 0; i < func.getParams().size(); ++i) {
- DartParameter param = func.getParams().get(i);
- JsParameter jsParam = tramp.getParameters().get(i + 2 + numClosureScopes);
- if (!param.getModifiers().isNamed()) {
- continue;
- }
-
- String paramNameStr = getPropNameForNamedParameter(jsParam);
- JsExpression paramName = string(getPropNameForNamedParameter(jsParam));
- JsExpression ifExpr = AstUtil.in(null, paramName, namedParam.getName().makeRef());
-
- JsExpression ppSeen = AstUtil.preinc(null, seen.makeRef());
- JsBinaryOperation thenExpr = AstUtil.comma(null, ppSeen,
- AstUtil.newNameRef(namedParam.getName().makeRef(), paramNameStr));
-
- DartExpression defaultValue = param.getDefaultExpr();
- JsExpression elseExpr = (defaultValue != null)
- ? generateDefaultValue(defaultValue)
- : undefined();
- JsExpression ppDef = AstUtil.preinc(null, def.makeRef());
- elseExpr = AstUtil.comma(null, ppDef, elseExpr);
-
- JsBinaryOperation asg = assign(
- jsParam.getName().makeRef(),
- new JsConditional(ifExpr, thenExpr, elseExpr));
-
- jsSwitch.getCases().add(AstUtil.newCase(number(i), asg.makeStmt()));
- }
- if (jsSwitch.getCases().size() > 0) {
- stmts.add(jsSwitch);
- }
-
- // if ((seen != $o.count) || (seen + def + $n != TOTAL)) {
- // $nsme();
- // }
- {
- JsBinaryOperation ifLeft = neq(seen.makeRef(),
- AstUtil.newNameRef(namedParam.getName().makeRef(), "count"));
-
- JsExpression add1 = add(seen.makeRef(), def.makeRef());
- JsExpression add2 = add(add1, countParam.getName().makeRef());
- JsExpression ifRight = neq(add2, number(func.getParams().size()));
-
- JsExpression ifExpr = or(ifLeft, ifRight);
- JsStatement thenStmt = AstUtil.newInvocation(new JsNameRef("$nsme")).makeStmt();
-
- stmts.add(new JsIf(ifExpr, thenStmt, null));
- }
- } else {
- // if ($o.count || ($n != TOTAL)) {
- // $nsme();
- // }
- {
- JsExpression ifExpr =
- or(AstUtil.newNameRef(namedParam.getName().makeRef(), "count"),
- neq(countParam.getName().makeRef(), number(func.getParams().size())));
- JsStatement thenStmt = AstUtil.newInvocation(new JsNameRef("$nsme")).makeStmt();
-
- stmts.add(new JsIf(ifExpr, thenStmt, null));
- }
- }
- JsInvocation jsInvoke = AstUtil.newInvocation(
- AstUtil.newNameRef(origJsName.getQualifier(), origJsName.getName()));
- if (preserveThis) {
- JsNameRef call = AstUtil.newNameRef(jsInvoke.getQualifier(), "call");
- jsInvoke = AstUtil.newInvocation(call, new JsThisRef());
- }
- for (int i = 0; i < numClosureScopes; ++i) {
- jsInvoke.getArguments().add(closureScopeParams.get(i).getName().makeRef());
- }
- for (JsParameter jsParam : explicitJsParams) {
- jsInvoke.getArguments().add(jsParam.getName().makeRef());
- }
- stmts.add(new JsReturn(jsInvoke));
-
- return tramp;
- }
-
- private String mangleNamedParameterName(String name) {
- return "$p_" + name;
- }
-
- private String getPropNameForNamedParameter(JsParameter jsParam) {
- return mangleNamedParameterName(jsParam.getName().getShortIdent());
- }
-
- private String getPropNameForNamedParameter(DartNamedExpression namedExpr) {
- return mangleNamedParameterName(namedExpr.getName().getTargetName());
- }
-
- /**
- * If necessary, add object holding aliases for any parameters
- * captured by function closures.
- */
- private void maybeAddFunctionScopeAlias(DartScope scope, JsFunction function) {
- if (scope.definesClosureReferencedSymbols()) {
- JsScope jsScope = function.getScope();
- JsBlock body = function.getBody();
-
- // Example:
- // function f(a,b) { ... }
- // to:
- // function f(a,b) {var s0={f:f,a:a,b:b} ... };
- JsObjectLiteral aliasInit = new JsObjectLiteral();
- for (Entry entry : scope.getSymbols().entrySet()) {
- if (entry.getValue().isReferencedFromClosure()) {
- JsName param = getJsName(entry.getKey());
- aliasInit.getPropertyInitializers().add(
- new JsPropertyInitializer(string(param.getIdent()), new JsNameRef(param)));
- }
- }
-
- JsName aliasName = scope.getAliasForJsScope(jsScope);
- // Scope objects are declared (in the JsScope) at first use. By construction scope-objects
- // are only created when they are used. Therefore the scope-object must exist in the
- // JsScope.
- assert aliasName != null;
- JsStatement aliasDecl = AstUtil.newVar(null, aliasName, aliasInit);
- body.getStatements().add(0, aliasDecl);
- }
- }
-
- private JsName getTraceCounter() {
- if (traceCounter == null) {
- traceCounter = globalScope.declareTemporary();
- JsStatement counterDecl = AstUtil.newVar(null, traceCounter, number(0));
- globalBlock.getStatements().add(0, counterDecl);
- }
- return traceCounter;
- }
-
- private JsNameRef makeMethodJsReference(Element element, JsName name) {
- JsNameRef qualifier;
- boolean isNonFactoryConstructor = Elements.isNonFactoryConstructor(element);
- Modifiers modifiers = element.getModifiers();
- JsNameRef classJsName = getJsName(element.getEnclosingElement()).makeRef();
- if (modifiers.isStatic() || modifiers.isFactory() || isNonFactoryConstructor) {
- // Static methods hang directly from the constructor.
- qualifier = classJsName;
- } else {
- // Instance methods hang from the prototype.
- qualifier = AstUtil.newPrototypeNameRef(classJsName);
- }
-
- JsNameRef prop = AstUtil.newNameRef(qualifier, name);
- // TODO(johnlenz): This should be the name node reference
- prop.setSourceRef(element.getNode());
- return prop;
- }
-
- private boolean isFactoryOrStaticContext(Modifiers modifiers) {
- return modifiers.isFactory() || modifiers.isStatic();
- }
-
- /**
- * Turns a method into a prototype assignment on the JS class. Clears the name from the given
- * function.
- */
- private void makeMethod(Element element, JsFunction func) {
- if (element.getEnclosingElement().getKind().equals(ElementKind.CLASS)) {
- JsNameRef prop = makeMethodJsReference(element, func.getName());
- func.setName(null);
- JsBinaryOperation asg = AstUtil.newAssignment(prop, func);
-
- // TODO(johnlenz): This should be the stmt node reference
- asg.setSourceRef(element.getNode());
- globalBlock.getStatements().add(asg.makeStmt());
-
- // If it's a (non-operator, non-property) method, generate its named trampoline.
- if (element.getKind().equals(ElementKind.METHOD) && !element.getModifiers().isOperator()
- && !element.getModifiers().isGetter() && !element.getModifiers().isSetter()) {
- // Declare the mangled trampoline's name in the same scope as its target.
- String mangled = mangler.mangleNamedMethod((MethodElement) element, unitLibrary);
- JsName namedName = prop.getName().getEnclosing().declareName(mangled);
- JsNameRef namedProp = makeMethodJsReference(element, namedName);
-
- DartMethodDefinition method = (DartMethodDefinition) element.getNode();
- JsFunction tramp = generateNamedParameterMethodTrampoline(method, prop);
-
- asg = assign(namedProp, tramp);
- globalBlock.getStatements().add(asg.makeStmt());
-
- // Generate a lookup method after finally writing function / named tramp
- assert currentScopeInfo == null : "Nested methods should be impossible";
- inFactory = element.getModifiers().isFactory();
- inFactoryOrStaticContext = isFactoryOrStaticContext(element.getModifiers());
- DartMethodDefinition x = (DartMethodDefinition) element.getNode();
- currentScopeInfo = ScopeRootInfo.makeScopeInfo(x, !shouldGenerateDeveloperModeChecks());
- rtt.generateRuntimeTypeInfo(x);
-
- assert currentScopeInfo != null;
- inFactory = false;
- inFactoryOrStaticContext = false;
- currentScopeInfo = null;
- }
- } else {
- globalBlock.getStatements().add(func.makeStmt());
- }
- }
-
- private JsExpression getGetterSetterQualifier(Element element) {
- if (isDeclaredAsStaticOrImplicitlyStatic(element)) {
- // The mangler makes sure that the mangled version of static
- // fields names encode the class name so we do not have to
- // read the fields through the class function.
- return new JsNameRef(ISOLATE_CURRENT);
- } else if (Elements.isTopLevel(element)) {
- return null;
- } else {
- return new JsThisRef();
- }
- }
-
- /**
- * Creates a getter that returns a JavaScript property.
- */
- private void makePropertyGetter(FieldElement element) {
- JsExpression qualifier = getGetterSetterQualifier(element);
- JsName fieldJsName = getJsName(element);
- JsNameRef ref = AstUtil.newNameRef(qualifier, fieldJsName);
- makeGetter(element, ref);
- }
-
- /**
- * Creates a getter that returns a constant (simple) JavaScript value.
- */
- private void makeConstantValueGetter(FieldElement element, JsExpression value) {
- assert element.getModifiers().isFinal();
- makeGetter(element, value);
- }
-
- private void makeGetter(FieldElement element, JsExpression expression) {
- String getterName = mangler.createGetterSyntax(element, unitLibrary);
- String fieldName = element.getName();
- JsName getterJsName = globalScope.declareName(getterName, getterName, fieldName);
- getterJsName.setObfuscatable(false);
- JsFunction func = new JsFunction(globalScope, getterJsName);
- func.setBody(AstUtil.newBlock(new JsReturn(expression)));
- makeMethod(element, func);
- }
-
- /**
- * Create a shim method for invoking a method through a field. Invoke the
- * getter to get the field value, then apply the shim's arguments to
- * the returned closure object.
- */
- private void makeMethodCallThroughFieldShim(DartField x) {
- FieldElement element = x.getSymbol();
- if (Elements.isTopLevel(element)) {
- // Don't bother making a call-though-field shim for global methods. They're always
- // statically resolved, so we'll never generate a call to one.
- return;
- }
-
- String shimName = mangler.mangleNamedMethod(element.getName(), unitLibrary);
- String fieldName = element.getName();
- JsName shimJsName = globalScope.declareName(shimName, shimName, fieldName);
- shimJsName.setObfuscatable(false);
- JsFunction func = new JsFunction(globalScope, shimJsName);
- JsExpression qualifier;
- if (element.getModifiers().isStatic()) {
- Element enclosingElement = element.getEnclosingElement();
- switch (enclosingElement.getKind()) {
- case CLASS:
- qualifier = AstUtil.newNameRef(null,
- mangler.mangleClassName((ClassElement) enclosingElement));
- break;
- case LIBRARY:
- qualifier = null;
- break;
- default:
- throw new InternalCompilerException(
- "Unhandled type of static element making method shim.");
- }
- } else {
- qualifier = getGetterSetterQualifier(element);
- }
- String getterName = mangler.createGetterSyntax(element, unitLibrary);
- JsExpression expression = AstUtil.newInvocation(AstUtil.newNameRef(qualifier, getterName));
- expression = AstUtil.newNameRef(expression, "apply");
- expression = AstUtil.newInvocation(expression, new JsThisRef(),
- AstUtil.newNameRef(null, "arguments"));
- func.setBody(AstUtil.newBlock(new JsReturn(expression)));
- makeMethod(element, func);
- }
-
- /**
- * Creates a getter method that lazily initializes the field (if necessary).
- */
- private void makeInitializingGetter(FieldElement element, JsExpression initExpression) {
- String getterName = mangler.createGetterSyntax(element, unitLibrary);
- String fieldName = element.getName();
- JsName getterJsName = globalScope.declareName(getterName, getterName, fieldName);
- getterJsName.setObfuscatable(false);
-
- JsFunction func = new JsFunction(globalScope, getterJsName);
- JsScope scope = new JsScope(globalScope, "temp");
-
- // Foo.x$getter = function() {
- // var t0 = isolate$current.Foo$x;
- // var t1 = $initializing;
- // if (t0 === t1) throw "circular initialization";
- // if (t0 !== $uninitialized) return t0;
- // isolate$current.Foo$x = t1;
- // var t2 = ... // initialization expression
- // isolate$current.Foo$x = t2;
- // return t2;
- // }
-
- JsExpression fieldQualifier = getGetterSetterQualifier(element);
- JsName fieldJsName = getJsName(element);
-
- JsName t0 = scope.declareTemporary();
- JsName t1 = scope.declareTemporary();
- JsName t2 = scope.declareTemporary();
-
- JsVars initializeT0 = AstUtil.newVar(
- null, t0, AstUtil.newNameRef(fieldQualifier, fieldJsName));
- JsVars initializeT1 = AstUtil.newVar(
- null, t1, new JsNameRef(STATIC_INITIALIZING));
- JsStatement checkIfCircular = new JsIf(
- new JsBinaryOperation(
- JsBinaryOperator.REF_EQ,
- t0.makeRef(),
- t1.makeRef()),
- new JsThrow(string("circular initialization")),
- null);
- JsStatement checkIfInitialized = new JsIf(
- new JsBinaryOperation(
- JsBinaryOperator.REF_NEQ,
- t0.makeRef(),
- new JsNameRef(STATIC_UNINITIALIZED)),
- new JsReturn(t0.makeRef()),
- null);
- JsStatement markField = AstUtil.newAssignment(
- AstUtil.newNameRef(fieldQualifier, fieldJsName), t1.makeRef()).makeStmt();
- JsStatement initializeT2 = AstUtil.newVar(
- null, t2, initExpression);
- JsStatement initializeField = AstUtil.newAssignment(
- AstUtil.newNameRef(fieldQualifier, fieldJsName), t2.makeRef()).makeStmt();
- JsStatement returnT2 = new JsReturn(t2.makeRef());
-
- // Construct the method from the statements.
- func.setBody(AstUtil.newBlock(
- initializeT0,
- initializeT1,
- checkIfCircular,
- checkIfInitialized,
- markField,
- initializeT2,
- initializeField,
- returnT2));
- makeMethod(element, func);
- }
-
- /**
- * Creates a setter and turns it into a prototype assignment on the
- * JS class.
- */
- private void makeSetter(FieldElement element) {
- String fieldName = element.getName();
- String setterName = mangler.createSetterSyntax(element, unitLibrary);
- JsName setterJsName = globalScope.declareName(setterName, setterName, fieldName);
- setterJsName.setObfuscatable(false);
- JsFunction func = new JsFunction(globalScope, setterJsName);
-
- JsScope scope = new JsScope(globalScope, "temp");
- JsName parameter = scope.declareTemporary();
- func.getParameters().add(0, new JsParameter(parameter));
-
- JsExpression qualifier = getGetterSetterQualifier(element);
-
- JsName fieldJsName = getJsName(element);
- JsNameRef ref = AstUtil.newNameRef(qualifier, fieldJsName);
- JsBinaryOperation asg = AstUtil.newAssignment(ref, parameter.makeRef());
- func.setBody(AstUtil.newBlock(new JsExprStmt(asg)));
-
- makeMethod(element, func);
- }
-
- @Override
- public JsNode visitInitializer(DartInitializer x) {
- JsExpression e = (JsExpression) generate(x.getValue());
- if (e != null && !x.isInvocation()) {
- JsName fieldJsName = getJsName(x.getName().getTargetSymbol());
- assert fieldJsName != null : "Field name must have been resolved.";
- JsNameRef field = AstUtil.newNameRef(new JsThisRef(), fieldJsName);
- e = AstUtil.newAssignment(field, e);
- e.setSourceRef(x);
- }
- return e != null ? new JsExprStmt(e) : null;
- }
-
- @Override
- public JsNode visitFieldDefinition(DartFieldDefinition node) {
- assert ElementKind.of(currentHolder).equals(ElementKind.LIBRARY);
- for (DartField field : node.getFields()) {
- generateTopLevelField(field);
- }
- return null;
- }
-
- private void generateTopLevelField(DartField field) {
- if (field.getSymbol().getModifiers().isAbstractField()) {
- generate(field.getAccessor());
- } else {
- generate(field);
- }
- }
-
- @Override
- public JsNode visitField(DartField x) {
- makeMethodCallThroughFieldShim(x);
- FieldElement element = x.getSymbol();
- Modifiers modifiers = element.getModifiers();
- if (modifiers.isAbstractField()) {
- generateAbstractField(element);
- return null;
- }
-
- DartExpression initializer = x.getValue();
- JsExprStmt result = null;
-
- if (initializer != null || Elements.isTopLevel(element)) {
- currentScopeInfo = ScopeRootInfo.makeScopeInfo(x, !shouldGenerateDeveloperModeChecks());
- inFactoryOrStaticContext = true;
-
- // There's an initializer, so emit an assignment statement.
- JsNameRef fieldName;
- if (isDeclaredAsStaticOrImplicitlyStatic(element)) {
- JsExpression qualifier = getGetterSetterQualifier(element);
- fieldName = AstUtil.newNameRef(qualifier, translationContext.getNames().getName(element));
- } else {
- fieldName = AstUtil.newNameRef(new JsThisRef(), getJsName(element));
- }
-
- JsExpression initExpr;
- if (initializer == null) {
- initExpr = undefined();
- } else {
- initExpr = (JsExpression) generate(initializer);
- }
-
- boolean emitStaticInitialization = true;
- if (x.getModifiers().isFinal() &&
- (initializer == null || initExpr instanceof JsValueLiteral)) {
- makeConstantValueGetter(element, initExpr);
- emitStaticInitialization = false;
- } else if (initializer == null || initExpr instanceof JsLiteral) {
- makePropertyGetter(element);
- } else {
- makeInitializingGetter(element, initExpr);
- initExpr = new JsNameRef(STATIC_UNINITIALIZED);
- }
-
- if (emitStaticInitialization) {
- JsBinaryOperation assignment = AstUtil.newAssignment(fieldName, initExpr);
- assignment.setSourceRef(x);
- result = new JsExprStmt(assignment);
- staticInit.add(result);
- }
-
- assert currentScopeInfo != null;
- currentScopeInfo = null;
- inFactoryOrStaticContext = false;
- } else {
- makePropertyGetter(element);
- }
-
- if (!element.getModifiers().isFinal()) {
- makeSetter(element);
- }
- return result;
- }
-
- @Override
- public JsNode visitFunction(DartFunction x) {
- if (x.getBody() == null) {
- if (ElementKind.of(currentHolder).equals(ElementKind.CLASS)
- && ((ClassElement) currentHolder).isInterface()) {
- return null;
- }
- }
-
- functionStack.push(x);
- jsNewDeclarationsStack.push(new HashSet());
-
- // The JsFunction was already created and pushed in visit(DartFunction).
- JsFunction jsFunc = translationContext.getMethods().get(x);
-
- // Generate and set the body.
- JsBlock body;
- if (x.getBody() == null) {
- // The resolution has checked already that it is valid for this method
- // to not have a body.
- body = new JsBlock();
- } else {
- body = (JsBlock) generate(x.getBody());
- }
- jsFunc.setBody(body);
-
- // Create JS parameters
- List params = x.getParams();
- List jsParams = jsFunc.getParameters();
- if (!jsFunc.isHoisted()) {
- generateAll(params, jsParams, JsParameter.class);
- }
-
-
- // Create the runtime type checks that will be inserted later
- List checks = Lists.newArrayList();
-
- // TODO(zundel): Issue 925: these runtime checks do not work in hoisted functions
- // created inside of factory methods if the parameter references type variables.
- // A bad reference to $typeArgs caused an error in the closure compiler backend.
- boolean omitTypeVariableChecks = false;
- if (inFactory) {
- Element element = (Element)x.getParent().getSymbol();
- if (!ElementKind.of(element).equals(ElementKind.CONSTRUCTOR)) {
- // The code being emitted is something other than the factory method itself.
- omitTypeVariableChecks = true;
- }
- }
-
- int numParams = params.size();
- for (int i = 0; i < numParams; ++i) {
- JsNameRef jsParam = jsParams.get(i).getName().makeRef();
- DartParameter param = params.get(i);
- Type paramType = param.getSymbol().getType();
- if (omitTypeVariableChecks && TypeKind.of(paramType).equals(TypeKind.VARIABLE)) {
- continue;
- }
- JsExpression expr = rtt.addTypeCheck(getCurrentClass(), jsParam, paramType, null, param);
- if (expr != jsParam) {
- // if the expression was returned unchanged, omit the check
- checks.add(new JsExprStmt(expr));
- }
- }
-
-
- // Add temporary variable declarations, if any.
- declareTempsInBlock(body, jsNewDeclarationsStack.pop());
-
- DartNode parent = x.getParent();
- assert parent != null;
- if (parent instanceof DartMethodDefinition) {
- DartMethodDefinition method = (DartMethodDefinition) parent;
- if (isFactory(method)) {
- rtt.maybeAddTypeParameterToFactory(method, jsFunc);
- }
- if (Elements.isNonFactoryConstructor((Element) parent.getSymbol())) {
- this.addSuperOrRedirectConstructorCall(method);
- }
- }
-
- // Call the function prologue setup functions in the reserve order that
- // their output need to appear as each adds to the front of the function
- // body.
- // 3. setup the scope aliases (after default init)
- maybeAddFunctionScopeAlias(currentScopeInfo.getScope(x),
- translationContext.getMethods().get(x));
-
- // 2. call function trace before anything else.
- maybeAddFunctionTracing(x);
-
- // 1. insert parameter type checks at the beginning of the method
- body.getStatements().addAll(0, checks);
-
- functionStack.pop();
- return jsFunc.setSourceRef(x);
- }
-
- /**
- * Get the type associated with a type node
- *
- * @param typeNode a {@link DartTypeNode}, which may be null
- * @return a {@link Type} corresponding to the type node or null to indicate unknown
- */
- private Type typeOf(DartTypeNode typeNode) {
- if (typeNode == null) {
- return null;
- }
- return typeNode.getType();
- }
-
- private boolean isFactory(DartMethodDefinition method) {
- return method.getModifiers().isFactory();
- }
-
- private void maybeAddFunctionTracing(DartFunction dartFunction) {
- // TODO(floitsch): temporary way to enable tracing is by setting a system property.
- String tracingCallTarget = System.getProperty("Trace");
- if (tracingCallTarget != null) {
- JsFunction function = translationContext.getMethods().get(dartFunction);
-
- // Example:
- // function f(a,b) { ... }
- // to:
- // function f(a, b) {
- // nestingCounter++;
- // (nestingCounter, "f(a, b)", a, b);
- // try { ... }
- // finally { nestingCounter--; }
- // }
- JsExpression increment = new JsPostfixOperation(JsUnaryOperator.INC,
- new JsNameRef(getTraceCounter()));
- JsExpression decrement = new JsPostfixOperation(JsUnaryOperator.DEC,
- new JsNameRef(getTraceCounter()));
-
- JsInvocation tracerCall = new JsInvocation();
- tracerCall.setQualifier(new JsNameRef(tracingCallTarget));
- List traceArguments = tracerCall.getArguments();
- traceArguments.add(new JsNameRef(getTraceCounter()));
- traceArguments.add(null); // Reserve space for string description.
- StringBuffer description = new StringBuffer();
- JsName name = function.getName();
- if (name != null) {
- description.append(function.getName().toString());
- } else {
- description.append("");
- }
- description.append("(");
- dartFunction.getParams();
- for (DartParameter param : dartFunction.getParams()) {
- JsName paramName = getJsName(param.getSymbol());
- description.append(paramName.toString());
- traceArguments.add(new JsNameRef(paramName));
- }
- description.append(")");
- // Update string description in argument list.
- traceArguments.set(1, string(description.toString()));
-
- JsTry countingTry = new JsTry();
- countingTry.setTryBlock(function.getBody());
- countingTry.setFinallyBlock(AstUtil.newBlock(decrement.makeStmt()));
- JsBlock newBody = AstUtil.newBlock(increment.makeStmt(),
- tracerCall.makeStmt(),
- countingTry);
- function.setBody(newBody);
- }
- }
-
- @Override
- public JsNode visitParameter(DartParameter x) {
- if (x.getSymbol() != null) {
- return new JsParameter(getJsName(x.getSymbol())).setSourceRef(x);
- } else {
- // TODO(ngeoffray): A parameter in a function type does not have a symbol.
- return null;
- }
- }
-
- @Override
- public JsNode visitBlock(DartBlock x) {
- // Basic block handling
- JsBlock jsBlock = new JsBlock();
- // TODO(johnlenz): merge redundant JsBlock nodes.
- generateAll(x.getStatements(), jsBlock.getStatements(), JsStatement.class);
-
- //
- // For names defined in this scope that are captured by a function
- // closure rewrite, inject an object to hold the aliases for the
- // value for use by the closure. This simulates lexically scoped names
- // in JavaScript and once the closures are hoisted out of the scope
- // prevents the capture of value that would otherwise be protected in
- // another scope.
- //
-
- // Inject scope alias initialization and clean up.
- ScopeRootInfo methodInfo = currentScopeInfo;
- if (methodInfo != null) {
- DartScope scope = methodInfo.getScope(x);
- if (scope.definesClosureReferencedSymbols()) {
- // Make sure the alias is defined in the scope.
- JsScope currentFunctionScope = getCurrentFunctionScope();
- JsName aliasName = scope.findAliasForJsScope(currentFunctionScope);
- // Scope objects are declared (in the JsScope) at first use. By construction scope-objects
- // are only created when they are used. Therefore the scope-object must exist in the
- // JsScope.
- assert aliasName != null;
- registerForDeclaration(aliasName);
-
- // Init and clean up the scope alias
- // TODO(johnlenz): this really should be in a finally block,
- // debate the runtime cost of doing this, version the possibility of
- // a memory leak (It is only really needed if there are closures
- // outside this DartScope).
- // Alternately, once the closures have been hoisted out, the cleanup
- // code can be removed completely.
- List list = jsBlock.getStatements();
- JsStatement init = AstUtil.newAssignment(
- new JsNameRef(aliasName), new JsObjectLiteral())
- .makeStmt();
- JsStatement cleanup = AstUtil.newAssignment(
- new JsNameRef(aliasName), undefined())
- .makeStmt();
- list.add(0, init);
- list.add(cleanup);
- }
- }
- return jsBlock.setSourceRef(x);
- }
-
- @Override
- public JsNode visitIfStatement(DartIfStatement x) {
- JsExpression jsCondition = (JsExpression) generate(x.getCondition());
- jsCondition = rtt.addTypeCheck(getCurrentClass(), jsCondition, typeProvider.getBoolType(),
- x.getCondition().getType(), x);
- JsStatement jsThenStmt = (JsStatement) generate(x.getThenStatement());
- JsStatement jsElseStmt = null;
- if (x.getElseStatement() != null) {
- jsElseStmt = (JsStatement) generate(x.getElseStatement());
- }
- return new JsIf(jsCondition, jsThenStmt, jsElseStmt).setSourceRef(x);
- }
-
- @Override
- public JsNode visitSwitchStatement(DartSwitchStatement x) {
- JsSwitch jsSwitch = new JsSwitch();
- jsSwitch.setExpr((JsExpression) generate(x.getExpression()));
- generateAll(x.getMembers(), jsSwitch.getCases(), JsSwitchMember.class);
- return jsSwitch.setSourceRef(x);
- }
-
- @Override
- public JsNode visitCase(DartCase x) {
- JsCase jsCase = new JsCase();
- jsCase.setCaseExpr((JsExpression) generate(x.getExpr()));
- generateAll(x.getStatements(), jsCase.getStmts(), JsStatement.class);
- return jsCase.setSourceRef(x);
- }
-
- @Override
- public JsNode visitDefault(DartDefault x) {
- JsDefault jsDefault = new JsDefault();
- generateAll(x.getStatements(), jsDefault.getStmts(), JsStatement.class);
- return jsDefault.setSourceRef(x);
- }
-
- @Override
- public JsNode visitWhileStatement(DartWhileStatement x) {
- JsExpression condition = (JsExpression) generate(x.getCondition());
- condition = rtt.addTypeCheck(getCurrentClass(), condition, typeProvider.getBoolType(),
- x.getCondition().getType(), x);
- JsBlock body = (JsBlock) generate(x.getBody());
- return new JsWhile(condition, body).setSourceRef(x);
- }
-
- @Override
- public JsNode visitDoWhileStatement(DartDoWhileStatement x) {
- JsExpression condition = (JsExpression) generate(x.getCondition());
- condition = rtt.addTypeCheck(getCurrentClass(), condition, typeProvider.getBoolType(),
- x.getCondition().getType(), x);
- JsBlock body = (JsBlock) generate(x.getBody());
- return new JsDoWhile(condition, body).setSourceRef(x);
- }
-
- @Override
- public JsNode visitForStatement(DartForStatement x) {
- // Dart AST normalization removes init expressions.
- assert x.getInit() == null;
-
- JsFor jsFor = new JsFor().setSourceRef(x);
- if (x.getCondition() != null) {
- JsExpression condExpr = (JsExpression) generate(x.getCondition());
- condExpr = rtt.addTypeCheck(getCurrentClass(), condExpr, typeProvider.getBoolType(),
- x.getCondition().getType(), x);
- jsFor.setCondition(condExpr);
- }
- if (x.getIncrement() != null) {
- jsFor.setIncrExpr((JsExpression) generate(x.getIncrement()));
- }
- jsFor.setBody((JsStatement) generate(x.getBody()));
- return jsFor.setSourceRef(x);
- }
-
- @Override
- public JsNode visitForInStatement(DartForInStatement x) {
- DartStatement normalizedNode = x.getNormalizedNode();
- if (normalizedNode == null) {
- throw new InternalCompilerException("For-in statement should have been normalized.");
- }
- return normalizedNode.accept(this);
- }
-
- @Override
- public JsNode visitContinueStatement(DartContinueStatement x) {
- JsContinue jsContinue = null;
- if (x.getTargetSymbol() != null) {
- jsContinue = new JsContinue(getJsName(x.getTargetSymbol()).makeRef());
- } else {
- jsContinue = new JsContinue();
- }
- return jsContinue.setSourceRef(x);
- }
-
- @Override
- public JsNode visitBreakStatement(DartBreakStatement x) {
- JsBreak jsBreak = null;
- if (x.getTargetSymbol() != null) {
- jsBreak = new JsBreak(getJsName(x.getTargetSymbol()).makeRef());
- } else {
- jsBreak = new JsBreak();
- }
- return jsBreak.setSourceRef(x);
- }
-
- @Override
- public JsNode visitReturnStatement(DartReturnStatement x) {
- JsReturn jsRet = new JsReturn();
- DartExpression returnValue = x.getValue();
- if (returnValue != null) {
- JsExpression expr = (JsExpression) generate(returnValue);
- DartFunction function = functionStack.peek();
- if (function != null) {
- // NOTE: FunctionExpressionInliner might be leaving return statements around
- DartTypeNode returnTypeNode = function.getReturnTypeNode();
- Type returnType = null;
- if (returnTypeNode == null) {
- // check for factory methods, which return the type of their name
- returnType = getFactoryReturnType(function);
- }
- if (returnType == null) {
- returnType = typeOf(returnTypeNode);
- }
- expr = rtt.addTypeCheck(getCurrentClass(), expr, returnType, returnValue.getType(), x);
- }
- jsRet.setExpr(expr);
- }
- return jsRet.setSourceRef(x);
- }
-
- /**
- * Get the return type of a factory method.
- *
- * @param function
- * @return {@link Type} instance or null if not a factory method or otherwise unavailable
- */
- private Type getFactoryReturnType(DartFunction function) {
- // TODO: implement
- return null;
- }
-
- @Override
- public JsNode visitTryStatement(DartTryStatement x) {
- JsTry jsTry = new JsTry();
- jsTry.setTryBlock((JsBlock) generate(x.getTryBlock()));
-
- // TODO(jgw): The Javascript AST allows multiple catch blocks for some reason,
- // even though that makes no sense. Sort this out once structured exceptions are
- // worked out in Dart.
- List catchBlocks = x.getCatchBlocks();
- if (catchBlocks != null && !catchBlocks.isEmpty()) {
- // Transform a sequence of catch blocks into nested if-statements.
- // Example:
- // try {
- // } catch (SomeException e1) {
- // } catch (OtherException e2) {
- // }
- // becomes
- // try {
- // } catch(tmpVar) {
- // if (tmpVar instanceof SomeException) { var e1 = tmpVar;
- // } else if (tmpVar instanceof OtherException) { var e2 = tmpVar;
- // } else { throw tmpVar; }
- // }
- //
- // Note that when no type is given for the Dart exception, it catches always. Then we
- // don't need a rethrow.
- // The JsCatch scope only contains one variable. There is hence no clash possible.
- JsCatch jsCatch = new JsCatch(getCurrentFunctionScope(), "e");
- JsName exceptionVar = jsCatch.getScope().findExistingName("e");
-
- jsTry.getCatches().add(jsCatch);
- JsBlock jsCatchBody = new JsBlock();
- // Tease out browser built-in exceptions
- JsExpression filterBuiltin = AstUtil.newAssignment(exceptionVar.makeRef(),
- AstUtil.newInvocation(AstUtil.newNameRef(null, "$transformBrowserException"),
- exceptionVar.makeRef()));
- jsCatchBody.getStatements().add(filterBuiltin.makeStmt());
- jsCatch.setBody(jsCatchBody);
- JsStatement jsElse = new JsThrow(new JsNameRef(exceptionVar));
-
- catchVarStack.push(exceptionVar);
- for (int i = catchBlocks.size() - 1; i >= 0; i--) {
- DartCatchBlock catchBlock = catchBlocks.get(i);
- JsBlock jsClauseBody = (JsBlock) generate(catchBlock.getBlock());
- if (catchBlock.getStackTrace() != null) {
- // TODO(ngeoffray): do something with the stackTrace.
- JsParameter jsStackParam = (JsParameter) generate(catchBlock.getStackTrace());
- registerForDeclaration(jsStackParam.getName());
- }
- JsParameter jsClauseParam = (JsParameter) generate(catchBlock.getException());
- JsName jsClauseParamName = jsClauseParam.getName();
-
- JsExpression assignment = AstUtil.newAssignment(new JsNameRef(jsClauseParamName),
- new JsNameRef(exceptionVar));
- jsClauseBody.getStatements().add(0, assignment.makeStmt());
- // The exception variable is not declared by the catch-block anymore. Register for
- // declaration so that it becomes a local variable.
- // Note that the name could already be in the list (if two catch-clauses share the same
- // name). In this case the declaration-clause will declare the same variable multiple
- // times (ex: var e, e, e;).
- registerForDeclaration(jsClauseParamName);
-
- DartParameter exception = catchBlock.getException();
- DartTypeNode exceptionType = exception.getTypeNode();
- if (exceptionType == null) {
- // No type has been given. This clause catches everything.
- jsElse = jsClauseBody;
- continue;
- }
-
- JsExpression instanceCheck = rtt.generateInstanceOfComparison(
- getCurrentClass(),
- new JsNameRef(exceptionVar),
- exceptionType,
- exceptionType).setSourceRef(exception);
- jsElse = new JsIf(instanceCheck, jsClauseBody, jsElse);
- }
- jsCatchBody.getStatements().add(jsElse);
- catchVarStack.pop();
- }
-
- if (x.getFinallyBlock() != null) {
- JsBlock jsFinallyBlock = (JsBlock) generate(x.getFinallyBlock());
- jsTry.setFinallyBlock(jsFinallyBlock);
- }
-
- // Allow a try block to be a target of a label by surrounding it with a block.
- JsNode result = jsTry.setSourceRef(x);
- if (x.getParent() instanceof DartLabel) {
- result = new JsBlock(jsTry).setSourceRef(x);
- }
- return result;
- }
-
- @Override
- public JsNode visitThrowStatement(DartThrowStatement x) {
- JsNameRef error = new JsNameRef("$Dart$ThrowException");
- JsInvocation invoc = AstUtil.newInvocation(error);
- JsExpression exception;
- if (x.getException() != null) {
- exception = (JsExpression) generate(x.getException());
- } else {
- // rethrow the exception
- JsName name = catchVarStack.peek();
- if (name != null) {
- exception = name.makeRef();
- } else {
- // TODO(johnlenz): validate this is the correct behavior
- throw new InternalCompilerException("invalid rethrow context");
- }
- }
- invoc.getArguments().add(exception);
- return new JsExprStmt(invoc.setSourceRef(x));
- }
-
-
- @Override
- public JsNode visitVariableStatement(DartVariableStatement x) {
-
- // Dart AST Normalization creates one declaration per VAR.
- assert x.getVariables().size() == 1;
-
- JsNode node = generate(x.getVariables().get(0));
- if (node instanceof JsVar) {
- JsVars jsVars = new JsVars();
- jsVars.insert((JsVar)node);
- return jsVars.setSourceRef(x);
- } else {
-
- // Variables captured by closures may be transformed to property
- // assignments.
- assert node instanceof JsStatement;
-
- return node;
- }
- }
-
- @Override
- public JsNode visitVariable(DartVariable x) {
- Symbol targetSymbol = x.getSymbol();
-
- // If the name is referenced by a closure use the scope alias.
- JsNameRef scopeAliasRef = maybeMakeScopeAliasReference(targetSymbol);
- JsNode result = null;
- DartExpression value = x.getValue();
- if (scopeAliasRef != null) {
- if (value != null) {
- JsExpression initExpr = (JsExpression) generate(value);
- Type type = getTypeOfIdentifier(x.getName());
- initExpr = rtt.addTypeCheck(getCurrentClass(), initExpr, type, value.getType(), x);
- result = AstUtil.newAssignment(scopeAliasRef, initExpr).setSourceRef(x).makeStmt();
- } else {
- // we need to put some statement in to keep the expected number
- // of values on the stack.
- result = translationContext.getProgram().getEmptyStmt();
- }
- } else {
- JsVars.JsVar jsVar = new JsVars.JsVar(getJsName(targetSymbol));
- if (value != null) {
- JsExpression initExpr = (JsExpression) generate(value);
- Type type = getTypeOfIdentifier(x.getName());
- initExpr = rtt.addTypeCheck(getCurrentClass(), initExpr, type, value.getType(), x);
- jsVar.setInitExpr(initExpr);
- } else {
- jsVar.setInitExpr(undefined());
- }
- result = jsVar.setSourceRef(x);
- }
-
- return result;
- }
-
- @Override
- public JsNode visitEmptyStatement(DartEmptyStatement x) {
- x.visitChildren(this);
- // TODO(johnlenz): Set source info?
- return translationContext.getProgram().getEmptyStmt();
- }
-
- @Override
- public JsNode visitSyntheticErrorExpression(DartSyntheticErrorExpression node) {
- String name = node.getSource().getName();
- int line = node.getSourceLine();
- int col = node.getSourceColumn();
- throw new AssertionError("Generating JS with parse error at " + name + ":"
- + line + ":" + col);
- }
-
- @Override
- public JsNode visitSyntheticErrorStatement(DartSyntheticErrorStatement node) {
- String name = node.getSource().getName();
- int line = node.getSourceLine();
- int col = node.getSourceColumn();
- throw new AssertionError("Generating JS with parse error at " + name + ":"
- + line + ":" + col);
- }
-
- @Override
- public JsNode visitLabel(DartLabel x) {
- JsStatement jsStmt = (JsStatement) generate(x.getStatement());
- JsLabel jsLabel = new JsLabel(getJsName(x.getSymbol()));
- jsLabel.setStmt(jsStmt);
- return jsLabel.setSourceRef(x);
- }
-
- @Override
- public JsNode visitExprStmt(DartExprStmt x) {
- JsNode node = generate(x.getExpression());
- if (node instanceof JsVars) {
- // Function statements maybe transformed to var statements.
- // TODO(johnlenz): Create a JsFunctionStatement so that those statements
- // aren't wrapped in expressions.
- // Note(floitsch): When removing this special case please update the comments
- // in 'endVisit(DartFunctionExpression, ...)'.
- return node;
- } else {
- JsExpression expr = (JsExpression) node;
- return new JsExprStmt(expr).setSourceRef(x);
- }
- }
-
- @Override
- public JsNode visitConditional(DartConditional x) {
- JsExpression testExpr = (JsExpression) generate(x.getCondition());
- testExpr = rtt.addTypeCheck(getCurrentClass(), testExpr, typeProvider.getBoolType(),
- x.getCondition().getType(), x);
- JsExpression thenExpr = (JsExpression) generate(x.getThenExpression());
- JsExpression elseExpr = (JsExpression) generate(x.getElseExpression());
- return new JsConditional(testExpr, thenExpr, elseExpr).setSourceRef(x);
- }
-
- @Override
- public JsNode visitBinaryExpression(DartBinaryExpression x) {
- assert x == x.getNormalizedNode();
-
- Token operator = x.getOperator();
-
- if (operator == Token.IS) {
- return generateInstanceOfComparison(x);
- }
-
- DartExpression arg1 = x.getArg1();
- DartExpression arg2 = x.getArg2();
- JsExpression rhs = (JsExpression) generate(arg2);
- if (operator == Token.ASSIGN) {
- return arg1.accept(new Assignment(x, rhs, arg2.getType()));
- }
-
- assert !operator.isUserDefinableOperator() || !operator.isAssignmentOperator() : x;
-
- // We can skip shims for non-user-definable operators (NE is a special case because it's not
- // user-definable, but still has to be shimmed).
- boolean skipShim = (!operator.isUserDefinableOperator() && (operator != Token.NE));
- JsExpression lhs = (JsExpression) generate(arg1);
- Token op = x.getOperator();
-
- lhs = rtt.addTypeCheck(getCurrentClass(), lhs, getRequiredType(op), arg1.getType(), arg1);
- rhs = rtt.addTypeCheck(getCurrentClass(), rhs, getRequiredType(op), arg2.getType(), arg2);
-
- if (skipShim) {
- if (op.isEqualityOperator()) {
- op = mapToStrictEquals(op);
- // TODO (fabiomfv) - This optimization targets a v8 perf issue. V8 double equals
- // comparison to undefined is up to 4 times slower than == null. It seems that it was
- // fixed on v8 3.5. once we move to 3.5 and the fix confirmed, this should be revisited.
- if (arg2 instanceof DartNullLiteral) {
- op = mapToNonStrictEquals(op);
- rhs = nulle();
- }
- if (arg1 instanceof DartNullLiteral) {
- JsExpression tmp = lhs;
- lhs = rhs;
- rhs = tmp;
- op = mapToNonStrictEquals(op);
- rhs = nulle();
- }
- }
- JsExpression binOp = new JsBinaryOperation(mapBinaryOp(op), lhs, rhs);
- binOp.setSourceRef(x);
- return binOp;
- } else {
- JsNameRef ref = new JsNameRef(mangler.createOperatorSyntax(operator));
- return AstUtil.newInvocation(ref, lhs, rhs).setSourceRef(x);
- }
- }
-
- /**
- * Return a type which an operator requires for its operands.
- *
- * @param op operator
- * @return a {@link Type} instance, which will be {@code null} if there are
- * no restrictions
- */
- private Type getRequiredType(Token op) {
- switch (op) {
- case OR:
- case AND:
- return typeProvider.getBoolType();
- // TODO: other operators?
- default:
- return null;
- }
- }
-
- private Type getTypeOfIdentifier(DartIdentifier ident) {
- Element element = ident.getReferencedElement();
- DartTypeNode typeNode = null;
- if (element == null) {
- DartNode parent = ident.getParent();
- if (parent instanceof DartVariable) {
- DartVariableStatement varStmt = (DartVariableStatement) parent.getParent();
- typeNode = varStmt.getTypeNode();
- }
- } else {
- switch (element.getKind()) {
- case VARIABLE:
- DartVariableStatement varStmt = (DartVariableStatement) element.getNode().getParent();
- typeNode = varStmt.getTypeNode();
- break;
- case PARAMETER:
- DartParameter param = (DartParameter) element.getNode();
- typeNode = param.getTypeNode();
- break;
- case FIELD:
- DartFieldDefinition fieldDef = (DartFieldDefinition) element.getNode().getParent();
- typeNode = fieldDef.getTypeNode();
- break;
- default:
- break;
- }
- }
- if (typeNode != null) {
- return typeNode.getType();
- }
- return null;
- }
-
- private JsExpression generateInstanceOfComparison(DartBinaryExpression x) {
- JsExpression lhs = (JsExpression) generate(x.getArg1());
- DartExpression rhs = x.getArg2();
- boolean isNot = false;
- if (rhs instanceof DartUnaryExpression) {
- isNot = true;
- rhs = ((DartUnaryExpression) rhs).getArg();
- }
- JsExpression expr = rtt.generateInstanceOfComparison(getCurrentClass(),
- lhs, ((DartTypeExpression) rhs).getTypeNode(), rhs).setSourceRef(x);
- if (isNot) {
- expr = new JsPrefixOperation(JsUnaryOperator.NOT, expr);
- }
- return expr;
- }
-
- private JsBinaryOperation assign(JsNameRef op1, JsExpression op2) {
- return AstUtil.newAssignment(op1, op2);
- }
-
- private JsBinaryOperation neq(JsExpression op1, JsExpression op2) {
- return new JsBinaryOperation(JsBinaryOperator.NEQ, op1, op2);
- }
-
- private JsBinaryOperation or(JsExpression op1, JsExpression op2) {
- return new JsBinaryOperation(JsBinaryOperator.OR, op1, op2);
- }
-
- private JsNumberLiteral number(double num) {
- return translationContext.getProgram().getNumberLiteral(num);
- }
-
- private JsStringLiteral string(String str) {
- return translationContext.getProgram().getStringLiteral(str);
- }
-
- private JsNullLiteral nulle() {
- return translationContext.getProgram().getNullLiteral();
- }
-
- private JsNameRef undefined() {
- return translationContext.getProgram().getUndefinedLiteral();
- }
-
- private JsEmpty empty() {
- return translationContext.getProgram().getEmptyStmt();
- }
-
- @Override
- public JsNode visitTypeNode(DartTypeNode x) {
- // This backend does not need types.
- return null;
- }
-
- @Override
- public JsNode visitTypeParameter(DartTypeParameter x) {
- // This backend does not need types.
- return null;
- }
-
- @Override
- public JsNode visitTypeExpression(DartTypeExpression x) {
- throw new AssertionError("Unreachable");
- }
-
- @Override
- public JsNode visitUnaryExpression(DartUnaryExpression x) {
- assert x == x.getNormalizedNode();
- Token operator = x.getOperator();
- JsNode result;
- JsExpression arg = (JsExpression) generate(x.getArg());
- if (operator == Token.SUB) {
- JsNameRef ref =
- new JsNameRef(mangler.createOperatorSyntax(DartMangler.NEGATE_OPERATOR_NAME));
- result = (AstUtil.newInvocation(ref, arg));
- return result.setSourceRef(x);
- } else if (operator.isUserDefinableOperator()) {
- JsNameRef ref = new JsNameRef(mangler.createOperatorSyntax(operator));
- result = (AstUtil.newInvocation(ref, arg));
- return result.setSourceRef(x);
- } else {
- JsUnaryOperator jsUnaryOperator;
- switch (operator) {
- case INC:
- jsUnaryOperator = JsUnaryOperator.INC;
- break;
- case DEC:
- jsUnaryOperator = JsUnaryOperator.DEC;
- break;
- case NOT:
- jsUnaryOperator = JsUnaryOperator.NOT;
- arg = rtt.addTypeCheck(getCurrentClass(), arg, typeProvider.getBoolType(),
- x.getArg().getType(), x.getArg());
- break;
- default:
- throw new AssertionError("Unexpected unary operator " + operator.name());
- }
-
- if (x.isPrefix()) {
- result = new JsPrefixOperation(jsUnaryOperator, arg);
- } else {
- result = new JsPostfixOperation(jsUnaryOperator, arg);
- }
-
- return result.setSourceRef(x);
- }
- }
-
- @Override
- public JsNode visitPropertyAccess(DartPropertyAccess x) {
- return generateLoad(x.getQualifier(), x.getName()).setSourceRef(x);
- }
-
- @Override
- public JsNode visitArrayAccess(DartArrayAccess x) {
- JsExpression target = (JsExpression) generate(x.getTarget());
- JsExpression key = (JsExpression) generate(x.getKey());
- JsNameRef ref = AstUtil.newNameRef(target, mangler.createOperatorSyntax(Token.INDEX));
- JsInvocation invoke = AstUtil.newInvocation(ref, key);
- return invoke.setSourceRef(x);
- }
-
- @Override
- public JsNode visitUnqualifiedInvocation(DartUnqualifiedInvocation x) {
- DartIdentifier target = x.getTarget();
- Element element = target.getTargetSymbol();
- ElementKind kind = ElementKind.of(element);
- JsExpression qualifier;
- String mangledName;
- MethodElement method = null;
- switch (kind) {
- case FUNCTION_OBJECT:
- mangledName = null;
- qualifier = (JsExpression) generate(target);
- EnclosingElement enclosingElement = element.getEnclosingElement();
- if (enclosingElement != null && enclosingElement.getKind() == ElementKind.CLASS) {
- // Function-object invocations can be made directly, unless they're closures (in which
- // case their enclosing-element will be null).
- method = (MethodElement) element;
- }
- break;
- case FIELD:
- case PARAMETER:
- case VARIABLE:
- mangledName = null;
- qualifier = (JsExpression) generate(target);
- break;
-
- case NONE:
- mangledName = mangler.mangleMethod(x.getTarget().getTargetName(), unitLibrary);
- qualifier = new JsThisRef();
- break;
-
- case METHOD:
- method = (MethodElement) element;
- mangledName = mangler.mangleMethod(method, unitLibrary);
- if (element.getModifiers().isStatic()) {
- qualifier = referenceName(element.getEnclosingElement(), x.getTarget());
- } else if (Elements.isTopLevel(element)) {
- qualifier = null;
- } else {
- qualifier = new JsThisRef();
- }
- break;
-
- default:
- throw new AssertionError("Cannot be an unqualified invocation " + kind);
- }
- return generateInvocation(x, qualifier, false, mangledName, method);
- }
-
- @Override
- public JsNode visitFunctionObjectInvocation(DartFunctionObjectInvocation x) {
- DartExpression target = x.getTarget();
- if (target instanceof DartFunctionExpression) {
- DartFunctionExpression functionExpression = (DartFunctionExpression) target;
- if (functionExpression.getSymbol().getModifiers().isInlinable() &&
- !shouldGenerateDeveloperModeChecks()) {
- // TODO FunctionExpressionInliner conflics with developer mode checks
- return new FunctionExpressionInliner(functionExpression, x.getArgs()).call();
- }
- }
- JsExpression qualifier = (JsExpression) generate(target);
- return generateInvocation(x, qualifier, false, null, null);
- }
-
- /**
- * Takes a function expression and inlines it with the given arguments, for
- * example:
- * {@code
- * function(parameter) { return parameter; }(argument)
- * }
- * becomes:
- * {@code
- * ($1 = argument, $1)
- * }
- */
- private class FunctionExpressionInliner implements Callable {
- private final List arguments;
- private final List parameters;
- private final Map parameterMap = new HashMap();
- private final List statements;
- private final JsExpression[] expressions;
-
- FunctionExpressionInliner(DartFunctionExpression functionExpression,
- List arguments) {
- final DartFunction function = functionExpression.getFunction();
- this.arguments = arguments;
- parameters = function.getParams();
- assert arguments.size() == parameters.size();
- statements = function.getBody().getStatements();
- expressions = new JsExpression[parameters.size() + statements.size()];
- }
-
- @Override
- public JsExpression call() {
- int i = 0;
- Iterator argumentsIterator = arguments.iterator();
- for (DartParameter parameter : parameters) {
- // Assign each argument to a new temporary.
- // For example: "arg" becomes: "$i = arg"
- expressions[i++] = rewriteArgument(parameter, argumentsIterator.next());
- }
- for (DartStatement statement : statements) {
- // Inline each statement after rewriting references to the parameters.
- // For example: "return parameter_i;" becomes: "$i"
- expressions[i++] = rewriteStatement(statement);
- }
- if (i == 1) {
- return expressions[0];
- } else {
- return AstUtil.newSequence(expressions);
- }
- }
-
- private JsExpression rewriteArgument(DartParameter parameter, DartExpression argument) {
- JsName temporary = createTemporary();
- VariableElement element = Elements.makeVariable(temporary.getIdent());
- parameterMap.put(parameter.getSymbol(), element);
- translationContext.getNames().setName(element, temporary);
- return AstUtil.newAssignment(temporary.makeRef(), (JsExpression) generate(argument));
- }
-
- private JsExpression rewriteStatement(DartStatement node) {
- node.accept(new ParameterRewriter());
- JsNode jsNode = generate(node);
- if (jsNode instanceof JsExprStmt) {
- return ((JsExprStmt) jsNode).getExpression();
- } else if (jsNode instanceof JsReturn) {
- return ((JsReturn) jsNode).getExpr();
- } else {
- throw new AssertionError(node);
- }
- }
-
- private class ParameterRewriter extends DartNodeTraverser {
- @Override
- public Void visitIdentifier(DartIdentifier node) {
- Element element = parameterMap.get(node.getTargetSymbol());
- if (element != null) {
- DartIdentifier identifier = new DartIdentifier(element.getName());
- identifier.setSourceInfo(node);
- identifier.setSymbol(element);
- node.setNormalizedNode(identifier);
- }
- return null;
- }
- }
- }
-
- @Override
- public JsNode visitMethodInvocation(DartMethodInvocation x) {
- Element element = (Element) x.getTargetSymbol();
- MethodElement method = null;
- JsExpression qualifier;
- String mangledName;
-
- if (element == null) {
- mangledName = mangler.mangleNamedMethod(x.getFunctionNameString(), unitLibrary);
- qualifier = (JsExpression) generate(x.getTarget());
- } else {
- switch (element.getKind()) {
- case METHOD: {
- mangledName = mangler.mangleMethod((MethodElement) element, unitLibrary);
- if (element.getModifiers().isStatic()) {
- qualifier = referenceName(element.getEnclosingElement(), x.getTarget());
- } else if (Elements.isTopLevel(element)) {
- qualifier = null;
- } else {
- qualifier = (JsExpression) generate(x.getTarget());
- }
- method = (MethodElement) element;
- break;
- }
-
- case FIELD: {
- if(ElementKind.of(x.getTarget().getSymbol()) == ElementKind.LIBRARY) {
- // Handled very much like a unqualified invocation
- mangledName = null;
- qualifier = (JsExpression) generate(x.getFunctionName());
- } else {
- mangledName = mangler.mangleNamedMethod(x.getFunctionNameString(), unitLibrary);
- qualifier = (JsExpression) generate(x.getTarget());
- }
- break;
- }
-
- default: {
- throw new AssertionError("Unexpected invocation target.");
- }
- }
- }
-
- boolean isSuperCall = isSuperCall(x.getTarget().getSymbol());
- return generateInvocation(x, qualifier, isSuperCall, mangledName, method);
- }
-
- private JsExpression generateConstructorInvocation(
- DartNewExpression x, JsExpression qualifier,
- MethodElement method) {
- JsInvocation invoke = (JsInvocation)generateInvocation(x, qualifier, false, null, method);
- // TODO(johnlenz): if generateInvocation generates a "noSuchMethod" call. This will add
- // useless parameters to the call, this is harmless at the moment.
- rtt.mayAddRuntimeTypeToConstrutorOrFactoryCall(getCurrentClass(), x, invoke);
- return invoke;
- }
-
- private JsExpression generateInvocation(DartInvocation x,
- JsExpression qualifier,
- boolean isSuperCall,
- String mangledName,
- MethodElement method) {
- JsInvocation jsInvoke = new JsInvocation();
-
- if (method != null) {
- if (!generateDirectCallArgs(x, method, jsInvoke)) {
- // Call cannot succeed. Generate $nsme() invocation.
- return AstUtil.newInvocation(new JsNameRef("$nsme"));
- }
- } else {
- generateNamedCallArgs(x, jsInvoke);
- }
-
- JsExpression explicitReceiver = null;
- int argsLength = jsInvoke.getArguments().size();
- qualifier = referenceMethodMember(qualifier, mangledName);
-
- // If it's a super-call, and we need to adjust the 'this'.
- if (isSuperCall) {
- qualifier = AstUtil.newNameRef(qualifier, "call");
- }
-
- if (isSuperCall) {
- assert explicitReceiver == null;
- explicitReceiver = new JsThisRef();
- }
- if (explicitReceiver != null) {
- jsInvoke.getArguments().add(0, explicitReceiver);
- }
- jsInvoke.setQualifier(qualifier);
- return jsInvoke.setSourceRef(x);
- }
-
- /**
- * @return false if the invocation cannot succeed
- */
- private boolean generateDirectCallArgs(DartInvocation x, MethodElement target,
- JsInvocation jsInvoke) {
- // Direct call. Standard calling convention.
- List args = x.getArgs();
- List jsArgs = jsInvoke.getArguments();
-
- // Reorder named parameters.
- List posArgs = new ArrayList();
- Map namedArgs = new HashMap();
- for (DartExpression arg : args) {
- if (arg instanceof DartNamedExpression) {
- DartNamedExpression named = (DartNamedExpression) arg;
- namedArgs.put(named.getName().getTargetName(), named.getExpression());
- } else {
- posArgs.add(arg);
- }
- }
-
- int idx = 0, posUsed = 0;
- for (VariableElement param : target.getParameters()) {
- String name = param.getName();
- if (name != null) {
- DartExpression namedArg = namedArgs.remove(name);
- if (namedArg != null) {
- if (!param.getModifiers().isNamed()) {
- // Provided a named argument to a positional parameter.
- return false;
- }
- jsArgs.add((JsExpression) generate(namedArg));
- } else if (idx < posArgs.size()) {
- ++posUsed;
- jsArgs.add((JsExpression) generate(posArgs.get(idx)));
- } else if (param.getDefaultValue() != null) {
- assert(param.isNamed());
- jsArgs.add(generateDefaultValue(param.getDefaultValue()));
- } else {
- if (param.isNamed()) {
- jsArgs.add(undefined());
- } else {
- return false;
- }
- }
- }
- ++idx;
- }
-
- // Caller specified a named argument that wasn't declared in the method definition.
- if (!namedArgs.isEmpty()) {
- return false;
- }
-
- if (posUsed != posArgs.size()) {
- // Unused positional arguments.
- return false;
- }
-
- return true;
- }
-
- private JsExpression generateDefaultValue(DartExpression defaultValue) {
- if (defaultValue != null) {
- if (defaultValue instanceof DartFunctionExpression) {
- // This should be caught much earlier and rejected. This check avoids an NPE later.
- return nulle();
- }
- }
- return (JsExpression) generate(defaultValue);
- }
-
- private void generateNamedCallArgs(DartInvocation invoke, JsInvocation jsInvoke) {
- // Indirect call. Named-parameter calling convention.
- // method(parg_count, { na0:NA0, na1:NA1, ..., count:N }, pa0, pa1, ...);
- List args = invoke.getArgs();
- List jsArgs = jsInvoke.getArguments();
-
- int namedCount = 0;
- for (DartExpression arg : args) {
- if (arg instanceof DartNamedExpression) {
- ++namedCount;
- }
- }
-
- JsExpression argmap;
- if (namedCount == 0) {
- argmap = new JsNameRef("$noargs");
- } else {
- JsObjectLiteral bag = new JsObjectLiteral();
- for (DartExpression arg : args) {
- if (arg instanceof DartNamedExpression) {
- DartNamedExpression namedExpr = ((DartNamedExpression) arg);
- JsExpression targetName = string(getPropNameForNamedParameter(namedExpr));
- JsPropertyInitializer propInit = new JsPropertyInitializer(
- targetName,
- (JsExpression) generate(namedExpr.getExpression()));
- bag.getPropertyInitializers().add(propInit);
- }
- }
- JsPropertyInitializer countProp = new JsPropertyInitializer(string("count"),
- number(namedCount));
- bag.getPropertyInitializers().add(countProp);
- argmap = bag;
- }
-
- jsArgs.add(number(args.size() - namedCount));
- jsArgs.add(argmap);
- for (DartExpression arg : args) {
- if (!(arg instanceof DartNamedExpression)) {
- jsArgs.add((JsExpression) generate(arg));
- }
- }
- }
-
- private JsExpression referenceMethodMember(JsExpression qualifier,
- String mangledName) {
- if (mangledName != null) {
- qualifier = AstUtil.newNameRef(qualifier, mangledName);
- }
- return qualifier;
- }
-
- @Override
- public JsNode visitThisExpression(DartThisExpression x) {
- return new JsThisRef().setSourceRef(x);
- }
-
- @Override
- public JsNode visitSuperExpression(DartSuperExpression x) {
- ClassElement element = x.getSymbol().getClassElement();
- JsNameRef superRef = AstUtil.newPrototypeNameRef(getJsName(element).makeRef());
- return superRef.setSourceRef(x);
- }
-
- @Override
- public JsNode visitSuperConstructorInvocation(DartSuperConstructorInvocation x) {
- return generateSuperConstructorInvocation(x);
- }
-
- @Override
- public JsNode visitNativeBlock(DartNativeBlock x) {
- JsBlock jsBlock = new JsBlock();
-
- DartMethodDefinition method =
- (DartMethodDefinition) currentScopeInfo.getContainingClassMember();
- String name = mangler.mangleNativeMethod(method.getSymbol());
-
- JsNameRef nativeRef = new JsNameRef(name);
- JsInvocation nativeCall;
- if (method.getModifiers().isStatic()) {
- nativeCall = AstUtil.newInvocation(nativeRef);
- } else {
- JsNameRef callRef = AstUtil.newNameRef(nativeRef, "call");
- nativeCall = AstUtil.newInvocation(callRef, new JsThisRef());
- }
-
- for (DartParameter p : method.getFunction().getParams()) {
- nativeCall.getArguments().add(getJsName(p.getSymbol()).makeRef());
- }
-
- jsBlock.getStatements().add(new JsReturn(nativeCall));
- return jsBlock.setSourceRef(x);
- }
-
- @Override
- public JsNode visitNewExpression(DartNewExpression x) {
- ConstructorElement element = x.getSymbol();
- JsExpression newExpr;
- if (element != null && element.getConstructorType() != null) {
- String className = element.getConstructorType().getName();
- // TODO(floitsch): We should have a JsNames instead of creating the string representations.
- String name = mangler.createFactorySyntax(className, element.getName(), unitLibrary);
- // We add the class name of the holder of the constructor as a qualifier.
- JsName classJsName = getJsName(element.getEnclosingElement());
- JsNameRef consName = AstUtil.newNameRef(classJsName.makeRef(), name);
- newExpr = generateConstructorInvocation(x, consName, element);
- if (x.isConst()) {
- newExpr = maybeInternConst(newExpr, Types.constructorType(x).getArguments());
- }
- } else {
- JsInvocation jsInvocation = AstUtil.newInvocation(new JsNameRef("$nsme2"));
- JsStringLiteral ctorName = translationContext.getProgram().getStringLiteral(
- x.getConstructor().toSource());
- JsArrayLiteral jsArgsArray = new JsArrayLiteral();
- List expressions = jsArgsArray.getExpressions();
- List dartArgs = x.getArgs();
- for (DartExpression arg : dartArgs) {
- expressions.add((JsExpression) generate(arg));
- }
- List jsInvocationArguments = jsInvocation.getArguments();
- jsInvocationArguments.add(ctorName);
- jsInvocationArguments.add(jsArgsArray);
- newExpr = jsInvocation;
- }
- return newExpr;
- }
-
-
- // Compile time constants expressions must be canonicalized.
- // We do this with the javascript native "$intern" method.
- private JsExpression maybeInternConst(JsExpression newExpr, List typeParams) {
- JsInvocation intern = AstUtil.newInvocation(new JsNameRef(INTERN_CONST_FUNCTION), newExpr);
- if (typeParams != null && typeParams.size() != 0) {
- JsArrayLiteral arr = new JsArrayLiteral();
- for (Type t : typeParams) {
- JsExpression typeName;
- if (t.getKind() != TypeKind.DYNAMIC) {
- typeName = rtt.getRTTClassId((ClassElement)t.getElement());
- } else {
- typeName = string("");
- }
- arr.getExpressions().add(typeName);
- }
- intern.getArguments().add(arr);
- }
- return intern;
- }
-
- private boolean shouldBindThis(ScopeRootInfo.ClosureInfo info) {
- if (shouldGenerateDeveloperModeChecks()) {
- return true;
- }
-
- return !inFactoryOrStaticContext && info.referencesThis;
- }
-
- private boolean shouldGenerateDeveloperModeChecks() {
- return context.getCompilerConfiguration().developerModeChecks();
- }
-
- @Override
- public JsNode visitFunctionExpression(DartFunctionExpression x) {
- JsFunction fn = (JsFunction) generate(x.getFunction());
- JsName fnDeclaredName;
- JsName hoistedName;
- String hoistedRttName = null;
-
- // TODO(johnlenz): values used in super class init methods are currently
- // evaluated twice (once for the init and once for the constructor), but
- // this is problematic. We won't need to keep track of the hoisted
- // state once the re-evaluation problem is fixed.
- boolean fnWasPreviouslyHoisted = fn.isHoisted();
- if (fnWasPreviouslyHoisted) {
- fnDeclaredName = fn.getName();
- hoistedName = fn.getName();
- hoistedRttName = mangler.mangleRttLookupMethod(hoistedName.toString(), unitLibrary);
- } else {
-
- // 0) Save off the original name
- fnDeclaredName = fn.getName();
-
- // 1) Create a global name for this method
- hoistedName = makeClosureHoistedJsName(currentHolder, currentScopeInfo, x);
-
- // 2) Give it a unique name.
- fn.setName(hoistedName);
-
- // 3) Insert it into global scope
- fn.rebaseScope(globalScope);
-
- // 4) Make it statement, if it isn't already
- globalBlock.getStatements().add(fn.makeStmt());
-
- // 5) Mark the function as hoisted
- fn.setHoisted();
- }
-
- ScopeRootInfo.ClosureInfo info = currentScopeInfo.getClosureInfo(x.getFunction());
- List list = info.getSortedReferencedScopeList();
-
- // TODO(jgw): See johnlenz' comment above about re-evaluation. This guard can go away once
- // that problem is fixed.
- if (!fnWasPreviouslyHoisted) {
- // Generate the named-parameter trampoline.
- boolean includesClosureScope = !list.isEmpty();
- boolean preserveThis = shouldBindThis(info);
- JsFunction tramp = generateNamedParameterTrampoline(x.getFunction(),
- hoistedName.makeRef(),
- list.size(), preserveThis);
- String mangled = mangler.mangleNamedMethod(hoistedName.getIdent(), unitLibrary);
- hoistedName = globalScope.declareName(mangled);
- tramp.setName(hoistedName);
- globalBlock.getStatements().add(tramp.makeStmt());
-
- if (x.getParent() != null && !(x.getParent() instanceof DartFunctionObjectInvocation)) {
- hoistedRttName = mangler.mangleRttLookupMethod(hoistedName.toString(), unitLibrary);
- rtt.generateRuntimeTypeInfo(x, hoistedRttName);
- }
- } else {
- String mangled = mangler.mangleNamedMethod(hoistedName.getIdent(), unitLibrary);
- hoistedName = globalScope.declareName(mangled);
- hoistedRttName = mangler.mangleRttLookupMethod(hoistedName.toString(), unitLibrary);
- }
-
- if (x.getParent() == null || (x.getParent() instanceof DartFunctionObjectInvocation)) {
- hoistedRttName = null;
- }
-
- // 5) Bind the necessary scope references and possibly "this".
- JsExpression replacement;
-
- if (list.isEmpty() && inFactoryOrStaticContext) {
- // Simply replace the function
- replacement = AstUtil.newInvocation(new JsNameRef("$bind"), new JsNameRef(hoistedName),
- hoistedRttName != null ? new JsNameRef(hoistedRttName) : nulle(), undefined());
- } else {
- // Replace "function (){}" with "bind(hoistedName, this, scope1, scope2, ...)"
- // so that references to class fields can be resolved.
-
- JsExpression thisRef = undefined();
- // Only bind 'this' if 'this' is referenced
- if (shouldBindThis(info)) {
- thisRef = new JsThisRef();
- }
-
- // Replace the definition with a reference to the
- // hoisted function, and bind the necessary values
- // to it.
- int scopeCount = list.size();
- int argCount = fn.getParameters().size() + 2; // +2 => Named-parameter calling convention
- String jsBindName = "$bind";
-
- JsInvocation invoke = AstUtil.newInvocation(new JsNameRef(jsBindName),
- new JsNameRef(hoistedName),
- hoistedRttName != null ? new JsNameRef(hoistedRttName) : nulle(), thisRef);
-
- // Add the scope alias to the bind call and function parameter list
- int parameterIndex = 0;
- for (DartScope s : list) {
- // Add the scope-object as argument to the bind call. The scope-object is referenced
- // in the outer function (currentFunctionScope).
- JsName aliasJsName = s.getAliasForJsScope(getCurrentFunctionScope());
- invoke.getArguments().add(new JsNameRef(aliasJsName));
- // Add the scope-object as parameter to the hoisted signature. The scope-object is
- // referenced from the inner function.
- JsName jsName = s.findAliasForJsScope(fn.getScope());
- // Scope objects are declared (in the JsScope) at first use. By construction scope-objects
- // are only created when they are used. Therefore the scope-object must exist in the
- // JsScope.
- assert jsName != null;
- // TODO(johnlenz): remove this hoisted check once the constructor/init
- // parameters aren't reused.
- if (!fnWasPreviouslyHoisted) {
- fn.getParameters().add(parameterIndex, new JsParameter(jsName));
- }
- parameterIndex += 1;
- }
-
- replacement = invoke;
- }
-
- // 6) If this is a named function expression, then we need to build the scope object.
- if (!x.isStatement() && x.getName() != null) {
- ScopeRootInfo scopeInfo = currentScopeInfo;
- DartScope scope = scopeInfo.getScope(x);
- // If the function is not used by name, then we might not need to create a scope.
- if (scope.definesClosureReferencedSymbols()) {
- // Make sure the alias is defined in the scope.
- JsScope currentFunctionScope = getCurrentFunctionScope();
- // This must be the second use of the scope in this function scope. The first use was
- // as argument to the bind-invocation above.
- JsName aliasName = scope.findAliasForJsScope(currentFunctionScope);
- assert aliasName != null;
- registerForDeclaration(aliasName);
-
- // Assume that the initial expression was x = function f() { }.
- // Up to this point the function has been hoisted and replaced by a binding call:
- // x = bind(hoistedName, this, scope1, ...)
- // The variable "replacement" is equal to the bind call.
- //
- // One of the scopes - say "scope2" - is the FunctionExpressionScope that defines 'f'
- // itself. We now need to set up this scope.
- // Transform:
- // x = bind(hoistedName, this, scope1, ...) into
- // x = (scope2 = {}, scope2.f = bind(hoistedName, this, scope1, ...)).
- JsExpression init =
- AstUtil.newAssignment(new JsNameRef(aliasName), new JsObjectLiteral());
- JsNameRef scopeF = makeScopeAliasNameRef(scope, x.getSymbol());
- JsExpression assig = AstUtil.newAssignment(scopeF, replacement);
- replacement = new JsBinaryOperation(JsBinaryOperator.COMMA, init, assig);
- // TODO(floitsch): we need to clear the scope object.
- }
- }
-
- if (x.isStatement()) {
- // If the name is referenced by a closure use the scope alias.
- JsNameRef scopeAliasRef = maybeMakeScopeAliasReference(x.getSymbol());
- if (scopeAliasRef != null) {
- JsExpression assig = AstUtil.newAssignment(scopeAliasRef, replacement);
- // We must not return a statement. The parent has a check and handles JsVars differently.
- // By default it actually expects an expression.
- return assig.setSourceRef(x);
- } else {
- // The parent expects an expression, but handles Var statements separately.
- assert !hoistedName.equals(fnDeclaredName);
- JsVars vars = AstUtil.newVar(x.getName(), fnDeclaredName, replacement);
- return vars.setSourceRef(x);
- }
- } else {
- return replacement.setSourceRef(x);
- }
- }
-
- private JsName makeClosureHoistedJsName(
- Element holder, ScopeRootInfo info, DartFunctionExpression x) {
- Element element = info.getContainingElement();
- String closureIdentifier = info.getNextClosureName();
- String closureName = x.getFunctionName();
- String hoistedName =
- mangler.createHoistedFunctionName(holder, element, closureIdentifier, closureName);
- return globalScope.declareName(hoistedName, hoistedName, closureName);
- }
-
- @Override
- public JsNode visitIdentifier(DartIdentifier x) {
- DartExpression normalizedNode = x.getNormalizedNode();
- if (normalizedNode != x) {
- return normalizedNode.accept(this);
- }
-
- return generateLoad(null, x).setSourceRef(x);
- }
-
- /**
- * @return A NameRef to the scoped alias if needed.
- */
- private JsNameRef maybeMakeScopeAliasReference(Symbol targetSymbol) {
- if (!functionStack.isEmpty()) {
- /*
- * Currently, you must be inside of a DartFunction in order to be able to generate a
- * scope alias.
- */
- ScopeRootInfo methodInfo = currentScopeInfo;
- if (methodInfo != null) {
- DartScope.DartSymbolInfo symbolInfo = methodInfo.getSymbolInfo(targetSymbol);
- if (symbolInfo != null && symbolInfo.isReferencedFromClosure()) {
- return makeScopeAliasNameRef(symbolInfo.getOwningScope(), targetSymbol);
- }
- }
- }
- return null;
- }
-
- private JsNameRef makeScopeAliasNameRef(DartScope scope, Symbol targetSymbol) {
- JsName qualifier = scope.getAliasForJsScope(getCurrentFunctionScope());
- return AstUtil.newNameRef(new JsNameRef(qualifier), getJsName(targetSymbol).getIdent());
- }
-
- @Override
- public JsNode visitNullLiteral(DartNullLiteral x) {
- // TODO(johnlenz): set source location?
- return undefined();
- }
-
- @Override
- public JsNode visitStringLiteral(DartStringLiteral x) {
- // TODO(johnlenz): properly set source location?
- return string(x.getValue()).setSourceRef(x);
- }
-
- @Override
- public JsNode visitStringInterpolation(DartStringInterpolation x) {
- List strings = x.getStrings();
- List expressions = x.getExpressions();
-
- JsExpression res = null;
- Iterator eIter = expressions.iterator();
- boolean first = true;
- for (DartStringLiteral lit : strings) {
- if (first) {
- first = false;
- res = (JsExpression) generate(lit);
- } else {
- assert eIter.hasNext() : "DartStringInterpolation invariant broken.";
- JsExpression expr = (JsExpression) generate(eIter.next());
- JsInvocation exprToString = new JsInvocation();
- exprToString.setQualifier(new JsNameRef("$toString"));
- exprToString.getArguments().add(expr);
- res = new JsBinaryOperation(JsBinaryOperator.ADD,
- new JsBinaryOperation(JsBinaryOperator.ADD, res, exprToString),
- (JsExpression) generate(lit)).setSourceRef(x);
- }
- }
- assert res != null;
- return res;
- }
-
- @Override
- public JsNode visitBooleanLiteral(DartBooleanLiteral x) {
- // TODO(johnlenz): set source location?
- return x.getValue() ? translationContext.getProgram().getTrueLiteral() : translationContext.getProgram().getFalseLiteral();
- }
-
- @Override
- public JsNode visitIntegerLiteral(DartIntegerLiteral x) {
- // TODO(johnlenz): set source location?
- return number(x.getValue().doubleValue());
- }
-
- @Override
- public JsNode visitDoubleLiteral(DartDoubleLiteral x) {
- // TODO(johnlenz): set source location?
- return number(x.getValue());
- }
-
- @Override
- public JsNode visitArrayLiteral(DartArrayLiteral x) {
- Type elementType = x.getType().getArguments().get(0);
- JsArrayLiteral jsArray = new JsArrayLiteral();
- for (DartNode node : x.getExpressions()) {
- JsExpression expr = (JsExpression) generate(node);
- JsExpression checkedExpr = rtt.addTypeCheck(getCurrentClass(), expr,
- elementType, node.getType(), node.getSourceInfo());
- jsArray.getExpressions().add(checkedExpr);
- }
- jsArray.setSourceRef(x);
- JsExpression result = rtt.maybeAddRuntimeTypeForArrayLiteral(getCurrentClass(), x, jsArray);
- if (x.isConst()) {
- result = this.maybeInternConst(result, x.getType().getArguments());
- }
- return result;
- }
-
- @Override
- @SuppressWarnings("deprecation")
- public JsNode visitMapLiteral(DartMapLiteral x) {
- // Map { 'a': 3, 'b': "foo" } to
- // (tmp = new Map(), tmp.a = 3, tmp.b = "foo", tmp)
- // TODO(floitsch): optimize map-literal creation.
- JsName tmpVar = createTemporary();
- // TODO(floitsch): hardcoded reference to "LinkedHashMapImplementation".
- // We should instead get the element from the DartMapLiteral x.
- String name = "LinkedHashMapImplementation";
- String mangledMap = mangler.mangleClassNameHack(null, name);
- String mangledFactory = mangler.createFactorySyntax(name, "", unitLibrary);
- JsNameRef runtimeMap = AstUtil.newNameRef(new JsNameRef(mangledMap), mangledFactory);
- JsInvocation invoke = AstUtil.newInvocation(runtimeMap);
- rtt.maybeAddRuntimeTypeToMapLiteralConstructor(getCurrentClass(), x, invoke);
- JsExpression assig = AstUtil.newAssignment(tmpVar.makeRef(), invoke.setSourceRef(x));
- JsExpression result = assig;
- Type actualEntryType = x.getType().getArguments().get(1);
- for (DartMapLiteralEntry entry : x.getEntries()) {
- result = AstUtil.newSequence(result, visitMapLiteralEntry(entry, tmpVar, actualEntryType));
- }
- result = AstUtil.newSequence(result, tmpVar.makeRef());
- if (x.isConst()) {
- result = this.maybeInternConst(result, x.getType().getArguments());
- }
- return result;
- }
-
- private JsExpression visitMapLiteralEntry(DartMapLiteralEntry x, JsName map, Type valueType) {
- String addMethod = mangler.createOperatorSyntax(Token.ASSIGN_INDEX);
- JsExpression value = (JsExpression) generate(x.getValue());
- value = rtt.addTypeCheck(getCurrentClass(), value, valueType, x.getType(), x.getSourceInfo());
- JsExpression key = (JsExpression) generate(x.getKey());
- JsNameRef methodName = AstUtil.newNameRef(map.makeRef(), addMethod);
- return AstUtil.newInvocation(methodName, key, value).setSourceRef(x);
- }
-
- @Override
- public JsNode visitMapLiteralEntry(DartMapLiteralEntry x) {
- throw new InternalCompilerException("MapLiteralEntries are handled by the 2-arg variant.");
- }
-
- @Override
- public JsNode visitNamedExpression(DartNamedExpression node) {
- return generate(node.getExpression());
- }
-
- @Override
- public JsNode visitRedirectConstructorInvocation(DartRedirectConstructorInvocation x) {
- return generateSuperConstructorInvocation(x);
- }
-
- private JsNode generateSuperConstructorInvocation(DartInvocation x) {
- // Must use SuperClass.call(this, ...) to get the correct 'this' context in the callee:
- // .$Constructor.call(this, ...).
- ConstructorElement element = (ConstructorElement) x.getSymbol();
- Element classElement;
- String elementName;
- if (element == null) {
- classElement = ((ClassElement) currentHolder).getSupertype().getElement();
- elementName = classElement.getName();
- } else {
- classElement = element.getEnclosingElement();
- elementName = element.getName();
- }
-
- // Skip emitting the super calls call if it is Object.
- if (classElement.equals(typeProvider.getObjectType().getElement())) {
- return null;
- }
-
- // TODO(floitsch): it would be good, if we could get a js-name instead of just a string.
- // This way the debugging information would be better.
- // We need to generate the JsName (for the initializer/factory) once only and store it
- // in some hashtable. Then instead of reusing the mangler, we should reuse those JsNames.
- // The debugging information would then contain a link from the property-access to the
- // constructor. Without JsName the debugger just assumes we access some random property.
- String name = mangler.mangleConstructor(elementName, unitLibrary);
- JsNameRef constructorRef = AstUtil.newNameRef(getJsName(classElement).makeRef(), name);
- return generateInvocation(x, constructorRef, true, null, element);
- }
-
- private JsBinaryOperator mapBinaryOp(Token operator) {
- switch (operator) {
- /* Assignment operators. */
- case ASSIGN: return JsBinaryOperator.ASG;
- case ASSIGN_BIT_OR: return JsBinaryOperator.ASG_BIT_OR;
- case ASSIGN_BIT_XOR: return JsBinaryOperator.ASG_BIT_XOR;
- case ASSIGN_BIT_AND: return JsBinaryOperator.ASG_BIT_AND;
- case ASSIGN_SHL: return JsBinaryOperator.ASG_SHL;
- case ASSIGN_SAR: return JsBinaryOperator.ASG_SHR;
- case ASSIGN_ADD: return JsBinaryOperator.ASG_ADD;
- case ASSIGN_SUB: return JsBinaryOperator.ASG_SUB;
- case ASSIGN_MUL: return JsBinaryOperator.ASG_MUL;
- case ASSIGN_DIV: return JsBinaryOperator.ASG_DIV;
- case ASSIGN_MOD: return JsBinaryOperator.ASG_MOD;
-
- /* Binary operators sorted by precedence. */
- case OR: return JsBinaryOperator.OR;
- case AND: return JsBinaryOperator.AND;
- case BIT_OR: return JsBinaryOperator.BIT_OR;
- case BIT_XOR: return JsBinaryOperator.BIT_XOR;
- case BIT_AND: return JsBinaryOperator.BIT_AND;
- case SHL: return JsBinaryOperator.SHL;
- case SAR: return JsBinaryOperator.SHR;
- case ADD: return JsBinaryOperator.ADD;
- case SUB: return JsBinaryOperator.SUB;
- case MUL: return JsBinaryOperator.MUL;
- case DIV: return JsBinaryOperator.DIV;
- case MOD: return JsBinaryOperator.MOD;
-
- /* Compare operators sorted by precedence. */
- case EQ: return JsBinaryOperator.EQ;
- case NE: return JsBinaryOperator.NEQ;
- case EQ_STRICT: return JsBinaryOperator.REF_EQ;
- case NE_STRICT: return JsBinaryOperator.REF_NEQ;
- case LT: return JsBinaryOperator.LT;
- case GT: return JsBinaryOperator.GT;
- case LTE: return JsBinaryOperator.LTE;
- case GTE: return JsBinaryOperator.GTE;
-
- // Only used by 'for'.
- case COMMA: return JsBinaryOperator.COMMA;
-
- default:
- throw new InternalCompilerException("Invalid binary operator");
- }
- }
-
- private JsUnaryOperator mapUnaryOp(Token operator) {
- switch (operator) {
- case BIT_NOT:
- return JsUnaryOperator.BIT_NOT;
- case NOT:
- return JsUnaryOperator.NOT;
- case SUB:
- return JsUnaryOperator.NEG;
- case INC:
- return JsUnaryOperator.INC;
- case DEC:
- return JsUnaryOperator.DEC;
- default:
- throw new InternalCompilerException("Invalid unary operator.");
- }
- }
-
- private Token mapToStrictEquals(Token op) {
- switch (op) {
- case EQ:
- return Token.EQ_STRICT;
- case NE:
- return Token.NE_STRICT;
- case EQ_STRICT:
- return Token.EQ_STRICT;
- case NE_STRICT:
- return Token.NE_STRICT;
- default:
- throw new InternalCompilerException("Invalid equals operator.");
- }
- }
-
- private Token mapToNonStrictEquals(Token op) {
- switch (op) {
- case EQ_STRICT:
- return Token.EQ;
- case NE_STRICT:
- return Token.NE;
- case EQ:
- return Token.EQ;
- case NE:
- return Token.NE;
- default:
- throw new InternalCompilerException("Invalid equals operator.");
- }
- }
-
- class Assignment extends DartNodeTraverser {
- private final DartNode info;
- private final JsExpression rhs;
- private final Type rhsType;
-
- public Assignment(DartNode info, JsExpression rhs, Type rhsType) {
- this.info = info;
- this.rhs = rhs;
- this.rhsType = rhsType;
- }
-
- @Override
- public JsNode visitNode(DartNode lhs) {
- throw new AssertionError(lhs.getClass().getSimpleName());
- }
-
- @Override
- public JsNode visitIdentifier(DartIdentifier lhs) {
- DartExpression normalizedNode = lhs.getNormalizedNode();
- if (lhs != normalizedNode) {
- return normalizedNode.accept(this);
- }
- Type type = getTypeOfIdentifier(lhs);
- JsExpression wrapped = rtt.addTypeCheck(getCurrentClass(), rhs, type, rhsType, info);
- // On the form e1.name = rhs.
- return generateStore(null, lhs, wrapped).setSourceRef(info);
- }
-
- @Override
- public JsNode visitPropertyAccess(DartPropertyAccess lhs) {
- // On the form e1.name = rhs.
- Type type = lhs.getType();
- JsExpression wrapped = rtt.addTypeCheck(getCurrentClass(), rhs, type, rhsType, info);
- return generateStore(lhs.getQualifier(), lhs.getName(), wrapped).setSourceRef(info);
- }
-
- @Override
- public JsNode visitArrayAccess(DartArrayAccess lhs) {
- // On the form e1[key] = argument.
- // Generate: e1.$set(key, $0 = argument), $0
-
- JsExpression key = (JsExpression) generate(lhs.getKey());
- JsExpression e1 = (JsExpression) generate(lhs.getTarget());
- Type type = lhs.getType();
- JsExpression wrapped = rtt.addTypeCheck(getCurrentClass(), rhs, type, rhsType, info);
- JsNameRef $0 = new JsNameRef(createTemporary());
- String $set = mangler.createOperatorSyntax(Token.ASSIGN_INDEX);
- // Generate: $0 = rhs
- JsExpression e = AstUtil.newAssignment($0, wrapped);
- // Generate: e1.$set(key, $0 = rhs)
- e = AstUtil.newInvocation(AstUtil.newNameRef(e1, $set), key, e);
- // Generate: e, $0
- return new JsBinaryOperation(JsBinaryOperator.COMMA, e, $0).setSourceRef(info);
- }
- }
-
- private final JsNode generate(DartNode node) {
- if (node != null) {
- try {
- return node.getNormalizedNode().accept(this);
- } catch (AssertionError e) {
- reportError(node, e);
- // Wrap assertion error to prevent repeated messages for the same error.
- throw new RuntimeException(e);
- }
- } else {
- return null;
- }
- }
-
- private JsExpression inlineArrayIndexCheck(JsExpression array, JsExpression index) {
- return AstUtil.newInvocation(new JsNameRef("$inlineArrayIndexCheck"), array, index);
- }
-
- private void reportError(DartNode node, Throwable exception) {
- context.onError(new DartCompilationError(node, JsErrorCode.INTERNAL_ERROR,
- exception.getLocalizedMessage()));
- }
-
- private final void generateAll(List extends DartNode> nodes, List result,
- Class extends T> cls) {
- for (DartNode node : nodes) {
- result.add(cls.cast(generate(node)));
- }
- }
-
- JsNameRef referenceName(Symbol symbol, SourceInfo info) {
- // If the value if captured by a closure, change the reference to
- // use the alias of the value.
- JsNameRef jsNode = maybeMakeScopeAliasReference(symbol);
- if (jsNode == null) {
- jsNode = getJsName(symbol).makeRef();
- }
- jsNode.setSourceRef(info);
- return jsNode;
- }
-
- @Override
- public void visit(List extends DartNode> nodes) {
- if (nodes != null) {
- for (DartNode node : nodes) {
- node.accept(this);
- }
- }
- }
-
- @Override
- public JsNode visitAssertion(DartAssertion node) {
- if (inDevMode()) {
- JsExpression expression = (JsExpression) generate(node.getExpression());
- JsNameRef assertName = new JsNameRef("assert");
- JsInvocation jsInvoke;
- jsInvoke = AstUtil.newInvocation(assertName, expression);
- return new JsExprStmt(jsInvoke).setSourceRef(node);
- }
- // Just emit an empty statement if not in checked mode.
- return empty();
- }
-
- private boolean inDevMode() {
- return context.getCompilerConfiguration().developerModeChecks();
- }
-
- @Override
- public JsNode visitParenthesizedExpression(DartParenthesizedExpression node) {
- return node.getExpression().accept(this);
- }
-
- @Override
- public JsNode visitCatchBlock(DartCatchBlock node) {
- throw new AssertionError("should never be called directly");
- }
-
- @Override
- public JsNode visitUnit(DartUnit unit) {
- throw new AssertionError("should never be called directly");
- /*
- unit.visitChildren(this);
- // Initialize static fields after declaring every method, getters &
- // setters (b/4101270)
- // TODO(johnlenz): canonicalize statics values
- globalBlock.getStatements().addAll(staticInit);
- */
- }
-
- @Override
- public JsNode visitFunctionTypeAlias(DartFunctionTypeAlias node) {
- // TODO(codefu): Optimize away if we're never the rhs of a "is" check.
- ClassElement classElement = node.getSymbol();
- JsName classJsName = getJsName(classElement);
- JsFunction jsClass = new JsFunction(globalScope, classJsName).setSourceRef(node);
- jsClass.setIsConstructor(false);
- jsClass.setBody(new JsBlock());
- globalBlock.getStatements().add(jsClass.makeStmt());
-
- rtt.generateRuntimeTypeInfo(node);
- return null;
- }
-
- private JsExpression generateQualifiedFieldAccess(DartNode qualifier,
- String accessorName) {
- // Generate this.ACCESSOR();
- JsExpression jsQualifier;
- if (qualifier == null || (qualifier instanceof DartThisExpression)) {
- jsQualifier = new JsThisRef();
- } else {
- jsQualifier = (JsExpression) generate(qualifier);
- }
-
- jsQualifier.setSourceRef(qualifier);
- JsNameRef nameRef = AstUtil.newNameRef(jsQualifier, accessorName);
- return AstUtil.newInvocation(nameRef);
- }
-
- private JsExpression generateUnresolvedAccess(DartNode qualifier,
- String accessorName) {
- if (qualifier == null) {
- return generateQualifiedFieldAccess(qualifier, accessorName);
- }
- // Generate qualifier.ACCESSOR();
- JsExpression jsQualifier = (JsExpression) generate(qualifier);
- jsQualifier.setSourceRef(qualifier);
- JsNameRef method = AstUtil.newNameRef(jsQualifier, accessorName);
- return AstUtil.newInvocation(method);
- }
-
- private JsInvocation generateSuperFieldAccess(DartNode qualifier,
- String accessorName) {
- // Generate CLASS.prototype.ACCESSOR.call(this);
- ClassElement superClass = ((SuperElement) qualifier.getSymbol()).getClassElement();
- JsExpression jsQualifier = AstUtil.newPrototypeNameRef(getJsName(superClass).makeRef());
- jsQualifier.setSourceRef(qualifier);
- JsNameRef method = AstUtil.newNameRef(jsQualifier, accessorName);
- method = AstUtil.newNameRef(method, "call");
- JsInvocation jsInvoke = AstUtil.newInvocation(method);
- jsInvoke.getArguments().add(0, new JsThisRef());
- return jsInvoke;
- }
-
- private JsInvocation generateStaticFieldAccess(FieldElement element,
- DartNode qualifier,
- String accessorName) {
- // Generate CLASS.ACCESSOR();
- JsExpression jsQualifier = referenceName(element.getEnclosingElement(), qualifier);
- jsQualifier.setSourceRef(qualifier);
- JsNameRef method = AstUtil.newNameRef(jsQualifier, accessorName);
- return AstUtil.newInvocation(method);
- }
-
- private JsInvocation generateLibraryFieldAccess(String accessorName) {
- // Generate ACCESSOR();
- return AstUtil.newInvocation(new JsNameRef(accessorName));
- }
-
- private JsExpression generateFieldAccess(FieldElement field, DartNode qualifier,
- String accessorName) {
- boolean isSuperCall = (qualifier != null) && isSuperCall(qualifier.getSymbol());
- if (isSuperCall) {
- return generateSuperFieldAccess(qualifier, accessorName);
- } else if (Elements.isTopLevel(field)) {
- return generateLibraryFieldAccess(accessorName);
- } else if (field.isStatic()) {
- return generateStaticFieldAccess(field, qualifier, accessorName);
- } else {
- return generateQualifiedFieldAccess(qualifier, accessorName);
- }
- }
-
- /*
- * A method is accessed as if a closure object
- * class A { foo() { return 1; })
- * Function f = A.foo;
- */
- private JsExpression generateMethodBoundToVariable(DartIdentifier methodNode,
- MethodElement methodElement, DartNode qualifier) {
- JsExpression boundMethod;
- String mangledName = mangler.mangleNamedMethod(methodElement, unitLibrary);
- String mangledGetter = mangler.createGetterSyntax(methodElement, unitLibrary);
- boolean isSuperCall = (qualifier != null) && isSuperCall(qualifier.getSymbol());
- if (isSuperCall) {
- boundMethod = generateSuperFieldAccess(qualifier,
- mangler.createGetterSyntax(methodElement.getName(), unitLibrary));
- } else if (Elements.isTopLevel(methodElement)) {
- boundMethod = AstUtil.newInvocation(AstUtil.newNameRef(null, mangledGetter));
- } else if (methodElement.isStatic()) {
- if (qualifier == null) {
- qualifier = methodElement.getEnclosingElement().getNode();
- assert (qualifier instanceof DartClass);
- boundMethod = AstUtil.newNameRef(getJsName(qualifier.getSymbol()).makeRef(),
- mangledGetter);
- } else {
- boundMethod = AstUtil.newNameRef((JsExpression) generate(qualifier), mangledGetter);
- }
- boundMethod = AstUtil.newInvocation(boundMethod);
- } else {
- // Should be an invocation on an instance
- if (qualifier == null) {
- qualifier = DartThisExpression.get();
- }
- JsExpression methodQualifier = (JsExpression) generate(qualifier);
- ClassElement classElement = (ClassElement) methodElement.getEnclosingElement();
- String className = mangler.mangleClassName(classElement);
- JsNameRef prototypeRef = AstUtil.newPrototypeNameRef(new JsNameRef(className));
- JsExpression methodToCall = AstUtil.newNameRef(prototypeRef, mangledName);
- JsExpression methodRtt = AstUtil.newNameRef(prototypeRef,
- mangler.mangleRttLookupMethod(methodElement, unitLibrary));
- boundMethod = AstUtil.newInvocation(new JsNameRef("$bind"), methodToCall, methodRtt, methodQualifier);
- }
- boundMethod.setSourceRef(methodNode);
- return boundMethod;
- }
-
- private JsExpression generateLoadTemporary(Element element, DartIdentifier node) {
- return referenceName(element, node);
- }
-
- private JsExpression generateLoad(DartNode qualifier, DartIdentifier node) {
- Element element = node.getTargetSymbol();
-
- switch (ElementKind.of(element)) {
- case VARIABLE:
- case PARAMETER:
- case FUNCTION_OBJECT:
- // TODO(5089961): we should not generate code for class expressions.
- case CLASS:
- return generateLoadTemporary(element, node);
-
- case NONE:
- if (qualifier != null && isSuperCall(qualifier.getSymbol())) {
- return generateSuperFieldAccess(qualifier,
- mangler.createGetterSyntax(node.getTargetName(), unitLibrary));
- }
- return generateUnresolvedAccess(qualifier,
- mangler.createGetterSyntax(node.getTargetName(), unitLibrary));
-
- case FIELD: {
- FieldElement field = (FieldElement) element;
- String accessorName;
- accessorName = mangler.createGetterSyntax(field, unitLibrary);
- return generateFieldAccess(field, qualifier, accessorName);
- }
-
- case METHOD: {
- MethodElement method = (MethodElement) element;
- return generateMethodBoundToVariable(node, method, qualifier);
- }
-
- default:
- throw new AssertionError("I do not know how to load: " + ElementKind.of(element));
- }
- }
-
- private JsExpression generateStoreTemporary(Element element,
- DartIdentifier node,
- JsExpression rhs) {
- JsNameRef jsName = referenceName(element, node);
- return AstUtil.newAssignment(jsName, rhs);
- }
-
- private JsExpression generateStoreField(JsExpression fieldAccess,
- JsExpression rhs) {
- if (fieldAccess instanceof JsInvocation) {
- JsNameRef $0 = new JsNameRef(createTemporary());
- // Generate: $0 = rhs
- JsExpression e = AstUtil.newAssignment($0, rhs);
-
- // Add ($0 = rhs) as parameter of the field access.
- ((JsInvocation) fieldAccess).getArguments().add(e);
- // Generate: e1.set$name($0 = rhs), $0
- return new JsBinaryOperation(JsBinaryOperator.COMMA, fieldAccess, $0);
- } else {
- assert (fieldAccess instanceof JsNameRef);
- return AstUtil.newAssignment((JsNameRef) fieldAccess, rhs);
- }
- }
-
- private JsExpression generateStore(DartNode qualifier, DartIdentifier node, JsExpression rhs) {
- Element element = node.getTargetSymbol();
-
- switch (ElementKind.of(element)) {
- case VARIABLE:
- case PARAMETER:
- return generateStoreTemporary(element, node, rhs);
-
- case NONE: {
- JsExpression invoke =
- generateUnresolvedAccess(qualifier,
- mangler.createSetterSyntax(node.getTargetName(), unitLibrary));
- return generateStoreField(invoke, rhs);
- }
-
- case FIELD: {
- FieldElement field = (FieldElement) element;
- String accessorName;
-
- accessorName = mangler.createSetterSyntax(field, unitLibrary);
-
- JsExpression invoke = generateFieldAccess(field, qualifier, accessorName);
- return generateStoreField(invoke, rhs);
- }
-
- default:
- throw new AssertionError("I do not know how to store into: " + ElementKind.of(element));
- }
- }
-
- @Override
- public JsNode visitParameterizedTypeNode(DartParameterizedTypeNode node) {
- return node.getExpression().accept(this);
- }
-
- @Override
- public JsNode visitImportDirective(DartImportDirective node) {
- throw new AssertionError("should never be called directly");
- }
-
- @Override
- public JsNode visitLibraryDirective(DartLibraryDirective node) {
- throw new AssertionError("should never be called directly");
- }
-
- @Override
- public JsNode visitNativeDirective(DartNativeDirective node) {
- throw new AssertionError("should never be called directly");
- }
-
- @Override
- public JsNode visitResourceDirective(DartResourceDirective node) {
- throw new AssertionError("should never be called directly");
- }
-
- @Override
- public JsNode visitSourceDirective(DartSourceDirective node) {
- throw new AssertionError("should never be called directly");
- }
-
- @Override
- public DartClassMember> getCurrentClassMember() {
- if (this.currentScopeInfo != null) {
- return currentScopeInfo.getContainingClassMember();
- }
- return null;
- }
-
- private ClassElement getCurrentClass() {
- if (currentHolder.getKind() == ElementKind.CLASS) {
- return (ClassElement) currentHolder;
- }
- return null;
- }
- }
-
- GenerateJavascriptAST(DartUnit unit, CoreTypeProvider typeProvider, DartCompilerContext context) {
- this.unit = unit;
- this.context = context;
- this.typeProvider = typeProvider;
- }
-
- public void translateNode(TranslationContext translationContext, DartNode node,
- JsBlock blockStatics) {
- GenerateJavascriptVisitor generator =
- new GenerateJavascriptVisitor(unit, context, translationContext,
- typeProvider);
- // Generate the Javascript AST.
- node.accept(generator);
- // Set aside the static initializations
- generator.addStaticInitsToBlock(blockStatics);
- }
-}
diff --git a/compiler/java/com/google/dart/compiler/backend/js/GenerateNamesAndScopes.java b/compiler/java/com/google/dart/compiler/backend/js/GenerateNamesAndScopes.java
deleted file mode 100644
index 771f984ca04..00000000000
--- a/compiler/java/com/google/dart/compiler/backend/js/GenerateNamesAndScopes.java
+++ /dev/null
@@ -1,214 +0,0 @@
-// 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.
-
-package com.google.dart.compiler.backend.js;
-
-import com.google.dart.compiler.ast.DartClass;
-import com.google.dart.compiler.ast.DartContext;
-import com.google.dart.compiler.ast.DartField;
-import com.google.dart.compiler.ast.DartFunction;
-import com.google.dart.compiler.ast.DartFunctionExpression;
-import com.google.dart.compiler.ast.DartLabel;
-import com.google.dart.compiler.ast.DartMethodDefinition;
-import com.google.dart.compiler.ast.DartParameter;
-import com.google.dart.compiler.ast.DartVariable;
-import com.google.dart.compiler.backend.js.ast.JsFunction;
-import com.google.dart.compiler.backend.js.ast.JsName;
-import com.google.dart.compiler.backend.js.ast.JsScope;
-import com.google.dart.compiler.common.Symbol;
-import com.google.dart.compiler.resolver.ConstructorElement;
-import com.google.dart.compiler.resolver.Elements;
-import com.google.dart.compiler.resolver.FieldElement;
-import com.google.dart.compiler.resolver.LibraryElement;
-import com.google.dart.compiler.resolver.MethodElement;
-
-import java.util.Deque;
-import java.util.LinkedList;
-
-/**
- * This visitor generates Javascript scopes and names for all the Dart nodes, filling in the
- * node->name map in 'names'.
- */
-class GenerateNamesAndScopes extends NormalizedVisitor {
-
- /**
- * A JsScope used to manage fields and methods. A MemberJsScope can become
- * parentless.
- */
- private static class MemberJsScope extends JsScope {
- private MemberJsScope(JsScope parent, String description) {
- super(parent, description);
- }
-
- @Override
- protected void detachFromParent() {
- super.detachFromParent();
- }
- }
-
- private final Deque scopes = new LinkedList();
- private DartClass currentClass = null;
- private int labelUniqifier = 0; // to resolve label name collisions.
- private int varUniqifier = 0; // to resolve variable name collisions.
-
- private final TranslationContext translationContext;
- private final LibraryElement unitLibrary;
-
- private JsScope getGlobalScope() {
- return translationContext.getProgram().getScope();
- }
-
- public GenerateNamesAndScopes(TranslationContext data, LibraryElement unitLibrary) {
- this.translationContext = data;
- this.unitLibrary = unitLibrary;
- scopes.push(getGlobalScope());
- }
-
- @Override
- public boolean visit(DartClass x, DartContext ctx) {
- assert currentClass == null;
- // Global variables are declared lazily. We don't declare the class now.
- currentClass = x;
- // We add the member scope into the hierarchy, so that the resolution works on unqualified
- // identifiers. Once the resolution is done, we can rip out the scope from the hierarchy.
- scopes.push(new MemberJsScope(scopes.peek(), x.getClassName()));
- return true;
- }
-
- @Override
- public boolean visit(DartField x, DartContext ctx) {
- FieldElement element = x.getSymbol();
- String mangledFieldName = translationContext.getMangler().mangleField(element, unitLibrary);
- JsName fieldName = declare(x.getSymbol(), mangledFieldName, element.getName());
- fieldName.setObfuscatable(false);
- return true;
- }
-
- public boolean generateConstructorName(DartMethodDefinition x) {
- ConstructorElement element = (ConstructorElement) x.getSymbol();
- String name = translationContext.getMangler().mangleConstructor(element.getName(), unitLibrary);
- JsName jsName = function(x.getSymbol(), name, element.getName(), x.getFunction());
- // Constructors are globally accessible.
- jsName.setObfuscatable(false);
- return true;
- }
-
- @Override
- public boolean visit(DartMethodDefinition x, DartContext ctx) {
- MethodElement element = x.getSymbol();
- if (Elements.isNonFactoryConstructor(element)) {
- return generateConstructorName(x);
- }
- if (x.getModifiers().isFactory()) {
- String className = ((ConstructorElement) element).getConstructorType().getName();
- String name = translationContext.getMangler().createFactorySyntax(className, element.getName(), unitLibrary);
- JsName jsName = function(x.getSymbol(), name, element.getName(), x.getFunction());
- // Factories are globally accessible.
- jsName.setObfuscatable(false);
- return true;
- }
-
- String mangledName = translationContext.getMangler().mangleMethod(element, unitLibrary);
- JsName methodName = function(x.getSymbol(), mangledName, element.getName(), x.getFunction());
- methodName.setObfuscatable(false);
- return true;
- }
-
- @Override
- public boolean visit(DartFunctionExpression x, DartContext ctx) {
- function(x.getSymbol(), x.getFunctionName(), x.getFunctionName(), x.getFunction());
- return true;
- }
-
- @Override
- public boolean visit(DartParameter x, DartContext ctx) {
- // TODO(ngeoffray): A parameter in a function type does not have a symbol.
- if (x.getSymbol() != null) {
- declareExclusively(x.getSymbol(), x.getParameterName());
- }
- return true;
- }
-
- @Override
- public boolean visit(DartVariable x, DartContext ctx) {
- declareExclusively(x.getSymbol(), x.getVariableName());
- return true;
- }
-
- @Override
- public boolean visit(DartLabel x, DartContext ctx) {
- declareExclusively(x.getSymbol(), String.format("L%X", labelUniqifier++));
- return true;
- }
-
- @Override
- public void endVisit(DartMethodDefinition x, DartContext ctx) {
- scopes.pop();
- }
-
- @Override
- public void endVisit(DartFunctionExpression x, DartContext ctx) {
- scopes.pop();
- }
-
- @Override
- public void endVisit(DartClass x, DartContext ctx) {
- currentClass = null;
- // Rip out the member scope. Members are always accessed through an object and don't clash
- // with other variables.
- GenerateNamesAndScopes.MemberJsScope memberScope = (GenerateNamesAndScopes.MemberJsScope) scopes.pop();
- memberScope.rebaseChildScopes(memberScope.getParent());
- memberScope.detachFromParent();
- translationContext.getMemberScopes().put(x.getSymbol(), memberScope);
- }
-
- private JsName function(Symbol symbol, String name, String originalName, DartFunction func) {
- JsName jsName = name != null ? declareExclusively(symbol, name, originalName) : null;
- JsFunction jsFunc = new JsFunction(scopes.peek(), jsName);
- jsFunc.setFromDart(true);
- scopes.push(jsFunc.getScope());
- translationContext.getMethods().put(func, jsFunc);
- return jsName;
- }
-
- private JsName declare(Symbol x, String name, String originalName) {
- return declareInScope(scopes.peek(), x, name, originalName);
- }
-
- private JsName declareExclusively(Symbol x, String name, String originalName) {
- return declareExclusivelyInScope(scopes.peek(), x, name, originalName);
- }
-
- private JsName declareExclusively(Symbol x, String name) {
- return declareExclusivelyInScope(scopes.peek(), x, name, name);
- }
-
- private static final int BIG_PRIME_UNDER_0XFFFFF = 985531;
-
- /**
- * Create a unique name for this variable in this scope.
- *
- * Try to keep this from being a linear scan of the namespace, and keep
- * it under 5 hex digits (over 1,000,000 unique suffixes).
- *
- */
- private JsName declareExclusivelyInScope(JsScope scope, Symbol x,
- String name, String originalName) {
- String mappedName = name;
- int offset = 0;
- while (scope.findExistingName(mappedName) != null) {
- mappedName = String.format("%s_%X", mappedName, varUniqifier);
- varUniqifier = (varUniqifier + offset++) % BIG_PRIME_UNDER_0XFFFFF;
- }
- return declareInScope(scope, x, mappedName, originalName);
- }
-
- private JsName declareInScope(JsScope scope, Symbol x, String name, String originalName) {
- JsName jsName = scope.declareName(name, name, originalName);
- jsName.getClass(); // Fast null check.
- x.getClass(); // Fast null check.
- translationContext.getNames().setName(x, jsName);
- return jsName;
- }
-}
\ No newline at end of file
diff --git a/compiler/java/com/google/dart/compiler/backend/js/JavascriptBackend.java b/compiler/java/com/google/dart/compiler/backend/js/JavascriptBackend.java
deleted file mode 100644
index c33143c38c5..00000000000
--- a/compiler/java/com/google/dart/compiler/backend/js/JavascriptBackend.java
+++ /dev/null
@@ -1,181 +0,0 @@
-// 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.
-
-package com.google.dart.compiler.backend.js;
-
-import com.google.common.io.CharStreams;
-import com.google.common.io.Closeables;
-import com.google.dart.compiler.DartCompilerContext;
-import com.google.dart.compiler.DartSource;
-import com.google.dart.compiler.LibrarySource;
-import com.google.dart.compiler.ast.LibraryNode;
-import com.google.dart.compiler.ast.LibraryUnit;
-import com.google.dart.compiler.backend.js.analysis.TreeShaker;
-import com.google.dart.compiler.metrics.CompilerMetrics;
-import com.google.dart.compiler.resolver.CoreTypeProvider;
-
-import java.io.IOException;
-import java.io.Reader;
-import java.io.Writer;
-import java.util.Collection;
-
-/**
- * A compiler backend that produces raw Javascript.
- */
-public class JavascriptBackend extends AbstractJsBackend {
-
- public static final String EXTENSION_APP_JS_COMPLETE = EXTENSION_APP_JS + ".complete";
-
- /**
- * Wraps an Appendable and keeps track of the current offset as line/columns.
- */
- static class CountingAppendable implements Appendable {
-
- private int line = 0;
- private int column = 0;
- private Appendable out;
- private long charCount = 0;
-
- CountingAppendable(Appendable out) {
- this.out = out;
- }
-
- @Override
- public Appendable append(CharSequence csq) throws IOException {
- incCount(csq, 0, csq.length());
- return out.append(csq);
- }
-
- @Override
- public Appendable append(char c) throws IOException {
- incCount(c);
- return out.append(c);
- }
-
- @Override
- public Appendable append(CharSequence csq, int start, int end)
- throws IOException {
- incCount(csq, start, end);
- return out.append(csq, start, end);
- }
-
- private void incCount(CharSequence cs, int start, int end) {
- for (int i = 0; i < cs.length(); i++) {
- incCount(cs.charAt(i));
- }
- }
-
- private void incCount(char c) {
- ++charCount;
- if (c == '\n') {
- line++;
- column = 0;
- } else {
- column++;
- }
- }
- }
-
- private static class DepsWritingCallback implements DepsCallback {
- private final DartCompilerContext context;
- private CountingAppendable out;
- DepsWritingCallback(
- DartCompilerContext context,
- CountingAppendable out) {
- this.out = out;
- this.context = context;
- }
-
- @Override
- public void visitNative(LibraryUnit libUnit, LibraryNode node)
- throws IOException {
- DartSource nativeSrc = libUnit.getSource().getSourceFor(node.getText());
- Reader r = nativeSrc.getSourceReader();
- long charsWrittenForFile = CharStreams.copy(r, out);
- }
-
- @Override
- public void visitPart(Part part) throws IOException {
- DartSource src = part.unit.getSource();
- assert(src != null);
- Reader r = context.getArtifactReader(src, part.part, EXTENSION_JS);
- if (r == null) {
- return;
- }
-
- long partSize = 0;
- boolean failed = true;
- try {
- partSize = CharStreams.copy(r, out);
- failed = false;
- } finally {
- Closeables.close(r, failed);
- }
- }
-
- public long getCharsWritten() {
- return out.charCount;
- }
- }
-
- private static long packageLibs(Writer w,
- DartCompilerContext context) throws IOException {
- final CountingAppendable out = new CountingAppendable(w);
-
- DepsWritingCallback callback = new DepsWritingCallback(context, out);
- DependencyBuilder.build(context.getAppLibraryUnit(), callback);
- return callback.getCharsWritten();
- }
-
- @Override
- public void packageApp(LibrarySource app,
- Collection libraries,
- DartCompilerContext context,
- CoreTypeProvider typeProvider)
- throws IOException {
-
- LibraryUnit appLibraryUnit = context.getAppLibraryUnit();
- boolean hasEntryPoint = appLibraryUnit.getElement().getEntryPoint() != null;
-
- String completeArtifactName = EXTENSION_APP_JS;
- if (hasEntryPoint) {
- // Apps with entry points will be reduced so we write into a different file name
- completeArtifactName = EXTENSION_APP_JS_COMPLETE;
- }
-
- Writer out = context.getArtifactWriter(app, "", completeArtifactName);
- long outputFileSize = 0;
- boolean failed = true;
- try {
- // Emit the concatenated Javascript sources in dependency order.
- outputFileSize = packageLibs(out, context);
- outputFileSize += writeEntryPointCall(getMangledEntryPoint(context), out);
- failed = false;
- } finally {
- Closeables.close(out, failed);
- }
-
-
- if (hasEntryPoint) {
- Writer artifactWriter = context.getArtifactWriter(app, "", EXTENSION_APP_JS);
- try {
- failed = true;
- outputFileSize = TreeShaker.reduce(app, context, completeArtifactName, artifactWriter);
- failed = false;
- } finally {
- Closeables.close(artifactWriter, failed);
- }
- }
-
- CompilerMetrics compilerMetrics = context.getCompilerMetrics();
- if (compilerMetrics != null) {
- compilerMetrics.packagedJsApplication(outputFileSize, -1);
- }
- }
-
- @Override
- public String getAppExtension() {
- return EXTENSION_APP_JS;
- }
-}
diff --git a/compiler/java/com/google/dart/compiler/backend/js/JsConstructExpressionVisitor.java b/compiler/java/com/google/dart/compiler/backend/js/JsConstructExpressionVisitor.java
deleted file mode 100644
index 8d70657a31e..00000000000
--- a/compiler/java/com/google/dart/compiler/backend/js/JsConstructExpressionVisitor.java
+++ /dev/null
@@ -1,114 +0,0 @@
-// 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.
-
-package com.google.dart.compiler.backend.js;
-
-import com.google.dart.compiler.backend.js.ast.JsArrayAccess;
-import com.google.dart.compiler.backend.js.ast.JsArrayLiteral;
-import com.google.dart.compiler.backend.js.ast.JsContext;
-import com.google.dart.compiler.backend.js.ast.JsExpression;
-import com.google.dart.compiler.backend.js.ast.JsFunction;
-import com.google.dart.compiler.backend.js.ast.JsInvocation;
-import com.google.dart.compiler.backend.js.ast.JsNameRef;
-import com.google.dart.compiler.backend.js.ast.JsNew;
-import com.google.dart.compiler.backend.js.ast.JsObjectLiteral;
-import com.google.dart.compiler.backend.js.ast.JsVisitable;
-import com.google.dart.compiler.backend.js.ast.JsVisitor;
-
-/**
- * Searches for method invocations in constructor expressions that would not
- * normally be surrounded by parentheses.
- */
-public class JsConstructExpressionVisitor extends JsVisitor {
-
- public static boolean exec(JsExpression expression) {
- if (JsPrecedenceVisitor.exec(expression) < JsPrecedenceVisitor.PRECEDENCE_NEW) {
- return true;
- }
- JsConstructExpressionVisitor visitor = new JsConstructExpressionVisitor();
- visitor.accept(expression);
- return visitor.containsInvocation;
- }
-
- private boolean containsInvocation = false;
-
- private JsConstructExpressionVisitor() {
- }
-
- /**
- * We only look at the array expression since the index has its own scope.
- */
- @Override
- public boolean visit(JsArrayAccess x, JsContext ctx) {
- accept(x.getArrayExpr());
- return false;
- }
-
- /**
- * Array literals have their own scoping.
- */
- @Override
- public boolean visit(JsArrayLiteral x, JsContext ctx) {
- return false;
- }
-
- /**
- * Functions have their own scoping.
- */
- @Override
- public boolean visit(JsFunction x, JsContext ctx) {
- return false;
- }
-
- @Override
- public boolean visit(JsInvocation x, JsContext ctx) {
- containsInvocation = true;
- return false;
- }
-
- @Override
- public boolean visit(JsNameRef x, JsContext ctx) {
- if (!x.isLeaf()) {
- accept(x.getQualifier());
- }
- return false;
- }
-
- /**
- * New constructs bind to the nearest set of parentheses.
- */
- @Override
- public boolean visit(JsNew x, JsContext ctx) {
- return false;
- }
-
- /**
- * Object literals have their own scope.
- */
- @Override
- public boolean visit(JsObjectLiteral x, JsContext ctx) {
- return false;
- }
-
- /**
- * We only look at nodes that would not normally be surrounded by parentheses.
- */
- @Override
- protected T doAccept(T node) {
- // Assign to Object to prevent 'inconvertible types' compile errors due
- // to http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6548436
- // reproducible in jdk1.6.0_02.
- Object o = node;
- if (o instanceof JsExpression) {
- JsExpression expression = (JsExpression) o;
- int precedence = JsPrecedenceVisitor.exec(expression);
- // Only visit expressions that won't automatically be surrounded by
- // parentheses
- if (precedence < JsPrecedenceVisitor.PRECEDENCE_NEW) {
- return node;
- }
- }
- return super.doAccept(node);
- }
-}
diff --git a/compiler/java/com/google/dart/compiler/backend/js/JsErrorCode.java b/compiler/java/com/google/dart/compiler/backend/js/JsErrorCode.java
deleted file mode 100644
index abdde376fbc..00000000000
--- a/compiler/java/com/google/dart/compiler/backend/js/JsErrorCode.java
+++ /dev/null
@@ -1,49 +0,0 @@
-// 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.
-package com.google.dart.compiler.backend.js;
-
-import com.google.dart.compiler.ErrorCode;
-import com.google.dart.compiler.ErrorSeverity;
-import com.google.dart.compiler.SubSystem;
-
-/**
- * {@link ErrorCode}s for JavaScript backend.
- */
-public enum JsErrorCode implements ErrorCode {
- INTERNAL_ERROR("internal error: %s");
- private final ErrorSeverity severity;
- private final String message;
-
- /**
- * Initialize a newly created error code to have the given message and ERROR severity.
- */
- private JsErrorCode(String message) {
- this(ErrorSeverity.ERROR, message);
- }
-
- /**
- * Initialize a newly created error code to have the given severity and message.
- */
- private JsErrorCode(ErrorSeverity severity, String message) {
- this.severity = severity;
- this.message = message;
- }
-
- public String getMessage() {
- return message;
- }
-
- public ErrorSeverity getErrorSeverity() {
- return severity;
- }
-
- public SubSystem getSubSystem() {
- return SubSystem.JS_BACKEND;
- }
-
- @Override
- public boolean needsRecompilation() {
- return true;
- }
-}
\ No newline at end of file
diff --git a/compiler/java/com/google/dart/compiler/backend/js/JsFirstExpressionVisitor.java b/compiler/java/com/google/dart/compiler/backend/js/JsFirstExpressionVisitor.java
deleted file mode 100644
index 6fb4dc4f82b..00000000000
--- a/compiler/java/com/google/dart/compiler/backend/js/JsFirstExpressionVisitor.java
+++ /dev/null
@@ -1,134 +0,0 @@
-// 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.
-
-package com.google.dart.compiler.backend.js;
-
-import com.google.dart.compiler.backend.js.ast.JsArrayAccess;
-import com.google.dart.compiler.backend.js.ast.JsArrayLiteral;
-import com.google.dart.compiler.backend.js.ast.JsBinaryOperation;
-import com.google.dart.compiler.backend.js.ast.JsConditional;
-import com.google.dart.compiler.backend.js.ast.JsContext;
-import com.google.dart.compiler.backend.js.ast.JsExprStmt;
-import com.google.dart.compiler.backend.js.ast.JsExpression;
-import com.google.dart.compiler.backend.js.ast.JsFunction;
-import com.google.dart.compiler.backend.js.ast.JsInvocation;
-import com.google.dart.compiler.backend.js.ast.JsNameRef;
-import com.google.dart.compiler.backend.js.ast.JsNew;
-import com.google.dart.compiler.backend.js.ast.JsObjectLiteral;
-import com.google.dart.compiler.backend.js.ast.JsPostfixOperation;
-import com.google.dart.compiler.backend.js.ast.JsPrefixOperation;
-import com.google.dart.compiler.backend.js.ast.JsRegExp;
-import com.google.dart.compiler.backend.js.ast.JsVisitor;
-
-/**
- * Determines if an expression statement needs to be surrounded by parentheses.
- *
- * The statement or the left-most expression needs to be surrounded by
- * parentheses if the left-most expression is an object literal or a function
- * object. Function declarations do not need parentheses.
- *
- * For example the following require parentheses:
- *
- * - { key : 'value'}
- * - { key : 'value'}.key
- * - function () {return 1;}()
- * - function () {return 1;}.prototype
- *
- *
- * The following do not require parentheses:
- *
- * - var x = { key : 'value'}
- * - "string" + { key : 'value'}.key
- * - function func() {}
- * - function() {}
- *
- */
-public class JsFirstExpressionVisitor extends JsVisitor {
-
- public static boolean exec(JsExprStmt statement) {
- JsFirstExpressionVisitor visitor = new JsFirstExpressionVisitor();
- JsExpression expression = statement.getExpression();
- // Pure function declarations do not need parentheses
- if (expression instanceof JsFunction) {
- return false;
- }
- visitor.accept(statement.getExpression());
- return visitor.needsParentheses;
- }
-
- private boolean needsParentheses = false;
-
- private JsFirstExpressionVisitor() {
- }
-
- @Override
- public boolean visit(JsArrayAccess x, JsContext ctx) {
- accept(x.getArrayExpr());
- return false;
- }
-
- @Override
- public boolean visit(JsArrayLiteral x, JsContext ctx) {
- return false;
- }
-
- @Override
- public boolean visit(JsBinaryOperation x, JsContext ctx) {
- accept(x.getArg1());
- return false;
- }
-
- @Override
- public boolean visit(JsConditional x, JsContext ctx) {
- accept(x.getTestExpression());
- return false;
- }
-
- @Override
- public boolean visit(JsFunction x, JsContext ctx) {
- needsParentheses = true;
- return false;
- }
-
- @Override
- public boolean visit(JsInvocation x, JsContext ctx) {
- accept(x.getQualifier());
- return false;
- }
-
- @Override
- public boolean visit(JsNameRef x, JsContext ctx) {
- if (!x.isLeaf()) {
- accept(x.getQualifier());
- }
- return false;
- }
-
- @Override
- public boolean visit(JsNew x, JsContext ctx) {
- return false;
- }
-
- @Override
- public boolean visit(JsObjectLiteral x, JsContext ctx) {
- needsParentheses = true;
- return false;
- }
-
- @Override
- public boolean visit(JsPostfixOperation x, JsContext ctx) {
- accept(x.getArg());
- return false;
- }
-
- @Override
- public boolean visit(JsPrefixOperation x, JsContext ctx) {
- return false;
- }
-
- @Override
- public boolean visit(JsRegExp x, JsContext ctx) {
- return false;
- }
-}
diff --git a/compiler/java/com/google/dart/compiler/backend/js/JsNameProvider.java b/compiler/java/com/google/dart/compiler/backend/js/JsNameProvider.java
deleted file mode 100644
index d8469e20630..00000000000
--- a/compiler/java/com/google/dart/compiler/backend/js/JsNameProvider.java
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright 2011, the Dart project 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.
-
-package com.google.dart.compiler.backend.js;
-
-import com.google.dart.compiler.backend.js.ast.JsName;
-import com.google.dart.compiler.backend.js.ast.JsProgram;
-import com.google.dart.compiler.backend.js.ast.JsScope;
-import com.google.dart.compiler.common.Symbol;
-import com.google.dart.compiler.resolver.ClassElement;
-import com.google.dart.compiler.resolver.ElementKind;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * A helper class for managing global names.
- * @author johnlenz@google.com (John Lenz)
- */
-class JsNameProvider {
- private final DartMangler mangler;
- private Map names = new HashMap();
- private JsScope globalScope;
-
- JsNameProvider(JsProgram program, DartMangler mangler) {
- this.globalScope = program.getScope();
- this.mangler = mangler;
- }
-
- /**
- * Returns the JsName for the given element. If the element is global and
- * hasn't been declared yet, it is done now.
- */
- JsName getName(Symbol symbol) {
- JsName jsName = names.get(symbol);
- if (jsName != null) {
- assert !jsName.getShortIdent().equals("Object$Dart");
- return jsName;
- }
- assert ElementKind.of(symbol).equals(ElementKind.CLASS)
- || ElementKind.of(symbol).equals(ElementKind.FUNCTION_TYPE_ALIAS)
- : "Only classes or typedefs can be lazily declared. Undeclared: "
- + symbol.getOriginalSymbolName();
- ClassElement classElement = (ClassElement) symbol;
- String name = classElement.getName();
- String nativeName = classElement.getNativeName();
- if (nativeName == null) {
- String mangledClassName = mangler.mangleClassName(classElement);
- jsName = globalScope.declareName(mangledClassName, mangledClassName, name);
- } else {
- jsName = globalScope.declareName(nativeName);
- }
- // Class names are globally accessible.
- jsName.setObfuscatable(false);
- names.put(symbol, jsName);
- assert !jsName.getShortIdent().equals("Object$Dart") : "unexpected " + ((ClassElement) symbol).getNode().getSource().getName();
- return jsName;
- }
-
- void setName(Symbol symbol, JsName name) {
- names.put(symbol, name);
- }
-}
diff --git a/compiler/java/com/google/dart/compiler/backend/js/JsNamer.java b/compiler/java/com/google/dart/compiler/backend/js/JsNamer.java
deleted file mode 100644
index 41e99061eda..00000000000
--- a/compiler/java/com/google/dart/compiler/backend/js/JsNamer.java
+++ /dev/null
@@ -1,23 +0,0 @@
-// 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.
-
-package com.google.dart.compiler.backend.js;
-
-import com.google.dart.compiler.backend.js.ast.JsProgram;
-
-/**
- * A namer runs through a program and renames the short names of JsNames.
- * Namers must assign short names that don't clash and that are valid
- * JS-identifiers. Nested JsScopes must not shadow JsNames from outer
- * scopes.
- * If a JsName is marked as non-obfuscatable then it must retain its short
- * name.
- */
-public interface JsNamer {
- /**
- * Names the shortNames of all JsNames of the program so that they are valid
- * JS-identifiers and that there are no clashes and no shadowing.
- */
- public void exec(JsProgram program);
-}
diff --git a/compiler/java/com/google/dart/compiler/backend/js/JsNormalizer.java b/compiler/java/com/google/dart/compiler/backend/js/JsNormalizer.java
deleted file mode 100644
index 5eeadf69bd1..00000000000
--- a/compiler/java/com/google/dart/compiler/backend/js/JsNormalizer.java
+++ /dev/null
@@ -1,112 +0,0 @@
-// 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.
-
-package com.google.dart.compiler.backend.js;
-
-import com.google.dart.compiler.backend.js.ast.JsBinaryOperation;
-import com.google.dart.compiler.backend.js.ast.JsBinaryOperator;
-import com.google.dart.compiler.backend.js.ast.JsContext;
-import com.google.dart.compiler.backend.js.ast.JsExpression;
-import com.google.dart.compiler.backend.js.ast.JsModVisitor;
-import com.google.dart.compiler.backend.js.ast.JsPostfixOperation;
-import com.google.dart.compiler.backend.js.ast.JsPrefixOperation;
-import com.google.dart.compiler.backend.js.ast.JsProgram;
-import com.google.dart.compiler.backend.js.ast.JsUnaryOperation;
-import com.google.dart.compiler.backend.js.ast.JsUnaryOperator;
-
-/**
- * Fixes any semantic errors introduced by JS AST gen.
- *
- *
- * - Creating clinit calls can put comma expressions as lvalues; the modifying
- * operation must be moved inside the comma expression to the last argument.
- *
- */
-public class JsNormalizer {
-
- /**
- * Resolves any unresolved JsNameRefs.
- */
- private static class JsNormalizing extends JsModVisitor {
-
- @Override
- public void endVisit(JsBinaryOperation x, JsContext ctx) {
- maybeShuffleModifyingBinary(x, ctx);
- }
-
- @Override
- public void endVisit(JsPostfixOperation x, JsContext ctx) {
- maybeShuffleModifyingUnary(x, ctx);
- }
-
- @Override
- public void endVisit(JsPrefixOperation x, JsContext ctx) {
- maybeShuffleModifyingUnary(x, ctx);
- }
-
- /**
- * Due to the way clinits are constructed, you can end up with a comma
- * operation as the argument to a modifying operation, which is illegal.
- * Juggle things to put the operator inside of the comma expression.
- */
- private void maybeShuffleModifyingBinary(JsBinaryOperation x, JsContext ctx) {
- JsBinaryOperator myOp = x.getOperator();
- JsExpression lhs = x.getArg1();
-
- if (myOp.isAssignment() && (lhs instanceof JsBinaryOperation)) {
- // Find the rightmost comma operation
- JsBinaryOperation curLhs = (JsBinaryOperation) lhs;
- assert (curLhs.getOperator() == JsBinaryOperator.COMMA);
- while (curLhs.getArg2() instanceof JsBinaryOperation) {
- curLhs = (JsBinaryOperation) curLhs.getArg2();
- assert (curLhs.getOperator() == JsBinaryOperator.COMMA);
- }
- // curLhs is now the rightmost comma operation; slide our operation in
- x.setArg1(curLhs.getArg2());
- curLhs.setArg2(x);
- // replace myself with the comma expression
- ctx.replaceMe(lhs);
- }
- }
-
- /**
- * Due to the way clinits are constructed, you can end up with a comma
- * operation as the argument to a modifying operation, which is illegal.
- * Juggle things to put the operator inside of the comma expression.
- */
- private void maybeShuffleModifyingUnary(JsUnaryOperation x, JsContext ctx) {
- JsUnaryOperator myOp = x.getOperator();
- JsExpression arg = x.getArg();
- if (myOp.isModifying() && (arg instanceof JsBinaryOperation)) {
- // Find the rightmost comma operation
- JsBinaryOperation curArg = (JsBinaryOperation) arg;
- assert (curArg.getOperator() == JsBinaryOperator.COMMA);
- while (curArg.getArg2() instanceof JsBinaryOperation) {
- curArg = (JsBinaryOperation) curArg.getArg2();
- assert (curArg.getOperator() == JsBinaryOperator.COMMA);
- }
- // curArg is now the rightmost comma operation; slide our operation in
- x.setArg(curArg.getArg2());
- curArg.setArg2(x);
- // replace myself with the comma expression
- ctx.replaceMe(arg);
- }
- }
- }
-
- public static void exec(JsProgram program) {
- new JsNormalizer(program).execImpl();
- }
-
- private final JsProgram program;
-
- private JsNormalizer(JsProgram program) {
- this.program = program;
- }
-
- private void execImpl() {
- JsNormalizing normalizer = new JsNormalizing();
- normalizer.accept(program);
- }
-}
diff --git a/compiler/java/com/google/dart/compiler/backend/js/JsParserException.java b/compiler/java/com/google/dart/compiler/backend/js/JsParserException.java
deleted file mode 100644
index 79b53c1d69e..00000000000
--- a/compiler/java/com/google/dart/compiler/backend/js/JsParserException.java
+++ /dev/null
@@ -1,92 +0,0 @@
-// 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.
-
-package com.google.dart.compiler.backend.js;
-
-/**
- * Indicates inability to parse JavaScript source.
- */
-public class JsParserException extends Exception {
-
- /**
- * Represents the location of a parser exception.
- */
- public static class SourceDetail {
- private final String fileName;
- private final int line;
- private final int lineOffset;
- private final String lineSource;
-
- public SourceDetail(int line, String lineSource, int lineOffset, String fileName) {
- this.line = line;
- this.lineSource = lineSource;
- this.lineOffset = lineOffset;
- this.fileName = fileName;
- }
-
- public String getFileName() {
- return fileName;
- }
-
- public int getLine() {
- return line;
- }
-
- public int getLineOffset() {
- return lineOffset;
- }
-
- public String getLineSource() {
- return lineSource;
- }
- }
-
- private static String createMessageWithDetail(String msg, SourceDetail sourceDetail) {
- if (sourceDetail == null) {
- return msg;
- }
- StringBuffer sb = new StringBuffer();
- sb.append(sourceDetail.getFileName());
- sb.append('(');
- sb.append(sourceDetail.getLine());
- sb.append(')');
- sb.append(": ");
- sb.append(msg);
- if (sourceDetail.getLineSource() != null) {
- sb.append("\n> ");
- sb.append(sourceDetail.getLineSource());
- sb.append("\n> ");
- for (int i = 0, n = sourceDetail.getLineOffset(); i < n; ++i) {
- sb.append('-');
- }
- sb.append('^');
- }
- return sb.toString();
- }
-
- private final SourceDetail sourceDetail;
-
- public JsParserException(String msg) {
- this(msg, null);
- }
-
- public JsParserException(String msg, int line, String lineSource, int lineOffset, String fileName) {
- this(msg, new SourceDetail(line, lineSource, lineOffset, fileName));
- }
-
- public JsParserException(String msg, SourceDetail sourceDetail) {
- super(createMessageWithDetail(msg, sourceDetail));
- this.sourceDetail = sourceDetail;
- }
-
- /**
- * Provides additional source detail in some cases.
- *
- * @return additional detail regarding the error, or null if no
- * additional detail is available
- */
- public SourceDetail getSourceDetail() {
- return sourceDetail;
- }
-}
diff --git a/compiler/java/com/google/dart/compiler/backend/js/JsPrecedenceVisitor.java b/compiler/java/com/google/dart/compiler/backend/js/JsPrecedenceVisitor.java
deleted file mode 100644
index 4b306872f7e..00000000000
--- a/compiler/java/com/google/dart/compiler/backend/js/JsPrecedenceVisitor.java
+++ /dev/null
@@ -1,317 +0,0 @@
-// 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.
-
-package com.google.dart.compiler.backend.js;
-
-import com.google.dart.compiler.backend.js.ast.JsArrayAccess;
-import com.google.dart.compiler.backend.js.ast.JsArrayLiteral;
-import com.google.dart.compiler.backend.js.ast.JsBinaryOperation;
-import com.google.dart.compiler.backend.js.ast.JsBlock;
-import com.google.dart.compiler.backend.js.ast.JsBooleanLiteral;
-import com.google.dart.compiler.backend.js.ast.JsBreak;
-import com.google.dart.compiler.backend.js.ast.JsCase;
-import com.google.dart.compiler.backend.js.ast.JsCatch;
-import com.google.dart.compiler.backend.js.ast.JsConditional;
-import com.google.dart.compiler.backend.js.ast.JsContext;
-import com.google.dart.compiler.backend.js.ast.JsContinue;
-import com.google.dart.compiler.backend.js.ast.JsDebugger;
-import com.google.dart.compiler.backend.js.ast.JsDefault;
-import com.google.dart.compiler.backend.js.ast.JsDoWhile;
-import com.google.dart.compiler.backend.js.ast.JsEmpty;
-import com.google.dart.compiler.backend.js.ast.JsExprStmt;
-import com.google.dart.compiler.backend.js.ast.JsExpression;
-import com.google.dart.compiler.backend.js.ast.JsFor;
-import com.google.dart.compiler.backend.js.ast.JsForIn;
-import com.google.dart.compiler.backend.js.ast.JsFunction;
-import com.google.dart.compiler.backend.js.ast.JsIf;
-import com.google.dart.compiler.backend.js.ast.JsInvocation;
-import com.google.dart.compiler.backend.js.ast.JsLabel;
-import com.google.dart.compiler.backend.js.ast.JsNameRef;
-import com.google.dart.compiler.backend.js.ast.JsNew;
-import com.google.dart.compiler.backend.js.ast.JsNullLiteral;
-import com.google.dart.compiler.backend.js.ast.JsNumberLiteral;
-import com.google.dart.compiler.backend.js.ast.JsObjectLiteral;
-import com.google.dart.compiler.backend.js.ast.JsParameter;
-import com.google.dart.compiler.backend.js.ast.JsPostfixOperation;
-import com.google.dart.compiler.backend.js.ast.JsPrefixOperation;
-import com.google.dart.compiler.backend.js.ast.JsProgram;
-import com.google.dart.compiler.backend.js.ast.JsPropertyInitializer;
-import com.google.dart.compiler.backend.js.ast.JsRegExp;
-import com.google.dart.compiler.backend.js.ast.JsReturn;
-import com.google.dart.compiler.backend.js.ast.JsStringLiteral;
-import com.google.dart.compiler.backend.js.ast.JsSwitch;
-import com.google.dart.compiler.backend.js.ast.JsThisRef;
-import com.google.dart.compiler.backend.js.ast.JsThrow;
-import com.google.dart.compiler.backend.js.ast.JsTry;
-import com.google.dart.compiler.backend.js.ast.JsVars;
-import com.google.dart.compiler.backend.js.ast.JsVisitor;
-import com.google.dart.compiler.backend.js.ast.JsWhile;
-import com.google.dart.compiler.backend.js.ast.JsVars.JsVar;
-
-/**
- * Precedence indices from "JavaScript - The Definitive Guide" 4th Edition (page
- * 57)
- *
- * Precedence 17 is for indivisible primaries that either don't have children,
- * or provide their own delimiters.
- *
- * Precedence 16 is for really important things that have their own AST classes.
- *
- * Precedence 15 is for the new construct.
- *
- * Precedence 14 is for unary operators.
- *
- * Precedences 12 through 4 are for non-assigning binary operators.
- *
- * Precedence 3 is for the tertiary conditional.
- *
- * Precedence 2 is for assignments.
- *
- * Precedence 1 is for comma operations.
- */
-class JsPrecedenceVisitor extends JsVisitor {
-
- static final int PRECEDENCE_NEW = 15;
-
- public static int exec(JsExpression expression) {
- JsPrecedenceVisitor visitor = new JsPrecedenceVisitor();
- visitor.accept(expression);
- if (visitor.answer < 0) {
- throw new RuntimeException("Precedence must be >= 0!");
- }
- return visitor.answer;
- }
-
- private int answer = -1;
-
- private JsPrecedenceVisitor() {
- }
-
- @Override
- public boolean visit(JsArrayAccess x, JsContext ctx) {
- answer = 16;
- return false;
- }
-
- @Override
- public boolean visit(JsArrayLiteral x, JsContext ctx) {
- answer = 17; // primary
- return false;
- }
-
- @Override
- public boolean visit(JsBinaryOperation x, JsContext ctx) {
- answer = x.getOperator().getPrecedence();
- return false;
- }
-
- @Override
- public boolean visit(JsBlock x, JsContext ctx) {
- throw new RuntimeException("Only expressions have precedence.");
- }
-
- @Override
- public boolean visit(JsBooleanLiteral x, JsContext ctx) {
- answer = 17; // primary
- return false;
- }
-
- @Override
- public boolean visit(JsBreak x, JsContext ctx) {
- throw new RuntimeException("Only expressions have precedence.");
- }
-
- @Override
- public boolean visit(JsCase x, JsContext ctx) {
- throw new RuntimeException("Only expressions have precedence.");
- }
-
- @Override
- public boolean visit(JsCatch x, JsContext ctx) {
- throw new RuntimeException("Only expressions have precedence.");
- }
-
- @Override
- public boolean visit(JsConditional x, JsContext ctx) {
- answer = 3;
- return false;
- }
-
- @Override
- public boolean visit(JsContinue x, JsContext ctx) {
- throw new RuntimeException("Only expressions have precedence.");
- }
-
- @Override
- public boolean visit(JsDebugger x, JsContext ctx) {
- throw new RuntimeException("Only expressions have precedence.");
- }
-
- @Override
- public boolean visit(JsDefault x, JsContext ctx) {
- throw new RuntimeException("Only expressions have precedence.");
- }
-
- @Override
- public boolean visit(JsDoWhile x, JsContext ctx) {
- throw new RuntimeException("Only expressions have precedence.");
- }
-
- @Override
- public boolean visit(JsEmpty x, JsContext ctx) {
- throw new RuntimeException("Only expressions have precedence.");
- }
-
- @Override
- public boolean visit(JsExprStmt x, JsContext ctx) {
- throw new RuntimeException("Only expressions have precedence.");
- }
-
- @Override
- public boolean visit(JsFor x, JsContext ctx) {
- throw new RuntimeException("Only expressions have precedence.");
- }
-
- @Override
- public boolean visit(JsForIn x, JsContext ctx) {
- throw new RuntimeException("Only expressions have precedence.");
- }
-
- @Override
- public boolean visit(JsFunction x, JsContext ctx) {
- answer = 17; // primary
- return false;
- }
-
- @Override
- public boolean visit(JsIf x, JsContext ctx) {
- throw new RuntimeException("Only expressions have precedence.");
- }
-
- @Override
- public boolean visit(JsInvocation x, JsContext ctx) {
- answer = 16;
- return false;
- }
-
- @Override
- public boolean visit(JsLabel x, JsContext ctx) {
- throw new RuntimeException("Only expressions have precedence.");
- }
-
- @Override
- public boolean visit(JsNameRef x, JsContext ctx) {
- if (x.isLeaf()) {
- answer = 17; // primary
- } else {
- answer = 16; // property access
- }
- return false;
- }
-
- @Override
- public boolean visit(JsNew x, JsContext ctx) {
- answer = PRECEDENCE_NEW;
- return false;
- }
-
- @Override
- public boolean visit(JsNullLiteral x, JsContext ctx) {
- answer = 17; // primary
- return false;
- }
-
- @Override
- public boolean visit(JsNumberLiteral x, JsContext ctx) {
- answer = 17; // primary
- return false;
- }
-
- @Override
- public boolean visit(JsObjectLiteral x, JsContext ctx) {
- answer = 17; // primary
- return false;
- }
-
- @Override
- public boolean visit(JsParameter x, JsContext ctx) {
- throw new RuntimeException("Only expressions have precedence.");
- }
-
- @Override
- public boolean visit(JsPostfixOperation x, JsContext ctx) {
- answer = x.getOperator().getPrecedence();
- return false;
- }
-
- @Override
- public boolean visit(JsPrefixOperation x, JsContext ctx) {
- answer = x.getOperator().getPrecedence();
- return false;
- }
-
- @Override
- public boolean visit(JsProgram x, JsContext ctx) {
- throw new RuntimeException("Only expressions have precedence.");
- }
-
- @Override
- public boolean visit(JsPropertyInitializer x, JsContext ctx) {
- answer = 17; // primary
- return false;
- }
-
- @Override
- public boolean visit(JsRegExp x, JsContext ctx) {
- answer = 17; // primary
- return false;
- }
-
- @Override
- public boolean visit(JsReturn x, JsContext ctx) {
- throw new RuntimeException("Only expressions have precedence.");
- }
-
- @Override
- public boolean visit(JsStringLiteral x, JsContext ctx) {
- answer = 17; // primary
- return false;
- }
-
- @Override
- public boolean visit(JsSwitch x, JsContext ctx) {
- throw new RuntimeException("Only expressions have precedence.");
- }
-
- @Override
- public boolean visit(JsThisRef x, JsContext ctx) {
- answer = 17; // primary
- return false;
- }
-
- @Override
- public boolean visit(JsThrow x, JsContext ctx) {
- throw new RuntimeException("Only expressions have precedence.");
- }
-
- @Override
- public boolean visit(JsTry x, JsContext ctx) {
- throw new RuntimeException("Only expressions have precedence.");
- }
-
- @Override
- public boolean visit(JsVar x, JsContext ctx) {
- throw new RuntimeException("Only expressions have precedence.");
- }
-
- @Override
- public boolean visit(JsVars x, JsContext ctx) {
- throw new RuntimeException("Only expressions have precedence.");
- }
-
- @Override
- public boolean visit(JsWhile x, JsContext ctx) {
- throw new RuntimeException("Only expressions have precedence.");
- }
-}
diff --git a/compiler/java/com/google/dart/compiler/backend/js/JsPrettyNamer.java b/compiler/java/com/google/dart/compiler/backend/js/JsPrettyNamer.java
deleted file mode 100644
index 4d18fdbf1be..00000000000
--- a/compiler/java/com/google/dart/compiler/backend/js/JsPrettyNamer.java
+++ /dev/null
@@ -1,127 +0,0 @@
-// 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.
-
-package com.google.dart.compiler.backend.js;
-
-import com.google.dart.compiler.backend.js.ast.JsName;
-import com.google.dart.compiler.backend.js.ast.JsProgram;
-import com.google.dart.compiler.backend.js.ast.JsRootScope;
-import com.google.dart.compiler.backend.js.ast.JsScope;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.IdentityHashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-
-/**
- * A namer that uses short, readable idents to maximize reability.
- */
-public class JsPrettyNamer implements JsNamer {
-
- public JsPrettyNamer() {
- this.program = null;
- }
-
- @Override
- public void exec(JsProgram program) {
- new JsPrettyNamer(program).execImpl();
- }
-
- /**
- * Communicates to a parent scope all the idents used by all child scopes.
- */
- private Set childIdents = null;
-
- private final JsProgram program;
-
- /**
- * A map containing the next integer to try as an identifier suffix for a
- * given JsScope.
- */
- private IdentityHashMap> startIdentForScope =
- new IdentityHashMap>();
-
- protected JsPrettyNamer(JsProgram program) {
- this.program = program;
- }
-
- private void execImpl() {
- visit(program.getRootScope());
- }
-
- private boolean isLegal(JsScope scope, Set childIdents, String newIdent) {
- if (JsReservedIdentifiers.isKeyword(newIdent)) {
- return false;
- }
- if (childIdents.contains(newIdent)) {
- // one of my children already claimed this ident
- return false;
- }
- /*
- * Never obfuscate a name into an identifier that conflicts with an existing
- * unobfuscatable name! It's okay if it conflicts with an existing
- * obfuscatable name; that name will get obfuscated out of the way.
- */
- return (scope.findExistingUnobfuscatableName(newIdent) == null);
- }
-
- private void visit(JsScope scope) {
- HashMap startIdent = startIdentForScope.get(scope);
- if (startIdent == null) {
- startIdent = new HashMap();
- startIdentForScope.put(scope, startIdent);
- }
-
- // Save off the childIdents which is currently being computed for my parent.
- Set myChildIdents = childIdents;
-
- /*
- * Visit my children first. Reset childIdents so that my children will get a
- * clean slate: I do not communicate to my children.
- */
- childIdents = new HashSet();
- List children = scope.getChildren();
- for (Iterator it = children.iterator(); it.hasNext();) {
- visit(it.next());
- }
-
- JsRootScope rootScope = program.getRootScope();
- if (scope == rootScope) {
- return;
- }
-
- // Visit all my idents.
- for (Iterator it = scope.getAllNames(); it.hasNext();) {
- JsName name = it.next();
- if (!name.isObfuscatable()) {
- // Unobfuscatable names become themselves.
- name.setShortIdent(name.getIdent());
- continue;
- }
-
- String newIdent = name.getShortIdent();
- if (!isLegal(scope, childIdents, newIdent)) {
- String checkIdent;
-
- // Start searching using a suffix hint stored in the scope.
- // We still do a search in case there is a collision with
- // a user-provided identifier
- Integer s = startIdent.get(newIdent);
- int suffix = (s == null) ? 0 : s.intValue();
- do {
- checkIdent = newIdent + "_" + suffix++;
- } while (!isLegal(scope, childIdents, checkIdent));
- startIdent.put(newIdent, suffix);
- name.setShortIdent(checkIdent);
- } else {
- // nothing to do; the short name is already good
- }
- childIdents.add(name.getShortIdent());
- }
- myChildIdents.addAll(childIdents);
- childIdents = myChildIdents;
- }
-}
diff --git a/compiler/java/com/google/dart/compiler/backend/js/JsRequiresSemiVisitor.java b/compiler/java/com/google/dart/compiler/backend/js/JsRequiresSemiVisitor.java
deleted file mode 100644
index b099959ad1a..00000000000
--- a/compiler/java/com/google/dart/compiler/backend/js/JsRequiresSemiVisitor.java
+++ /dev/null
@@ -1,158 +0,0 @@
-// 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.
-
-package com.google.dart.compiler.backend.js;
-
-import com.google.dart.compiler.backend.js.ast.JsBlock;
-import com.google.dart.compiler.backend.js.ast.JsBreak;
-import com.google.dart.compiler.backend.js.ast.JsContext;
-import com.google.dart.compiler.backend.js.ast.JsDebugger;
-import com.google.dart.compiler.backend.js.ast.JsDoWhile;
-import com.google.dart.compiler.backend.js.ast.JsEmpty;
-import com.google.dart.compiler.backend.js.ast.JsExprStmt;
-import com.google.dart.compiler.backend.js.ast.JsFor;
-import com.google.dart.compiler.backend.js.ast.JsForIn;
-import com.google.dart.compiler.backend.js.ast.JsIf;
-import com.google.dart.compiler.backend.js.ast.JsLabel;
-import com.google.dart.compiler.backend.js.ast.JsReturn;
-import com.google.dart.compiler.backend.js.ast.JsStatement;
-import com.google.dart.compiler.backend.js.ast.JsSwitch;
-import com.google.dart.compiler.backend.js.ast.JsThrow;
-import com.google.dart.compiler.backend.js.ast.JsTry;
-import com.google.dart.compiler.backend.js.ast.JsVars;
-import com.google.dart.compiler.backend.js.ast.JsVisitor;
-import com.google.dart.compiler.backend.js.ast.JsWhile;
-
-/**
- * Determines if a statement at the end of a block requires a semicolon.
- *
- * For example, the following statements require semicolons:
- *
- * - if (cond);
- * - while (cond);
- *
- *
- * The following do not require semicolons:
- *
- * - return 1
- * - do {} while(true)
- *
- */
-public class JsRequiresSemiVisitor extends JsVisitor {
-
- public static boolean exec(JsStatement lastStatement) {
- JsRequiresSemiVisitor visitor = new JsRequiresSemiVisitor();
- visitor.accept(lastStatement);
- return visitor.needsSemicolon;
- }
-
- private boolean needsSemicolon = false;
-
- private JsRequiresSemiVisitor() {
- }
-
- @Override
- public boolean visit(JsBlock x, JsContext ctx) {
- return false;
- }
-
- @Override
- public boolean visit(JsBreak x, JsContext ctx) {
- return false;
- }
-
- @Override
- public boolean visit(JsDebugger x, JsContext ctx) {
- return false;
- }
-
- @Override
- public boolean visit(JsDoWhile x, JsContext ctx) {
- return false;
- }
-
- @Override
- public boolean visit(JsEmpty x, JsContext ctx) {
- return false;
- }
-
- @Override
- public boolean visit(JsExprStmt x, JsContext ctx) {
- return false;
- }
-
- @Override
- public boolean visit(JsFor x, JsContext ctx) {
- if (x.getBody() instanceof JsEmpty) {
- needsSemicolon = true;
- }
- return false;
- }
-
- @Override
- public boolean visit(JsForIn x, JsContext ctx) {
- if (x.getBody() instanceof JsEmpty) {
- needsSemicolon = true;
- }
- return false;
- }
-
- @Override
- public boolean visit(JsIf x, JsContext ctx) {
- JsStatement thenStmt = x.getThenStmt();
- JsStatement elseStmt = x.getElseStmt();
- JsStatement toCheck = thenStmt;
- if (elseStmt != null) {
- toCheck = elseStmt;
- }
- if (toCheck instanceof JsEmpty) {
- needsSemicolon = true;
- } else {
- // Must recurse to determine last statement (possible if-else chain).
- accept(toCheck);
- }
- return false;
- }
-
- @Override
- public boolean visit(JsLabel x, JsContext ctx) {
- if (x.getStmt() instanceof JsEmpty) {
- needsSemicolon = true;
- }
- return false;
- }
-
- @Override
- public boolean visit(JsReturn x, JsContext ctx) {
- return false;
- }
-
- @Override
- public boolean visit(JsSwitch x, JsContext ctx) {
- return false;
- }
-
- @Override
- public boolean visit(JsThrow x, JsContext ctx) {
- return false;
- }
-
- @Override
- public boolean visit(JsTry x, JsContext ctx) {
- return false;
- }
-
- @Override
- public boolean visit(JsVars x, JsContext ctx) {
- return false;
- }
-
- @Override
- public boolean visit(JsWhile x, JsContext ctx) {
- if (x.getBody() instanceof JsEmpty) {
- needsSemicolon = true;
- }
- return false;
- }
-}
diff --git a/compiler/java/com/google/dart/compiler/backend/js/JsReservedIdentifiers.java b/compiler/java/com/google/dart/compiler/backend/js/JsReservedIdentifiers.java
deleted file mode 100644
index 56ae5428a3d..00000000000
--- a/compiler/java/com/google/dart/compiler/backend/js/JsReservedIdentifiers.java
+++ /dev/null
@@ -1,223 +0,0 @@
-// 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.
-
-package com.google.dart.compiler.backend.js;
-
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Determines whether or not a particular string is a JavaScript keyword or not.
- */
-public class JsReservedIdentifiers {
-
- private static Set javaScriptKeywords;
- private static Set reservedGlobalSymbols;
- private static Set reservedPropertySymbols;
-
- static {
- javaScriptKeywords = new HashSet();
- reservedGlobalSymbols = new HashSet();
- reservedPropertySymbols = new HashSet();
- initJavaScriptKeywords();
- initReservedGlobalSymbols();
- initReservedPropertySymbols();
- }
-
- public static boolean isKeyword(String s) {
- return javaScriptKeywords.contains(s);
- }
-
- private static void initJavaScriptKeywords() {
- String[] keywords = new String[] {
- // These are current keywords
- "break", "delete", "function", "return", "typeof", "case", "do", "if", "switch", "var",
- "catch", "else", "in", "this", "void", "continue", "false", "instanceof", "throw",
- "while", "debugger", "finally", "new", "true", "with", "default", "for",
- "null", "try",
-
- // These are future keywords
- "abstract", "double", "goto", "native", "static", "boolean", "enum", "implements",
- "package", "super", "byte", "export", "import", "private", "synchronized", "char",
- "extends", "int", "protected", "throws", "class", "final", "interface", "public",
- "transient", "const", "float", "long", "short", "volatile"
- };
-
- for (int i = 0; i < keywords.length; i++) {
- javaScriptKeywords.add(keywords[i]);
- }
- }
-
- /**
- * @return a set containing all known reserved global identifiers. This set must not be modified.
- */
- public static Set getReservedGlobalSymbols() {
- return reservedGlobalSymbols;
- }
-
- /**
- * Returns true if the string s can not be used as a global identifier. The check includes
- * JavaScript keywords (as they must not be used either).
- * @param s
- * @return true if the given String must not be used as a global identifier.
- */
- public static boolean isReservedGlobalSymbol(String s) {
- return isKeyword(s) || reservedGlobalSymbols.contains(s);
- }
-
- private static void initReservedGlobalSymbols() {
- // Section references are from Ecma-262
- // (http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf)
- String[] commonBuiltins = new String[] {
- // 15.1.1 Value Properties of the Global Object
- "NaN", "Infinity", "undefined",
-
- // 15.1.2 Function Properties of the Global Object
- "eval", "parseInt", "parseFloat", "isNan", "isFinite",
-
- // 15.1.3 URI Handling Function Properties
- "decodeURI", "decodeURIComponent",
- "encodeURI",
- "encodeURIComponent",
-
- // 15.1.4 Constructor Properties of the Global Object
- "Object", "Function", "Array", "String", "Boolean", "Number", "Date",
- "RegExp", "Error", "EvalError", "RangeError", "ReferenceError",
- "SyntaxError", "TypeError", "URIError",
-
- // 15.1.5 Other Properties of the Global Object
- "Math",
-
- // 10.1.6 Activation Object
- "arguments",
-
- // B.2 Additional Properties (non-normative)
- "escape", "unescape",
-
- // Window props (https://developer.mozilla.org/en/DOM/window)
- "applicationCache", "closed", "Components", "content", "controllers",
- "crypto", "defaultStatus", "dialogArguments", "directories",
- "document", "frameElement", "frames", "fullScreen", "globalStorage",
- "history", "innerHeight", "innerWidth", "length",
- "location", "locationbar", "localStorage", "menubar",
- "mozInnerScreenX", "mozInnerScreenY", "mozScreenPixelsPerCssPixel",
- "name", "navigator", "opener", "outerHeight", "outerWidth",
- "pageXOffset", "pageYOffset", "parent", "personalbar", "pkcs11",
- "returnValue", "screen", "scrollbars", "scrollMaxX", "scrollMaxY",
- "self", "sessionStorage", "sidebar", "status", "statusbar", "toolbar",
- "top", "window",
-
- // Window methods (https://developer.mozilla.org/en/DOM/window)
- "alert", "addEventListener", "atob", "back", "blur", "btoa",
- "captureEvents", "clearInterval", "clearTimeout", "close", "confirm",
- "disableExternalCapture", "dispatchEvent", "dump",
- "enableExternalCapture", "escape", "find", "focus", "forward",
- "GeckoActiveXObject", "getAttention", "getAttentionWithCycleCount",
- "getComputedStyle", "getSelection", "home", "maximize", "minimize",
- "moveBy", "moveTo", "open", "openDialog", "postMessage", "print",
- "prompt", "QueryInterface", "releaseEvents", "removeEventListener",
- "resizeBy", "resizeTo", "restore", "routeEvent", "scroll", "scrollBy",
- "scrollByLines", "scrollByPages", "scrollTo", "setInterval",
- "setResizeable", "setTimeout", "showModalDialog", "sizeToContent",
- "stop", "uuescape", "updateCommands", "XPCNativeWrapper",
- "XPCSafeJSOjbectWrapper",
-
- // Mozilla Window event handlers, same cite
- "onabort", "onbeforeunload", "onchange", "onclick", "onclose",
- "oncontextmenu", "ondragdrop", "onerror", "onfocus", "onhashchange",
- "onkeydown", "onkeypress", "onkeyup", "onload", "onmousedown",
- "onmousemove", "onmouseout", "onmouseover", "onmouseup",
- "onmozorientation", "onpaint", "onreset", "onresize", "onscroll",
- "onselect", "onsubmit", "onunload",
-
- // Safari Web Content Guide
- // http://developer.apple.com/library/safari/#documentation/AppleApplications/Reference/SafariWebContent/SafariWebContent.pdf
- // WebKit Window member data, from WebKit DOM Reference
- // (http://developer.apple.com/safari/library/documentation/AppleApplications/Reference/WebKitDOMRef/DOMWindow_idl/Classes/DOMWindow/index.html)
- // TODO(fredsa) Many, many more functions and member data to add
- "ontouchcancel", "ontouchend", "ontouchmove", "ontouchstart",
- "ongesturestart", "ongesturechange", "ongestureend",
-
- // extra window methods
- "uneval",
-
- // keywords https://developer.mozilla.org/en/New_in_JavaScript_1.7,
- // https://developer.mozilla.org/en/New_in_JavaScript_1.8.1
- "getPrototypeOf", "let", "yield",
-
- // "future reserved words"
- "abstract", "int", "short", "boolean", "interface", "static", "byte",
- "long", "char", "final", "native", "synchronized", "float", "package",
- "throws", "goto", "private", "transient", "implements", "protected",
- "volatile", "double", "public",
-
- // IE methods
- // (http://msdn.microsoft.com/en-us/library/ms535873(VS.85).aspx#)
- "attachEvent", "clientInformation", "clipboardData", "createPopup",
- "dialogHeight", "dialogLeft", "dialogTop", "dialogWidth",
- "onafterprint", "onbeforedeactivate", "onbeforeprint",
- "oncontrolselect", "ondeactivate", "onhelp", "onresizeend",
-
- // Common browser-defined identifiers not defined in ECMAScript
- "event", "external", "Debug", "Enumerator", "Global", "Image",
- "ActiveXObject", "VBArray", "Components",
-
- // Functions commonly defined on Object
- "toString", "getClass", "constructor", "prototype", "valueOf",
-
- // Client-side JavaScript identifiers, which are needed for linkers
- // that don't ensure GWT's window != $wnd, document != $doc, etc.
- // Taken from the Rhino book, pg 715
- "Anchor", "Applet", "Attr", "Canvas", "CanvasGradient",
- "CanvasPattern", "CanvasRenderingContext2D", "CDATASection",
- "CharacterData", "Comment", "CSS2Properties", "CSSRule",
- "CSSStyleSheet", "Document", "DocumentFragment", "DocumentType",
- "DOMException", "DOMImplementation", "DOMParser", "Element", "Event",
- "ExternalInterface", "FlashPlayer", "Form", "Frame", "History",
- "HTMLCollection", "HTMLDocument", "HTMLElement", "IFrame", "Image",
- "Input", "JSObject", "KeyEvent", "Link", "Location", "MimeType",
- "MouseEvent", "Navigator", "Node", "NodeList", "Option", "Plugin",
- "ProcessingInstruction", "Range", "RangeException", "Screen", "Select",
- "Table", "TableCell", "TableRow", "TableSelection", "Text", "TextArea",
- "UIEvent", "Window", "XMLHttpRequest", "XMLSerializer",
- "XPathException", "XPathResult", "XSLTProcessor",
-
- // These keywords trigger the loading of the java-plugin. For the
- // next-generation plugin, this results in starting a new Java process.
- "java", "Packages", "netscape", "sun", "JavaObject", "JavaClass",
- "JavaArray", "JavaMember",
-
- // GWT-defined identifiers
- "$wnd", "$doc", "$entry", "$moduleName", "$moduleBase", "$gwt_version", "$sessionId",
-
- // Identifiers used by JsStackEmulator; later set to obfuscatable
- "$stack", "$stackDepth", "$location",
-
- // TODO: prove why this is necessary or remove it
- "call"
- };
- for (int i = 0; i < commonBuiltins.length; i++) {
- reservedGlobalSymbols.add(commonBuiltins[i]);
- }
- }
-
- /**
- * Returns true if the given string can not be used as property symbol. The check excludes
- * keywords as JavaScript allow keywords as properties.
- * @param s
- * @return true if the given string must not be used as a property.
- */
- public static boolean isReservedPropertySymbol(String s) {
- return reservedPropertySymbols.contains(s);
- }
-
- private static void initReservedPropertySymbols() {
- // TODO(floitsch): fill in reserved property symbols.
- reservedPropertySymbols.add("__PROTO__");
- reservedPropertySymbols.add("prototype");
- }
-
- private JsReservedIdentifiers() {
- }
-}
diff --git a/compiler/java/com/google/dart/compiler/backend/js/JsSourceGenerationVisitor.java b/compiler/java/com/google/dart/compiler/backend/js/JsSourceGenerationVisitor.java
deleted file mode 100644
index ebb836a7228..00000000000
--- a/compiler/java/com/google/dart/compiler/backend/js/JsSourceGenerationVisitor.java
+++ /dev/null
@@ -1,39 +0,0 @@
-// 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.
-
-package com.google.dart.compiler.backend.js;
-
-import com.google.dart.compiler.backend.js.ast.JsBlock;
-import com.google.dart.compiler.backend.js.ast.JsContext;
-import com.google.dart.compiler.backend.js.ast.JsProgram;
-import com.google.dart.compiler.backend.js.ast.JsProgramFragment;
-import com.google.dart.compiler.util.TextOutput;
-
-/**
- * Generates JavaScript source from an AST.
- */
-public class JsSourceGenerationVisitor extends JsToStringGenerationVisitor {
-
- public JsSourceGenerationVisitor(TextOutput out) {
- super(out);
- }
-
- @Override
- public boolean visit(JsProgram x, JsContext ctx) {
- // Descend naturally.
- return true;
- }
-
- @Override
- public boolean visit(JsProgramFragment x, JsContext ctx) {
- // Descend naturally.
- return true;
- }
-
- @Override
- public boolean visit(JsBlock x, JsContext ctx) {
- printJsBlock(x, false, true);
- return false;
- }
-}
diff --git a/compiler/java/com/google/dart/compiler/backend/js/JsToStringGenerationVisitor.java b/compiler/java/com/google/dart/compiler/backend/js/JsToStringGenerationVisitor.java
deleted file mode 100644
index ed0666c9d97..00000000000
--- a/compiler/java/com/google/dart/compiler/backend/js/JsToStringGenerationVisitor.java
+++ /dev/null
@@ -1,1354 +0,0 @@
-// 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.
-
-package com.google.dart.compiler.backend.js;
-
-import com.google.common.collect.Lists;
-import com.google.dart.compiler.backend.js.ast.HasName;
-import com.google.dart.compiler.backend.js.ast.JsArrayAccess;
-import com.google.dart.compiler.backend.js.ast.JsArrayLiteral;
-import com.google.dart.compiler.backend.js.ast.JsBinaryOperation;
-import com.google.dart.compiler.backend.js.ast.JsBinaryOperator;
-import com.google.dart.compiler.backend.js.ast.JsBlock;
-import com.google.dart.compiler.backend.js.ast.JsBooleanLiteral;
-import com.google.dart.compiler.backend.js.ast.JsBreak;
-import com.google.dart.compiler.backend.js.ast.JsCase;
-import com.google.dart.compiler.backend.js.ast.JsCatch;
-import com.google.dart.compiler.backend.js.ast.JsConditional;
-import com.google.dart.compiler.backend.js.ast.JsContext;
-import com.google.dart.compiler.backend.js.ast.JsContinue;
-import com.google.dart.compiler.backend.js.ast.JsDebugger;
-import com.google.dart.compiler.backend.js.ast.JsDefault;
-import com.google.dart.compiler.backend.js.ast.JsDoWhile;
-import com.google.dart.compiler.backend.js.ast.JsEmpty;
-import com.google.dart.compiler.backend.js.ast.JsExprStmt;
-import com.google.dart.compiler.backend.js.ast.JsExpression;
-import com.google.dart.compiler.backend.js.ast.JsFor;
-import com.google.dart.compiler.backend.js.ast.JsForIn;
-import com.google.dart.compiler.backend.js.ast.JsFunction;
-import com.google.dart.compiler.backend.js.ast.JsIf;
-import com.google.dart.compiler.backend.js.ast.JsInvocation;
-import com.google.dart.compiler.backend.js.ast.JsLabel;
-import com.google.dart.compiler.backend.js.ast.JsName;
-import com.google.dart.compiler.backend.js.ast.JsNameRef;
-import com.google.dart.compiler.backend.js.ast.JsNew;
-import com.google.dart.compiler.backend.js.ast.JsNullLiteral;
-import com.google.dart.compiler.backend.js.ast.JsNumberLiteral;
-import com.google.dart.compiler.backend.js.ast.JsObjectLiteral;
-import com.google.dart.compiler.backend.js.ast.JsOperator;
-import com.google.dart.compiler.backend.js.ast.JsParameter;
-import com.google.dart.compiler.backend.js.ast.JsPostfixOperation;
-import com.google.dart.compiler.backend.js.ast.JsPrefixOperation;
-import com.google.dart.compiler.backend.js.ast.JsProgram;
-import com.google.dart.compiler.backend.js.ast.JsProgramFragment;
-import com.google.dart.compiler.backend.js.ast.JsPropertyInitializer;
-import com.google.dart.compiler.backend.js.ast.JsRegExp;
-import com.google.dart.compiler.backend.js.ast.JsReturn;
-import com.google.dart.compiler.backend.js.ast.JsStatement;
-import com.google.dart.compiler.backend.js.ast.JsStringLiteral;
-import com.google.dart.compiler.backend.js.ast.JsSwitch;
-import com.google.dart.compiler.backend.js.ast.JsThisRef;
-import com.google.dart.compiler.backend.js.ast.JsThrow;
-import com.google.dart.compiler.backend.js.ast.JsTry;
-import com.google.dart.compiler.backend.js.ast.JsUnaryOperator;
-import com.google.dart.compiler.backend.js.ast.JsVars;
-import com.google.dart.compiler.backend.js.ast.JsVisitable;
-import com.google.dart.compiler.backend.js.ast.JsVisitor;
-import com.google.dart.compiler.backend.js.ast.JsWhile;
-import com.google.dart.compiler.backend.js.ast.JsVars.JsVar;
-import com.google.dart.compiler.common.HasSourceInfo;
-import com.google.dart.compiler.util.TextOutput;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-import java.util.regex.Pattern;
-
-/**
- * Produces text output from a JavaScript AST.
- */
-public class JsToStringGenerationVisitor extends JsVisitor {
-
- private static final char[] CHARS_BREAK = "break".toCharArray();
- private static final char[] CHARS_CASE = "case".toCharArray();
- private static final char[] CHARS_CATCH = "catch".toCharArray();
- private static final char[] CHARS_CONTINUE = "continue".toCharArray();
- private static final char[] CHARS_DEBUGGER = "debugger".toCharArray();
- private static final char[] CHARS_DEFAULT = "default".toCharArray();
- private static final char[] CHARS_DO = "do".toCharArray();
- private static final char[] CHARS_ELSE = "else".toCharArray();
- private static final char[] CHARS_FALSE = "false".toCharArray();
- private static final char[] CHARS_FINALLY = "finally".toCharArray();
- private static final char[] CHARS_FOR = "for".toCharArray();
- private static final char[] CHARS_FUNCTION = "function".toCharArray();
- private static final char[] CHARS_IF = "if".toCharArray();
- private static final char[] CHARS_IN = "in".toCharArray();
- private static final char[] CHARS_NEW = "new".toCharArray();
- private static final char[] CHARS_NULL = "null".toCharArray();
- private static final char[] CHARS_RETURN = "return".toCharArray();
- private static final char[] CHARS_SWITCH = "switch".toCharArray();
- private static final char[] CHARS_THIS = "this".toCharArray();
- private static final char[] CHARS_THROW = "throw".toCharArray();
- private static final char[] CHARS_TRUE = "true".toCharArray();
- private static final char[] CHARS_TRY = "try".toCharArray();
- private static final char[] CHARS_VAR = "var".toCharArray();
- private static final char[] CHARS_WHILE = "while".toCharArray();
- private static final char[] HEX_DIGITS = {
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
-
- /**
- * How many lines of code to print inside of a JsBlock when printing terse.
- */
- private static final int JSBLOCK_LINES_TO_PRINT = 3;
-
- /**
- * A variable name is valid if it contains only letters, numbers, _, $ and
- * does not begin with a number. There are actually other valid variable
- * names, such as ones that contain escaped Unicode characters, but we
- * surround those names with quotes in property initializers to be safe.
- */
- private static final Pattern VALID_NAME_PATTERN = Pattern.compile("[a-zA-Z_$][\\w$]*");
-
- public static String javaScriptString(String value) {
- return javaScriptString(value, false);
- }
-
- /**
- * Generate JavaScript code that evaluates to the supplied string. Adapted
- * from {@link ScriptRuntime#escapeString(String)}
- * . The difference is that we quote with either " or ' depending on
- * which one is used less inside the string.
- */
- public static String javaScriptString(String value, boolean forceDoubleQuote) {
- char[] chars = value.toCharArray();
- final int n = chars.length;
- int quoteCount = 0;
- int aposCount = 0;
- for (int i = 0; i < n; ++i) {
- switch (chars[i]) {
- case '"':
- ++quoteCount;
- break;
- case '\'':
- ++aposCount;
- break;
- }
- }
-
- StringBuffer result = new StringBuffer(value.length() + 16);
-
- char quoteChar = (quoteCount < aposCount || forceDoubleQuote) ? '"' : '\'';
- result.append(quoteChar);
-
- for (int i = 0; i < n; ++i) {
- char c = chars[i];
-
- if (' ' <= c && c <= '~' && c != quoteChar && c != '\\') {
- // an ordinary print character (like C isprint())
- result.append(c);
- continue;
- }
-
- int escape = -1;
- switch (c) {
- case '\b':
- escape = 'b';
- break;
- case '\f':
- escape = 'f';
- break;
- case '\n':
- escape = 'n';
- break;
- case '\r':
- escape = 'r';
- break;
- case '\t':
- escape = 't';
- break;
- case '"':
- escape = '"';
- break; // only reach here if == quoteChar
- case '\'':
- escape = '\'';
- break; // only reach here if == quoteChar
- case '\\':
- escape = '\\';
- break;
- }
-
- if (escape >= 0) {
- // an \escaped sort of character
- result.append('\\');
- result.append((char) escape);
- } else {
- /*
- * Emit characters from 0 to 31 that don't have a single character
- * escape sequence in octal where possible. This saves one or two
- * characters compared to the hexadecimal format '\xXX'.
- *
- * These short octal sequences may only be used at the end of the string
- * or where the following character is a non-digit. Otherwise, the
- * following character would be incorrectly interpreted as belonging to
- * the sequence.
- */
- if (c < ' ' && (i == n - 1 || chars[i + 1] < '0' || chars[i + 1] > '9')) {
- result.append('\\');
- if (c > 0x7) {
- result.append((char) ('0' + (0x7 & (c >> 3))));
- }
- result.append((char) ('0' + (0x7 & c)));
- } else {
- int hexSize;
- if (c < 256) {
- // 2-digit hex
- result.append("\\x");
- hexSize = 2;
- } else {
- // Unicode.
- result.append("\\u");
- hexSize = 4;
- }
- // append hexadecimal form of ch left-padded with 0
- for (int shift = (hexSize - 1) * 4; shift >= 0; shift -= 4) {
- int digit = 0xf & (c >> shift);
- result.append(HEX_DIGITS[digit]);
- }
- }
- }
- }
- result.append(quoteChar);
- escapeClosingTags(result);
- String resultString = result.toString();
- return resultString;
- }
-
- /**
- * Escapes any closing XML tags embedded in str, which could
- * potentially cause a parse failure in a browser, for example, embedding a
- * closing <script> tag.
- *
- * @param str an unescaped literal; May be null
- */
- private static void escapeClosingTags(StringBuffer str) {
- if (str == null) {
- return;
- }
-
- int index = 0;
-
- while ((index = str.indexOf("", index)) != -1) {
- str.insert(index + 1, '\\');
- }
- }
-
- protected boolean needSemi = true;
-
- /**
- * "Global" blocks are either the global block of a fragment, or a block
- * nested directly within some other global block. This definition matters
- * because the statements designated by statementEnds and statementStarts are
- * those that appear directly within these global blocks.
- */
- private Set globalBlocks = new HashSet();
- private final TextOutput p;
- private ArrayList statementEnds = new ArrayList();
- private ArrayList