/*
* 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 static org.formulacompiler.compiler.internal.bytecode.ByteCodeEngineCompiler.*;
import org.formulacompiler.compiler.CompilerException;
import org.formulacompiler.compiler.internal.model.SectionModel;
import org.formulacompiler.runtime.spreadsheet.RangeAddress;
import org.formulacompiler.runtime.spreadsheet.CellAddress;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.GeneratorAdapter;
final class SubSectionCompiler extends SectionCompiler
{
private final SectionCompiler parentSectionCompiler;
private final String arrayDescriptor;
private final Type arrayType;
private final String getterName;
private final String getterDescriptor;
SubSectionCompiler( SectionCompiler _parent, SectionModel _model, boolean _computationListenerEnabled )
{
super( _parent.engineCompiler(), _model, _parent.engineCompiler().newSubClassName(), _computationListenerEnabled );
this.parentSectionCompiler = _parent;
this.arrayDescriptor = "[" + classDescriptor();
this.arrayType = Type.getType( arrayDescriptor() );
this.getterName = "get" + className();
this.getterDescriptor = "()" + arrayDescriptor();
_parent.addSubSectionCompiler( _model, this );
}
@Override
protected SectionCompiler parentSectionCompiler()
{
return this.parentSectionCompiler;
}
@Override
protected RootSectionCompiler rootSectionCompiler()
{
return parentSectionCompiler().rootSectionCompiler();
}
String arrayDescriptor()
{
return this.arrayDescriptor;
}
Type arrayType()
{
return this.arrayType;
}
String getterName()
{
return this.getterName;
}
String getterDescriptor()
{
return this.getterDescriptor;
}
private Type parentType()
{
return parentSectionCompiler().classType();
}
private Type rootType()
{
return rootSectionCompiler().classType();
}
@Override
protected void buildMembers()
{
super.buildMembers();
buildParentMember();
buildRootMember();
if (this.isComputationListenerEnabled()) buildIndex();
}
private void buildParentMember()
{
// Package visible so subsections can read it.
newField( Opcodes.ACC_FINAL, PARENT_MEMBER_NAME, parentType().getDescriptor() );
}
private void buildRootMember()
{
// Package visible so subsections can read it.
newField( Opcodes.ACC_FINAL, ROOT_MEMBER_NAME, rootType().getDescriptor() );
}
private void buildIndex()
{
newField( Opcodes.ACC_PRIVATE + Opcodes.ACC_FINAL, INDEX_MEMBER_NAME, INDEX_TYPE.getDescriptor() );
}
@Override
protected void buildConstructorWithInputs() throws CompilerException
{
final StringBuilder descriptor = new StringBuilder( "(" );
descriptor.append( inputType().getDescriptor() );
descriptor.append( parentType().getDescriptor() );
if (this.isComputationListenerEnabled()) descriptor.append( INDEX_TYPE.getDescriptor() );
descriptor.append( ")V" );
final MethodCompiler constructorCompiler = new MethodCompiler( this, 0, "<init>", descriptor.toString() )
{
@Override
protected void compileBody() throws CompilerException
{
final GeneratorAdapter mv = mv();
// super( _inputs ); or super(); or super( _inputs, _parent );
callInheritedConstructor( mv, 1 );
// this.parent = _parent;
mv.loadThis();
mv.loadArg( 1 );
mv.putField( classType(), PARENT_MEMBER_NAME, parentType() );
// this.root = _parent.root();
mv.loadThis();
mv.loadArg( 1 );
final Type rootType = rootSectionCompiler().classType();
if (!(parentSectionCompiler() instanceof RootSectionCompiler)) {
// parent.root is package visible
mv.getField( parentType(), ROOT_MEMBER_NAME, rootType );
}
mv.putField( SubSectionCompiler.this.classType(), ROOT_MEMBER_NAME, rootType );
// this.inputs = _inputs;
if (hasInputs()) {
mv.loadThis();
mv.loadArg( 0 );
storeInputs( mv );
}
//this.sectionInfo = new SectionInfoImpl(...);
if (isComputationListenerEnabled()) {
mv.loadThis();
mv.loadArg( 2 ); //section index
final ExpressionCompilerForNumbers c = numericCompiler();
final SectionModel sectionModel = model();
final RangeAddress range = (RangeAddress) model().getSource();
final CellAddress topLeft = range.getTopLeft();
final CellAddress bottomRight = range.getBottomRight();
c.compile_util_createSectionInfo( sectionModel.getName(),
topLeft.getSheetName(), topLeft.getRowIndex(), topLeft.getColumnIndex(),
bottomRight.getSheetName(), bottomRight.getRowIndex(), bottomRight.getColumnIndex() );
mv.putField( section().classType(), SECTION_INFO_MEMBER_NAME, SECTION_INFO_CLASS );
}
mv.visitInsn( Opcodes.RETURN );
}
};
constructorCompiler.compile();
}
@Override
protected void finalizeConstructor() throws CompilerException
{
// Finalized already.
}
@Override
protected boolean callConstructorWithInputs( GeneratorAdapter _mv, int _inputsVar )
{
final int P_PARENT = 2;
// try super( _inputs, _parent );
try {
// ensure it is here and accessible
outputClass().getConstructor( inputClass(), parentSectionCompiler().model().getOutputClass() );
}
catch (NoSuchMethodException e) {
return super.callConstructorWithInputs( _mv, _inputsVar );
}
_mv.loadThis();
if (0 <= _inputsVar) {
_mv.visitVarInsn( Opcodes.ALOAD, _inputsVar );
}
else {
_mv.visitInsn( Opcodes.ACONST_NULL );
}
_mv.visitVarInsn( Opcodes.ALOAD, P_PARENT );
_mv.visitMethodInsn( Opcodes.INVOKESPECIAL, outputType().getInternalName(), "<init>", "("
+ inputType().getDescriptor() + parentSectionCompiler().outputType().getDescriptor() + ")V" );
return true;
}
@Override
protected void compileEnvironmentAccess( GeneratorAdapter _mv )
{
final Type rootType = rootType();
_mv.loadThis();
_mv.getField( classType(), ROOT_MEMBER_NAME, rootType );
_mv.getField( rootType, ENV_MEMBER_NAME, ENV_CLASS );
}
@Override
protected void compileComputationModeAccess( final GeneratorAdapter _mv )
{
final Type rootType = rootType();
_mv.loadThis();
_mv.getField( classType(), ROOT_MEMBER_NAME, rootType );
rootSectionCompiler().compileComputationModeAccessGivenThis( _mv );
}
@Override
protected void compileComputationTimeAccess( GeneratorAdapter _mv )
{
final Type rootType = rootType();
_mv.loadThis();
_mv.getField( classType(), ROOT_MEMBER_NAME, rootType );
rootSectionCompiler().compileComputationTimeAccessGivenThis( _mv );
}
}