/*
* Copyright (c) 2014, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.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.eclipse.org/legal/epl-v10.html
*
* 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.dart.java2dart.engine;
import com.google.common.collect.Lists;
import com.google.dart.engine.ast.AstNode;
import com.google.dart.engine.ast.ClassDeclaration;
import com.google.dart.engine.ast.CompilationUnit;
import com.google.dart.engine.ast.ConstructorDeclaration;
import com.google.dart.engine.ast.DefaultFormalParameter;
import com.google.dart.engine.ast.Expression;
import com.google.dart.engine.ast.FieldDeclaration;
import com.google.dart.engine.ast.FormalParameterList;
import com.google.dart.engine.ast.MethodDeclaration;
import com.google.dart.engine.ast.MethodInvocation;
import com.google.dart.engine.ast.SimpleFormalParameter;
import com.google.dart.engine.ast.SimpleIdentifier;
import com.google.dart.engine.ast.VariableDeclaration;
import com.google.dart.engine.utilities.translation.DartBlockBody;
import com.google.dart.java2dart.Context;
import com.google.dart.java2dart.ParsedAnnotation;
import com.google.dart.java2dart.processor.SemanticProcessor;
import com.google.dart.java2dart.util.ToFormattedSourceVisitor;
import static com.google.dart.java2dart.util.AstFactory.annotation;
import static com.google.dart.java2dart.util.AstFactory.identifier;
import static com.google.dart.java2dart.util.AstFactory.namedExpression;
import static com.google.dart.java2dart.util.AstFactory.namedFormalParameter;
import static com.google.dart.java2dart.util.AstFactory.positionalFormalParameter;
import org.apache.commons.lang3.StringUtils;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
/**
* Applies {@link DartBlockBody} and other annotations.
*/
public class EngineAnnotationProcessor extends SemanticProcessor {
public EngineAnnotationProcessor(Context context) {
super(context);
}
@Override
@SuppressWarnings("unchecked")
public void process(CompilationUnit unit) {
Map<AstNode, List<ParsedAnnotation>> nodeAnnotations = context.getNodeAnnotations();
for (Entry<AstNode, List<ParsedAnnotation>> entry : nodeAnnotations.entrySet()) {
AstNode node = entry.getKey();
for (ParsedAnnotation annotation : entry.getValue()) {
String annotationName = annotation.getName();
if (annotationName.equals("DartBlockBody")) {
List<String> bodyLines = (List<String>) annotation.get("value");
String bodySource = "";
if (!bodyLines.isEmpty()) {
bodySource = StringUtils.join(bodyLines, "\n ");
bodySource = " " + bodySource.trim();
}
node.setProperty(ToFormattedSourceVisitor.BLOCK_BODY_KEY, bodySource);
} else if (annotationName.equals("DartExpressionBody")) {
String bodySource = (String) annotation.get("value");
node.setProperty(ToFormattedSourceVisitor.EXPRESSION_BODY_KEY, bodySource);
} else if (annotationName.equals("DartName")) {
String newName = (String) annotation.get("value");
if (node instanceof ClassDeclaration) {
ClassDeclaration classDeclaration = (ClassDeclaration) node;
SimpleIdentifier nameNode = classDeclaration.getName();
context.renameIdentifier(nameNode, newName);
} else if (node instanceof ConstructorDeclaration) {
ConstructorDeclaration constructorDeclaration = (ConstructorDeclaration) node;
context.renameConstructor(constructorDeclaration, newName);
} else if (node instanceof FieldDeclaration) {
FieldDeclaration fieldDeclaration = (FieldDeclaration) node;
List<VariableDeclaration> fields = fieldDeclaration.getFields().getVariables();
if (fields.size() != 1) {
throw new IllegalArgumentException(
"@DartName is supported only field declarations with a single field.");
}
SimpleIdentifier nameNode = fields.get(0).getName();
context.renameIdentifier(nameNode, newName);
} else if (node instanceof MethodDeclaration) {
MethodDeclaration methodDeclaration = (MethodDeclaration) node;
SimpleIdentifier nameNode = methodDeclaration.getName();
context.renameIdentifier(nameNode, newName);
} else {
throw new IllegalArgumentException("@DartName is not supported for: " + node.getClass());
}
} else if (annotationName.equals("DartOmit")) {
AstNode parent = node.getParent();
if (parent instanceof CompilationUnit) {
unit.getDeclarations().remove(node);
} else if (parent instanceof ClassDeclaration) {
((ClassDeclaration) parent).getMembers().remove(node);
}
} else if (annotationName.equals("DartOptional")) {
SimpleFormalParameter parameter = (SimpleFormalParameter) node;
AstNode parameterList = parameter.getParent();
// prepare annotation arguments
String kindName = (String) annotation.get("kind");
String defaultValueSource = (String) annotation.get("defaultValue");
// replace normal parameter with default
DefaultFormalParameter defaultParameter;
if (kindName == null || kindName.endsWith(".POSITIONAL")) {
defaultParameter = positionalFormalParameter(parameter, null);
} else {
replaceInvocationArgumentWithNamed(parameter);
defaultParameter = namedFormalParameter(parameter, null);
}
replaceNode(parameterList, parameter, defaultParameter);
// set default value
defaultParameter.setProperty(
ToFormattedSourceVisitor.DEFAULT_VALUE_KEY,
defaultValueSource);
} else if (annotationName.equals("Override")) {
if (node instanceof MethodDeclaration) {
MethodDeclaration method = (MethodDeclaration) node;
method.setMetadata(Lists.newArrayList(annotation(identifier("override"))));
}
} else {
// throw new IllegalArgumentException("Unknown annotation: " + annotationName);
}
}
}
}
private void replaceInvocationArgumentWithNamed(SimpleFormalParameter parameter) {
String parameterName = parameter.getIdentifier().getName();
FormalParameterList parameterList = (FormalParameterList) parameter.getParent();
AstNode member = parameterList.getParent();
int index = parameterList.getParameters().indexOf(parameter);
if (member instanceof MethodDeclaration) {
MethodDeclaration method = (MethodDeclaration) member;
List<MethodInvocation> invocations = context.getInvocations(method);
for (MethodInvocation invocation : invocations) {
List<Expression> arguments = invocation.getArgumentList().getArguments();
Expression argument = arguments.get(index);
arguments.set(index, namedExpression(parameterName, argument));
}
}
}
}