org.smeup.sys.dk.compiler.rpj.writer.JDTCallableUnitWriter.java Source code

Java tutorial

Introduction

Here is the source code for org.smeup.sys.dk.compiler.rpj.writer.JDTCallableUnitWriter.java

Source

/**
 *  Copyright (c) 2012, 2016 Sme.UP and others.
 *  All rights reserved. This program and the accompanying materials
 *  are made available under the terms of the Eclipse Public License v1.0
 *  which accompanies this distribution, and is available at
 *  http://www.eclipse.org/legal/epl-v10.html
 *
 *
 * Contributors:
 *   Mattia Rocchi           - Initial API and implementation
 *   Giuliano Giancristofaro - Implementation
 */
package org.smeup.sys.dk.compiler.rpj.writer;

import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.inject.Inject;

import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.datatools.modelbase.sql.query.QueryExpressionBody;
import org.eclipse.datatools.modelbase.sql.query.QuerySelect;
import org.eclipse.datatools.modelbase.sql.query.QuerySelectStatement;
import org.eclipse.datatools.modelbase.sql.query.QueryStatement;
import org.eclipse.datatools.modelbase.sql.query.ValueExpressionVariable;
import org.eclipse.datatools.modelbase.sql.query.helper.StatementHelper;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.ArrayCreation;
import org.eclipse.jdt.core.dom.ArrayInitializer;
import org.eclipse.jdt.core.dom.Assignment;
import org.eclipse.jdt.core.dom.Assignment.Operator;
import org.eclipse.jdt.core.dom.Block;
import org.eclipse.jdt.core.dom.EnumConstantDeclaration;
import org.eclipse.jdt.core.dom.EnumDeclaration;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.ExpressionStatement;
import org.eclipse.jdt.core.dom.FieldDeclaration;
import org.eclipse.jdt.core.dom.IfStatement;
import org.eclipse.jdt.core.dom.MarkerAnnotation;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword;
import org.eclipse.jdt.core.dom.Name;
import org.eclipse.jdt.core.dom.ParameterizedType;
import org.eclipse.jdt.core.dom.ReturnStatement;
import org.eclipse.jdt.core.dom.SimpleType;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.jdt.core.dom.StringLiteral;
import org.eclipse.jdt.core.dom.Type;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import org.smeup.sys.db.esql.CursorType;
import org.smeup.sys.db.esql.QCursor;
import org.smeup.sys.db.esql.QCursorTerm;
import org.smeup.sys.db.esql.QStatement;
import org.smeup.sys.db.esql.QStatementTerm;
import org.smeup.sys.db.esql.annotation.CursorDef;
import org.smeup.sys.db.syntax.QQueryParser;
import org.smeup.sys.dk.compiler.DevelopmentKitCompilerRuntimeException;
import org.smeup.sys.dk.compiler.QCompilationSetup;
import org.smeup.sys.dk.compiler.QCompilationUnit;
import org.smeup.sys.dk.compiler.QCompilerLinker;
import org.smeup.sys.dk.compiler.QCompilerManager;
import org.smeup.sys.dk.compiler.QDevelopmentKitCompilerFactory;
import org.smeup.sys.dk.compiler.UnitScope;
import org.smeup.sys.dk.compiler.rpj.RPJCallableUnitInfo;
import org.smeup.sys.dk.compiler.rpj.RPJContextHelper;
import org.smeup.sys.dk.compiler.rpj.dbl.DBLQuerySelectWriter;
import org.smeup.sys.dk.core.annotation.Supported;
import org.smeup.sys.dk.core.annotation.ToDo;
import org.smeup.sys.dk.core.annotation.Unsupported;
import org.smeup.sys.dk.test.annotation.TestStarted;
import org.smeup.sys.il.core.term.QTerm;
import org.smeup.sys.il.data.QBufferedData;
import org.smeup.sys.il.data.QBufferedElement;
import org.smeup.sys.il.data.QData;
import org.smeup.sys.il.data.annotation.Entry;
import org.smeup.sys.il.data.annotation.Main;
import org.smeup.sys.il.data.annotation.Open;
import org.smeup.sys.il.data.annotation.Optional;
import org.smeup.sys.il.data.annotation.PostMain;
import org.smeup.sys.il.data.annotation.PreMain;
import org.smeup.sys.il.data.annotation.Snap;
import org.smeup.sys.il.data.def.QPointerDef;
import org.smeup.sys.il.data.term.QDataTerm;
import org.smeup.sys.il.data.term.QRemap;
import org.smeup.sys.il.esam.QDataSet;
import org.smeup.sys.il.esam.QDataSetTerm;
import org.smeup.sys.il.esam.QDisplay;
import org.smeup.sys.il.esam.QDisplayTerm;
import org.smeup.sys.il.esam.QIntegratedLanguageEsamPackage;
import org.smeup.sys.il.esam.QKSDataSet;
import org.smeup.sys.il.esam.QKeyListTerm;
import org.smeup.sys.il.esam.QPrint;
import org.smeup.sys.il.esam.QPrintTerm;
import org.smeup.sys.il.esam.QRRDataSet;
import org.smeup.sys.il.esam.QSMDataSet;
import org.smeup.sys.il.esam.annotation.FileDef;
import org.smeup.sys.il.expr.IntegratedLanguageExpressionRuntimeException;
import org.smeup.sys.il.expr.QExpression;
import org.smeup.sys.il.expr.QExpressionParser;
import org.smeup.sys.il.expr.QTermExpression;
import org.smeup.sys.il.flow.QAnnotationTest;
import org.smeup.sys.il.flow.QBlock;
import org.smeup.sys.il.flow.QCallableUnit;
import org.smeup.sys.il.flow.QConversion;
import org.smeup.sys.il.flow.QDataSection;
import org.smeup.sys.il.flow.QEntry;
import org.smeup.sys.il.flow.QEntryParameter;
import org.smeup.sys.il.flow.QIntegratedLanguageFlowFactory;
import org.smeup.sys.il.flow.QMethodExec;
import org.smeup.sys.il.flow.QModule;
import org.smeup.sys.il.flow.QParameterList;
import org.smeup.sys.il.flow.QProcedure;
import org.smeup.sys.il.flow.QPrototype;
import org.smeup.sys.il.flow.QRoutine;
import org.smeup.sys.il.flow.QUnit;
import org.smeup.sys.mi.core.util.QLists;
import org.smeup.sys.os.file.QExternalFile;

public abstract class JDTCallableUnitWriter extends JDTUnitWriter {

    private QExpressionParser expressionParser;
    private QQueryParser queryParser;

    public JDTCallableUnitWriter(JDTNamedNodeWriter root, QCompilationUnit compilationUnit,
            QCompilationSetup compilationSetup, String name, UnitScope scope) {
        super(root, compilationUnit, compilationSetup, name, scope);

        expressionParser = getCompilationUnit().getContext().get(QExpressionParser.class);
        queryParser = getCompilationUnit().getContext().get(QQueryParser.class);
    }

