Skip to content

Commit

Permalink
Rework parser to better match the spec for UnaryExpression and Update…
Browse files Browse the repository at this point in the history
…Expression.

Relevant productions are:

UnaryExpression :=
    UpdateExpression
    { delete | void | typeof | + | - | ~ | ! } UnaryExpression

UpdateExpression :=
    { ++ | -- } UnaryExpression
    LeftHandSideExpression [no LineTerminator here] { ++ | -- }

This is preparatory work for adding ExponentiationExpression (** operator).

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=127963105
  • Loading branch information
brad4d authored and blickly committed Jul 21, 2016
1 parent 7505969 commit 5eb8043
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 78 deletions.
37 changes: 14 additions & 23 deletions src/com/google/javascript/jscomp/parsing/IRFactory.java
Expand Up @@ -109,7 +109,6 @@
import com.google.javascript.jscomp.parsing.parser.trees.ParenExpressionTree; import com.google.javascript.jscomp.parsing.parser.trees.ParenExpressionTree;
import com.google.javascript.jscomp.parsing.parser.trees.ParseTree; import com.google.javascript.jscomp.parsing.parser.trees.ParseTree;
import com.google.javascript.jscomp.parsing.parser.trees.ParseTreeType; import com.google.javascript.jscomp.parsing.parser.trees.ParseTreeType;
import com.google.javascript.jscomp.parsing.parser.trees.PostfixExpressionTree;
import com.google.javascript.jscomp.parsing.parser.trees.ProgramTree; import com.google.javascript.jscomp.parsing.parser.trees.ProgramTree;
import com.google.javascript.jscomp.parsing.parser.trees.PropertyNameAssignmentTree; import com.google.javascript.jscomp.parsing.parser.trees.PropertyNameAssignmentTree;
import com.google.javascript.jscomp.parsing.parser.trees.RecordTypeTree; import com.google.javascript.jscomp.parsing.parser.trees.RecordTypeTree;
Expand All @@ -131,6 +130,8 @@
import com.google.javascript.jscomp.parsing.parser.trees.TypedParameterTree; import com.google.javascript.jscomp.parsing.parser.trees.TypedParameterTree;
import com.google.javascript.jscomp.parsing.parser.trees.UnaryExpressionTree; import com.google.javascript.jscomp.parsing.parser.trees.UnaryExpressionTree;
import com.google.javascript.jscomp.parsing.parser.trees.UnionTypeTree; import com.google.javascript.jscomp.parsing.parser.trees.UnionTypeTree;
import com.google.javascript.jscomp.parsing.parser.trees.UpdateExpressionTree;
import com.google.javascript.jscomp.parsing.parser.trees.UpdateExpressionTree.OperatorPosition;
import com.google.javascript.jscomp.parsing.parser.trees.VariableDeclarationListTree; import com.google.javascript.jscomp.parsing.parser.trees.VariableDeclarationListTree;
import com.google.javascript.jscomp.parsing.parser.trees.VariableDeclarationTree; import com.google.javascript.jscomp.parsing.parser.trees.VariableDeclarationTree;
import com.google.javascript.jscomp.parsing.parser.trees.VariableStatementTree; import com.google.javascript.jscomp.parsing.parser.trees.VariableStatementTree;
Expand Down Expand Up @@ -717,7 +718,7 @@ private boolean shouldAttachJSDocHere(ParseTree tree) {
case BINARY_OPERATOR: case BINARY_OPERATOR:
case MEMBER_EXPRESSION: case MEMBER_EXPRESSION:
case MEMBER_LOOKUP_EXPRESSION: case MEMBER_LOOKUP_EXPRESSION:
case POSTFIX_EXPRESSION: case UPDATE_EXPRESSION:
ParseTree nearest = findNearestNode(tree); ParseTree nearest = findNearestNode(tree);
if (nearest.type == ParseTreeType.PAREN_EXPRESSION) { if (nearest.type == ParseTreeType.PAREN_EXPRESSION) {
return false; return false;
Expand Down Expand Up @@ -749,8 +750,8 @@ private static ParseTree findNearestNode(ParseTree tree) {
case MEMBER_LOOKUP_EXPRESSION: case MEMBER_LOOKUP_EXPRESSION:
tree = tree.asMemberLookupExpression().operand; tree = tree.asMemberLookupExpression().operand;
continue; continue;
case POSTFIX_EXPRESSION: case UPDATE_EXPRESSION:
tree = tree.asPostfixExpression().operand; tree = tree.asUpdateExpression().operand;
continue; continue;
default: default:
return tree; return tree;
Expand Down Expand Up @@ -1921,25 +1922,20 @@ Node processUnaryExpression(UnaryExpressionTree exprNode) {
msg, msg,
sourceName, sourceName,
operand.getLineno(), 0); operand.getLineno(), 0);
} else if (type == Token.INC || type == Token.DEC) {
return createIncrDecrNode(type, false, operand);
} }


return newNode(type, operand); return newNode(type, operand);
} }
} }


