Skip to content

Commit

Permalink
Internally, keep track of the FeatureSet (i.e. which features are pre…
Browse files Browse the repository at this point in the history
…sent in the tree) rather than the LanguageMode. This allows us to indicate, for instance, "The tree currently contains no ES6 modules but does contain other ES6 features"

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=157153453
  • Loading branch information
tbreisacher authored and blickly committed May 25, 2017
1 parent 17fd49b commit 30beedc
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 89 deletions.
10 changes: 3 additions & 7 deletions src/com/google/javascript/jscomp/AbstractCompiler.java
Expand Up @@ -22,6 +22,7 @@
import com.google.common.collect.ImmutableMap;
import com.google.javascript.jscomp.deps.ModuleLoader;
import com.google.javascript.jscomp.parsing.Config;
import com.google.javascript.jscomp.parsing.parser.FeatureSet;
import com.google.javascript.jscomp.parsing.parser.trees.Comment;
import com.google.javascript.jscomp.type.ReverseAbstractInterpreter;
import com.google.javascript.rhino.ErrorReporter;
Expand Down Expand Up @@ -396,14 +397,9 @@ boolean isNormalizedObfuscated() {

abstract CompilerOptions getOptions();

/**
* The language mode of the current root node. This will match the languageIn
* field of the {@link CompilerOptions} before transpilation happens, and
* match the languageOut field after transpilation.
*/
abstract CompilerOptions.LanguageMode getLanguageMode();
abstract FeatureSet getFeatureSet();

abstract void setLanguageMode(CompilerOptions.LanguageMode mode);
abstract void setFeatureSet(FeatureSet fs);

// TODO(bashir) It would be good to extract a single dumb data object with
// only getters and setters that keeps all global information we keep for a
Expand Down
65 changes: 20 additions & 45 deletions src/com/google/javascript/jscomp/AstValidator.java
Expand Up @@ -18,7 +18,7 @@

import static com.google.common.base.Strings.isNullOrEmpty;

import com.google.javascript.jscomp.CompilerOptions.LanguageMode;
import com.google.javascript.jscomp.parsing.parser.FeatureSet.Feature;
import com.google.javascript.rhino.InputId;
import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.Token;
Expand Down Expand Up @@ -357,7 +357,7 @@ public void validateExpression(Node n) {
}

private void validateYield(Node n) {
validateEs6Feature("yield", n);
validateFeature(Feature.GENERATORS, n);
validateNodeType(Token.YIELD, n);
validateChildCountIn(n, 0, 1);
if (n.hasChildren()) {
Expand All @@ -366,7 +366,7 @@ private void validateYield(Node n) {
}

private void validateAwait(Node n) {
validateEs6Feature("async function", n);
validateFeature(Feature.ASYNC_FUNCTIONS, n);
validateNodeType(Token.AWAIT, n);
validateWithinAsyncFunction(n);
}
Expand All @@ -379,7 +379,7 @@ private void validateWithinAsyncFunction(Node n) {
}

private void validateImport(Node n) {
validateEs6Feature("import statement", n);
validateFeature(Feature.MODULES, n);
validateNodeType(Token.IMPORT, n);
validateChildCount(n);

Expand Down Expand Up @@ -457,15 +457,15 @@ private void validateExportSpecifier(Node n) {
}

private void validateTaggedTemplateLit(Node n) {
validateEs6Feature("template literal", n);
validateFeature(Feature.TEMPLATE_LITERALS, n);
validateNodeType(Token.TAGGED_TEMPLATELIT, n);
validateChildCount(n);
validateExpression(n.getFirstChild());
validateTemplateLit(n.getLastChild());
}

private void validateTemplateLit(Node n) {
validateEs6Feature("template literal", n);
validateFeature(Feature.TEMPLATE_LITERALS, n);
validateNodeType(Token.TEMPLATELIT, n);
if (!n.hasChildren()) {
return;
Expand All @@ -490,7 +490,7 @@ private void validateTemplateLitSub(Node n) {
}

private void validateInterface(Node n) {
validateEs6TypedFeature("interface", n);
validateFeature(Feature.INTERFACE, n);
validateNodeType(Token.INTERFACE, n);
validateChildCount(n);
Node name = n.getFirstChild();
Expand Down Expand Up @@ -566,7 +566,7 @@ private void validateClass(Node n) {
}

private void validateClassHelper(Node n, boolean isAmbient) {
validateEs6Feature("classes", n);
validateFeature(Feature.CLASSES, n);
validateNodeType(Token.CLASS, n);
validateChildCount(n);

Expand Down Expand Up @@ -724,7 +724,7 @@ private void validateFunctionExpressionHelper(Node n, boolean isAmbient) {
Node name = n.getFirstChild();
Node body = n.getLastChild();
if (n.isArrowFunction()) {
validateEs6Feature("arrow functions", n);
validateFeature(Feature.ARROW_FUNCTIONS, n);
validateEmptyName(name);
if (body.isNormalBlock()) {
validateBlock(body);
Expand All @@ -747,21 +747,6 @@ private void validateFunctionBody(Node n, boolean noBlock) {

private void validateParameters(Node n) {
validateNodeType(Token.PARAM_LIST, n);

if (isEs6OrHigher()) {
validateParametersEs6(n);
} else {
validateParametersEs5(n);
}
}

private void validateParametersEs5(Node n) {
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
validateName(c);
}
}

private void validateParametersEs6(Node n) {
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (c.isRest()) {
if (c.getNext() != null) {
Expand All @@ -783,6 +768,7 @@ private void validateParametersEs6(Node n) {
}

private void validateDefaultValue(Token type, Node n) {
validateFeature(Feature.DEFAULT_PARAMETERS, n);
validateAssignmentExpression(n);
Node lhs = n.getFirstChild();

Expand Down Expand Up @@ -810,6 +796,7 @@ private void validateCall(Node n) {
* @param n
*/
private void validateRest(Token contextType, Node n) {
validateFeature(Feature.REST_PARAMETERS, n);
validateNodeType(Token.REST, n);
validateChildCount(n);
validateLHS(contextType, n.getFirstChild());
Expand Down Expand Up @@ -886,6 +873,7 @@ private void validateLHS(Token contextType, Node n) {
}

private void validateArrayPattern(Token type, Node n) {
validateFeature(Feature.DESTRUCTURING, n);
validateNodeType(Token.ARRAY_PATTERN, n);
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
// When the array pattern is a direct child of a var/let/const node,
Expand All @@ -905,6 +893,7 @@ private void validateArrayPattern(Token type, Node n) {
}

private void validateObjectPattern(Token type, Node n) {
validateFeature(Feature.DESTRUCTURING, n);
validateNodeType(Token.OBJECT_PATTERN, n);
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
// When the object pattern is a direct child of a var/let/const node,
Expand Down Expand Up @@ -1253,11 +1242,7 @@ private void validateObjectLitStringKey(Node n) {
validateNodeType(Token.STRING_KEY, n);
validateObjectLiteralKeyName(n);

if (isEs6OrHigher()) {
validateChildCountIn(n, 0, 1);
} else {
validateChildCount(n, 1);
}
validateChildCountIn(n, 0, 1);

if (n.hasOneChild()) {
validateExpression(n.getFirstChild());
Expand Down Expand Up @@ -1342,13 +1327,13 @@ private void validateNamedType(Node n) {
}

private void validateTypeAlias(Node n) {
validateEs6TypedFeature("type alias", n);
validateFeature(Feature.TYPE_ALIAS, n);
validateNodeType(Token.TYPE_ALIAS, n);
validateChildCount(n);
}

private void validateAmbientDeclaration(Node n) {
validateEs6TypedFeature("ambient declaration", n);
validateFeature(Feature.AMBIENT_DECLARATION, n);
validateNodeType(Token.DECLARE, n);
validateAmbientDeclarationHelper(n.getFirstChild());
}
Expand Down Expand Up @@ -1384,7 +1369,7 @@ private void validateAmbientDeclarationHelper(Node n) {
}

private void validateNamespace(Node n, boolean isAmbient) {
validateEs6TypedFeature("namespace", n);
validateFeature(Feature.NAMESPACE_DECLARATION, n);
validateNodeType(Token.NAMESPACE, n);
validateChildCount(n);
validateNamespaceName(n.getFirstChild());
Expand Down Expand Up @@ -1476,19 +1461,9 @@ private void validateMaximumChildCount(Node n, int i) {
}
}

private void validateEs6Feature(String feature, Node n) {
if (!isEs6OrHigher()) {
violation("Feature '" + feature + "' is only allowed in ES6 mode.", n);
}
}

private boolean isEs6OrHigher() {
return compiler.getLanguageMode().isEs6OrHigher();
}

private void validateEs6TypedFeature(String feature, Node n) {
if (!compiler.getLanguageMode().equals(LanguageMode.ECMASCRIPT6_TYPED)) {
violation("Feature '" + feature + "' is only allowed in ES6 Typed mode.", n);
private void validateFeature(Feature feature, Node n) {
if (!compiler.getFeatureSet().contains(feature)) {
violation("AST should not contain " + feature, n);
}
}
}
54 changes: 27 additions & 27 deletions src/com/google/javascript/jscomp/Compiler.java
Expand Up @@ -37,6 +37,7 @@
import com.google.javascript.jscomp.deps.SortedDependencies.MissingProvideException;
import com.google.javascript.jscomp.parsing.Config;
import com.google.javascript.jscomp.parsing.ParserRunner;
import com.google.javascript.jscomp.parsing.parser.FeatureSet;
import com.google.javascript.jscomp.parsing.parser.trees.Comment;
import com.google.javascript.jscomp.type.ChainableReverseAbstractInterpreter;
import com.google.javascript.jscomp.type.ClosureReverseAbstractInterpreter;
Expand Down Expand Up @@ -159,9 +160,7 @@ public class Compiler extends AbstractCompiler implements ErrorHandler, SourceFi
// Used for debugging; to see the compiled code between passes
private String lastJsSource = null;

/** @see #getLanguageMode() */
private CompilerOptions.LanguageMode languageMode =
CompilerOptions.LanguageMode.ECMASCRIPT3;
private FeatureSet featureSet;

private final Map<InputId, CompilerInput> inputsById = new ConcurrentHashMap<>();

Expand Down Expand Up @@ -345,7 +344,7 @@ void setOriginalSourcesLoader(ExternalSourceLoader originalSourcesLoader) {
*/
public void initOptions(CompilerOptions options) {
this.options = options;
this.languageMode = options.getLanguageIn();
this.setFeatureSet(options.getLanguageIn().toFeatureSet());
if (errorManager == null) {
if (this.outStream == null) {
setErrorManager(
Expand Down Expand Up @@ -468,8 +467,7 @@ protected void reconcileOptionsWithGuards() {
CheckLevel.WARNING);
}

if (options.checkGlobalThisLevel.isOn() &&
!options.disables(DiagnosticGroups.GLOBAL_THIS)) {
if (options.checkGlobalThisLevel.isOn() && !options.disables(DiagnosticGroups.GLOBAL_THIS)) {
options.setWarningLevel(
DiagnosticGroups.GLOBAL_THIS,
options.checkGlobalThisLevel);
Expand All @@ -486,10 +484,8 @@ protected void reconcileOptionsWithGuards() {
// checks the externs file for validity. If you don't want to warn
// about missing variable declarations, we shut that specific
// error off.
if (!options.checkSymbols &&
!options.enables(DiagnosticGroups.CHECK_VARIABLES)) {
options.setWarningLevel(
DiagnosticGroups.CHECK_VARIABLES, CheckLevel.OFF);
if (!options.checkSymbols && !options.enables(DiagnosticGroups.CHECK_VARIABLES)) {
options.setWarningLevel(DiagnosticGroups.CHECK_VARIABLES, CheckLevel.OFF);
}
}

Expand Down Expand Up @@ -1312,13 +1308,13 @@ public Node getRoot() {
}

@Override
CompilerOptions.LanguageMode getLanguageMode() {
return languageMode;
FeatureSet getFeatureSet() {
return featureSet;
}

@Override
void setLanguageMode(CompilerOptions.LanguageMode mode) {
languageMode = mode;
void setFeatureSet(FeatureSet fs) {
featureSet = fs;
}

/**
Expand Down Expand Up @@ -1349,8 +1345,7 @@ public String get() {

@Override
boolean areNodesEqualForInlining(Node n1, Node n2) {
if (options.shouldAmbiguateProperties() ||
options.shouldDisambiguateProperties()) {
if (options.shouldAmbiguateProperties() || options.shouldDisambiguateProperties()) {
// The type based optimizations require that type information is preserved
// during other optimizations.
return n1.isEquivalentToTyped(n2);
Expand Down Expand Up @@ -1863,10 +1858,10 @@ Node parseInputs() {

// TODO(johnlenz): we shouldn't need to check both isExternExportsEnabled and
// externExportsPath.
if (options.sourceMapOutputPath != null ||
options.isExternExportsEnabled() ||
options.externExportsPath != null ||
!options.replaceStringsFunctionDescriptions.isEmpty()) {
if (options.sourceMapOutputPath != null
|| options.isExternExportsEnabled()
|| options.externExportsPath != null
|| !options.replaceStringsFunctionDescriptions.isEmpty()) {

// Annotate the nodes in the tree with information from the
// input file. This information is used to construct the SourceMap.
Expand Down Expand Up @@ -2092,6 +2087,8 @@ void processEs6Modules(List<CompilerInput> inputsToProcess, boolean forceRewrite
}
new ProcessEs6Modules(this).processFile(root, forceRewrite);
}

setFeatureSet(featureSet.withoutModules());
}

/**
Expand Down Expand Up @@ -3103,7 +3100,7 @@ public void addNewScript(JsAst ast) {
}

private void processNewScript(JsAst ast, Node originalRoot) {
languageMode = options.getLanguageIn();
setFeatureSet(options.getLanguageIn().toFeatureSet());

Node js = ast.getAstRoot(this);
checkNotNull(js);
Expand Down Expand Up @@ -3287,6 +3284,7 @@ private static class CompilerState implements Serializable {
private final Node externAndJsRoot;
private final Node externsRoot;
private final Node jsRoot;
private final FeatureSet featureSet;
private final List<CompilerInput> externs;
private final List<CompilerInput> inputs;
private final Map<InputId, CompilerInput> inputsById;
Expand All @@ -3309,12 +3307,13 @@ private static class CompilerState implements Serializable {

CompilerState(Compiler compiler) {
this.externsRoot = checkNotNull(compiler.externsRoot);
this.jsRoot = checkNotNull(compiler.jsRoot);
this.externAndJsRoot = checkNotNull(compiler.externAndJsRoot);
this.typeRegistry = compiler.typeRegistry;
this.externs = compiler.externs;
this.inputs = checkNotNull(compiler.inputs);
this.inputsById = checkNotNull(compiler.inputsById);
this.jsRoot = checkNotNull(compiler.jsRoot);
this.externAndJsRoot = checkNotNull(compiler.externAndJsRoot);
this.featureSet = checkNotNull(compiler.featureSet);
this.typeRegistry = compiler.typeRegistry;
this.externs = compiler.externs;
this.inputs = checkNotNull(compiler.inputs);
this.inputsById = checkNotNull(compiler.inputsById);
this.mostRecentTypeChecker = compiler.mostRecentTypechecker;
this.synthesizedExternsInput = compiler.synthesizedExternsInput;
this.synthesizedExternsInputAtEnd = compiler.synthesizedExternsInputAtEnd;
Expand Down Expand Up @@ -3360,6 +3359,7 @@ public CompilerState call() throws Exception {
return compilerState;
}
});
featureSet = compilerState.featureSet;
externs = compilerState.externs;
inputs = compilerState.inputs;
inputsById.clear();
Expand Down

0 comments on commit 30beedc

Please sign in to comment.