/*
 ***** BEGIN LICENSE BLOCK *****
 * Version: EPL 2.0/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Eclipse Public
 * 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.eclipse.org/legal/epl-v20.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.
 *
 * 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 EPL, 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 EPL, the GPL or the LGPL.
 ***** END LICENSE BLOCK *****/

package org.jruby.runtime;

import org.jruby.EvalType;
import org.jruby.ir.JIT;
import org.jruby.parser.StaticScope;
import org.jruby.runtime.builtin.IRubyObject;

public abstract class DynamicScope implements Cloneable {
    // Static scoping information for this scope
    protected final StaticScope staticScope;

    // Captured dynamic scopes
    protected final DynamicScope parent;

    private EvalType evalType;

    private boolean lambda;

    protected DynamicScope(StaticScope staticScope, DynamicScope parent) {
        this.staticScope = staticScope;
        this.parent = parent;
        this.evalType = EvalType.NONE;
    }

    public static DynamicScope newDynamicScope(StaticScope staticScope, DynamicScope parent) {
        return staticScope.construct(parent);
    }

    public static DynamicScope newDynamicScope(StaticScope staticScope, DynamicScope parent, EvalType evalType) {
        DynamicScope newScope = newDynamicScope(staticScope, parent);
        newScope.setEvalType(evalType);
        return newScope;
    }