Node processPostfixExpression(PostfixExpressionTree exprNode) { Node processUpdateExpression(UpdateExpressionTree updateExpr) {
Token type = transformPostfixTokenType(exprNode.operator.type); Token type = transformUpdateTokenType(updateExpr.operator.type);
Node operand = transform(exprNode.operand); Node operand = transform(updateExpr.operand);
if (type == Token.INC || type == Token.DEC) { return createUpdateNode(
return createIncrDecrNode(type, true, operand); type, updateExpr.operatorPosition == OperatorPosition.POSTFIX, operand);
}
Node node = newNode(type, operand);
return node;
} }


private Node createIncrDecrNode(Token type, boolean postfix, Node operand) { private Node createUpdateNode(Token type, boolean postfix, Node operand) {
if (!operand.isValidAssignmentTarget()) { if (!operand.isValidAssignmentTarget()) {
errorReporter.error( errorReporter.error(
SimpleFormat.format("Invalid %s %s operand.", SimpleFormat.format("Invalid %s %s operand.",
Expand Down Expand Up @@ -2712,8 +2708,8 @@ public Node process(ParseTree node) {
return processComputedPropertySetter(node.asComputedPropertySetter()); return processComputedPropertySetter(node.asComputedPropertySetter());
case RETURN_STATEMENT: case RETURN_STATEMENT:
return processReturnStatement(node.asReturnStatement()); return processReturnStatement(node.asReturnStatement());
case POSTFIX_EXPRESSION: case UPDATE_EXPRESSION:
return processPostfixExpression(node.asPostfixExpression()); return processUpdateExpression(node.asUpdateExpression());
case PROGRAM: case PROGRAM:
return processAstRoot(node.asProgram()); return processAstRoot(node.asProgram());
case LITERAL_EXPRESSION: // STRING, NUMBER, TRUE, FALSE, NULL, REGEXP case LITERAL_EXPRESSION: // STRING, NUMBER, TRUE, FALSE, NULL, REGEXP
Expand Down Expand Up @@ -3136,7 +3132,7 @@ static Token transformBooleanTokenType(TokenType token) {
} }
} }


static Token transformPostfixTokenType(TokenType token) { static Token transformUpdateTokenType(TokenType token) {
switch (token) { switch (token) {
case PLUS_PLUS: case PLUS_PLUS:
return Token.INC; return Token.INC;
Expand All @@ -3163,11 +3159,6 @@ static Token transformUnaryTokenType(TokenType token) {
case TYPEOF: case TYPEOF:
return Token.TYPEOF; return Token.TYPEOF;


case PLUS_PLUS:
return Token.INC;
case MINUS_MINUS:
return Token.DEC;

case VOID: case VOID:
return Token.VOID; return Token.VOID;


Expand Down
40 changes: 21 additions & 19 deletions src/com/google/javascript/jscomp/parsing/parser/Parser.java
Expand Up @@ -87,7 +87,6 @@
import com.google.javascript.jscomp.parsing.parser.trees.ParenExpressionTree; import com.google.javascript.jscomp.parsing.parser.trees.ParenExpressionTree;
import com.google.javascript.jscomp.parsing.parser.trees.ParseTree; import com.google.javascript.jscomp.parsing.parser.trees.ParseTree;
import com.google.javascript.jscomp.parsing.parser.trees.ParseTreeType; import com.google.javascript.jscomp.parsing.parser.trees.ParseTreeType;
import com.google.javascript.jscomp.parsing.parser.trees.PostfixExpressionTree;
import com.google.javascript.jscomp.parsing.parser.trees.ProgramTree; import com.google.javascript.jscomp.parsing.parser.trees.ProgramTree;
import com.google.javascript.jscomp.parsing.parser.trees.PropertyNameAssignmentTree; import com.google.javascript.jscomp.parsing.parser.trees.PropertyNameAssignmentTree;
import com.google.javascript.jscomp.parsing.parser.trees.RecordTypeTree; import com.google.javascript.jscomp.parsing.parser.trees.RecordTypeTree;
Expand All @@ -109,6 +108,7 @@
import com.google.javascript.jscomp.parsing.parser.trees.TypedParameterTree; import com.google.javascript.jscomp.parsing.parser.trees.TypedParameterTree;
import com.google.javascript.jscomp.parsing.parser.trees.UnaryExpressionTree; import com.google.javascript.jscomp.parsing.parser.trees.UnaryExpressionTree;
import com.google.javascript.jscomp.parsing.parser.trees.UnionTypeTree; import com.google.javascript.jscomp.parsing.parser.trees.UnionTypeTree;
import com.google.javascript.jscomp.parsing.parser.trees.UpdateExpressionTree;
import com.google.javascript.jscomp.parsing.parser.trees.VariableDeclarationListTree; import com.google.javascript.jscomp.parsing.parser.trees.VariableDeclarationListTree;
import com.google.javascript.jscomp.parsing.parser.trees.VariableDeclarationTree; import com.google.javascript.jscomp.parsing.parser.trees.VariableDeclarationTree;
import com.google.javascript.jscomp.parsing.parser.trees.VariableStatementTree; import com.google.javascript.jscomp.parsing.parser.trees.VariableStatementTree;
Expand Down Expand Up @@ -3223,7 +3223,7 @@ private ParseTree parseUnaryExpression() {
} else if (peekAwaitExpression()) { } else if (peekAwaitExpression()) {
return parseAwaitExpression(); return parseAwaitExpression();
} else { } else {
return parsePostfixExpression(); return parseUpdateExpression();
} }
} }


Expand All @@ -3232,8 +3232,6 @@ private boolean peekUnaryOperator() {
case DELETE: case DELETE:
case VOID: case VOID:
case TYPEOF: case TYPEOF:
case PLUS_PLUS:
case MINUS_MINUS:
case PLUS: case PLUS:
case MINUS: case MINUS:
case TILDE: case TILDE:
Expand All @@ -3259,27 +3257,31 @@ private ParseTree parseAwaitExpression() {
return new AwaitExpressionTree(getTreeLocation(start), expression); return new AwaitExpressionTree(getTreeLocation(start), expression);
} }


// 11.3 Postfix Expression private ParseTree parseUpdateExpression() {
private ParseTree parsePostfixExpression() {
SourcePosition start = getTreeStartLocation(); SourcePosition start = getTreeStartLocation();
ParseTree operand = parseLeftHandSideExpression(); if (peekUpdateOperator()) {
while (peekPostfixOperator()) {
Token operator = nextToken(); Token operator = nextToken();
operand = new PostfixExpressionTree(getTreeLocation(start), operand, operator); ParseTree operand = parseUnaryExpression();
return UpdateExpressionTree.prefix(getTreeLocation(start), operator, operand);
} else {
ParseTree lhs = parseLeftHandSideExpression();
if (peekUpdateOperator() && !peekImplicitSemiColon()) {
// newline not allowed before an update operator.
Token operator = nextToken();
return UpdateExpressionTree.postfix(getTreeLocation(start), operator, lhs);
} else {
return lhs;
}
} }
return operand;
} }


private boolean peekPostfixOperator() { private boolean peekUpdateOperator() {
if (peekImplicitSemiColon()) {
return false;
}
switch (peekType()) { switch (peekType()) {
case PLUS_PLUS: case PLUS_PLUS:
case MINUS_MINUS: case MINUS_MINUS:
return true; return true;
default: default:
return false; return false;
} }
} }


Expand Down
Expand Up @@ -114,7 +114,6 @@ public ObjectLiteralExpressionTree asObjectLiteralExpression() {
return (ObjectLiteralExpressionTree) this; } return (ObjectLiteralExpressionTree) this; }
public ObjectPatternTree asObjectPattern() { return (ObjectPatternTree) this; } public ObjectPatternTree asObjectPattern() { return (ObjectPatternTree) this; }
public ParenExpressionTree asParenExpression() { return (ParenExpressionTree) this; } public ParenExpressionTree asParenExpression() { return (ParenExpressionTree) this; }
public PostfixExpressionTree asPostfixExpression() { return (PostfixExpressionTree) this; }
public ProgramTree asProgram() { return (ProgramTree) this; } public ProgramTree asProgram() { return (ProgramTree) this; }
public PropertyNameAssignmentTree asPropertyNameAssignment() { public PropertyNameAssignmentTree asPropertyNameAssignment() {
return (PropertyNameAssignmentTree) this; } return (PropertyNameAssignmentTree) this; }
Expand Down Expand Up @@ -170,6 +169,11 @@ public NamespaceDeclarationTree asNamespaceDeclaration() {
public NewTargetExpressionTree asNewTargetExpression() { public NewTargetExpressionTree asNewTargetExpression() {
return (NewTargetExpressionTree) this; return (NewTargetExpressionTree) this;
} }

public UpdateExpressionTree asUpdateExpression() {
return (UpdateExpressionTree) this;
}

public boolean isPattern() { public boolean isPattern() {
ParseTree parseTree = this; ParseTree parseTree = this;
while (parseTree.type == ParseTreeType.PAREN_EXPRESSION) { while (parseTree.type == ParseTreeType.PAREN_EXPRESSION) {
Expand Down
Expand Up @@ -68,7 +68,7 @@ public enum ParseTreeType {
BINARY_OPERATOR, BINARY_OPERATOR,
CONDITIONAL_EXPRESSION, CONDITIONAL_EXPRESSION,
UNARY_EXPRESSION, UNARY_EXPRESSION,
POSTFIX_EXPRESSION, UPDATE_EXPRESSION,
MEMBER_EXPRESSION, MEMBER_EXPRESSION,
NEW_EXPRESSION, NEW_EXPRESSION,
ARGUMENT_LIST, ARGUMENT_LIST,
Expand Down

This file was deleted.

@@ -0,0 +1,63 @@
/*
* Copyright 2016 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.parsing.parser.trees;

import com.google.javascript.jscomp.parsing.parser.Token;
import com.google.javascript.jscomp.parsing.parser.util.SourceRange;

/**
* Represents UpdateExpression productions from the spec.
*
* <pre><code>
* UpdateExpression :=
* { ++ | -- } UnaryExpression
* LeftHandSideExpression [no LineTerminator here] { ++ | -- }
* </code></pre>
*/
public class UpdateExpressionTree extends ParseTree {

/**
* Position of the operator relative to the operand.
*/
public enum OperatorPosition {
PREFIX,
POSTFIX;
}

public final Token operator;
public final OperatorPosition operatorPosition;
public final ParseTree operand;

public UpdateExpressionTree(
SourceRange location, Token operator, OperatorPosition operatorPosition, ParseTree operand) {
super(ParseTreeType.UPDATE_EXPRESSION, location);

this.operator = operator;
this.operatorPosition = operatorPosition;
this.operand = operand;
}

public static UpdateExpressionTree prefix(
SourceRange location, Token operator, ParseTree operand) {
return new UpdateExpressionTree(location, operator, OperatorPosition.PREFIX, operand);
}

public static UpdateExpressionTree postfix(
SourceRange location, Token operator, ParseTree operand) {
return new UpdateExpressionTree(location, operator, OperatorPosition.POSTFIX, operand);
}
}

0 comments on commit 5eb8043

Please sign in to comment.