| /***** BEGIN LICENSE BLOCK ***** |
| * Version: CPL 1.0/GPL 2.0/LGPL 2.1 |
| * |
| * The contents of this file are subject to the Common Public |
| * License Version 1.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/cpl-v10.html |
| * |
| * Software distributed under the License is distributed on an "AS |
| * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or |
| * implied. See the License for the specific language governing |
| * rights and limitations under the License. |
| * |
| * Copyright (C) 2006 Thomas E Enebo <enebo@acm.org> |
| * |
| * Alternatively, the contents of this file may be used under the terms of |
| * either of the GNU General Public License Version 2 or later (the "GPL"), |
| * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), |
| * in which case the provisions of the GPL or the LGPL are applicable instead |
| * of those above. If you wish to allow use of your version of this file only |
| * under the terms of either the GPL or the LGPL, and not to allow others to |
| * use your version of this file under the terms of the CPL, indicate your |
| * decision by deleting the provisions above and replace them with the notice |
| * and other provisions required by the GPL or the LGPL. If you do not delete |
| * the provisions above, a recipient may use your version of this file under |
| * the terms of any one of the CPL, the GPL or the LGPL. |
| ***** END LICENSE BLOCK *****/ |
| package org.jruby.parser; |
| |
| import java.io.Serializable; |
| |
| import org.jruby.ast.AssignableNode; |
| import org.jruby.ast.Node; |
| import org.jruby.lexer.yacc.ISourcePosition; |
| |
| public abstract class StaticScope implements Serializable { |
| private static final long serialVersionUID = 4843861446986961013L; |
| |
| private StaticScope enclosingScope; |
| |
| // Our name holder (offsets are assigned as variables are added |
| private String[] variableNames; |
| |
| protected StaticScope(StaticScope enclosingScope) { |
| this.enclosingScope = enclosingScope; |
| } |
| |
| public int addVariable(String name) { |
| int slot = isDefined(name); |
| |
| if (slot >= 0) { |
| return slot; |
| } |
| |
| // This is perhaps innefficient timewise? Optimal spacewise |
| if (variableNames == null) { |
| variableNames = new String[1]; |
| variableNames[0] = name; |
| } else { |
| String[] newVariableNames = new String[variableNames.length + 1]; |
| System.arraycopy(variableNames, 0, newVariableNames, 0, variableNames.length); |
| variableNames = newVariableNames; |
| variableNames[variableNames.length - 1] = name; |
| } |
| |
| // Returns slot of variable |
| return variableNames.length - 1; |
| } |
| |
| public String[] getVariables() { |
| return variableNames; |
| } |
| |
| public int getNumberOfVariables() { |
| return variableNames == null ? 0 : variableNames.length; |
| } |
| |
| public void setVariables(String[] names) { |
| if (names == null) { |
| return; |
| } |
| |
| variableNames = new String[names.length]; |
| System.arraycopy(names, 0, variableNames, 0, names.length); |
| } |
| |
| /** |
| * Next outer most scope in list of scopes. An enclosing scope may have no direct scoping |
| * relationship to its child. If I am in a localScope and then I enter something which |
| * creates another localScope the enclosing scope will be the first scope, but there are |
| * no valid scoping relationships between the two. Methods which walk the enclosing scopes |
| * are responsible for enforcing appropriate scoping relationships. |
| * |
| * @return the parent scope |
| */ |
| public StaticScope getEnclosingScope() { |
| return enclosingScope; |
| } |
| |
| /** |
| * Does the variable exist? |
| * |
| * @param name of the variable to find |
| * @return index of variable or -1 if it does not exist |
| */ |
| public int exists(String name) { |
| if (variableNames != null) { |
| for (int i = 0; i < variableNames.length; i++) { |
| if (name == variableNames[i] || name.equals(variableNames[i])) { |
| return i; |
| } |
| } |
| } |
| |
| return -1; |
| } |
| |
| /** |
| * Is this name in the visible to the current scope |
| * |
| * @param name to be looked for |
| * @return a location where the left-most 16 bits of number of scopes down it is and the |
| * right-most 16 bits represents its index in that scope |
| */ |
| public int isDefined(String name) { |
| return isDefined(name, 0); |
| } |
| |
| /** |
| * Make a DASgn or LocalAsgn node based on scope logic |
| * |
| * @param position |
| * @param name |
| * @param value |
| * @return |
| */ |
| public AssignableNode assign(ISourcePosition position, String name, Node value) { |
| return assign(position, name, value, this, 0); |
| } |
| |
| /** |
| * Get all visible variables that we can see from this scope |
| * |
| * @return a list of all names (sans $~ and $_ which are special names) |
| */ |
| public abstract String[] getAllNamesInScope(); |
| |
| protected abstract int isDefined(String name, int depth); |
| protected abstract AssignableNode assign(ISourcePosition position, String name, Node value, |
| StaticScope topScope, int depth); |
| protected abstract Node declare(ISourcePosition position, String name, int depth); |
| |
| /** |
| * Make a DVar or LocalVar node based on scoping logic |
| * |
| * @param position the location that in the source that the new node will come from |
| * @param name of the variable to be created is named |
| * @return a DVarNode or LocalVarNode |
| */ |
| public Node declare(ISourcePosition position, String name) { |
| return declare(position, name, 0); |
| } |
| |
| /** |
| * Gets the Local Scope relative to the current Scope. For LocalScopes this will be itself. |
| * Blocks will contain the LocalScope it contains. |
| * |
| * @return localScope |
| */ |
| public abstract StaticScope getLocalScope(); |
| } |