    @SuppressWarnings("unchecked")
    public void writeLabels(Collection<String> labels, boolean private_, boolean static_) {

        if (labels.isEmpty())
            return;

        EnumDeclaration enumType = getAST().newEnumDeclaration();
        enumType.setName(getAST().newSimpleName("TAG"));

        if (private_)
            enumType.modifiers().add(getAST().newModifier(Modifier.ModifierKeyword.PRIVATE_KEYWORD));
        else
            enumType.modifiers().add(getAST().newModifier(Modifier.ModifierKeyword.PUBLIC_KEYWORD));

        if (static_)
            enumType.modifiers().add(getAST().newModifier(Modifier.ModifierKeyword.STATIC_KEYWORD));

        // elements
        int num = 0;

        for (String label : labels) {

            EnumConstantDeclaration constantDeclaration = getAST().newEnumConstantDeclaration();
            constantDeclaration.setName(getAST().newSimpleName(getCompilationUnit().normalizeLabelName(label)));

            enumType.enumConstants().add(num, constantDeclaration);
            num++;
        }

        getTarget().bodyDeclarations().add(enumType);
    }

    @SuppressWarnings("unchecked")
    public void writeMessages(Collection<String> messages) {

        EnumDeclaration enumType = getAST().newEnumDeclaration();
        enumType.setName(getAST().newSimpleName("QCPFMSG"));
        enumType.modifiers().add(getAST().newModifier(Modifier.ModifierKeyword.PUBLIC_KEYWORD));
        enumType.modifiers().add(getAST().newModifier(Modifier.ModifierKeyword.STATIC_KEYWORD));

        // elements
        int num = 0;

        for (String message : messages) {
            if (message.equalsIgnoreCase("CPF0000"))
                continue;
            EnumConstantDeclaration constantDeclaration = getAST().newEnumConstantDeclaration();
            constantDeclaration.setName(getAST().newSimpleName(normalizeEnumName(message)));

            enumType.enumConstants().add(num, constantDeclaration);
            num++;
        }

        getTarget().bodyDeclarations().add(enumType);
    }

    @SuppressWarnings("unchecked")
    public void writeModuleFields(List<String> modules, UnitScope scope) {

        for (String module : modules) {

            VariableDeclarationFragment variable = getAST().newVariableDeclarationFragment();
            FieldDeclaration field = getAST().newFieldDeclaration(variable);

            // writeAnnotation(field, ModuleDef.class, "name", moduleName);
            writeAnnotation(field, Inject.class);
            // writeAnnotation(field, Named.class, "value", moduleName);

            // TODO remove me
            if ((module.equalsIgnoreCase("MUB") || module.equalsIgnoreCase("MDV"))
                    && !(getCompilationUnit().getNode() instanceof QProcedure))
                field.modifiers().add(getAST().newModifier(ModifierKeyword.PROTECTED_KEYWORD));
            else {
                switch (scope) {
                case FRIENDLY:
                    break;
                case PRIVATE:
                    field.modifiers().add(getAST().newModifier(ModifierKeyword.PRIVATE_KEYWORD));
                    break;
                case PROTECTED:
                    field.modifiers().add(getAST().newModifier(ModifierKeyword.PROTECTED_KEYWORD));
                    break;
                case PUBLIC:
                    field.modifiers().add(getAST().newModifier(ModifierKeyword.PUBLIC_KEYWORD));
                    break;
                }
            }
            String moduleName = getCompilationUnit().normalizeTypeName(module);
            field.setType(getAST().newSimpleType(getAST().newName(moduleName)));

            variable.setName(getAST().newSimpleName(getCompilationUnit().normalizeModuleName(module)));

            getTarget().bodyDeclarations().add(field);
        }

    }

    public void writeDataFields(QDataSection dataSection, UnitScope scope) {

        List<String> fields = new ArrayList<String>();
        // fields
        for (QDataTerm<?> dataTerm : dataSection.getDatas()) {

            if (dataTerm.getDefinition() == null)
                continue;

            dataTerm = getCompilationUnit().getDataTerm(dataTerm.getName(), false);

            if (fields.contains(getCompilationUnit().normalizeTermName(dataTerm.getName())))
                continue;

            if (dataTerm.getDefinition() instanceof QPointerDef) {
                writeField(dataTerm, false, UnitScope.PROTECTED);
            } else {
                writeField(dataTerm, false, scope);
            }

            fields.add(getCompilationUnit().normalizeTermName(dataTerm.getName()));
        }

    }

