OperandEncoderMap.java

package org.jruby.ir.persistence;

import org.jruby.ir.IRVisitor;
import org.jruby.ir.operands.*;
import org.jruby.ir.operands.Boolean;
import org.jruby.ir.operands.Float;
import org.jruby.util.KeyValuePair;

/**
 * Can cycles develop or will IR output guarantee non-cyclical nested operands?
 */
class OperandEncoderMap extends IRVisitor {
    private final IRWriterEncoder encoder;

    public OperandEncoderMap(IRWriterEncoder encoder) {
        this.encoder = encoder;
    }
    // FIXME: Potentially some of these values should not need to have their type prefixed.
    public void encode(Operand operand) {
        encoder.encode(operand.getOperandType().getCoded());
        operand.visit(this);
    }

    @Override public void Array(Array array) {
        Operand[] elts = array.getElts();

        encoder.encode(elts.length);
        for (Operand elt: elts) {
            encode(elt);
        }
    }

    @Override public void AsString(AsString asstring) { encoder.encode(asstring.getSource()); }

    @Override public void Backref(Backref backref) { encoder.encode(backref.type); }

    @Override public void Bignum(Bignum bignum) { encoder.encode(bignum.value.toString()); }

    @Override public void Boolean(Boolean booleanliteral) { encoder.encode(booleanliteral.isTrue()); }

    @Override public void ClosureLocalVariable(ClosureLocalVariable variable) {
        // We can refigure out closure scope it is in.
        encoder.encode(variable.getName());
        encoder.encode(variable.getScopeDepth());
    }

    @Override public void CurrentScope(CurrentScope scope) {
        encoder.encode(scope.getScopeNestingDepth());
    }

    //@Override public void DynamicSymbol(DynamicSymbol dsym) { encode(dsym.getSymbolName()); }
    @Override public void DynamicSymbol(DynamicSymbol dsym) {  }

    @Override public void Fixnum(Fixnum fixnum) { encoder.encode(fixnum.value); }

    @Override public void Float(Float flote) { encoder.encode(flote.value); }

    @Override public void GlobalVariable(GlobalVariable variable) { encoder.encode(variable.getName()); }

    @Override public void Hash(Hash hash) {
        encoder.encode(hash.pairs.size());
        for (KeyValuePair<Operand, Operand> pair: hash.pairs) {
            encoder.encode(pair.getKey());
            encoder.encode(pair.getValue());
        }
    }

    @Override public void IRException(IRException irexception) { encoder.encode((byte) irexception.getType().ordinal()); }

    @Override public void Label(Label label) {
        encoder.encode(label.prefix);
        encoder.encode(label.id);
    }

    @Override public void LocalVariable(LocalVariable variable) {
        encoder.encode(variable.getName());
        encoder.encode(variable.getScopeDepth());
    }

    @Override public void Nil(Nil nil) {} // No data

    @Override public void NthRef(NthRef nthref) { encoder.encode(nthref.matchNumber); }

    @Override public void ObjectClass(ObjectClass objectclass) {} // No data

    @Override public void Regexp(Regexp regexp) {
        encode(regexp.getRegexp());
        encoder.encode(regexp.options.isEncodingNone());
        encoder.encode(regexp.options.toEmbeddedOptions());
    }

    @Override public void ScopeModule(ScopeModule scope) { encoder.encode(scope.getScopeModuleDepth()); }

    @Override public void Self(Self self) {} // No data

    @Override public void Splat(Splat splat) { encode(splat.getArray()); encoder.encode(splat.unsplatArgs); }

    @Override public void StandardError(StandardError standarderror) {} // No data

    @Override public void StringLiteral(StringLiteral stringliteral) { encoder.encode(stringliteral.string); }

    @Override public void SValue(SValue svalue) { encode(svalue.getArray()); }

    @Override public void Symbol(Symbol symbol) { encoder.encode(symbol.getName()); }

    @Override public void TemporaryBooleanVariable(TemporaryBooleanVariable variable) {
        encoder.encode((byte) variable.getType().ordinal());
        encoder.encode(variable.getOffset());
    }

    @Override public void TemporaryFixnumVariable(TemporaryFixnumVariable variable) {
        encoder.encode((byte) variable.getType().ordinal());
        encoder.encode(variable.getOffset());
    }

    @Override public void TemporaryFloatVariable(TemporaryFloatVariable variable) {
        encoder.encode((byte) variable.getType().ordinal());
        encoder.encode(variable.getOffset());
    }

    @Override public void TemporaryLocalVariable(TemporaryLocalVariable variable) {
        encoder.encode((byte) variable.getType().ordinal());

        if (variable.getType() == TemporaryVariableType.CLOSURE) {
            encoder.encode(((TemporaryClosureVariable) variable).getClosureId());
        }
        encoder.encode(variable.getOffset());
    }

    // Only for CURRENT_SCOPE and CURRENT_MODULE now which is weird
    @Override public void TemporaryVariable(TemporaryVariable variable) {
        encoder.encode((byte) variable.getType().ordinal());
        encoder.encode(((TemporaryLocalVariable) variable).getOffset());
    }

    @Override public void UnboxedBoolean(org.jruby.ir.operands.UnboxedBoolean booleanliteral) { encoder.encode(booleanliteral.isTrue()); }

    @Override public void UnboxedFixnum(UnboxedFixnum fixnum) { encoder.encode(fixnum.value); }

    @Override public void UnboxedFloat(UnboxedFloat flote) { encoder.encode(flote.value); }

    @Override public void UndefinedValue(UndefinedValue undefinedvalue) {} // No data

    @Override public void UnexecutableNil(UnexecutableNil unexecutablenil) {} // No data

    @Override public void WrappedIRClosure(WrappedIRClosure scope) {
        encoder.encode(scope.getSelf());
        encoder.encode(scope.getClosure());
    }
}