| /* |
| * 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.codehaus.groovy.ast; |
| |
| import java.util.Collections; |
| import java.util.Iterator; |
| import java.util.LinkedHashMap; |
| import java.util.Map; |
| |
| /** |
| * Represents a variable scope. This is primarily used to determine variable sharing |
| * across method and closure boundaries. |
| */ |
| public class VariableScope { |
| |
| private VariableScope parent; |
| private ClassNode classScope; |
| private boolean inStaticContext; |
| private boolean resolvesDynamic; |
| |
| private Map<String, Variable> declaredVariables = Collections.emptyMap(); |
| private Map<String, Variable> referencedLocalVariables = Collections.emptyMap(); |
| private Map<String, Variable> referencedClassVariables = Collections.emptyMap(); |
| |
| public VariableScope() { |
| super(); |
| } |
| |
| public VariableScope(VariableScope parent) { |
| this.parent = parent; |
| } |
| |
| public VariableScope getParent() { |
| return parent; |
| } |
| |
| public boolean isRoot() { |
| return parent == null; |
| } |
| |
| /** |
| * Non-null iff this scope corresponds to a class; as opposed to a method, "if" statement, block statement, etc. |
| */ |
| public ClassNode getClassScope() { |
| return classScope; |
| } |
| |
| /** |
| * Returns true iff this scope corresponds to a class; as opposed to a method, "if" statement, block statement, etc. |
| */ |
| public boolean isClassScope() { |
| return classScope != null; |
| } |
| |
| public void setClassScope(ClassNode classScope) { |
| this.classScope = classScope; |
| } |
| |
| public boolean isInStaticContext() { |
| return inStaticContext; |
| } |
| |
| public void setInStaticContext(boolean inStaticContext) { |
| this.inStaticContext = inStaticContext; |
| } |
| |
| // |
| |
| public Variable getDeclaredVariable(String name) { |
| return declaredVariables.get(name); |
| } |
| |
| public Variable getReferencedLocalVariable(String name) { |
| return referencedLocalVariables.get(name); |
| } |
| |
| public Variable getReferencedClassVariable(String name) { |
| return referencedClassVariables.get(name); |
| } |
| |
| public boolean isReferencedLocalVariable(String name) { |
| return referencedLocalVariables.containsKey(name); |
| } |
| |
| public boolean isReferencedClassVariable(String name) { |
| return referencedClassVariables.containsKey(name); |
| } |
| |
| /** |
| * Gets a map containing the variables declared in this scope. This map cannot be modified. |
| * |
| * @return a map containing the declared variable references |
| */ |
| public Map<String, Variable> getDeclaredVariables() { |
| if (declaredVariables == Collections.EMPTY_MAP) { |
| return declaredVariables; |
| } else { |
| return Collections.unmodifiableMap(declaredVariables); |
| } |
| } |
| |
| /** |
| * Gets a map containing the class variables referenced by this scope. This not can not be modified. |
| * |
| * @return a map containing the class variable references |
| */ |
| public Map<String, Variable> getReferencedClassVariables() { |
| if (referencedClassVariables == Collections.EMPTY_MAP) { |
| return referencedClassVariables; |
| } else { |
| return Collections.unmodifiableMap(referencedClassVariables); |
| } |
| } |
| |
| public int getReferencedLocalVariablesCount() { |
| return referencedLocalVariables.size(); |
| } |
| |
| /** |
| * Gets an iterator for the declared class variables. The remove operation is not supported. |
| * |
| * @return an iterator for the declared variables |
| */ |
| public Iterator<Variable> getDeclaredVariablesIterator() { |
| return getDeclaredVariables().values().iterator(); |
| } |
| |
| /** |
| * Gets an iterator for the referenced local variables. The remove operation *is* supported. |
| * |
| * @return an iterator for the referenced local variables |
| */ |
| public Iterator<Variable> getReferencedLocalVariablesIterator() { |
| return referencedLocalVariables.values().iterator(); |
| } |
| |
| /** |
| * Gets an iterator for the referenced class variables. The remove operation is not supported. |
| * |
| * @return an iterator for the referenced class variables |
| */ |
| public Iterator<Variable> getReferencedClassVariablesIterator() { |
| return getReferencedClassVariables().values().iterator(); |
| } |
| |
| public void putDeclaredVariable(Variable var) { |
| if (declaredVariables == Collections.EMPTY_MAP) |
| declaredVariables = new LinkedHashMap<>(); |
| declaredVariables.put(var.getName(), var); |
| } |
| |
| public void putReferencedLocalVariable(Variable var) { |
| if (referencedLocalVariables == Collections.EMPTY_MAP) |
| referencedLocalVariables = new LinkedHashMap<>(); |
| referencedLocalVariables.put(var.getName(), var); |
| } |
| |
| public void putReferencedClassVariable(Variable var) { |
| if (referencedClassVariables == Collections.EMPTY_MAP) |
| referencedClassVariables = new LinkedHashMap<>(); |
| referencedClassVariables.put(var.getName(), var); |
| } |
| |
| public Object removeReferencedClassVariable(String name) { |
| if (referencedClassVariables.isEmpty()) { |
| return null; |
| } else { |
| return referencedClassVariables.remove(name); |
| } |
| } |
| |
| // |
| |
| // TODO: implement Cloneable and override Object.clone() |
| public VariableScope copy() { |
| VariableScope copy = new VariableScope(parent); |
| copy.classScope = classScope; |
| copy.inStaticContext = inStaticContext; |
| copy.resolvesDynamic = resolvesDynamic; |
| if (!declaredVariables.isEmpty()) { |
| copy.declaredVariables = new LinkedHashMap<>(declaredVariables); |
| } |
| if (!referencedLocalVariables.isEmpty()) { |
| copy.referencedLocalVariables = new LinkedHashMap<>(referencedLocalVariables); |
| } |
| if (!referencedClassVariables.isEmpty()) { |
| copy.referencedClassVariables = new LinkedHashMap<>(referencedClassVariables); |
| } |
| return copy; |
| } |
| } |