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.ParseTree;
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.PropertyNameAssignmentTree;
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.UnaryExpressionTree;
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.VariableDeclarationTree;
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 MEMBER_EXPRESSION:
case MEMBER_LOOKUP_EXPRESSION:
case POSTFIX_EXPRESSION:
case UPDATE_EXPRESSION:
ParseTree nearest = findNearestNode(tree);
if (nearest.type == ParseTreeType.PAREN_EXPRESSION) {
return false;
Expand Down Expand Up @@ -749,8 +750,8 @@ private static ParseTree findNearestNode(ParseTree tree) {
case MEMBER_LOOKUP_EXPRESSION:
tree = tree.asMemberLookupExpression().operand;
continue;
case POSTFIX_EXPRESSION:
tree = tree.asPostfixExpression().operand;
case UPDATE_EXPRESSION:
tree = tree.asUpdateExpression().operand;
continue;
default:
return tree;
Expand Down Expand Up @@ -1921,25 +1922,20 @@ Node processUnaryExpression(UnaryExpressionTree exprNode) {
msg,
sourceName,
operand.getLineno(), 0);
} else if (type == Token.INC || type == Token.DEC) {
return createIncrDecrNode(type, false, operand);
}

return newNode(type, operand);
}
}

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

private Node createIncrDecrNode(Token type, boolean postfix, Node operand) {
private Node createUpdateNode(Token type, boolean postfix, Node operand) {
if (!operand.isValidAssignmentTarget()) {
errorReporter.error(
SimpleFormat.format("Invalid %s %s operand.",
Expand Down Expand Up @@ -2712,8 +2708,8 @@ public Node process(ParseTree node) {
return processComputedPropertySetter(node.asComputedPropertySetter());
case RETURN_STATEMENT:
return processReturnStatement(node.asReturnStatement());
case POSTFIX_EXPRESSION:
return processPostfixExpression(node.asPostfixExpression());
case UPDATE_EXPRESSION:
return processUpdateExpression(node.asUpdateExpression());
case PROGRAM:
return processAstRoot(node.asProgram());
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) {
case PLUS_PLUS:
return Token.INC;
Expand All @@ -3163,11 +3159,6 @@ static Token transformUnaryTokenType(TokenType token) {
case TYPEOF:
return Token.TYPEOF;

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

case 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.ParseTree;
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.PropertyNameAssignmentTree;
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.UnaryExpressionTree;
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.VariableDeclarationTree;
import com.google.javascript.jscomp.parsing.parser.trees.VariableStatementTree;
Expand Down Expand Up @@ -3223,7 +3223,7 @@ private ParseTree parseUnaryExpression() {
} else if (peekAwaitExpression()) {
return parseAwaitExpression();
} else {
return parsePostfixExpression();
return parseUpdateExpression();
}
}

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

// 11.3 Postfix Expression
private ParseTree parsePostfixExpression() {
private ParseTree parseUpdateExpression() {
SourcePosition start = getTreeStartLocation();
ParseTree operand = parseLeftHandSideExpression();
while (peekPostfixOperator()) {
if (peekUpdateOperator()) {
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() {
if (peekImplicitSemiColon()) {
return false;
}
private boolean peekUpdateOperator() {
switch (peekType()) {
case PLUS_PLUS:
case MINUS_MINUS:
return true;
default:
return false;
case PLUS_PLUS:
case MINUS_MINUS:
return true;
default:
return false;
}
}

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

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

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