    @SuppressWarnings("unchecked")
    public void writeDataSets(List<QDataSetTerm> dataSets) throws IOException {

        writeImport(QDataSet.class);

        for (QDataSetTerm dataSetTerm : dataSets) {

            VariableDeclarationFragment variable = getAST().newVariableDeclarationFragment();
            FieldDeclaration field = getAST().newFieldDeclaration(variable);

            String className = null;

            if (dataSetTerm.isKeyedAccess()) {
                writeImport(QKSDataSet.class);
                className = QKSDataSet.class.getSimpleName();
            } else {
                if (dataSetTerm.getFacet(QExternalFile.class) != null) {
                    writeImport(QRRDataSet.class);
                    className = QRRDataSet.class.getSimpleName();
                } else {
                    writeImport(QSMDataSet.class);
                    className = QSMDataSet.class.getSimpleName();
                }
            }

            Type dataSetType = getAST().newSimpleType(getAST().newSimpleName(className));
            ParameterizedType parType = getAST().newParameterizedType(dataSetType);

            QCompilerLinker compilerLinker = dataSetTerm.getFacet(QCompilerLinker.class);
            if (compilerLinker != null) {
                writeImport(compilerLinker.getLinkedClass());
                parType.typeArguments().add(
                        getAST().newSimpleType(getAST().newName(compilerLinker.getLinkedClass().getSimpleName())));
            } else {
                String argument = dataSetTerm.getFormatName();
                if (argument == null)
                    argument = dataSetTerm.getName();

                parType.typeArguments().add(getAST().newSimpleType(getAST().newSimpleName(argument)));
            }

            if (!((SimpleType) parType.typeArguments().get(0)).getName().toString().equals(dataSetTerm.getName()))
                writeAnnotation(field, FileDef.class, "name", dataSetTerm.getName());

            EObject eDataSet = (EObject) dataSetTerm;

            if (eDataSet.eIsSet(QIntegratedLanguageEsamPackage.eINSTANCE.getFileTerm_UserOpen()))
                writeAnnotation(field, FileDef.class, "userOpen", dataSetTerm.isUserOpen());

            if (eDataSet.eIsSet(QIntegratedLanguageEsamPackage.eINSTANCE.getFileTerm_InfoStruct()))
                writeAnnotation(field, FileDef.class, "info",
                        getCompilationUnit().normalizeTermName(dataSetTerm.getInfoStruct()));

            if (eDataSet.eIsSet(QIntegratedLanguageEsamPackage.eINSTANCE.getDataSetTerm_Prefix()))
                writeAnnotation(field, FileDef.class, "prefix", dataSetTerm.getPrefix());

            if (eDataSet.eIsSet(QIntegratedLanguageEsamPackage.eINSTANCE.getDataSetTerm_ExternalFile())) {
                QDataTerm<?> externalFileTerm = getCompilationUnit().getDataTerm(dataSetTerm.getExternalFile(),
                        true);
                writeAnnotation(field, FileDef.class, "externalFile",
                        getCompilationUnit().getQualifiedName(externalFileTerm));
            }

            if (eDataSet.eIsSet(QIntegratedLanguageEsamPackage.eINSTANCE.getDataSetTerm_ExternalMember())) {
                QDataTerm<?> externalFileMember = getCompilationUnit().getDataTerm(dataSetTerm.getExternalMember(),
                        true);
                writeAnnotation(field, FileDef.class, "externalMember",
                        getCompilationUnit().getQualifiedName(externalFileMember));
            }

            if (getCompilationUnit().getNode() instanceof QModule)
                field.modifiers().add(getAST().newModifier(ModifierKeyword.PUBLIC_KEYWORD));
            else
                field.modifiers().add(getAST().newModifier(ModifierKeyword.PROTECTED_KEYWORD));

            field.modifiers().add(getAST().newModifier(ModifierKeyword.TRANSIENT_KEYWORD));

            field.setType(parType);
            if (dataSetTerm.getFormatName() != null)
                variable.setName(getAST()
                        .newSimpleName(getCompilationUnit().normalizeTermName(dataSetTerm.getFormatName())));
            else
                variable.setName(
                        getAST().newSimpleName(getCompilationUnit().normalizeTermName(dataSetTerm.getName())));

            getTarget().bodyDeclarations().add(field);

            // internal file definition
            if (compilerLinker == null && dataSetTerm.getFormat() != null) {
                if (dataSetTerm.getFormatName() != null)
                    writeInnerRecord(dataSetTerm.getFormatName(), dataSetTerm.getFormat().getDefinition());
                else
                    writeInnerRecord(dataSetTerm.getName(), dataSetTerm.getFormat().getDefinition());
            }
        }

    }

    public void writeKeyLists(List<QKeyListTerm> keyLists) {

        writeImport(QBufferedData.class);

        for (QKeyListTerm keyList : keyLists)
            if (!RPJContextHelper.containsArray(expressionParser, keyList))
                writeKeyList(keyList);
    }

    @SuppressWarnings("unchecked")
    public void writeKeyList(QKeyListTerm keyList) {

        writeImport(QBufferedElement.class);

        VariableDeclarationFragment variable = getAST().newVariableDeclarationFragment();
        variable.setName(getAST().newSimpleName(getCompilationUnit().normalizeTermName(keyList.getName())));
        FieldDeclaration field = getAST().newFieldDeclaration(variable);
        field.modifiers().add(getAST().newModifier(ModifierKeyword.PRIVATE_KEYWORD));

        Type bufferedType = getAST().newSimpleType(getAST().newSimpleName(QBufferedElement.class.getSimpleName()));
        field.setType(getAST().newArrayType(bufferedType));

        // array of bufferedData
        ArrayCreation arrayCreation = getAST().newArrayCreation();
        arrayCreation.setType(getAST().newArrayType(
                getAST().newSimpleType(getAST().newSimpleName(QBufferedElement.class.getSimpleName()))));

        ArrayInitializer arrayInitializer = getAST().newArrayInitializer();
        for (String keyField : keyList.getKeyFields()) {

            QExpression expression = expressionParser.parseExpression(keyField);
            Expression jdtExpression = JDTStatementHelper.buildExpression(getAST(), getCompilationUnit(),
                    expression, null);
            arrayInitializer.expressions().add(jdtExpression);
        }
        arrayCreation.setInitializer(arrayInitializer);

        variable.setInitializer(arrayCreation);

        getTarget().bodyDeclarations().add(field);
    }

    @SuppressWarnings("unchecked")
    public void writeCursors(List<QCursorTerm> cursors) {

        writeImport(QCursor.class);
        writeImport(CursorType.class);

        for (QCursorTerm cursorTerm : cursors) {

            VariableDeclarationFragment variable = getAST().newVariableDeclarationFragment();
            FieldDeclaration field = getAST().newFieldDeclaration(variable);

            writeAnnotation(field, CursorDef.class, "type", cursorTerm.getCursorType());
            if (cursorTerm.isHold())
                writeAnnotation(field, CursorDef.class, "hold", cursorTerm.isHold());
            if (cursorTerm.getStatementName() != null)
                writeAnnotation(field, CursorDef.class, "statement",
                        getCompilationUnit().normalizeTermName(cursorTerm.getStatementName()));

            if (cursorTerm.getSql() != null) {

                try {
                    List<ValueExpressionVariable> variables = StatementHelper.getAllVariablesInQueryStatement(
                            queryParser.parseQuery(cursorTerm.getSql()).getQueryStatement());
                    if (variables.isEmpty())
                        writeAnnotation(field, CursorDef.class, "sql", cursorTerm.getSql());
                } catch (SQLException e) {
                    throw new DevelopmentKitCompilerRuntimeException("Invalid statement: " + cursorTerm);
                }
            }

            field.modifiers().add(getAST().newModifier(ModifierKeyword.PROTECTED_KEYWORD));

            field.modifiers().add(getAST().newModifier(ModifierKeyword.TRANSIENT_KEYWORD));

            Type dataSetType = getAST().newSimpleType(getAST().newSimpleName(QCursor.class.getSimpleName()));
            field.setType(dataSetType);
            variable.setName(getAST().newSimpleName(getCompilationUnit().normalizeTermName(cursorTerm.getName())));

            getTarget().bodyDeclarations().add(field);
        }

    }

    @SuppressWarnings("unchecked")
    public void writeStatements(List<QStatementTerm> statements) {

        writeImport(QStatement.class);

        for (QStatementTerm statementTerm : statements) {

            VariableDeclarationFragment variable = getAST().newVariableDeclarationFragment();
            FieldDeclaration field = getAST().newFieldDeclaration(variable);
            field.modifiers().add(getAST().newModifier(ModifierKeyword.PROTECTED_KEYWORD));
            field.modifiers().add(getAST().newModifier(ModifierKeyword.TRANSIENT_KEYWORD));

            Type dataSetType = getAST().newSimpleType(getAST().newSimpleName(QStatement.class.getSimpleName()));
            field.setType(dataSetType);
            variable.setName(
                    getAST().newSimpleName(getCompilationUnit().normalizeTermName(statementTerm.getName())));
            getTarget().bodyDeclarations().add(field);
        }
    }

