blob: 35b9686279252a5b7214bec7270aed53ebbbc282 [file] [log] [blame]
/*******************************************************************************
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.sling.scripting.sightly.java.compiler.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import org.apache.sling.commons.compiler.source.JavaEscapeHelper;
import org.apache.sling.scripting.sightly.compiler.util.VariableTracker;
import org.apache.sling.scripting.sightly.java.compiler.SightlyJavaCompilerException;
/**
* Data structure used in the analysis of variables
* during the compilation process
*/
public class VariableAnalyzer {
private final VariableTracker<VariableDescriptor> tracker = new VariableTracker<>();
private final List<VariableDescriptor> variables = new ArrayList<>();
private final HashMap<String, VariableDescriptor> dynamicVariables = new HashMap<>();
private final HashMap<String, VariableDescriptor> staticVariables = new HashMap<>();
private static final String DYNAMIC_PREFIX = "_dynamic_";
private static final String GLOBAL_PREFIX = "_global_";
/**
* Mark the declaration of a variable in the Java code
* @param originalName the original name of the variable
* @param type the variable's type
* @return - a variable descriptor uniquely assigned to this variable
*/
public VariableDescriptor declareVariable(String originalName, Type type) {
originalName = originalName.toLowerCase();
VariableDescriptor descriptor =
new VariableDescriptor(originalName, JavaEscapeHelper.getJavaIdentifier(originalName), type, VariableScope.SCOPED);
tracker.pushVariable(originalName, descriptor);
variables.add(descriptor);
return descriptor;
}
/**
* Declare a global variable. Redundant declarations are ignored
* @param originalName the original name of the variable
* @return a variable descriptor
*/
public VariableDescriptor declareGlobal(String originalName) {
originalName = originalName.toLowerCase();
VariableDescriptor descriptor = staticVariables.get(originalName);
if (descriptor == null) {
String assignedName = findGlobalName(originalName);
descriptor = new VariableDescriptor(originalName, assignedName, Type.UNKNOWN, VariableScope.GLOBAL);
variables.add(descriptor);
staticVariables.put(originalName, descriptor);
}
return descriptor;
}
/**
* Mark this variable as a template
* @param originalName the original name of the variable
* @return a variable descriptor
*/
public VariableDescriptor declareTemplate(String originalName) {
originalName = originalName.toLowerCase();
VariableDescriptor descriptor = dynamicDescriptor(originalName);
descriptor.markAsTemplate();
return descriptor;
}
/**
* Mark the end of a variable scope
*/
public VariableDescriptor endVariable() {
VariableDescriptor descriptor = tracker.peek().getValue();
tracker.popVariable();
return descriptor;
}
/**
* Get a the descriptor for the given variable
* @param name the original lowerName of the variable
* @return the variable descriptor. If the variable is not in scope,
* then a dynamic variable descriptor is provided
*/
public VariableDescriptor descriptor(String name) {
String lowerName = name.toLowerCase();
VariableDescriptor descriptor = tracker.get(lowerName);
if (descriptor == null) {
descriptor = staticVariables.get(lowerName);
}
if (descriptor == null) {
descriptor = dynamicDescriptor(lowerName);
}
return descriptor;
}
/**
* Get the collection of all the variables encountered so far
* @return an unmodifiable list of all the variables tracked by this analyzer
*/
public Collection<VariableDescriptor> allVariables() {
return Collections.unmodifiableList(variables);
}
/**
* Shortcut method that returns the assigned name for the given
* variable
* @param original the original variable name
* @return the assigned name for this compilation process
*/
public String assignedName(String original) {
return descriptor(original).getAssignedName();
}
private VariableDescriptor dynamicDescriptor(String original) {
VariableDescriptor descriptor = dynamicVariables.get(original);
if (descriptor == null) {
String dynamicName = findDynamicName(validName(original));
descriptor = new VariableDescriptor(original, dynamicName, Type.UNKNOWN, VariableScope.DYNAMIC);
dynamicVariables.put(original, descriptor);
variables.add(descriptor);
}
return descriptor;
}
private String findDynamicName(String original) {
return DYNAMIC_PREFIX + JavaEscapeHelper.getJavaIdentifier(original);
}
private String findGlobalName(String original) {
return GLOBAL_PREFIX + JavaEscapeHelper.getJavaIdentifier(original);
}
private String validName(String name) {
if (name == null || name.contains("-")) {
throw new SightlyJavaCompilerException("Unsupported identifier name: " + name);
}
return name.toLowerCase();
}
}