Java tutorial
/* * Copyright 2014 the original author or 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 org.gradle.model.dsl.internal.spike; import com.google.common.base.Predicate; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterators; import com.google.common.collect.Maps; import org.codehaus.groovy.ast.Parameter; import org.codehaus.groovy.ast.Variable; import org.codehaus.groovy.ast.VariableScope; import org.codehaus.groovy.ast.expr.*; import org.codehaus.groovy.ast.stmt.ExpressionStatement; import org.codehaus.groovy.control.SourceUnit; import org.codehaus.groovy.syntax.Token; import org.codehaus.groovy.syntax.Types; import org.gradle.groovy.scripts.internal.AstUtils; import org.gradle.util.CollectionUtils; import java.util.List; import java.util.Map; public class ScopeVisitor extends ReferenceDetectingVisitor { private final ModelRegistryDslHelperStatementGenerator statementGenerator; private final List<String> scope; private final SourceUnit sourceUnit; private final Map<String, String> referenceAliases = Maps.newHashMap(); public ScopeVisitor(SourceUnit sourceUnit, ModelRegistryDslHelperStatementGenerator statementGenerator) { this(sourceUnit, statementGenerator, ImmutableList.<String>of(), ImmutableMap.<String, String>of()); } private ScopeVisitor(SourceUnit sourceUnit, ModelRegistryDslHelperStatementGenerator statementGenerator, List<String> scope, Map<String, String> referenceAliases) { super(sourceUnit, "Expression not allowed"); this.statementGenerator = statementGenerator; this.scope = scope; this.sourceUnit = sourceUnit; this.referenceAliases.putAll(referenceAliases); } private ScopeVisitor nestedScope(String name) { ImmutableList.Builder<String> nestedScopeBuilder = ImmutableList.builder(); nestedScopeBuilder.addAll(scope); nestedScopeBuilder.add(name); return new ScopeVisitor(sourceUnit, statementGenerator, nestedScopeBuilder.build(), ImmutableMap.copyOf(referenceAliases)); } @Override public void visitDeclarationExpression(DeclarationExpression expression) { Expression rightExpression = expression.getRightExpression(); rightExpression.visit(this); String referencePath = rightExpression.getNodeMetaData(AST_NODE_REFERENCE_PATH_KEY); if (referencePath != null) { referenceAliases.put(expression.getLeftExpression().getText(), referencePath); } } @Override public void visitMethodCallExpression(MethodCallExpression call) { String methodName = AstUtils.extractConstantMethodName(call); if (methodName != null) { ClosureExpression nestedAction = AstUtils.getSingleClosureArg(call); if (nestedAction != null) { nestedAction.getCode().visit(nestedScope(methodName)); return; } } super.visitMethodCallExpression(call); } @Override public void visitBinaryExpression(BinaryExpression expression) { Token operation = expression.getOperation(); if (operation.isA(Types.LEFT_SHIFT) && expression.getLeftExpression() instanceof VariableExpression && expression.getRightExpression() instanceof ClosureExpression) { addCreator(scope, (VariableExpression) expression.getLeftExpression(), (ClosureExpression) expression.getRightExpression()); } else if (operation.isA(Types.ASSIGN)) { if (expression.getLeftExpression() instanceof VariableExpression) { addCreator(scope, (VariableExpression) expression.getLeftExpression(), expression.getRightExpression()); } else if (expression.getLeftExpression() instanceof PropertyExpression) { addCreator(scope, (PropertyExpression) expression.getLeftExpression(), expression.getRightExpression()); } else { super.visitBinaryExpression(expression); } } else { super.visitBinaryExpression(expression); } } private String getPath(List<String> scope, Expression propertyPathExpression) { String propertyPath = propertyPathExpression.getText(); String scopePath = CollectionUtils.join(".", scope); return scopePath.length() > 0 ? String.format("%s.%s", scopePath, propertyPath) : propertyPath; } private void addCreator(String path, ClosureExpression creator) { final ImmutableMap<String, String> referenceAliasesMap = ImmutableMap.copyOf(referenceAliases); ReferenceExtractor extractor = new ReferenceExtractor(sourceUnit, referenceAliasesMap); Iterators.removeIf(creator.getVariableScope().getReferencedLocalVariablesIterator(), new Predicate<Variable>() { public boolean apply(Variable variable) { return referenceAliasesMap.keySet().contains(variable.getName()); } }); creator.getCode().visit(extractor); statementGenerator.addCreator(path, creator, extractor.getReferencedPaths()); } private void addCreator(List<String> scope, VariableExpression propertyPathExpression, ClosureExpression creator) { addCreator(getPath(scope, propertyPathExpression), creator); } private void addCreator(String path, Expression expression) { ClosureExpression wrappingClosure = new ClosureExpression(new Parameter[0], new ExpressionStatement(expression)); wrappingClosure.setVariableScope(new VariableScope()); addCreator(path, wrappingClosure); } public void addCreator(List<String> scope, VariableExpression propertyPathExpression, Expression expression) { addCreator(getPath(scope, propertyPathExpression), expression); } public void addCreator(List<String> scope, PropertyExpression propertyPathExpression, Expression expression) { addCreator(getPath(scope, propertyPathExpression), expression); } @Override protected String getReferenceAliasPath(String aliasName) { return referenceAliases.get(aliasName); } }