    @SuppressWarnings("unchecked")
    public void writeDisplays(List<QDisplayTerm> displays) throws IOException {

        writeImport(QDisplay.class);

        for (QDisplayTerm displayTerm : displays) {

            VariableDeclarationFragment variable = getAST().newVariableDeclarationFragment();
            FieldDeclaration field = getAST().newFieldDeclaration(variable);

            String className = null;
            QCompilerLinker compilerLinker = displayTerm.getFacet(QCompilerLinker.class);

            writeImport(QDisplay.class);
            className = QDisplay.class.getSimpleName();

            Type displayType = getAST().newSimpleType(getAST().newSimpleName(className));
            ParameterizedType parType = getAST().newParameterizedType(displayType);

            if (compilerLinker != null) {
                writeImport(compilerLinker.getLinkedClass());
                parType.typeArguments().add(
                        getAST().newSimpleType(getAST().newName(compilerLinker.getLinkedClass().getSimpleName())));
            } else {
                String argument = displayTerm.getName();
                parType.typeArguments().add(getAST().newSimpleType(getAST().newSimpleName(argument)));
            }

            if (!((SimpleType) parType.typeArguments().get(0)).getName().toString().equals(displayTerm.getName()))
                writeAnnotation(field, FileDef.class, "name", displayTerm.getName());

            EObject eDataSet = (EObject) displayTerm;
            if (eDataSet.eIsSet(QIntegratedLanguageEsamPackage.eINSTANCE.getFileTerm_UserOpen()))
                writeAnnotation(field, FileDef.class, "userOpen", displayTerm.isUserOpen());

            if (eDataSet.eIsSet(QIntegratedLanguageEsamPackage.eINSTANCE.getFileTerm_InfoStruct()))
                writeAnnotation(field, FileDef.class, "info",
                        getCompilationUnit().normalizeTermName(displayTerm.getInfoStruct()));

            if (getCompilationUnit().getNode() instanceof QModule)
                field.modifiers().add(getAST().newModifier(ModifierKeyword.PUBLIC_KEYWORD));
            else
                field.modifiers().add(getAST().newModifier(ModifierKeyword.PROTECTED_KEYWORD));

            //         field.modifiers().add(getAST().newModifier(ModifierKeyword.TRANSIENT_KEYWORD));

            field.setType(parType);
            variable.setName(getAST().newSimpleName(getCompilationUnit().normalizeTermName(displayTerm.getName())));

            getTarget().bodyDeclarations().add(field);

        }

    }

    @SuppressWarnings("unchecked")
    public void writePrinters(List<QPrintTerm> printers) throws IOException {

        writeImport(QPrint.class);

        for (QPrintTerm printTerm : printers) {

            VariableDeclarationFragment variable = getAST().newVariableDeclarationFragment();
            FieldDeclaration field = getAST().newFieldDeclaration(variable);

            String className = null;
            QCompilerLinker compilerLinker = printTerm.getFacet(QCompilerLinker.class);

            writeImport(QPrint.class);
            className = QPrint.class.getSimpleName();

            Type printerType = getAST().newSimpleType(getAST().newSimpleName(className));
            ParameterizedType parType = getAST().newParameterizedType(printerType);

            if (compilerLinker != null) {
                writeImport(compilerLinker.getLinkedClass());
                parType.typeArguments().add(
                        getAST().newSimpleType(getAST().newName(compilerLinker.getLinkedClass().getSimpleName())));
            } else {
                //            String argument = printTerm.getName();
                String argument = "PRT198";
                writeImport("com.smeup.erp.file.prtf.XX.gen.PRT198");
                parType.typeArguments().add(getAST().newSimpleType(getAST().newSimpleName(argument)));
            }

            if (!((SimpleType) parType.typeArguments().get(0)).getName().toString().equals(printTerm.getName()))
                writeAnnotation(field, FileDef.class, "name", printTerm.getName());

            EObject eDataSet = (EObject) printTerm;
            if (eDataSet.eIsSet(QIntegratedLanguageEsamPackage.eINSTANCE.getFileTerm_UserOpen()))
                writeAnnotation(field, FileDef.class, "userOpen", printTerm.isUserOpen());

            if (eDataSet.eIsSet(QIntegratedLanguageEsamPackage.eINSTANCE.getFileTerm_InfoStruct()))
                writeAnnotation(field, FileDef.class, "info",
                        getCompilationUnit().normalizeTermName(printTerm.getInfoStruct()));

            if (getCompilationUnit().getNode() instanceof QModule)
                field.modifiers().add(getAST().newModifier(ModifierKeyword.PUBLIC_KEYWORD));
            else
                field.modifiers().add(getAST().newModifier(ModifierKeyword.PROTECTED_KEYWORD));

            //         field.modifiers().add(getAST().newModifier(ModifierKeyword.TRANSIENT_KEYWORD));

            field.setType(parType);
            variable.setName(getAST().newSimpleName(getCompilationUnit().normalizeTermName(printTerm.getName())));

            getTarget().bodyDeclarations().add(field);

        }
    }

    public void writeRoutines(QCallableUnit callableUnit, RPJCallableUnitInfo callableUnitInfo) {

        // special routines
        if (callableUnit.getFlowSection() != null)
            for (QRoutine routine : callableUnit.getFlowSection().getRoutines()) {
                if (!routine.getName().startsWith("*"))
                    continue;
                writeRoutine(routine);
            }

        // main
        if (callableUnit.getMain() != null) {
            QRoutine routine = QIntegratedLanguageFlowFactory.eINSTANCE.createRoutine();
            routine.setName("*MAIN");
            routine.setMain(callableUnit.getMain());
            MethodDeclaration methodDeclaration = writeRoutine(routine);
            if (callableUnit.getName().startsWith("MUTE")) {
                MarkerAnnotation entryAnnotation = getAST().newMarkerAnnotation();
                entryAnnotation.setTypeName(getAST().newSimpleName(TestStarted.class.getSimpleName()));
                writeImport(TestStarted.class);
                writeRoutineTestMain(methodDeclaration, callableUnit);
            }
        }

        // snap
        if (!callableUnitInfo.getResetObjects().isEmpty())
            writeSnapRoutine(callableUnit, callableUnitInfo);

        // routines
        if (callableUnit.getFlowSection() != null)
            for (QRoutine routine : callableUnit.getFlowSection().getRoutines()) {
                if (routine.getName().startsWith("*"))
                    continue;
                writeRoutine(routine);
            }
    }

