blob: 6a36a6b887616b01194bf25e6309b3545d7d213b [file] [log] [blame]
/***** 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();
}