Skip to content

Commit

Permalink
Make ProcessClosurePrimitives work under both ES6 and ES5
Browse files Browse the repository at this point in the history
Added Es6CompilerTestCase for passes that should work under both modes
-------------
Created by MOE: http://code.google.com/p/moe-java
MOE_MIGRATED_REVID=99065192
  • Loading branch information
Dominator008 authored and blickly committed Jul 24, 2015
1 parent 3d04abe commit 9070007
Show file tree
Hide file tree
Showing 4 changed files with 210 additions and 73 deletions.
6 changes: 6 additions & 0 deletions src/com/google/javascript/jscomp/NodeTraversal.java
Expand Up @@ -773,6 +773,12 @@ boolean inGlobalScope() {
return getScopeDepth() <= 1;
}

// Not dual of inGlobalScope, because of block scoping.
// They both return false in an inner block at top level.
boolean inFunction() {
return getCfgRoot().isFunction();
}

int getScopeDepth() {
return scopes.size() + scopeRoots.size();
}
Expand Down
10 changes: 5 additions & 5 deletions src/com/google/javascript/jscomp/ProcessClosurePrimitives.java
Expand Up @@ -312,7 +312,7 @@ public void visit(NodeTraversal t, Node n, Node parent) {
break;

case Token.CLASS:
if (t.inGlobalScope() && !NodeUtil.isClassExpression(n)) {
if (!t.inFunction() && !NodeUtil.isClassExpression(n)) {
String name = n.getFirstChild().getString();
ProvidedName pn = providedNames.get(name);
if (pn != null) {
Expand All @@ -324,7 +324,7 @@ public void visit(NodeTraversal t, Node n, Node parent) {
case Token.FUNCTION:
// If this is a declaration of a provided named function, this is an
// error. Hoisted functions will explode if they're provided.
if (t.inGlobalScope() &&
if (!t.inFunction() &&
!NodeUtil.isFunctionExpression(n)) {
String name = n.getFirstChild().getString();
ProvidedName pn = providedNames.get(name);
Expand All @@ -346,7 +346,7 @@ public void visit(NodeTraversal t, Node n, Node parent) {
}

private boolean validPrimitiveCall(NodeTraversal t, Node n) {
if (!n.getParent().isExprResult() || !t.inGlobalScope()) {
if (!n.getParent().isExprResult() || t.inFunction()) {
compiler.report(t.makeError(n, INVALID_CLOSURE_CALL_ERROR));
return false;
}
Expand Down Expand Up @@ -479,7 +479,7 @@ private void processDefineCall(NodeTraversal t, Node n, Node parent) {
private void handleTypedefDefinition(
NodeTraversal t, Node n) {
JSDocInfo info = n.getFirstChild().getJSDocInfo();
if (t.inGlobalScope() && info != null && info.hasTypedefType()) {
if (!t.inFunction() && info != null && info.hasTypedefType()) {
String name = n.getFirstChild().getQualifiedName();
if (name != null) {
ProvidedName pn = providedNames.get(name);
Expand All @@ -495,7 +495,7 @@ private void handleTypedefDefinition(
*/
private void handleCandidateProvideDefinition(
NodeTraversal t, Node n, Node parent) {
if (t.inGlobalScope()) {
if (!t.inFunction()) {
String name = null;
if (n.isName() && parent.isVar()) {
name = n.getString();
Expand Down
134 changes: 134 additions & 0 deletions test/com/google/javascript/jscomp/Es6CompilerTestCase.java
@@ -0,0 +1,134 @@
/*
* Copyright 2015 The Closure Compiler Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.javascript.jscomp;

import com.google.javascript.jscomp.CompilerOptions.LanguageMode;

/**
* CompilerTestCase for passes that run in both ES6 and ES5 modes.
*
* @author moz@google.com (Michael Zhou)
*/
public abstract class Es6CompilerTestCase extends CompilerTestCase {

/**
* Verifies that the compiler pass's JS output matches the expected output, under
* both ES5 and ES6 modes.
*
* @param js Input
* @param expected Expected JS output
*/
@Override
public void test(String js, String expected) {
setAcceptedLanguage(LanguageMode.ECMASCRIPT6);
super.test(js, expected);
setAcceptedLanguage(LanguageMode.ECMASCRIPT5);
super.test(js, expected);
}

/**
* Verifies that the compiler pass's JS output matches the expected output, under
* a specific language mode.
*
* @param js Input
* @param expected Expected JS output
*/
public void test(String js, String expected, LanguageMode mode) {
setAcceptedLanguage(mode);
super.test(js, expected);
}

/**
* Verifies that the compiler pass's JS output matches the expected output, under
* just ES6. Usually this implies that the input contains ES6 features.
*
* @param js Input
* @param expected Expected JS output
*/
public void testEs6(String js, String expected) {
test(js, expected, LanguageMode.ECMASCRIPT6);
}

/**
* Verifies that the compiler pass's JS output matches the expected output,
* under both ES5 and ES6 modes.
*
* @param moduleInputs Module inputs
* @param expected Expected JS outputs (one per module)
*/
public void testModule(String[] moduleInputs, String[] expected) {
setAcceptedLanguage(LanguageMode.ECMASCRIPT6);
super.test(createModuleStar(moduleInputs), expected, null);
setAcceptedLanguage(LanguageMode.ECMASCRIPT5);
super.test(createModuleStar(moduleInputs), expected, null);
}

/**
* Verifies that the compiler pass's JS output is the same as its input, under
* both ES5 and ES6 modes.
*
* @param js Input and output
*/
@Override
public void testSame(String js) {
setAcceptedLanguage(LanguageMode.ECMASCRIPT6);
super.test(js, js);
setAcceptedLanguage(LanguageMode.ECMASCRIPT5);
super.test(js, js);
}

/**
* Verifies that the compiler generates the given error for the given input,
* under both ES5 and ES6 modes.
*
* @param js Input
* @param error Expected error
*/
@Override
public void testError(String js, DiagnosticType error) {
setAcceptedLanguage(LanguageMode.ECMASCRIPT6);
super.testError(js, error);
setAcceptedLanguage(LanguageMode.ECMASCRIPT5);
super.testError(js, error);
}

/**
* Verifies that the compiler generates the given error for the given input,
* under a specific language mode.
*
* @param js Input
* @param error Expected error
* @param mode Specific language mode
*/
public void testError(String js, DiagnosticType error, LanguageMode mode) {
setAcceptedLanguage(mode);
assertNotNull("Must assert an error", error);
super.test(js, null, error, null);
}

/**
* Verifies that the compiler generates the given error for the given input,
* under just ES6. Usually this implies that the input contains ES6 features.
*
* @param js Input
* @param error Expected error
*/
public void testErrorEs6(String js, DiagnosticType error) {
testError(js, error, LanguageMode.ECMASCRIPT6);
}
}

0 comments on commit 9070007

Please sign in to comment.