org.formulacompiler.compiler.internal.bytecode.LinearizerCompiler.java Source code

Java tutorial

Introduction

Here is the source code for org.formulacompiler.compiler.internal.bytecode.LinearizerCompiler.java

Source

/*
 * Copyright (c) 2006-2009 by Abacus Research AG, Switzerland.
 * All rights reserved.
 *
 * This file is part of the Abacus Formula Compiler (AFC).
 *
 * For commercial licensing, please contact sales(at)formulacompiler.com.
 *
 * AFC is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * AFC is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with AFC.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.formulacompiler.compiler.internal.bytecode;

import org.formulacompiler.compiler.CompilerException;
import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.commons.GeneratorAdapter;

final class LinearizerCompiler extends MethodCompiler {
    private final int rows;
    private final int cols;

    LinearizerCompiler(SectionCompiler _section, int _rows, int _cols) {
        super(_section, Opcodes.ACC_FINAL, "$lin$" + _rows + "$" + _cols, "(II)I");
        this.rows = _rows;
        this.cols = _cols;
    }

    @Override
    protected void compileBody() throws CompilerException {
        final GeneratorAdapter mv = mv();
        final Label outOfRange = mv.newLabel();

        // range check row
        mv.visitVarInsn(Opcodes.ILOAD, 1); // row
        mv.push(1);
        mv.ifICmp(mv.LT, outOfRange);
        mv.visitVarInsn(Opcodes.ILOAD, 1); // row
        mv.push(this.rows);
        mv.ifICmp(mv.GT, outOfRange);

        // range check col
        mv.visitVarInsn(Opcodes.ILOAD, 2); // col
        mv.push(1);
        mv.ifICmp(mv.LT, outOfRange);
        mv.visitVarInsn(Opcodes.ILOAD, 2); // col
        mv.push(this.cols);
        mv.ifICmp(mv.GT, outOfRange);

        // (<row> - 1) * <num_cols>) + (<col> - 1);
        mv.visitVarInsn(Opcodes.ILOAD, 1); // row
        mv.push(1);
        mv.visitInsn(Opcodes.ISUB);
        mv.push(this.cols);
        mv.visitInsn(Opcodes.IMUL);
        mv.visitVarInsn(Opcodes.ILOAD, 2); // col
        mv.push(1);
        mv.visitInsn(Opcodes.ISUB);
        mv.visitInsn(Opcodes.IADD);
        mv.visitInsn(Opcodes.IRETURN);

        mv.visitLabel(outOfRange);
        mv.throwException(ExpressionCompiler.FORMULA_ERROR_TYPE,
                "#VALUE/REF! because index is out of range in INDEX");
    }

}