    public void writeSnapRoutine(QCallableUnit callableUnit, RPJCallableUnitInfo callableUnitInfo) {

        QRoutine routine = QIntegratedLanguageFlowFactory.eINSTANCE.createRoutine();
        routine.setName("*SNAP");
        routine.setMain(callableUnit.getMain());

        QBlock block = QIntegratedLanguageFlowFactory.eINSTANCE.createBlock();
        routine.setMain(block);
        for (String object : callableUnitInfo.getResetObjects()) {
            QMethodExec methodExec = QIntegratedLanguageFlowFactory.eINSTANCE.createMethodExec();
            methodExec.setObject(object);
            methodExec.setMethod("snap");
            block.getStatements().add(methodExec);
        }

        writeRoutine(routine);
    }

    @SuppressWarnings("unchecked")
    public MethodDeclaration writeRoutine(QRoutine routine) {

        MethodDeclaration methodDeclaration = getAST().newMethodDeclaration();

        String routineName = getCompilationUnit().normalizeRoutineName(routine.getName());
        if (routine.getName().equals("*INZSR")) {
            routineName = "_open";
            MarkerAnnotation openAnnotation = getAST().newMarkerAnnotation();
            openAnnotation.setTypeName(getAST().newSimpleName(Open.class.getSimpleName()));
            writeImport(Open.class);
            methodDeclaration.modifiers().add(openAnnotation);
        } else if (routine.getName().equals("*ENTRY")) {
            routineName = "_entry";
            MarkerAnnotation preMainAnnotation = getAST().newMarkerAnnotation();
            preMainAnnotation.setTypeName(getAST().newSimpleName(PreMain.class.getSimpleName()));
            writeImport(PreMain.class);
            methodDeclaration.modifiers().add(preMainAnnotation);
        } else if (routine.getName().equals("*MAIN")) {
            routineName = "_main";
            MarkerAnnotation mainAnnotation = getAST().newMarkerAnnotation();
            mainAnnotation.setTypeName(getAST().newSimpleName(Main.class.getSimpleName()));
            writeImport(Main.class);
            methodDeclaration.modifiers().add(mainAnnotation);
        } else if (routine.getName().equals("*SNAP")) {
            routineName = "_snap";
            MarkerAnnotation mainAnnotation = getAST().newMarkerAnnotation();
            mainAnnotation.setTypeName(getAST().newSimpleName(Snap.class.getSimpleName()));
            writeImport(Snap.class);
            methodDeclaration.modifiers().add(mainAnnotation);
        } else if (routine.getName().equals("*EXIT")) {
            routineName = "_exit";
            MarkerAnnotation postMainAnnotation = getAST().newMarkerAnnotation();
            postMainAnnotation.setTypeName(getAST().newSimpleName(PostMain.class.getSimpleName()));
            writeImport(PostMain.class);
            methodDeclaration.modifiers().add(postMainAnnotation);
        }

        getTarget().bodyDeclarations().add(methodDeclaration);

        methodDeclaration.setName(getAST().newSimpleName(routineName));
        methodDeclaration.modifiers().add(getAST().newModifier(ModifierKeyword.PUBLIC_KEYWORD));

        // writeSuppressWarning(methodDeclaration);

        Block block = getAST().newBlock();
        methodDeclaration.setBody(block);

        if (routine.getMain() == null)
            return methodDeclaration;

        // write java AST
        JDTStatementWriter statementWriter = getCompilationUnit().getContext().make(JDTStatementWriter.class);
        statementWriter.setAST(getAST());

        statementWriter.getBlocks().push(block);

        if (routine.getMain() instanceof QBlock) {
            QBlock qBlock = (QBlock) routine.getMain();
            for (org.smeup.sys.il.flow.QStatement qStatement : qBlock.getStatements())
                qStatement.accept(statementWriter);
        } else
            routine.getMain().accept(statementWriter);

        statementWriter.getBlocks().pop();

        return methodDeclaration;
    }

    @SuppressWarnings("unchecked")
    public void writePrototype(QPrototype prototype) {

        MethodDeclaration methodDeclaration = getAST().newMethodDeclaration();
        getTarget().bodyDeclarations().add(methodDeclaration);

        methodDeclaration
                .setName(getAST().newSimpleName(getCompilationUnit().normalizeTermName(prototype.getName())));
        methodDeclaration.modifiers().add(getAST().newModifier(ModifierKeyword.PUBLIC_KEYWORD));

        Block block = getAST().newBlock();
        methodDeclaration.setBody(block);

        if (prototype.getDefinition() != null) {
            Type type = getJavaType(prototype);
            methodDeclaration.setReturnType2(type);
        }

        // TODO QExternalProgram
        QExternalFile externalFile = prototype.getFacet(QExternalFile.class);
        if (externalFile != null) {
            writePrototypeCall(prototype, externalFile.getName(), methodDeclaration, block);

            if (prototype.getDefinition() != null) {
                ReturnStatement returnStatement = getAST().newReturnStatement();
                returnStatement.setExpression(getAST().newNullLiteral());
                block.statements().add(returnStatement);
            }

        } else {
            QProcedure procedure = getCompilationUnit().getProcedure(prototype.getName(), false);
            if (procedure == null)
                throw new DevelopmentKitCompilerRuntimeException("Invalid procedure bind: " + prototype);

            if (procedure.getEntry() != null)
                writeEntry(methodDeclaration, procedure.getEntry());

            writeLazyLoading(procedure, block);

            writeSetEntryParams(procedure, block);

            String namePrototype = getCompilationUnit().normalizeTermName(prototype.getName());
            MethodInvocation methodInvocation = getAST().newMethodInvocation();
            methodInvocation.setExpression(getAST().newName(namePrototype));
            methodInvocation.setName(getAST().newSimpleName("qExec"));

            for (Object entryParameter : methodDeclaration.parameters()) {
                SingleVariableDeclaration singleVariableDeclaration = (SingleVariableDeclaration) entryParameter;
                methodInvocation.arguments()
                        .add(getAST().newSimpleName(singleVariableDeclaration.getName().toString()));
            }

            if (prototype.getDefinition() != null) {
                ReturnStatement returnStatement = getAST().newReturnStatement();
                returnStatement.setExpression(methodInvocation);
                block.statements().add(returnStatement);
            } else {
                ExpressionStatement expressionStatement = getAST().newExpressionStatement(methodInvocation);
                block.statements().add(expressionStatement);
            }
        }
    }

