diff --git a/src/com/google/javascript/jscomp/parsing/IRFactory.java b/src/com/google/javascript/jscomp/parsing/IRFactory.java index b1075a5302a..92bfc22a31e 100644 --- a/src/com/google/javascript/jscomp/parsing/IRFactory.java +++ b/src/com/google/javascript/jscomp/parsing/IRFactory.java @@ -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; @@ -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; @@ -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; @@ -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; @@ -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.", @@ -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 @@ -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; @@ -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; diff --git a/src/com/google/javascript/jscomp/parsing/parser/Parser.java b/src/com/google/javascript/jscomp/parsing/parser/Parser.java index 7c897d31c09..d1c21a47079 100644 --- a/src/com/google/javascript/jscomp/parsing/parser/Parser.java +++ b/src/com/google/javascript/jscomp/parsing/parser/Parser.java @@ -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; @@ -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; @@ -3223,7 +3223,7 @@ private ParseTree parseUnaryExpression() { } else if (peekAwaitExpression()) { return parseAwaitExpression(); } else { - return parsePostfixExpression(); + return parseUpdateExpression(); } } @@ -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: @@ -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; } } diff --git a/src/com/google/javascript/jscomp/parsing/parser/trees/ParseTree.java b/src/com/google/javascript/jscomp/parsing/parser/trees/ParseTree.java index 906f3d902a8..2a67f276eed 100644 --- a/src/com/google/javascript/jscomp/parsing/parser/trees/ParseTree.java +++ b/src/com/google/javascript/jscomp/parsing/parser/trees/ParseTree.java @@ -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; } @@ -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) { diff --git a/src/com/google/javascript/jscomp/parsing/parser/trees/ParseTreeType.java b/src/com/google/javascript/jscomp/parsing/parser/trees/ParseTreeType.java index 8f9442f4cd8..df0f115f1df 100644 --- a/src/com/google/javascript/jscomp/parsing/parser/trees/ParseTreeType.java +++ b/src/com/google/javascript/jscomp/parsing/parser/trees/ParseTreeType.java @@ -68,7 +68,7 @@ public enum ParseTreeType { BINARY_OPERATOR, CONDITIONAL_EXPRESSION, UNARY_EXPRESSION, - POSTFIX_EXPRESSION, + UPDATE_EXPRESSION, MEMBER_EXPRESSION, NEW_EXPRESSION, ARGUMENT_LIST, diff --git a/src/com/google/javascript/jscomp/parsing/parser/trees/PostfixExpressionTree.java b/src/com/google/javascript/jscomp/parsing/parser/trees/PostfixExpressionTree.java deleted file mode 100644 index 4bbcae439aa..00000000000 --- a/src/com/google/javascript/jscomp/parsing/parser/trees/PostfixExpressionTree.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2011 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; - -public class PostfixExpressionTree extends ParseTree { - - public final ParseTree operand; - public final Token operator; - - public PostfixExpressionTree(SourceRange location, ParseTree operand, Token operator) { - super(ParseTreeType.POSTFIX_EXPRESSION, location); - - this.operand = operand; - this.operator = operator; - } - -} diff --git a/src/com/google/javascript/jscomp/parsing/parser/trees/UpdateExpressionTree.java b/src/com/google/javascript/jscomp/parsing/parser/trees/UpdateExpressionTree.java new file mode 100644 index 00000000000..cb8a2a419c1 --- /dev/null +++ b/src/com/google/javascript/jscomp/parsing/parser/trees/UpdateExpressionTree.java @@ -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. + * + *

+ * UpdateExpression :=
+ *     { ++ | -- } UnaryExpression
+ *     LeftHandSideExpression [no LineTerminator here] { ++ | -- }
+ * 
+ */ +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); + } +}