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.common.collect.ImmutableMap;
import com.google.javascript.jscomp.deps.ModuleLoader; import com.google.javascript.jscomp.deps.ModuleLoader;
import com.google.javascript.jscomp.parsing.Config; 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.parsing.parser.trees.Comment;
import com.google.javascript.jscomp.type.ReverseAbstractInterpreter; import com.google.javascript.jscomp.type.ReverseAbstractInterpreter;
import com.google.javascript.rhino.ErrorReporter; import com.google.javascript.rhino.ErrorReporter;
Expand Down Expand Up @@ -396,14 +397,9 @@ boolean isNormalizedObfuscated() {


abstract CompilerOptions getOptions(); abstract CompilerOptions getOptions();


/** abstract FeatureSet getFeatureSet();
* 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 void setLanguageMode(CompilerOptions.LanguageMode mode); abstract void setFeatureSet(FeatureSet fs);


// TODO(bashir) It would be good to extract a single dumb data object with // 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 // 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 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.InputId;
import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.Token; import com.google.javascript.rhino.Token;
Expand Down Expand Up @@ -357,7 +357,7 @@ public void validateExpression(Node n) {
} }


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


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


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


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


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


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


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


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


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


private void validateParameters(Node n) { private void validateParameters(Node n) {
validateNodeType(Token.PARAM_LIST, 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()) { for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (c.isRest()) { if (c.isRest()) {
if (c.getNext() != null) { if (c.getNext() != null) {
Expand All @@ -783,6 +768,7 @@ private void validateParametersEs6(Node n) {
} }


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


Expand Down Expand Up @@ -810,6 +796,7 @@ private void validateCall(Node n) {
* @param n * @param n
*/ */
private void validateRest(Token contextType, Node n) { private void validateRest(Token contextType, Node n) {
validateFeature(Feature.REST_PARAMETERS, n);
validateNodeType(Token.REST, n); validateNodeType(Token.REST, n);
validateChildCount(n); validateChildCount(n);
validateLHS(contextType, n.getFirstChild()); 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) { private void validateArrayPattern(Token type, Node n) {
validateFeature(Feature.DESTRUCTURING, n);
validateNodeType(Token.ARRAY_PATTERN, n); validateNodeType(Token.ARRAY_PATTERN, n);
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
// When the array pattern is a direct child of a var/let/const node, // 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) { private void validateObjectPattern(Token type, Node n) {
validateFeature(Feature.DESTRUCTURING, n);
validateNodeType(Token.OBJECT_PATTERN, n); validateNodeType(Token.OBJECT_PATTERN, n);
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
// When the object pattern is a direct child of a var/let/const node, // 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); validateNodeType(Token.STRING_KEY, n);
validateObjectLiteralKeyName(n); validateObjectLiteralKeyName(n);


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


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


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


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


private void validateNamespace(Node n, boolean isAmbient) { private void validateNamespace(Node n, boolean isAmbient) {
validateEs6TypedFeature("namespace", n); validateFeature(Feature.NAMESPACE_DECLARATION, n);
validateNodeType(Token.NAMESPACE, n); validateNodeType(Token.NAMESPACE, n);
validateChildCount(n); validateChildCount(n);
validateNamespaceName(n.getFirstChild()); 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) { private void validateFeature(Feature feature, Node n) {
if (!isEs6OrHigher()) { if (!compiler.getFeatureSet().contains(feature)) {
violation("Feature '" + feature + "' is only allowed in ES6 mode.", n); violation("AST should not contain " + feature, 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);
} }
} }
} }
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.deps.SortedDependencies.MissingProvideException;
import com.google.javascript.jscomp.parsing.Config; import com.google.javascript.jscomp.parsing.Config;
import com.google.javascript.jscomp.parsing.ParserRunner; 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.parsing.parser.trees.Comment;
import com.google.javascript.jscomp.type.ChainableReverseAbstractInterpreter; import com.google.javascript.jscomp.type.ChainableReverseAbstractInterpreter;
import com.google.javascript.jscomp.type.ClosureReverseAbstractInterpreter; 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 // Used for debugging; to see the compiled code between passes
private String lastJsSource = null; private String lastJsSource = null;


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


private final Map<InputId, CompilerInput> inputsById = new ConcurrentHashMap<>(); 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) { public void initOptions(CompilerOptions options) {
this.options = options; this.options = options;
this.languageMode = options.getLanguageIn(); this.setFeatureSet(options.getLanguageIn().toFeatureSet());
if (errorManager == null) { if (errorManager == null) {
if (this.outStream == null) { if (this.outStream == null) {
setErrorManager( setErrorManager(
Expand Down Expand Up @@ -468,8 +467,7 @@ protected void reconcileOptionsWithGuards() {
CheckLevel.WARNING); CheckLevel.WARNING);
} }


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


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


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


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


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


@Override @Override
boolean areNodesEqualForInlining(Node n1, Node n2) { boolean areNodesEqualForInlining(Node n1, Node n2) {
if (options.shouldAmbiguateProperties() || if (options.shouldAmbiguateProperties() || options.shouldDisambiguateProperties()) {
options.shouldDisambiguateProperties()) {
// The type based optimizations require that type information is preserved // The type based optimizations require that type information is preserved
// during other optimizations. // during other optimizations.
return n1.isEquivalentToTyped(n2); 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 // TODO(johnlenz): we shouldn't need to check both isExternExportsEnabled and
// externExportsPath. // externExportsPath.
if (options.sourceMapOutputPath != null || if (options.sourceMapOutputPath != null
options.isExternExportsEnabled() || || options.isExternExportsEnabled()
options.externExportsPath != null || || options.externExportsPath != null
!options.replaceStringsFunctionDescriptions.isEmpty()) { || !options.replaceStringsFunctionDescriptions.isEmpty()) {


// Annotate the nodes in the tree with information from the // Annotate the nodes in the tree with information from the
// input file. This information is used to construct the SourceMap. // 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); 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) { private void processNewScript(JsAst ast, Node originalRoot) {
languageMode = options.getLanguageIn(); setFeatureSet(options.getLanguageIn().toFeatureSet());


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


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

0 comments on commit 30beedc

Please sign in to comment.