    @SuppressWarnings("unchecked")
    private void writePrototypeCall(QPrototype prototype, String programName, MethodDeclaration methodDeclaration,
            Block block) {

        MethodInvocation methodInvocation = getAST().newMethodInvocation();
        methodInvocation.setExpression(getAST().newSimpleName("qRPJ"));
        methodInvocation.setName(getAST().newSimpleName("qCall"));

        // program name
        QTermExpression expression = expressionParser.parseTerm(programName);
        Expression jdtExpression = JDTStatementHelper.buildExpression(getAST(), getCompilationUnit(), expression,
                String.class);
        methodInvocation.arguments().add(jdtExpression);

        // array of parameter
        ArrayInitializer arrayInitializer = getAST().newArrayInitializer();
        if (prototype.getEntry() != null) {
            writeEntry(methodDeclaration, prototype.getEntry());

            for (QEntryParameter<?> entryParameter : prototype.getEntry().getParameters()) {

                if (!(entryParameter.getDelegate() instanceof QDataTerm<?>))
                    throw new DevelopmentKitCompilerRuntimeException("Invalid parameter: " + entryParameter);

                QDataTerm<?> parameterDelegate = (QDataTerm<?>) entryParameter.getDelegate();
                String parameterName = parameterDelegate.getName();
                parameterName = getCompilationUnit().normalizeTermName(parameterName);

                // call parameter
                if (parameterDelegate.isConstant() && !parameterDelegate.getDataTermType().isMultiple()
                        && !(parameterDelegate.getDefinition() instanceof QPointerDef)) {
                    ASTParser parser = ASTParser.newParser(AST.JLS8);
                    parser.setKind(ASTParser.K_EXPRESSION);
                    parser.setSource(("qRPJ.qBox(" + parameterName + ")").toCharArray());
                    ASTNode node = parser.createAST(new NullProgressMonitor());
                    arrayInitializer.expressions()
                            .add((Expression) ASTNode.copySubtree(getAST(), (Expression) node));
                } else
                    arrayInitializer.expressions().add(getAST().newName(parameterName));
            }
        }

        ArrayCreation arrayCreation = getAST().newArrayCreation();
        arrayCreation.setType(
                getAST().newArrayType(getAST().newSimpleType(getAST().newSimpleName(QData.class.getSimpleName()))));
        arrayCreation.setInitializer(arrayInitializer);
        methodInvocation.arguments().add(arrayCreation);

        ExpressionStatement expressionStatement = getAST().newExpressionStatement(methodInvocation);
        block.statements().add(expressionStatement);
    }

    @SuppressWarnings("unchecked")
    private void writeLazyLoading(QProcedure procedure, Block block) {

        IfStatement ifStatement = getAST().newIfStatement();
        String expression = getCompilationUnit().normalizeTermName(procedure.getName()) + " == null";
        ifStatement.setExpression(buildExpression(expression));

        Assignment assignment = getAST().newAssignment();
        assignment.setLeftHandSide(buildExpression(getCompilationUnit().normalizeTermName(procedure.getName())));
        assignment.setRightHandSide(buildExpression("qRPJ.bindProcedure(this, "
                + getCompilationUnit().normalizeTypeName(procedure.getName()) + ".class)"));
        assignment.setOperator(Operator.ASSIGN);
        ifStatement.setThenStatement(getAST().newExpressionStatement(assignment));

        block.statements().add(ifStatement);
    }

    @SuppressWarnings("unchecked")
    private void writeSetEntryParams(QProcedure procedure, Block block) {
        List<QEntryParameter<?>> entryParameters = new ArrayList<QEntryParameter<?>>();
        if (procedure.getEntry() != null) {
            entryParameters.addAll(procedure.getEntry().getParameters());
            Collections.reverse(entryParameters);
        }

        int p = entryParameters.size();

        IfStatement baseIf = null;
        IfStatement lastIf = null;
        for (QEntryParameter<?> entryParameter : entryParameters) {

            if (!entryParameter.isNullable())
                break;

            // first
            if (entryParameters.size() == p) {

                IfStatement ifStatement = getAST().newIfStatement();
                ifStatement.setExpression(buildExpression(
                        getCompilationUnit().normalizeTermName(entryParameter.getName()) + " != null"));
                Expression expression = buildExpression(getCompilationUnit().normalizeTermName(procedure.getName())
                        + ".qPRO.qParms().eval(" + p + ")");
                ExpressionStatement expressionStatement = getAST().newExpressionStatement(expression);
                ifStatement.setThenStatement(expressionStatement);

                Expression expressionElse = buildExpression(
                        getCompilationUnit().normalizeTermName(procedure.getName()) + ".qPRO.qParms().eval("
                                + (p - 1) + ")");
                ExpressionStatement expressionElseStatement = getAST().newExpressionStatement(expressionElse);
                ifStatement.setElseStatement(expressionElseStatement);

                baseIf = ifStatement;
                lastIf = ifStatement;
            } else {
                IfStatement ifStatement = getAST().newIfStatement();
                ifStatement.setExpression(buildExpression(
                        getCompilationUnit().normalizeTermName(entryParameter.getName()) + " != null"));

                Expression expression = buildExpression(getCompilationUnit().normalizeTermName(procedure.getName())
                        + ".qPRO.qParms().eval(" + p + ")");
                ExpressionStatement expressionStatement = getAST().newExpressionStatement(expression);
                ifStatement.setThenStatement(expressionStatement);

                Expression expressionElse = buildExpression(
                        getCompilationUnit().normalizeTermName(procedure.getName()) + ".qPRO.qParms().eval("
                                + (p - 1) + ")");
                ExpressionStatement expressionElseStatement = getAST().newExpressionStatement(expressionElse);
                ifStatement.setElseStatement(expressionElseStatement);

                lastIf.setElseStatement(ifStatement);
                lastIf = ifStatement;
            }
            p--;
        }

        if (baseIf != null)
            block.statements().add(baseIf);
    }

    public void writeInnerProcedure(QProcedure procedure) {

        QCompilerManager compilerManager = getCompilationUnit().getContext().get(QCompilerManager.class);
        QCompilationUnit procedureCompilationUnit = compilerManager.createChildCompilationUnit(getCompilationUnit(),
                procedure);
        QCompilationSetup compilationSetup = QDevelopmentKitCompilerFactory.eINSTANCE.createCompilationSetup();

        try {

            boolean static_ = false;
            UnitScope scope = UnitScope.PROTECTED;

            switch (getCompilationSetup().getProcedureType()) {
            case INNER:
                break;
            case NESTED:
                static_ = true;
                scope = UnitScope.PUBLIC;
                break;
            }

            JDTProcedureWriter procedureWriter = new JDTProcedureWriter(this, procedureCompilationUnit,
                    compilationSetup, getCompilationUnit().normalizeTermName(procedure.getName()), scope, static_);

            procedureWriter.writeProcedure(procedure);
        } catch (IOException e) {
            throw new DevelopmentKitCompilerRuntimeException("Invalid procedure: " + procedure, e);
        } finally {
            procedureCompilationUnit.close();
        }
    }