    public static DynamicScope newDummyScope(StaticScope staticScope, DynamicScope parent) {
        return DynamicScope.newDynamicScope(staticScope, parent);
    }

    
Get parent (capturing) scope. This is used by eval and closures to walk up to hard lexical boundary.
/** * Get parent (capturing) scope. This is used by eval and closures to * walk up to hard lexical boundary. * */
public final DynamicScope getParentScope() { return parent; } @Deprecated public DynamicScope getNextCapturedScope() { // Used by ruby-debug-ide return getParentScope(); }
Returns the n-th parent scope of this scope. May return null.
Params:
  • n – - number of levels above to look.
Returns:The n-th parent scope or null.
/** * Returns the n-th parent scope of this scope. * May return <code>null</code>. * @param n - number of levels above to look. * @return The n-th parent scope or <code>null</code>. */
public DynamicScope getNthParentScope(int n) { DynamicScope scope = this; for (int i = 0; i < n; i++) { if (scope == null) break; scope = scope.getParentScope(); } return scope; } public static DynamicScope newDynamicScope(StaticScope staticScope) { return newDynamicScope(staticScope, null); }
Get the static scope associated with this DynamicScope.
Returns:static complement to this scope
/** * Get the static scope associated with this DynamicScope. * * @return static complement to this scope */
public final StaticScope getStaticScope() { return staticScope; }
Get all variable names captured (visible) by this scope (sans $~ and $_).
Returns:a list of variable names
/** * Get all variable names captured (visible) by this scope (sans $~ and $_). * * @return a list of variable names */
public final String[] getAllNamesInScope() { return staticScope.getAllNamesInScope(); } public void growIfNeeded() { throw new RuntimeException("BUG: scopes of type " + getClass().getName() + " cannot grow"); } public IRubyObject[] getValues() { int numberOfVariables = staticScope.getNumberOfVariables(); IRubyObject[] values = new IRubyObject[numberOfVariables]; for (int i = 0; i < numberOfVariables; i++) { values[i] = getValueDepthZero(i); } return values; };
Get value from current scope or one of its captured scopes.
Params:
  • offset – zero-indexed value that represents where variable lives
  • depth – how many captured scopes down this variable should be set
Returns:the value here
/** * Get value from current scope or one of its captured scopes. * * @param offset zero-indexed value that represents where variable lives * @param depth how many captured scopes down this variable should be set * @return the value here */
@JIT public abstract IRubyObject getValue(int offset, int depth);
Variation of getValue for depth 0
/** * Variation of getValue for depth 0 */
@JIT public IRubyObject getValueDepthZero(int offset) { return getValue(offset, 0); }
getValue for index 0, depth 0
/** * getValue for index 0, depth 0 */
@JIT public IRubyObject getValueZeroDepthZero() { return getValueDepthZero(0); }
getValue for index 1, depth 0
/** * getValue for index 1, depth 0 */
@JIT public IRubyObject getValueOneDepthZero() { return getValueDepthZero(1); }
getValue for index 2, depth 0
/** * getValue for index 2, depth 0 */
@JIT public IRubyObject getValueTwoDepthZero() { return getValueDepthZero(2); }
getValue for index 3, depth 0
/** * getValue for index 3, depth 0 */
@JIT public IRubyObject getValueThreeDepthZero() { return getValueDepthZero(3); }
getValue for index 4, depth 0
/** * getValue for index 4, depth 0 */
@JIT public IRubyObject getValueFourDepthZero() { return getValueDepthZero(4); }
getValue for index 5, depth 0
/** * getValue for index 5, depth 0 */
@JIT public IRubyObject getValueFiveDepthZero() { return getValueDepthZero(5); }
getValue for index 6, depth 0
/** * getValue for index 6, depth 0 */
@JIT public IRubyObject getValueSixDepthZero() { return getValueDepthZero(6); }
getValue for index 7, depth 0
/** * getValue for index 7, depth 0 */
@JIT public IRubyObject getValueSevenDepthZero() { return getValueDepthZero(7); }
getValue for index 8, depth 0
/** * getValue for index 8, depth 0 */
@JIT public IRubyObject getValueEightDepthZero() { return getValueDepthZero(8); }
getValue for index 9, depth 0
/** * getValue for index 9, depth 0 */
@JIT public IRubyObject getValueNineDepthZero() { return getValueDepthZero(9); }
Variation of getValue that checks for nulls, returning and setting the given value (presumably nil)
/** * Variation of getValue that checks for nulls, returning and setting the given value (presumably nil) */
public IRubyObject getValueOrNil(int offset, int depth, IRubyObject nil) { if (depth > 0) { return parent.getValueOrNil(offset, depth - 1, nil); } else { return getValueDepthZeroOrNil(offset, nil); } }
getValueOrNil for depth 0
/** * getValueOrNil for depth 0 */
public IRubyObject getValueDepthZeroOrNil(int offset, IRubyObject nil) { IRubyObject value = getValueDepthZero(offset); return value == null ? setValueDepthZero(nil, offset) : value; }
getValueOrNil for index 0, depth 0
/** * getValueOrNil for index 0, depth 0 */
public IRubyObject getValueZeroDepthZeroOrNil(IRubyObject nil) { IRubyObject value = getValueZeroDepthZero(); return value == null ? setValueDepthZero(nil, 0) : value; }
getValueOrNil for index 1, depth 0
/** * getValueOrNil for index 1, depth 0 */
public IRubyObject getValueOneDepthZeroOrNil(IRubyObject nil) { IRubyObject value = getValueOneDepthZero(); return value == null ? setValueDepthZero(nil, 1) : value; }
getValueOrNil for index 2, depth 0
/** * getValueOrNil for index 2, depth 0 */
public IRubyObject getValueTwoDepthZeroOrNil(IRubyObject nil) { IRubyObject value = getValueTwoDepthZero(); return value == null ? setValueDepthZero(nil, 2) : value; }
getValueOrNil for index 3, depth 0
/** * getValueOrNil for index 3, depth 0 */
public IRubyObject getValueThreeDepthZeroOrNil(IRubyObject nil) { IRubyObject value = getValueThreeDepthZero(); return value == null ? setValueDepthZero(nil, 3) : value; }
getValueOrNil for index 4, depth 0
/** * getValueOrNil for index 4, depth 0 */
public IRubyObject getValueFourDepthZeroOrNil(IRubyObject nil) { IRubyObject value = getValueFourDepthZero(); return value == null ? setValueDepthZero(nil, 4) : value; }
getValueOrNil for index 5, depth 0
/** * getValueOrNil for index 5, depth 0 */
public IRubyObject getValueFiveDepthZeroOrNil(IRubyObject nil) { IRubyObject value = getValueFiveDepthZero(); return value == null ? setValueDepthZero(nil, 5) : value; }
getValueOrNil for index 6, depth 0
/** * getValueOrNil for index 6, depth 0 */
public IRubyObject getValueSixDepthZeroOrNil(IRubyObject nil) { IRubyObject value = getValueSixDepthZero(); return value == null ? setValueDepthZero(nil, 6) : value; }
getValueOrNil for index 7, depth 0
/** * getValueOrNil for index 7, depth 0 */
public IRubyObject getValueSevenDepthZeroOrNil(IRubyObject nil) { IRubyObject value = getValueSevenDepthZero(); return value == null ? setValueDepthZero(nil, 7) : value; }
getValueOrNil for index 8, depth 0
/** * getValueOrNil for index 8, depth 0 */
public IRubyObject getValueEightDepthZeroOrNil(IRubyObject nil) { IRubyObject value = getValueEightDepthZero(); return value == null ? setValueDepthZero(nil, 8) : value; }
getValueOrNil for index 9, depth 0
/** * getValueOrNil for index 9, depth 0 */
public IRubyObject getValueNineDepthZeroOrNil(IRubyObject nil) { IRubyObject value = getValueNineDepthZero(); return value == null ? setValueDepthZero(nil, 9) : value; }
Set value in current dynamic scope or one of its captured scopes.
Params:
  • offset – zero-indexed value that represents where variable lives
  • value – to set
  • depth – how many captured scopes down this variable should be set
/** * Set value in current dynamic scope or one of its captured scopes. * * @param offset zero-indexed value that represents where variable lives * @param value to set * @param depth how many captured scopes down this variable should be set */
public IRubyObject setValue(int offset, IRubyObject value, int depth) { setValueVoid(value, offset, depth); return value; }
Set value in current dynamic scope or one of its captured scopes.
Params:
  • offset – zero-indexed value that represents where variable lives
  • value – to set
  • depth – how many captured scopes down this variable should be set
/** * Set value in current dynamic scope or one of its captured scopes. * * @param offset zero-indexed value that represents where variable lives * @param value to set * @param depth how many captured scopes down this variable should be set */
public IRubyObject setValue(IRubyObject value, int offset, int depth) { setValueVoid(value, offset, depth); return value; }
Set value in current dynamic scope or one of its captured scopes.
Params:
  • offset – zero-indexed value that represents where variable lives
  • value – to set
  • depth – how many captured scopes down this variable should be set
/** * Set value in current dynamic scope or one of its captured scopes. * * @param offset zero-indexed value that represents where variable lives * @param value to set * @param depth how many captured scopes down this variable should be set */
@JIT public abstract void setValueVoid(IRubyObject value, int offset, int depth);
setValue for depth zero
Params:
  • value – to set
  • offset – zero-indexed value that represents where variable lives
/** * setValue for depth zero * * @param value to set * @param offset zero-indexed value that represents where variable lives */
public IRubyObject setValueDepthZero(IRubyObject value, int offset) { setValueDepthZeroVoid(value, offset); return value; }
setValue for depth zero
Params:
  • value – to set
  • offset – zero-indexed value that represents where variable lives
/** * setValue for depth zero * * @param value to set * @param offset zero-indexed value that represents where variable lives */
@JIT public void setValueDepthZeroVoid(IRubyObject value, int offset) { setValueVoid(value, offset, 0); }
Set value zero in this scope;
/** * Set value zero in this scope; */
public IRubyObject setValueZeroDepthZero(IRubyObject value) { setValueZeroDepthZeroVoid(value); return value; }
Set value zero in this scope;
/** * Set value zero in this scope; */
@JIT public void setValueZeroDepthZeroVoid(IRubyObject value) { setValueDepthZeroVoid(value, 0); }
Set value one in this scope.
/** * Set value one in this scope. */
public IRubyObject setValueOneDepthZero(IRubyObject value) { setValueOneDepthZeroVoid(value); return value; }
Set value one in this scope.
/** * Set value one in this scope. */
@JIT public void setValueOneDepthZeroVoid(IRubyObject value) { setValueDepthZeroVoid(value, 1); }
Set value two in this scope.
/** * Set value two in this scope. */
public IRubyObject setValueTwoDepthZero(IRubyObject value) { setValueTwoDepthZeroVoid(value); return value; }
Set value two in this scope.
/** * Set value two in this scope. */
@JIT public void setValueTwoDepthZeroVoid(IRubyObject value) { setValueDepthZeroVoid(value, 2); }
Set value three in this scope.
/** * Set value three in this scope. */
public IRubyObject setValueThreeDepthZero(IRubyObject value) { setValueThreeDepthZeroVoid(value); return value; }
Set value three in this scope.
/** * Set value three in this scope. */
@JIT public void setValueThreeDepthZeroVoid(IRubyObject value) { setValueDepthZeroVoid(value, 3); }
Set value four in this scope.
/** * Set value four in this scope. */
@JIT public void setValueFourDepthZeroVoid(IRubyObject value) { setValueDepthZeroVoid(value, 4); }
Set value five in this scope.
/** * Set value five in this scope. */
@JIT public void setValueFiveDepthZeroVoid(IRubyObject value) { setValueDepthZeroVoid(value, 5); }
Set value six in this scope.
/** * Set value six in this scope. */
@JIT public void setValueSixDepthZeroVoid(IRubyObject value) { setValueDepthZeroVoid(value, 6); }
Set value seven in this scope.
/** * Set value seven in this scope. */
@JIT public void setValueSevenDepthZeroVoid(IRubyObject value) { setValueDepthZeroVoid(value, 7); }
Set value eight in this scope.
/** * Set value eight in this scope. */
@JIT public void setValueEightDepthZeroVoid(IRubyObject value) { setValueDepthZeroVoid(value, 8); }
Set value nine in this scope.
/** * Set value nine in this scope. */
@JIT public void setValueNineDepthZeroVoid(IRubyObject value) { setValueDepthZeroVoid(value, 9); } @Override public String toString() { return toString(new StringBuffer(), ""); } // Helper function to give a good view of current dynamic scope with captured scopes public String toString(StringBuffer buf, String indent) { buf.append(indent).append("Static Type[" + hashCode() + "]: " + (staticScope.isBlockScope() ? "block" : "local")+" ["); int size = staticScope.getNumberOfVariables(); IRubyObject[] variableValues = getValues(); if (size != 0) { String names[] = staticScope.getVariables(); for (int i = 0; i < size-1; i++) { buf.append(names[i]).append("="); if (variableValues[i] == null) { buf.append("null"); } else { buf.append(variableValues[i]); } buf.append(","); } buf.append(names[size-1]).append("="); assert variableValues.length == names.length : "V: " + variableValues.length + " != N: " + names.length + " for " + buf; if (variableValues[size-1] == null) { buf.append("null"); } else { buf.append(variableValues[size-1]); } } buf.append("]"); if (parent != null) { buf.append("\n"); parent.toString(buf, indent + " "); } return buf.toString(); } public boolean inInstanceEval() { return evalType == EvalType.INSTANCE_EVAL; } public boolean inModuleEval() { return evalType == EvalType.MODULE_EVAL; } public boolean inBindingEval() { return evalType == EvalType.BINDING_EVAL; } public void setEvalType(EvalType evalType) { this.evalType = evalType == null ? EvalType.NONE : evalType; } public EvalType getEvalType() { return this.evalType; } public void clearEvalType() { evalType = EvalType.NONE; } public void setLambda(boolean lambda) { this.lambda = lambda; } public boolean isLambda() { return lambda; } @Deprecated public DynamicScope cloneScope() { try { return (DynamicScope) clone(); } catch (CloneNotSupportedException cnse) { throw new RuntimeException("BUG: failed to clone scope type " + getClass().getName()); } } }