Skip to content

Commit

Permalink
Further cleanup for definition & checking of input language feature s…
Browse files Browse the repository at this point in the history
…upport.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=124740265
  • Loading branch information
brad4d authored and blickly committed Jun 13, 2016
1 parent 8cf22e3 commit e29bcdb
Show file tree
Hide file tree
Showing 8 changed files with 176 additions and 90 deletions.
8 changes: 8 additions & 0 deletions src/com/google/javascript/jscomp/Compiler.java
Expand Up @@ -2150,6 +2150,14 @@ Config getParserConfig(ConfigContext context) {
parserConfig = createConfig(Config.LanguageMode.ECMASCRIPT6_TYPED);
externsParserConfig = parserConfig;
break;
case ECMASCRIPT7:
parserConfig = createConfig(Config.LanguageMode.ECMASCRIPT7);
externsParserConfig = parserConfig;
break;
case ECMASCRIPT8:
parserConfig = createConfig(Config.LanguageMode.ECMASCRIPT8);
externsParserConfig = parserConfig;
break;
default:
throw new IllegalStateException("unexpected language mode: "
+ options.getLanguageIn());
Expand Down
2 changes: 1 addition & 1 deletion src/com/google/javascript/jscomp/RhinoErrorReporter.java
Expand Up @@ -168,7 +168,7 @@ private RhinoErrorReporter(AbstractCompiler compiler) {
.put(Pattern.compile("^Octal .*literal.*"), INVALID_OCTAL_LITERAL)

.put(
Pattern.compile("^this language feature is only supported in es6 mode.*"),
Pattern.compile("^this language feature is only supported for ECMASCRIPT6 mode.*"),
ES6_FEATURE)

.put(Pattern.compile("^type syntax is only supported in ES6 typed mode.*"), ES6_TYPED)
Expand Down
48 changes: 42 additions & 6 deletions src/com/google/javascript/jscomp/parsing/Config.java
Expand Up @@ -18,6 +18,7 @@

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.javascript.jscomp.parsing.parser.FeatureSet;

import java.util.Set;

Expand All @@ -29,14 +30,49 @@
*/
public final class Config {

/**
* Level of language strictness required for the input source code.
*/
public enum StrictMode {
STRICT, SLOPPY;
}

/** JavaScript mode */
public enum LanguageMode {
ECMASCRIPT3,
ECMASCRIPT5,
ECMASCRIPT5_STRICT,
ECMASCRIPT6,
ECMASCRIPT6_STRICT,
ECMASCRIPT6_TYPED, // Implies STRICT.

// Note that minimumRequiredFor() relies on these being defined in order from fewest features to
// most features, and _STRICT versions should be supplied after unspecified strictness.
ECMASCRIPT3(FeatureSet.ES3, StrictMode.SLOPPY),
ECMASCRIPT5(FeatureSet.ES5, StrictMode.SLOPPY),
ECMASCRIPT5_STRICT(FeatureSet.ES5, StrictMode.STRICT),
ECMASCRIPT6(FeatureSet.ES6_MODULES, StrictMode.SLOPPY),
ECMASCRIPT6_STRICT(FeatureSet.ES6_MODULES, StrictMode.STRICT),
ECMASCRIPT7(FeatureSet.ES7_MODULES, StrictMode.STRICT),
ECMASCRIPT8(FeatureSet.ES8_MODULES, StrictMode.STRICT),
// TODO(bradfordcsmith): This should be renamed so it doesn't seem tied to es6
ECMASCRIPT6_TYPED(FeatureSet.TYPESCRIPT, StrictMode.STRICT),
;

public final FeatureSet featureSet;
public final StrictMode strictMode;

LanguageMode(FeatureSet featureSet, StrictMode strictMode) {
this.featureSet = featureSet;
this.strictMode = strictMode;
}

/**
* Returns the lowest {@link LanguageMode} that supports the specified feature.
*/
public static LanguageMode minimumRequiredFor(FeatureSet.Feature feature) {
// relies on the LanguageMode enums being in the right order
for (LanguageMode mode : LanguageMode.values()) {
if (mode.featureSet.contains(feature)) {
return mode;
}
}
throw new IllegalStateException("No input language mode supports feature: " + feature);
}
}

/**
Expand Down
79 changes: 41 additions & 38 deletions src/com/google/javascript/jscomp/parsing/IRFactory.java
Expand Up @@ -35,6 +35,7 @@
import com.google.common.collect.Lists;
import com.google.common.collect.UnmodifiableIterator;
import com.google.javascript.jscomp.parsing.Config.LanguageMode;
import com.google.javascript.jscomp.parsing.Config.StrictMode;
import com.google.javascript.jscomp.parsing.parser.FeatureSet;
import com.google.javascript.jscomp.parsing.parser.FeatureSet.Feature;
import com.google.javascript.jscomp.parsing.parser.IdentifierToken;
Expand Down Expand Up @@ -313,6 +314,8 @@ private IRFactory(String sourceString,
case ECMASCRIPT5_STRICT:
case ECMASCRIPT6_STRICT:
case ECMASCRIPT6_TYPED:
case ECMASCRIPT7:
case ECMASCRIPT8:
reservedKeywords = ES5_STRICT_RESERVED_KEYWORDS;
break;
default:
Expand Down Expand Up @@ -995,7 +998,7 @@ Node processArrayLiteral(ArrayLiteralExpressionTree tree) {
}

Node processArrayPattern(ArrayPatternTree tree) {
maybeWarnEs6Feature(tree, Feature.DESTRUCTURING);
maybeWarnForFeature(tree, Feature.DESTRUCTURING);

Node node = newNode(Token.ARRAY_PATTERN);
for (ParseTree child : tree.elements) {
Expand All @@ -1005,7 +1008,7 @@ Node processArrayPattern(ArrayPatternTree tree) {
}

Node processObjectPattern(ObjectPatternTree tree) {
maybeWarnEs6Feature(tree, Feature.DESTRUCTURING);
maybeWarnForFeature(tree, Feature.DESTRUCTURING);

Node node = newNode(Token.OBJECT_PATTERN);
for (ParseTree child : tree.fields) {
Expand Down Expand Up @@ -1150,7 +1153,7 @@ Node processForInLoop(ForInStatementTree loopNode) {
}

Node processForOf(ForOfStatementTree loopNode) {
maybeWarnEs6Feature(loopNode, Feature.FOR_OF);
maybeWarnForFeature(loopNode, Feature.FOR_OF);
Node initializer = transform(loopNode.initializer);
ImmutableSet<Token> invalidInitializers =
ImmutableSet.of(Token.ARRAYLIT, Token.OBJECTLIT);
Expand Down Expand Up @@ -1210,15 +1213,15 @@ Node processFunction(FunctionDeclarationTree functionTree) {
boolean isSignature = (functionTree.functionBody.type == ParseTreeType.EMPTY_STATEMENT);

if (isGenerator) {
maybeWarnEs6Feature(functionTree, Feature.GENERATORS);
maybeWarnForFeature(functionTree, Feature.GENERATORS);
}

if (isMember) {
maybeWarnEs6Feature(functionTree, Feature.MEMBER_DECLARATIONS);
maybeWarnForFeature(functionTree, Feature.MEMBER_DECLARATIONS);
}

if (isArrow) {
maybeWarnEs6Feature(functionTree, Feature.ARROW_FUNCTIONS);
maybeWarnForFeature(functionTree, Feature.ARROW_FUNCTIONS);
}

IdentifierToken name = functionTree.name;
Expand Down Expand Up @@ -1301,23 +1304,23 @@ Node processFormalParameterList(FormalParameterListTree tree) {
}

Node processDefaultParameter(DefaultParameterTree tree) {
maybeWarnEs6Feature(tree, Feature.DEFAULT_PARAMETERS);
maybeWarnForFeature(tree, Feature.DEFAULT_PARAMETERS);
return newNode(Token.DEFAULT_VALUE,
transform(tree.lhs), transform(tree.defaultValue));
}

Node processRestParameter(RestParameterTree tree) {
maybeWarnEs6Feature(tree, Feature.REST_PARAMETERS);
maybeWarnForFeature(tree, Feature.REST_PARAMETERS);

Node assignmentTarget = transformNodeWithInlineJsDoc(tree.assignmentTarget);
if (assignmentTarget.isDestructuringPattern()) {
maybeWarnEs6Feature(tree.assignmentTarget, Feature.DESTRUCTURING);
maybeWarnForFeature(tree.assignmentTarget, Feature.DESTRUCTURING);
}
return newNode(Token.REST, assignmentTarget);
}

Node processSpreadExpression(SpreadExpressionTree tree) {
maybeWarnEs6Feature(tree, Feature.SPREAD_EXPRESSIONS);
maybeWarnForFeature(tree, Feature.SPREAD_EXPRESSIONS);

return newNode(Token.SPREAD, transform(tree.expression));
}
Expand Down Expand Up @@ -1540,20 +1543,20 @@ Node processObjectLiteral(ObjectLiteralExpressionTree objTree) {
node.addChildToBack(key);
}
if (maybeWarn) {
maybeWarnEs6Feature(objTree, Feature.EXTENDED_OBJECT_LITERALS);
maybeWarnForFeature(objTree, Feature.EXTENDED_OBJECT_LITERALS);
}
return node;
}

Node processComputedPropertyDefinition(ComputedPropertyDefinitionTree tree) {
maybeWarnEs6Feature(tree, Feature.COMPUTED_PROPERTIES);
maybeWarnForFeature(tree, Feature.COMPUTED_PROPERTIES);

return newNode(Token.COMPUTED_PROP,
transform(tree.property), transform(tree.value));
}

Node processComputedPropertyMemberVariable(ComputedPropertyMemberVariableTree tree) {
maybeWarnEs6Feature(tree, Feature.COMPUTED_PROPERTIES);
maybeWarnForFeature(tree, Feature.COMPUTED_PROPERTIES);
maybeWarnTypeSyntax(tree, Feature.COMPUTED_PROPERTIES);

Node n = newNode(Token.COMPUTED_PROP, transform(tree.property));
Expand All @@ -1566,7 +1569,7 @@ Node processComputedPropertyMemberVariable(ComputedPropertyMemberVariableTree tr
}

Node processComputedPropertyMethod(ComputedPropertyMethodTree tree) {
maybeWarnEs6Feature(tree, Feature.COMPUTED_PROPERTIES);
maybeWarnForFeature(tree, Feature.COMPUTED_PROPERTIES);

Node n = newNode(Token.COMPUTED_PROP,
transform(tree.property), transform(tree.method));
Expand All @@ -1579,7 +1582,7 @@ Node processComputedPropertyMethod(ComputedPropertyMethodTree tree) {
}

Node processComputedPropertyGetter(ComputedPropertyGetterTree tree) {
maybeWarnEs6Feature(tree, Feature.COMPUTED_PROPERTIES);
maybeWarnForFeature(tree, Feature.COMPUTED_PROPERTIES);

Node key = transform(tree.property);
Node body = transform(tree.body);
Expand All @@ -1592,7 +1595,7 @@ Node processComputedPropertyGetter(ComputedPropertyGetterTree tree) {
}

Node processComputedPropertySetter(ComputedPropertySetterTree tree) {
maybeWarnEs6Feature(tree, Feature.COMPUTED_PROPERTIES);
maybeWarnForFeature(tree, Feature.COMPUTED_PROPERTIES);

Node key = transform(tree.property);
Node body = transform(tree.body);
Expand Down Expand Up @@ -1718,7 +1721,7 @@ private void validateRegExpFlags(LiteralExpressionTree tree, String flags) {
break;
case 'u': case 'y':
Feature feature = flag == 'u' ? Feature.REGEXP_FLAG_U : Feature.REGEXP_FLAG_Y;
maybeWarnEs6Feature(tree, feature);
maybeWarnForFeature(tree, feature);
break;
default:
errorReporter.error(
Expand Down Expand Up @@ -1767,7 +1770,7 @@ Node processStringLiteral(LiteralExpressionTree literalTree) {
}

Node processTemplateLiteral(TemplateLiteralExpressionTree tree) {
maybeWarnEs6Feature(tree, Feature.TEMPLATE_LITERALS);
maybeWarnForFeature(tree, Feature.TEMPLATE_LITERALS);
Node templateLitNode = newNode(Token.TEMPLATELIT);
setSourceInfo(templateLitNode, tree);
Node node = tree.operand == null
Expand Down Expand Up @@ -1931,11 +1934,11 @@ Node processVariableDeclarationList(VariableDeclarationListTree decl) {
Token declType;
switch (decl.declarationType) {
case CONST:
maybeWarnEs6Feature(decl, Feature.CONST_DECLARATIONS);
maybeWarnForFeature(decl, Feature.CONST_DECLARATIONS);
declType = Token.CONST;
break;
case LET:
maybeWarnEs6Feature(decl, Feature.LET_DECLARATIONS);
maybeWarnForFeature(decl, Feature.LET_DECLARATIONS);
declType = Token.LET;
break;
case VAR:
Expand Down Expand Up @@ -2068,7 +2071,7 @@ Node processCommaExpression(CommaExpressionTree tree) {
}

Node processClassDeclaration(ClassDeclarationTree tree) {
maybeWarnEs6Feature(tree, Feature.CLASSES);
maybeWarnForFeature(tree, Feature.CLASSES);

Node name = transformOrEmpty(tree.name, tree);
maybeProcessGenerics(name, tree.generics);
Expand Down Expand Up @@ -2125,12 +2128,12 @@ Node processEnumDeclaration(EnumDeclarationTree tree) {
}

Node processSuper(SuperExpressionTree tree) {
maybeWarnEs6Feature(tree, Feature.SUPER);
maybeWarnForFeature(tree, Feature.SUPER);
return newNode(Token.SUPER);
}

Node processNewTarget(NewTargetExpressionTree tree) {
maybeWarnEs6Feature(tree, Feature.NEW_TARGET);
maybeWarnForFeature(tree, Feature.NEW_TARGET);
return newNode(Token.NEW_TARGET);
}

Expand All @@ -2153,7 +2156,7 @@ Node processYield(YieldExpressionTree tree) {
}

Node processExportDecl(ExportDeclarationTree tree) {
maybeWarnEs6Feature(tree, Feature.MODULES);
maybeWarnForFeature(tree, Feature.MODULES);
Node decls = null;
if (tree.isExportAll) {
Preconditions.checkState(
Expand Down Expand Up @@ -2193,7 +2196,7 @@ Node processExportSpec(ExportSpecifierTree tree) {
}

Node processImportDecl(ImportDeclarationTree tree) {
maybeWarnEs6Feature(tree, Feature.MODULES);
maybeWarnForFeature(tree, Feature.MODULES);

Node firstChild = transformOrEmpty(tree.defaultBindingIdentifier, tree);
Node secondChild = (tree.nameSpaceImportIdentifier != null)
Expand Down Expand Up @@ -2525,11 +2528,15 @@ private Node transformListOrEmpty(
}
}

void maybeWarnEs6Feature(ParseTree node, Feature feature) {
void maybeWarnForFeature(ParseTree node, Feature feature) {
features = features.require(feature);
if (!isEs6Mode()) {
if (!isSupportedForInputLanguageMode(feature)) {

errorReporter.warning(
"this language feature is only supported in es6 mode: " + feature,
"this language feature is only supported for "
+ LanguageMode.minimumRequiredFor(feature)
+ " mode or better: "
+ feature,
sourceName,
lineno(node), charno(node));
}
Expand Down Expand Up @@ -2934,22 +2941,18 @@ String normalizeString(LiteralToken token, boolean templateLiteral) {
return result.toString();
}

boolean isEs6Mode() {
return config.languageMode == LanguageMode.ECMASCRIPT6
|| config.languageMode == LanguageMode.ECMASCRIPT6_STRICT
|| config.languageMode == LanguageMode.ECMASCRIPT6_TYPED;
boolean isSupportedForInputLanguageMode(Feature feature) {
return config.languageMode.featureSet.contains(feature);
}

boolean isEs5OrBetterMode() {
return config.languageMode != LanguageMode.ECMASCRIPT3;
return config.languageMode.featureSet.contains(FeatureSet.ES5);
}

private boolean inStrictContext() {
// TODO(johnlenz): in ECMASCRIPT5/6 is a "mixed" mode and we should track the context
// that we are in, if we want to support it.
return config.languageMode == LanguageMode.ECMASCRIPT5_STRICT
|| config.languageMode == LanguageMode.ECMASCRIPT6_STRICT
|| config.languageMode == LanguageMode.ECMASCRIPT6_TYPED;
return config.languageMode.strictMode == StrictMode.STRICT;
}

double normalizeNumber(LiteralToken token) {
Expand All @@ -2970,7 +2973,7 @@ private boolean inStrictContext() {
case 'b':
case 'B': {
features = features.require(Feature.BINARY_LITERALS);
if (!isEs6Mode()) {
if (!isSupportedForInputLanguageMode(Feature.BINARY_LITERALS)) {
errorReporter.warning(BINARY_NUMBER_LITERAL_WARNING,
sourceName,
lineno(token.location.start), charno(token.location.start));
Expand All @@ -2985,7 +2988,7 @@ private boolean inStrictContext() {
case 'o':
case 'O': {
features = features.require(Feature.OCTAL_LITERALS);
if (!isEs6Mode()) {
if (!isSupportedForInputLanguageMode(Feature.OCTAL_LITERALS)) {
errorReporter.warning(OCTAL_NUMBER_LITERAL_WARNING,
sourceName,
lineno(token.location.start), charno(token.location.start));
Expand Down
4 changes: 4 additions & 0 deletions src/com/google/javascript/jscomp/parsing/ParserRunner.java
Expand Up @@ -200,6 +200,10 @@ private static Mode mode(LanguageMode mode) {
return Mode.ES6_STRICT;
case ECMASCRIPT6_TYPED:
return Mode.ES6_TYPED;
case ECMASCRIPT7:
return Mode.ES7;
case ECMASCRIPT8:
return Mode.ES8;
default:
throw new IllegalStateException("unexpected language mode: " + mode);
}
Expand Down

0 comments on commit e29bcdb

Please sign in to comment.