    @SuppressWarnings("unchecked")
    public void writeMain(QParameterList parameterList, String name) {

        MethodDeclaration methodDeclaration = getAST().newMethodDeclaration();
        getTarget().bodyDeclarations().add(methodDeclaration);

        MarkerAnnotation entryAnnotation = getAST().newMarkerAnnotation();
        entryAnnotation.setTypeName(getAST().newSimpleName(Main.class.getSimpleName()));
        writeImport(Main.class);
        methodDeclaration.modifiers().add(entryAnnotation);

        methodDeclaration.setName(getAST().newSimpleName(name));
        methodDeclaration.modifiers().add(getAST().newModifier(ModifierKeyword.PUBLIC_KEYWORD));

        for (String parameterName : parameterList.getParameters()) {
            QDataTerm<?> dataTerm = getCompilationUnit().getDataTerm(parameterName, true);

            SingleVariableDeclaration parameterVariable = getAST().newSingleVariableDeclaration();
            parameterVariable
                    .setName(getAST().newSimpleName(getCompilationUnit().normalizeTermName(dataTerm.getName())));
            Type type = getJavaType(dataTerm);
            parameterVariable.setType(type);

            QConversion conversion = dataTerm.getFacet(QConversion.class);
            if (conversion != null) {
                MarkerAnnotation conversionAnnotation = getAST().newMarkerAnnotation();

                switch (conversion.getStatus()) {
                case POSSIBLE:
                    break;
                case SUPPORTED:
                    writeImport(Supported.class);
                    conversionAnnotation.setTypeName(getAST().newSimpleName(Supported.class.getSimpleName()));
                    parameterVariable.modifiers().add(conversionAnnotation);
                    break;
                case TODO:
                    writeImport(ToDo.class);
                    conversionAnnotation.setTypeName(getAST().newSimpleName(ToDo.class.getSimpleName()));
                    parameterVariable.modifiers().add(conversionAnnotation);
                    break;
                case UNSUPPORTED:
                    writeImport(Unsupported.class);
                    conversionAnnotation.setTypeName(getAST().newSimpleName(Unsupported.class.getSimpleName()));
                    parameterVariable.modifiers().add(conversionAnnotation);
                    break;
                }
            }

            writeDataDefAnnotation(parameterVariable, dataTerm.getDefinition());

            methodDeclaration.parameters().add(parameterVariable);
        }

        Block block = getAST().newBlock();
        methodDeclaration.setBody(block);
    }

    @SuppressWarnings("unchecked")
    public void writeInit() {

        writeImport(QBufferedElement.class);

        MethodDeclaration methodDeclaration = getAST().newMethodDeclaration();

        methodDeclaration.setName(getAST().newSimpleName("_init"));

        MarkerAnnotation entryAnnotation = getAST().newMarkerAnnotation();
        entryAnnotation.setTypeName(getAST().newSimpleName(PostConstruct.class.getSimpleName()));
        writeImport(PostConstruct.class);
        methodDeclaration.modifiers().add(entryAnnotation);

        methodDeclaration.modifiers().add(getAST().newModifier(ModifierKeyword.PUBLIC_KEYWORD));

        if (!(getCompilationUnit().getNode() instanceof QCallableUnit))
            return;

        Block block = getAST().newBlock();
        methodDeclaration.setBody(block);

        QCallableUnit callableUnit = (QCallableUnit) getCompilationUnit().getNode();
        if (callableUnit.getFileSection() != null) {

            // redefined record dataSet
            for (QDataSetTerm dataSetTerm : callableUnit.getFileSection().getDataSets()) {

                // remap
                if (dataSetTerm.getFormat() != null) {
                    for (QDataTerm<?> element : dataSetTerm.getFormat().getDefinition().getElements()) {
                        QRemap remap = element.getFacet(QRemap.class);
                        if (remap == null)
                            continue;

                        QDataTerm<?> remapDataTerm = getCompilationUnit().getDataTerm(remap.getName(), true);
                        if (remapDataTerm == null)
                            throw new IntegratedLanguageExpressionRuntimeException("Invalid term: " + remap);

                        if (getCompilationUnit().equalsTermName(element.getName(), remapDataTerm.getName()))
                            continue;

                        MethodInvocation methodInvocation = getAST().newMethodInvocation();
                        methodInvocation.setName(getAST().newSimpleName("assign"));

                        if (remap.getIndex() == null || remap.getIndex().isEmpty())
                            methodInvocation.setExpression(
                                    buildExpression(getCompilationUnit().getQualifiedName(remapDataTerm)));
                        else
                            methodInvocation.setExpression(
                                    buildExpression(getCompilationUnit().getQualifiedName(remapDataTerm) + ".get("
                                            + Integer.parseInt(remap.getIndex()) + ")"));

                        methodInvocation.arguments()
                                .add(buildExpression(getCompilationUnit().getQualifiedName(element)));
                        ExpressionStatement expressionStatement = getAST().newExpressionStatement(methodInvocation);
                        block.statements().add(expressionStatement);

                    }
                }
            }

            // assign statement parameters
            for (QCursorTerm cursorTerm : callableUnit.getFileSection().getCursors()) {
                if (cursorTerm.getSql() == null)
                    continue;

                try {
                    QueryStatement queryStatement = queryParser.parseQuery(cursorTerm.getSql()).getQueryStatement();

                    List<ValueExpressionVariable> variables = StatementHelper
                            .getAllVariablesInQueryStatement(queryStatement);
                    if (variables.isEmpty())
                        continue;

                    // array of bufferedData
                    ArrayCreation arrayCreation = getAST().newArrayCreation();
                    arrayCreation.setType(getAST().newArrayType(getAST()
                            .newSimpleType(getAST().newSimpleName(QBufferedElement.class.getSimpleName()))));
                    ArrayInitializer arrayInitializer = getAST().newArrayInitializer();
                    for (ValueExpressionVariable variable : variables) {
                        QExpression expression = expressionParser
                                .parseExpression(getCompilationUnit().normalizeTermName(variable.getName()));
                        Expression jdtExpression = JDTStatementHelper.buildExpression(getAST(),
                                getCompilationUnit(), expression, null);
                        arrayInitializer.expressions().add(jdtExpression);
                    }
                    arrayCreation.setInitializer(arrayInitializer);

                    DBLQuerySelectWriter querySelectWriter = new DBLQuerySelectWriter();
                    QuerySelectStatement selectStatement = (QuerySelectStatement) queryStatement;
                    QueryExpressionBody query = selectStatement.getQueryExpr().getQuery();
                    queryStatement = queryParser.parseQuery(cursorTerm.getSql()).getQueryStatement();
                    String newSQLString = querySelectWriter.normalizeQuerySelect((QuerySelect) query);

                    StringLiteral stringLiteral = getAST().newStringLiteral();
                    stringLiteral.setLiteralValue(newSQLString);

                    MethodInvocation methodInvocation = getAST().newMethodInvocation();
                    methodInvocation.setName(getAST().newSimpleName("qCreateCursor"));
                    methodInvocation.setExpression(getAST().newSimpleName("qSQL"));

                    Name labelName = getAST()
                            .newName(new String[] { cursorTerm.getCursorType().getClass().getSimpleName(),
                                    cursorTerm.getCursorType().name() });
                    methodInvocation.arguments().add(labelName);

                    methodInvocation.arguments().add(getAST().newBooleanLiteral(cursorTerm.isHold()));

                    methodInvocation.arguments().add(stringLiteral);

                    methodInvocation.arguments().add(arrayCreation);

                    Assignment assignment = getAST().newAssignment();
                    assignment.setLeftHandSide(buildExpression(getCompilationUnit().getQualifiedName(cursorTerm)));
                    assignment.setOperator(Operator.ASSIGN);
                    assignment.setRightHandSide(methodInvocation);

                    block.statements().add(getAST().newExpressionStatement(assignment));

                } catch (SQLException e) {
                    throw new DevelopmentKitCompilerRuntimeException("Invalid statement: " + cursorTerm);
                }
            }
        }

        if (!methodDeclaration.getBody().statements().isEmpty())
            getTarget().bodyDeclarations().add(methodDeclaration);
    }

