package org.jruby.runtime.scope;
import org.jruby.parser.StaticScope;
import org.jruby.runtime.DynamicScope;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.ArraySupport;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
public class ManyVarsDynamicScope extends DynamicScope {
private IRubyObject[] variableValues;
public static final MethodHandle CONSTRUCTOR;
static {
try {
CONSTRUCTOR = MethodHandles.lookup()
.findConstructor(ManyVarsDynamicScope.class, MethodType.methodType(void.class, StaticScope.class, DynamicScope.class))
.asType(MethodType.methodType(DynamicScope.class, StaticScope.class, DynamicScope.class));
} catch (Exception e) {
throw new RuntimeException("BUG: could not initialize constructor handle", e);
}
}
public ManyVarsDynamicScope(StaticScope staticScope, DynamicScope parent) {
super(staticScope, parent);
allocate();
}
private void allocate() {
if(variableValues == null) variableValues = IRubyObject.array(staticScope.getNumberOfVariables());
}
public IRubyObject[] getValues() {
return variableValues;
}
public IRubyObject getValue(int offset, int depth) {
if (depth > 0) {
return parent.getValue(offset, depth - 1);
}
IRubyObject[] variableValues = this.variableValues;
assert checkOffset(variableValues, offset) : failGet(this, offset, depth);
return variableValues[offset];
}
public IRubyObject getValueDepthZero(int offset) {
return variableValues[offset];
}
public IRubyObject getValueZeroDepthZero() {
return variableValues[0];
}
public IRubyObject getValueOneDepthZero() {
return variableValues[1];
}
public IRubyObject getValueTwoDepthZero() {
return variableValues[2];
}
public IRubyObject getValueThreeDepthZero() {
return variableValues[3];
}
public IRubyObject getValueOrNil(int offset, int depth, IRubyObject nil) {
if (depth > 0) {
return parent.getValueOrNil(offset, depth - 1, nil);
} else {
return getValueDepthZeroOrNil(offset, nil);
}
}
public IRubyObject getValueDepthZeroOrNil(int offset, IRubyObject nil) {
IRubyObject[] variableValues = this.variableValues;
assert checkOffset(variableValues, offset) : failGet(this, offset);
IRubyObject value = variableValues[offset];
return value == null ? setValueDepthZero(nil, offset) : value;
}
public IRubyObject getValueZeroDepthZeroOrNil(IRubyObject nil) {
IRubyObject[] variableValues = this.variableValues;
assert checkOffset(variableValues, 0) : failGet(this, 0);
IRubyObject value = variableValues[0];
return value == null ? setValueZeroDepthZero(nil) : value;
}
public IRubyObject getValueOneDepthZeroOrNil(IRubyObject nil) {
IRubyObject[] variableValues = this.variableValues;
assert checkOffset(variableValues, 1) : failGet(this, 1);
IRubyObject value = variableValues[1];
return value == null ? setValueOneDepthZero(nil) : value;
}
public IRubyObject getValueTwoDepthZeroOrNil(IRubyObject nil) {
IRubyObject[] variableValues = this.variableValues;
assert checkOffset(variableValues, 2) : failGet(this, 2);
IRubyObject value = variableValues[2];
return value == null ? setValueTwoDepthZero(nil) : value;
}
public IRubyObject getValueThreeDepthZeroOrNil(IRubyObject nil) {
IRubyObject[] variableValues = this.variableValues;
assert checkOffset(variableValues, 3) : failGet(this, 3);
IRubyObject value = variableValues[3];
return value == null ? setValueThreeDepthZero(nil) : value;
}
public void setValueVoid(IRubyObject value, int offset, int depth) {
if (depth > 0) {
DynamicScope parent = this.parent;
assert parent != null : "If depth > 0, then parent should not ever be null";
parent.setValueVoid(value, offset, depth - 1);
} else {
IRubyObject[] variableValues = this.variableValues;
assert checkOffset(variableValues, offset) : failSet(this, value, offset);
setValueDepthZeroVoid(value, offset);
}
}
public void setValueDepthZeroVoid(IRubyObject value, int offset) {
IRubyObject[] variableValues = this.variableValues;
assert checkOffset(variableValues, offset) : failSet(this, value, offset);
variableValues[offset] = value;
}
public void setValueZeroDepthZeroVoid(IRubyObject value) {
IRubyObject[] variableValues = this.variableValues;
assert checkOffset(variableValues, 0) : failSet(this, value, 0);
variableValues[0] = value;
}
public void setValueOneDepthZeroVoid(IRubyObject value) {
IRubyObject[] variableValues = this.variableValues;
assert checkOffset(variableValues, 1) : failSet(this, value, 1);
variableValues[1] = value;
}
public void setValueTwoDepthZeroVoid(IRubyObject value) {
IRubyObject[] variableValues = this.variableValues;
assert checkOffset(variableValues, 2) : failSet(this, value, 2);
variableValues[2] = value;
}
public void setValueThreeDepthZeroVoid(IRubyObject value) {
IRubyObject[] variableValues = this.variableValues;
assert checkOffset(variableValues, 3) : failSet(this, value, 3);
variableValues[3] = value;
}
public void setValueFourDepthZeroVoid(IRubyObject value) {
IRubyObject[] variableValues = this.variableValues;
assert checkOffset(variableValues, 3) : failSet(this, value, 3);
variableValues[4] = value;
}
public void setValueFiveDepthZeroVoid(IRubyObject value) {
IRubyObject[] variableValues = this.variableValues;
assert checkOffset(variableValues, 3) : failSet(this, value, 3);
variableValues[5] = value;
}
public void setValueSixDepthZeroVoid(IRubyObject value) {
IRubyObject[] variableValues = this.variableValues;
assert checkOffset(variableValues, 3) : failSet(this, value, 3);
variableValues[6] = value;
}
public void setValueSevenDepthZeroVoid(IRubyObject value) {
IRubyObject[] variableValues = this.variableValues;
assert checkOffset(variableValues, 3) : failSet(this, value, 3);
variableValues[7] = value;
}
public void setValueEightDepthZeroVoid(IRubyObject value) {
IRubyObject[] variableValues = this.variableValues;
assert checkOffset(variableValues, 3) : failSet(this, value, 3);
variableValues[8] = value;
}
public void setValueNineDepthZeroVoid(IRubyObject value) {
IRubyObject[] variableValues = this.variableValues;
assert checkOffset(variableValues, 3) : failSet(this, value, 3);
variableValues[9] = value;
}
private static boolean checkOffset(IRubyObject[] variableValues, int offset) {
return variableValues != null && offset < variableValues.length;
}
private static String failGet(ManyVarsDynamicScope scope, int offset) {
return failGet(scope, offset, 0);
}
private static String failGet(ManyVarsDynamicScope scope, int offset, int depth) {
return "No variables or index too big for getValue off: " + offset + ", Dep: " + depth + ", O: " + scope;
}
private static String failSet(ManyVarsDynamicScope scope, IRubyObject value, int offset) {
return "Setting " + offset + " to " + value + ", O: " + scope;
}
public void growIfNeeded() {
int dynamicSize = variableValues == null ? 0: variableValues.length;
if (staticScope.getNumberOfVariables() > dynamicSize) {
IRubyObject values[] = new IRubyObject[staticScope.getNumberOfVariables()];
if (dynamicSize > 0) {
ArraySupport.copy(variableValues, 0, values, 0, dynamicSize);
}
variableValues = values;
}
}
@Deprecated
public DynamicScope cloneScope() {
return new ManyVarsDynamicScope(staticScope, parent);
}
}