/*
* Copyright (C) 2010 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package lombok.ast.grammar;
import java.util.List;
import lombok.ast.ArrayAccess;
import lombok.ast.ArrayCreation;
import lombok.ast.ArrayDimension;
import lombok.ast.ArrayInitializer;
import lombok.ast.BinaryExpression;
import lombok.ast.Cast;
import lombok.ast.ClassLiteral;
import lombok.ast.ConstructorInvocation;
import lombok.ast.DanglingNodes;
import lombok.ast.Expression;
import lombok.ast.Identifier;
import lombok.ast.InlineIfExpression;
import lombok.ast.InstanceOf;
import lombok.ast.MethodInvocation;
import lombok.ast.Node;
import lombok.ast.Position;
import lombok.ast.Select;
import lombok.ast.Super;
import lombok.ast.This;
import lombok.ast.TypeReference;
import lombok.ast.TypeReferencePart;
import lombok.ast.UnaryExpression;
import lombok.ast.UnaryOperator;
import lombok.ast.VariableReference;
public class ExpressionsActions extends SourceActions {
public ExpressionsActions(Source source) {
super(source);
}
public Node createLeftAssociativeBinaryExpression(
org.parboiled.Node<Node> head,
List<org.parboiled.Node<Node>> operatorsNodes,
List<String> operators,
List<org.parboiled.Node<Node>> tail) {
Node currentLeft = head.getValue();
for (int i = 0; i < operators.size(); i++) {
currentLeft = new BinaryExpression()
.rawLeft(currentLeft)
.rawRight(tail.get(i).getValue()).rawOperator(operators.get(i));
source.registerStructure(currentLeft, operatorsNodes.get(i));
positionSpan(currentLeft, head, tail.get(i));
}
return currentLeft;
}
public Node createAssignmentExpression(Node lhs, String operator, Node rhs) {
if (rhs == null && operator == null) return lhs;
return posify(new BinaryExpression().rawLeft(lhs).rawRight(rhs).rawOperator(operator));
}
public Node createInlineIfExpression(
Node head, org.parboiled.Node<Node> operator1Node,
org.parboiled.Node<Node> operator2Node, Node tail1, Node tail2) {
if (tail1 == null || tail2 == null) return head;
InlineIfExpression result = new InlineIfExpression()
.rawCondition(head).rawIfTrue(tail1).rawIfFalse(tail2);
source.registerStructure(result, operator1Node);
source.registerStructure(result, operator2Node);
return posify(result);
}
public Node createUnaryPrefixExpression(Node operand, org.parboiled.Node<Node> opNode, String symbol) {
if (opNode == null) return operand;
if (!opNode.getChildren().isEmpty() && "cast".equals(opNode.getChildren().get(0).getLabel())) {
return posify(new Cast().rawOperand(operand).rawTypeReference(opNode.getValue()));
} else {
if (symbol != null) symbol = symbol.trim();
if (!symbol.isEmpty()) {
UnaryOperator op = UnaryOperator.fromSymbol(symbol, false);
UnaryExpression expr = new UnaryExpression().rawOperand(operand);
if (op != null) expr.astOperator(op);
return posify(expr);
}
}
return operand;
}
public Node createUnaryPrefixExpressions(
org.parboiled.Node<Node> operand,
List<org.parboiled.Node<Node>> operators,
List<String> operatorTexts) {
if (operators == null || operators.isEmpty()) return operand.getValue();
Node current = operand.getValue();
for (int i = operators.size() - 1; i >= 0; i--) {
org.parboiled.Node<Node> operator = operators.get(i);
Node prev = current;
if (operator == null) continue;
if (!operator.getChildren().isEmpty() && "cast".equals(operator.getChildren().get(0).getLabel())) {
current = new Cast().rawOperand(current).rawTypeReference(operator.getValue());
} else {
String symbol = operatorTexts.get(i);
if (symbol == null) continue;
symbol = symbol.trim();
if (symbol.isEmpty()) continue;
UnaryOperator op = UnaryOperator.fromSymbol(symbol, false);
UnaryExpression expr = new UnaryExpression().rawOperand(current);
if (op != null) expr.astOperator(op);
current = expr;
}
if (prev != null && !prev.getPosition().isUnplaced() && prev != current && current != null) {
positionSpan(current, operator, operand);
}
}
return current;
}
public Node createUnaryPostfixExpression(Node operand, List<org.parboiled.Node<Node>> nodes, List<String> operators) {
if (operators == null) return operand;
Node current = operand;
for (int i = 0; i < operators.size(); i++) {
String op = operators.get(i);
if (op == null) continue;
op = op.trim();
Node prev = current;
if (op.equals("++")) current = new UnaryExpression().rawOperand(current).astOperator(UnaryOperator.POSTFIX_INCREMENT);
else if (op.equals("--")) current = new UnaryExpression().rawOperand(current).astOperator(UnaryOperator.POSTFIX_DECREMENT);
org.parboiled.Node<Node> p = nodes.get(i);
if (prev != null && !prev.getPosition().isUnplaced() && p != null) {
current.setPosition(new Position(prev.getPosition().getStart(), p.getEndIndex()));
}
}
return current;
}
public Node createInstanceOfExpression(Node operand, Node type) {
if (type == null) return operand;
return posify(new InstanceOf().rawObjectReference(operand).rawTypeReference(type));
}
public Node createQualifiedConstructorInvocation(
Node constructorTypeArgs,
org.parboiled.Node<Node> identifier, org.parboiled.Node<Node> classTypeArgs,
Node methodArguments, Node classBody) {
TypeReferencePart classTypeArgs0;
boolean classTypeArgsCorrect = false;
Node identifierNode = identifier == null ? null : identifier.getValue();
if (classTypeArgs != null && classTypeArgs.getValue() instanceof TypeReferencePart) {
classTypeArgs0 = (TypeReferencePart)classTypeArgs.getValue();
classTypeArgsCorrect = true;
} else {
classTypeArgs0 = new TypeReferencePart();
if (identifierNode != null) {
classTypeArgs0.setPosition(identifierNode.getPosition());
}
}
TypeReference typeReference = new TypeReference().astParts().addToEnd(
classTypeArgs0.astIdentifier(createIdentifierIfNeeded(identifierNode, currentPos())));
if (!classTypeArgsCorrect) {
if (identifier != null && identifier.getValue() != null) {
typeReference.setPosition(identifier.getValue().getPosition());
}
} else {
positionSpan(typeReference, identifier, classTypeArgs);
}
ConstructorInvocation constructorInvocation = new ConstructorInvocation()
.rawTypeReference(typeReference)
.rawAnonymousClassBody(classBody);
if (constructorTypeArgs instanceof TemporaryNode.TypeArguments) {
for (Node arg : ((TemporaryNode.TypeArguments)constructorTypeArgs).arguments) {
constructorInvocation.rawConstructorTypeArguments().addToEnd(arg);
}
}
if (methodArguments instanceof TemporaryNode.MethodArguments) {
for (Node arg : ((TemporaryNode.MethodArguments)methodArguments).arguments) {
constructorInvocation.rawArguments().addToEnd(arg);
}
}
return posify(constructorInvocation);
}
public Node createChainOfQualifiedConstructorInvocations(
org.parboiled.Node<Node> qualifier,
List<org.parboiled.Node<Node>> constructorInvocations) {
Node current = qualifier.getValue();
if (constructorInvocations == null) return current;
for (org.parboiled.Node<Node> pNode : constructorInvocations) {
Node n = pNode.getValue();
if (n instanceof ConstructorInvocation) {
current = ((ConstructorInvocation)n).rawQualifier(current);
positionSpan(current, qualifier, pNode);
} else DanglingNodes.addDanglingNode(current, n);
}
return current;
}
public Node createMethodInvocationOperation(org.parboiled.Node<Node> dot, Node typeArguments, Node name, Node arguments) {
MethodInvocation mi = new MethodInvocation().astName(createIdentifierIfNeeded(name, currentPos()));
if (typeArguments instanceof TemporaryNode.TypeArguments) {
for (Node arg : ((TemporaryNode.TypeArguments)typeArguments).arguments) {
mi.rawMethodTypeArguments().addToEnd(arg);
}
} else DanglingNodes.addDanglingNode(mi, typeArguments);
if (arguments instanceof TemporaryNode.MethodArguments) {
for (Node arg : ((TemporaryNode.MethodArguments)arguments).arguments) {
mi.rawArguments().addToEnd(arg);
}
} else DanglingNodes.addDanglingNode(mi, arguments);
source.registerStructure(mi, dot);
return posify(mi);
}
public Node createSelectOperation(Node identifier) {
return posify(new Select().astIdentifier(createIdentifierIfNeeded(identifier, currentPos())));
}
public Node createArrayAccessOperation(Node indexExpression) {
return posify(new ArrayAccess().rawIndexExpression(indexExpression));
}
public Node createLevel1Expression(org.parboiled.Node<Node> operand, List<org.parboiled.Node<Node>> operations) {
Node current = operand.getValue();
if (operations == null) return current;
for (org.parboiled.Node<Node> pNode : operations) {
Node o = pNode.getValue();
if (o instanceof ArrayAccess) {
current = ((ArrayAccess)o).rawOperand(current);
} else if (o instanceof MethodInvocation) {
current = ((MethodInvocation)o).rawOperand(current);
} else if (o instanceof Select) {
current = ((Select)o).rawOperand(current);
} else {
DanglingNodes.addDanglingNode(current, o);
}
positionSpan(o, operand, pNode);
}
return current;
}
public Node createPrimary(Node identifier, Node methodArguments) {
Identifier id = createIdentifierIfNeeded(identifier, currentPos());
if (methodArguments instanceof TemporaryNode.MethodArguments) {
MethodInvocation invoke = new MethodInvocation().astName(id);
for (Node arg : ((TemporaryNode.MethodArguments)methodArguments).arguments) {
invoke.rawArguments().addToEnd(arg);
}
return posify(invoke);
} else {
VariableReference ref = new VariableReference().astIdentifier(id);
DanglingNodes.addDanglingNode(ref, methodArguments);
return posify(ref);
}
}
public Node createUnqualifiedConstructorInvocation(Node constructorTypeArgs, Node type, Node args, Node anonymousClassBody) {
ConstructorInvocation result = new ConstructorInvocation()
.rawTypeReference(type)
.rawAnonymousClassBody(anonymousClassBody);
if (constructorTypeArgs instanceof TemporaryNode.TypeArguments) {
for (Node arg : ((TemporaryNode.TypeArguments)constructorTypeArgs).arguments) {
result.rawConstructorTypeArguments().addToEnd(arg);
}
}
if (args instanceof TemporaryNode.MethodArguments) {
for (Node arg : ((TemporaryNode.MethodArguments)args).arguments) {
result.rawArguments().addToEnd(arg);
}
} else DanglingNodes.addDanglingNode(result, args);
return posify(result);
}
public Node createArrayInitializerExpression(Node head, List<Node> tail) {
ArrayInitializer ai = new ArrayInitializer();
if (head != null) ai.rawExpressions().addToEnd(head);
if (tail != null) for (Node n : tail) if (n != null) ai.rawExpressions().addToEnd(n);
return posify(ai);
}
public Node createDimension(Node dimExpr, org.parboiled.Node<Node> arrayOpen) {
ArrayDimension d = new ArrayDimension().rawDimension(dimExpr);
if (arrayOpen != null) d.setPosition(new Position(arrayOpen.getStartIndex(), currentPos()));
return d;
}
public Node createArrayCreationExpression(Node type, List<Node> dimensions, Node initializer) {
ArrayCreation ac = new ArrayCreation().rawComponentTypeReference(type).rawInitializer(initializer);
if (dimensions != null) for (Node d : dimensions) {
if (d != null) ac.rawDimensions().addToEnd(d);
}
return posify(ac);
}
public Node addParens(Node v) {
if (v instanceof Expression) {
((Expression)v).astParensPositions().add(new Position(startPos(), currentPos()));
}
return v;
}
public Node createThisOrSuperOrClass(org.parboiled.Node<Node> dot, String text, Node qualifier) {
Node result;
if ("super".equals(text)) result = new Super().rawQualifier(qualifier);
else if ("class".equals(text)) result = new ClassLiteral().rawTypeReference(qualifier);
else result = new This().rawQualifier(qualifier);
if (dot != null) source.registerStructure(result, dot);
return posify(result);
}
public boolean checkIfLevel1ExprIsValidForAssignment(Node node) {
return node instanceof VariableReference || node instanceof Select || node instanceof ArrayAccess;
}
public boolean checkIfMethodOrConstructorInvocation(Node node) {
return node instanceof MethodInvocation || node instanceof ConstructorInvocation;
}
public boolean typeIsAlsoLegalAsExpression(Node type) {
if (!(type instanceof TypeReference)) return true;
TypeReference tr = (TypeReference)type;
if (tr.astArrayDimensions() > 0) return false;
if (tr.isPrimitive() || tr.isVoid()) return false;
for (Node part : tr.rawParts()) {
if (part instanceof TypeReferencePart) {
if (!((TypeReferencePart)part).rawTypeArguments().isEmpty()) return false;
}
}
return true;
}
}