    @SuppressWarnings("unchecked")
    public void writeEntry(QParameterList parameterList, String name) {

        MethodDeclaration methodDeclaration = getAST().newMethodDeclaration();
        getTarget().bodyDeclarations().add(methodDeclaration);

        methodDeclaration.setName(getAST().newSimpleName(name));

        MarkerAnnotation entryAnnotation = getAST().newMarkerAnnotation();
        entryAnnotation.setTypeName(getAST().newSimpleName(Entry.class.getSimpleName()));
        writeImport(Entry.class);
        methodDeclaration.modifiers().add(entryAnnotation);

        methodDeclaration.modifiers().add(getAST().newModifier(ModifierKeyword.PUBLIC_KEYWORD));
        Type returnType = getAST()
                .newArrayType(getAST().newSimpleType(getAST().newSimpleName(QData.class.getSimpleName())));
        methodDeclaration.setReturnType2(returnType);

        Block block = getAST().newBlock();
        methodDeclaration.setBody(block);

        ArrayCreation arrayCreation = getAST().newArrayCreation();
        arrayCreation.setType(
                getAST().newArrayType(getAST().newSimpleType(getAST().newSimpleName(QData.class.getSimpleName()))));

        ArrayInitializer arrayInitializer = getAST().newArrayInitializer();
        arrayCreation.setInitializer(arrayInitializer);
        for (String parameterName : parameterList.getParameters()) {
            QExpression expression = expressionParser.parseExpression(parameterName);
            Expression jdtExpression = JDTStatementHelper.buildExpression(getAST(), getCompilationUnit(),
                    expression, null);
            arrayInitializer.expressions().add(jdtExpression);
        }

        ReturnStatement returnStatement = getAST().newReturnStatement();
        returnStatement.setExpression(arrayCreation);
        block.statements().add(returnStatement);
    }

    public void refactCallableUnit(QCallableUnit callableUnit) {

        refactUnit(callableUnit);

        // main
        if (callableUnit.getFlowSection() != null) {
            for (QUnit routine : callableUnit.getFlowSection().getRoutines())
                refactUnit(routine);
        }
    }

    protected Expression buildExpression(String expression) {

        ASTParser parser = ASTParser.newParser(AST.JLS8);
        parser.setKind(ASTParser.K_EXPRESSION);

        parser.setSource(expression.toCharArray());
        ASTNode node = parser.createAST(null);
        if (node.getLength() == 0)
            throw new IntegratedLanguageExpressionRuntimeException("Invalid java conversion: " + expression);

        Expression jdtExpression = (Expression) node;

        return (Expression) ASTNode.copySubtree(getAST(), jdtExpression);
    }

    @SuppressWarnings("unchecked")
    public void writeEntry(MethodDeclaration methodDeclaration, QEntry entry) {

        int p = 0;
        for (QEntryParameter<?> entryParameter : entry.getParameters()) {

            QTerm parameterDelegate = entryParameter.getDelegate();

            SingleVariableDeclaration singleVar = getAST().newSingleVariableDeclaration();

            if (entryParameter.isNullable())
                writeAnnotation(singleVar, Optional.class);

            String parameterName = parameterDelegate.getName();
            if (parameterName == null)
                parameterName = "arg" + p;
            singleVar.setName(getAST().newSimpleName(getCompilationUnit().normalizeTermName(parameterName)));

            if (parameterDelegate instanceof QDataTerm) {
                QDataTerm<?> dataTerm = (QDataTerm<?>) parameterDelegate;

                // primitive
                if (dataTerm.isConstant() && !dataTerm.getDataTermType().isMultiple())
                    singleVar.setType(getJavaPrimitive(dataTerm));
                else {
                    Type type = getJavaType(dataTerm);
                    singleVar.setType(type);
                }

            } else if (parameterDelegate instanceof QDataSetTerm) {

                Type dataSet = getAST().newSimpleType(getAST().newSimpleName(QDataSet.class.getSimpleName()));
                ParameterizedType parType = getAST().newParameterizedType(dataSet);
                parType.typeArguments().add(getAST().newWildcardType());

                singleVar.setType(parType);
            }

            methodDeclaration.parameters().add(singleVar);

            p++;
        }
    }

    protected void loadModules(Collection<String> modules, String module, boolean recursive) {

        if (module.equalsIgnoreCase("*C2LE"))
            return;

        addModule(modules, module);
        QModule qModule = getCompilationUnit().getModule(module, true);
        for (String moduleName : qModule.getSetupSection().getModules()) {
            if (recursive)
                loadModules(modules, moduleName, recursive);
            else
                addModule(modules, module);
        }
    }

    @SuppressWarnings("unchecked")
    private void writeRoutineTestMain(MethodDeclaration methodDeclaration, QCallableUnit program) {

        QLists listUtil = getCompilationUnit().getContext().get(QLists.class);

        MarkerAnnotation entryAnnotation = getAST().newMarkerAnnotation();
        entryAnnotation.setTypeName(getAST().newSimpleName(TestStarted.class.getSimpleName()));
        writeImport(TestStarted.class);

        listUtil.addFirst(methodDeclaration.modifiers(), entryAnnotation);

        Block assertionBlock = getAST().newBlock();

        JDTStatementWriter statementWriter = getCompilationUnit().getContext().make(JDTStatementWriter.class);
        statementWriter.setAST(getAST());
        statementWriter.getBlocks().push(assertionBlock);

        // test annotations
        for (QDataTerm<?> dataTerm : program.getDataSection().getDatas()) {
            for (QAnnotationTest annotationTest : dataTerm.getFacets(QAnnotationTest.class))
                statementWriter.writeAssertion(annotationTest, dataTerm.toString());
        }

        if (!assertionBlock.statements().isEmpty())
            listUtil.addFirst(methodDeclaration.getBody().statements(), assertionBlock);

        statementWriter.getBlocks().pop();
    }

    private void addModule(Collection<String> modules, String module) {

        if (!modules.contains(module))
            modules.add(module);
    }
}