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

Java tutorial

Introduction

Here is the source code for org.smeup.sys.dk.compiler.rpj.writer.JDTStatementWriter.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
 */
package org.smeup.sys.dk.compiler.rpj.writer;

import java.util.Date;
import java.util.Iterator;
import java.util.Stack;

import javax.inject.Inject;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EOperation;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ArrayCreation;
import org.eclipse.jdt.core.dom.ArrayInitializer;
import org.eclipse.jdt.core.dom.Block;
import org.eclipse.jdt.core.dom.BreakStatement;
import org.eclipse.jdt.core.dom.CatchClause;
import org.eclipse.jdt.core.dom.ContinueStatement;
import org.eclipse.jdt.core.dom.DoStatement;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.ExpressionStatement;
import org.eclipse.jdt.core.dom.ForStatement;
import org.eclipse.jdt.core.dom.IfStatement;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.Name;
import org.eclipse.jdt.core.dom.ReturnStatement;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.jdt.core.dom.StringLiteral;
import org.eclipse.jdt.core.dom.SwitchCase;
import org.eclipse.jdt.core.dom.SwitchStatement;
import org.eclipse.jdt.core.dom.ThrowStatement;
import org.eclipse.jdt.core.dom.TryStatement;
import org.eclipse.jdt.core.dom.Type;
import org.eclipse.jdt.core.dom.TypeLiteral;
import org.eclipse.jdt.core.dom.WhileStatement;
import org.smeup.sys.dk.compiler.QCompilationUnit;
import org.smeup.sys.dk.compiler.rpj.RPJContextHelper;
import org.smeup.sys.il.core.IntegratedLanguageCoreRuntimeException;
import org.smeup.sys.il.core.term.QNamedNode;
import org.smeup.sys.il.core.term.QNode;
import org.smeup.sys.il.core.term.QTerm;
import org.smeup.sys.il.data.QCharacter;
import org.smeup.sys.il.data.QData;
import org.smeup.sys.il.data.QDataArea;
import org.smeup.sys.il.data.QDatetime;
import org.smeup.sys.il.data.QDecimal;
import org.smeup.sys.il.data.QFloating;
import org.smeup.sys.il.data.QHexadecimal;
import org.smeup.sys.il.data.QIndicator;
import org.smeup.sys.il.data.QIntegratedLanguageDataPackage;
import org.smeup.sys.il.data.QNumeric;
import org.smeup.sys.il.data.term.QDataTerm;
import org.smeup.sys.il.esam.QDataSet;
import org.smeup.sys.il.esam.QDataSetTerm;
import org.smeup.sys.il.esam.QDisplayTerm;
import org.smeup.sys.il.esam.QPrintTerm;
import org.smeup.sys.il.expr.AtomicType;
import org.smeup.sys.il.expr.IntegratedLanguageExpressionRuntimeException;
import org.smeup.sys.il.expr.LogicalOperator;
import org.smeup.sys.il.expr.QArithmeticExpression;
import org.smeup.sys.il.expr.QAssignmentExpression;
import org.smeup.sys.il.expr.QAtomicTermExpression;
import org.smeup.sys.il.expr.QBlockExpression;
import org.smeup.sys.il.expr.QExpression;
import org.smeup.sys.il.expr.QExpressionParser;
import org.smeup.sys.il.expr.QIntegratedLanguageExpressionFactory;
import org.smeup.sys.il.expr.QLogicalExpression;
import org.smeup.sys.il.expr.QPredicateExpression;
import org.smeup.sys.il.expr.QRelationalExpression;
import org.smeup.sys.il.expr.QTermExpression;
import org.smeup.sys.il.expr.RelationalOperator;
import org.smeup.sys.il.flow.QAnnotationTest;
import org.smeup.sys.il.flow.QBlock;
import org.smeup.sys.il.flow.QBreak;
import org.smeup.sys.il.flow.QCall;
import org.smeup.sys.il.flow.QCallableUnit;
import org.smeup.sys.il.flow.QCommandExec;
import org.smeup.sys.il.flow.QContinue;
import org.smeup.sys.il.flow.QEntryParameter;
import org.smeup.sys.il.flow.QEval;
import org.smeup.sys.il.flow.QFor;
import org.smeup.sys.il.flow.QIf;
import org.smeup.sys.il.flow.QIntegratedLanguageFlowFactory;
import org.smeup.sys.il.flow.QIteration;
import org.smeup.sys.il.flow.QJump;
import org.smeup.sys.il.flow.QLabel;
import org.smeup.sys.il.flow.QMethodExec;
import org.smeup.sys.il.flow.QModule;
import org.smeup.sys.il.flow.QMonitor;
import org.smeup.sys.il.flow.QOnError;
import org.smeup.sys.il.flow.QProcedure;
import org.smeup.sys.il.flow.QProcedureExec;
import org.smeup.sys.il.flow.QProgram;
import org.smeup.sys.il.flow.QPrototype;
import org.smeup.sys.il.flow.QReturn;
import org.smeup.sys.il.flow.QRoutineExec;
import org.smeup.sys.il.flow.QStatement;
import org.smeup.sys.il.flow.QUntil;
import org.smeup.sys.il.flow.QWhile;
import org.smeup.sys.il.flow.impl.StatementVisitorImpl;
import org.smeup.sys.os.core.OperatingSystemMessageException;

public class JDTStatementWriter extends StatementVisitorImpl {

    @Inject
    private QCompilationUnit compilationUnit;
    @Inject
    private QExpressionParser expressionParser;

    private AST ast;
    private Stack<Block> blocks = new Stack<>();

    public void setAST(AST ast) {
        this.ast = ast;
    }

    public Stack<Block> getBlocks() {
        return blocks;
    }

    @Override
    public void endVisit(QBlock statement) {

        // double {} on if statement
        EObject eObject = (EObject) statement;
        if (!(eObject.eContainer() instanceof QIf) && !(eObject.eContainer() instanceof QIteration))
            blocks.pop();
    }

    @Override
    public void endVisit(QFor statement) {

        blocks.pop();

        super.endVisit(statement);
    }

    @Override
    public void endVisit(QUntil statement) {

        blocks.pop();

        super.endVisit(statement);
    }

    @Override
    public void endVisit(QWhile statement) {

        blocks.pop();

        super.endVisit(statement);
    }

    @SuppressWarnings("unchecked")
    @Override
    public boolean visit(QBlock statement) {

        Block block = blocks.peek();

        // double {} on if statement
        EObject eObject = (EObject) statement;
        if (!(eObject.eContainer() instanceof QIf) && !(eObject.eContainer() instanceof QIteration)) {
            Block newBlock = ast.newBlock();
            block.statements().add(newBlock);
            blocks.push(newBlock);
        }

        return super.visit(statement);
    }

    @SuppressWarnings("unchecked")
    @Override
    public boolean visit(QBreak statement) {

        Block block = blocks.peek();
        if (isParentOnError(statement)) {
            IfStatement ifSt = ast.newIfStatement();
            ifSt.setExpression(ast.newName(new String[] { "RPJProgramSupport", "TRUE" }));
            BreakStatement breakSt = ast.newBreakStatement();
            ifSt.setThenStatement(breakSt);

            block.statements().add(ifSt);
        } else {
            BreakStatement breakSt = ast.newBreakStatement();
            block.statements().add(breakSt);
        }

        return super.visit(statement);
    }

    @SuppressWarnings("unchecked")
    @Override
    public boolean visit(QCall statement) {

        Block block = blocks.peek();

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

        // program name
        QTermExpression expression = expressionParser.parseTerm(statement.getProgram());
        Expression jdtExpression = JDTStatementHelper.buildExpression(ast, compilationUnit, expression,
                String.class);
        methodInvocation.arguments().add(jdtExpression);

        // array of parameter
        ArrayCreation arrayCreation = ast.newArrayCreation();
        arrayCreation.setType(ast.newArrayType(ast.newSimpleType(ast.newSimpleName(QData.class.getSimpleName()))));
        ArrayInitializer arrayInitializer = ast.newArrayInitializer();
        for (String parameter : statement.getParameters()) {
            expression = expressionParser.parseTerm(parameter);
            jdtExpression = JDTStatementHelper.buildExpression(ast, compilationUnit, expression, QData.class);
            arrayInitializer.expressions().add(jdtExpression);

        }
        arrayCreation.setInitializer(arrayInitializer);
        methodInvocation.arguments().add(arrayCreation);

        // error indicator
        if (statement.getError() != null) {
            QTermExpression errorExpression = expressionParser.parseTerm(statement.getError());
            Expression jdtErrorExpression = JDTStatementHelper.buildExpression(ast, compilationUnit,
                    errorExpression, null);

            methodInvocation.arguments().add(jdtErrorExpression);
        }
        // error handling
        if (statement.getErrorHandling() != null) {
            QTermExpression errorExpression = expressionParser.parseTerm(statement.getErrorHandling());
            Expression jdtErrorExpression = JDTStatementHelper.buildExpression(ast, compilationUnit,
                    errorExpression, null);

            methodInvocation.arguments().add(jdtErrorExpression);
        }

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

        return super.visit(statement);
    }

    @SuppressWarnings("unchecked")
    @Override
    public boolean visit(QCommandExec statement) {

        Block block = blocks.peek();

        MethodInvocation methodInvocation = ast.newMethodInvocation();
        methodInvocation.setExpression(ast.newSimpleName("qCMD"));
        methodInvocation.setName(ast.newSimpleName("qExecute"));

        methodInvocation.arguments().add(ast.newThisExpression());

        StringLiteral stringLiteral = ast.newStringLiteral();
        stringLiteral.setLiteralValue(statement.getStatement());
        methodInvocation.arguments().add(stringLiteral);

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

        return super.visit(statement);
    }

    @SuppressWarnings("unchecked")
    @Override
    public boolean visit(QContinue statement) {

        Block block = blocks.peek();
        // TODO
        if (isParentOnError(statement) || isParentFor(statement)) {
            IfStatement ifSt = ast.newIfStatement();
            ifSt.setExpression(ast.newName(new String[] { "RPJProgramSupport", "TRUE" }));
            ContinueStatement continueSt = ast.newContinueStatement();
            ifSt.setThenStatement(continueSt);

            block.statements().add(ifSt);
        } else if (isParentIf(statement)) {
            ContinueStatement continueSt = ast.newContinueStatement();
            block.statements().add(continueSt);
        } else {
            ContinueStatement continueSt = ast.newContinueStatement();
            block.statements().add(continueSt);
        }

        return false;
    }

    @SuppressWarnings("unchecked")
    @Override
    public boolean visit(QEval statement) {

        Block block = blocks.peek();

        QAssignmentExpression assignmentExpression = expressionParser.parseAssignment(statement.getAssignment());
        MethodInvocation methodInvocation = buildAssignmentMethod(assignmentExpression, statement.isRightAdjust());

        if (statement.isHalfAdjust() || statement.isMaxPrecision())
            methodInvocation.arguments().add(ast.newBooleanLiteral(statement.isHalfAdjust()));

        if (statement.isMaxPrecision())
            methodInvocation.arguments().add(ast.newBooleanLiteral(statement.isMaxPrecision()));

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

        // test annotations
        for (QAnnotationTest annotationTest : statement.getFacets(QAnnotationTest.class))
            writeAssertion(annotationTest, statement.toString());

        return false;
    }

    @SuppressWarnings("unchecked")
    @Override
    public boolean visit(QIf statement) {

        Block block = blocks.peek();

        IfStatement ifSt = ast.newIfStatement();

        QPredicateExpression condition = expressionParser.parsePredicate(statement.getCondition());

        Expression expression = null;

        if (RPJContextHelper.isPrimitive(compilationUnit, condition))
            expression = JDTStatementHelper.buildExpression(ast, compilationUnit, condition, Boolean.class);
        else
            expression = JDTStatementHelper.buildExpression(ast, compilationUnit, condition, Boolean.class);

        ifSt.setExpression(expression);

        block.statements().add(ifSt);

        // then
        if (statement.getThen() != null) {
            Block thenBlock = null;
            if (ifSt.getThenStatement() instanceof Block)
                thenBlock = (Block) ifSt.getThenStatement();
            else {
                thenBlock = ast.newBlock();
                ifSt.setThenStatement(thenBlock);
            }

            blocks.push(thenBlock);
            statement.getThen().accept(this);
            blocks.pop();
        }

        // else
        if (statement.getElse() != null) {
            Block elseBlock = null;
            if (ifSt.getElseStatement() instanceof Block)
                elseBlock = (Block) ifSt.getElseStatement();
            else {
                elseBlock = ast.newBlock();
                ifSt.setElseStatement(elseBlock);
            }

            // walk else
            blocks.push(elseBlock);
            statement.getElse().accept(this);
            blocks.pop();
        }

        // interrupt navigation
        return false;
    }

    @SuppressWarnings("unchecked")
    @Override
    public boolean visit(QProcedureExec statement) {

        Block block = blocks.peek();

        MethodInvocation methodInvocation = ast.newMethodInvocation();

        QPrototype prototype = compilationUnit.getPrototype(statement.getProcedure(), true);

        if (prototype == null)
            prototype = compilationUnit.getMethod(null, statement.getProcedure());

        if (prototype == null)
            throw new IntegratedLanguageExpressionRuntimeException("Binding error: " + statement.getProcedure());

        methodInvocation.setName(ast.newSimpleName(compilationUnit.normalizeTermName(prototype.getName())));

        if (!isOwner(prototype)) {
            QNode parent = prototype.getParent();
            if (parent instanceof QModule) {
                methodInvocation.setExpression(
                        ast.newSimpleName(compilationUnit.normalizeModuleName(((QModule) parent).getName())));
            } else if (parent instanceof QNamedNode) {
                // invoke on module
                String qualifiedParent = compilationUnit.getQualifiedName((QNamedNode) parent);
                methodInvocation.setExpression(JDTStatementHelper.buildExpression(ast, compilationUnit,
                        expressionParser.parseTerm(qualifiedParent), null));
            } else
                throw new IntegratedLanguageExpressionRuntimeException(
                        "Invalid procedure: " + statement.getProcedure());

        }

        // entry
        if (prototype.getEntry() != null) {
            Iterator<QEntryParameter<?>> entryParameters = prototype.getEntry().getParameters().iterator();

            for (String parameter : statement.getParameters()) {

                QExpression expression = expressionParser.parseExpression(parameter);

                if (entryParameters.hasNext()) {
                    QEntryParameter<?> entryParameter = entryParameters.next();
                    QTerm parameterDelegate = entryParameter.getDelegate();

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

                        if (dataTerm.isConstant() && !dataTerm.getDataTermType().isMultiple()) {
                            Expression jdtExpression = JDTStatementHelper.buildExpression(ast, compilationUnit,
                                    expression, dataTerm.getDefinition().getJavaClass());
                            methodInvocation.arguments().add(jdtExpression);
                        } else {
                            Expression jdtExpression = JDTStatementHelper.buildExpression(ast, compilationUnit,
                                    expression, dataTerm.getDefinition().getDataClass());
                            methodInvocation.arguments().add(jdtExpression);
                        }
                    } else if (parameterDelegate instanceof QDataSetTerm) {
                        Expression jdtExpression = JDTStatementHelper.buildExpression(ast, compilationUnit,
                                expression, QDataSet.class);
                        methodInvocation.arguments().add(jdtExpression);
                    } else
                        throw new IntegratedLanguageExpressionRuntimeException(
                                "Invalid procedure invocation: " + statement.getProcedure());
                } else
                    throw new IntegratedLanguageExpressionRuntimeException(
                            "Invalid procedure invocation: " + statement.getProcedure());
            }

            while (entryParameters.hasNext()) {
                QEntryParameter<?> entryParameter = entryParameters.next();
                if (entryParameter.isNullable())
                    methodInvocation.arguments().add(ast.newNullLiteral());
                else
                    throw new IntegratedLanguageExpressionRuntimeException(
                            "Invalid procedure invocation: " + statement.getProcedure());
            }
        }

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

        return super.visit(statement);
    }

    @SuppressWarnings("unchecked")
    @Override
    public boolean visit(QJump statement) {

        Block block = blocks.peek();

        MethodInvocation methodInvocation = ast.newMethodInvocation();
        methodInvocation.setExpression(ast.newSimpleName("qRPJ"));
        methodInvocation.setName(ast.newSimpleName("qJump"));

        Name labelName = ast
                .newName(new String[] { "TAG", compilationUnit.normalizeLabelName(statement.getLabel()) });
        methodInvocation.arguments().add(0, labelName);

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

        // dummy break
        if (isParentFor(statement))
            block.statements().add(ast.newBreakStatement());

        return super.visit(statement);
    }

    @SuppressWarnings("unchecked")
    @Override
    public boolean visit(QLabel statement) {

        Block block = blocks.peek();

        MethodInvocation methodInvocation = ast.newMethodInvocation();
        methodInvocation.setExpression(ast.newSimpleName("qRPJ"));
        methodInvocation.setName(ast.newSimpleName("qLabel"));

        Name labelName = ast
                .newName(new String[] { "TAG", compilationUnit.normalizeLabelName(statement.getName()) });
        methodInvocation.arguments().add(0, labelName);

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

        return super.visit(statement);
    }

    @SuppressWarnings("unchecked")
    @Override
    public boolean visit(QMethodExec statement) {

        Block block = blocks.peek();
        if (statement.getObject() != null) {

            MethodInvocation methodInvocation = ast.newMethodInvocation();
            methodInvocation.setName(ast.newSimpleName(compilationUnit.normalizeTermName(statement.getMethod())));

            QExpression objectExpression = expressionParser.parseExpression(statement.getObject());
            QNamedNode namedNode = null;
            if (objectExpression instanceof QTermExpression) {
                QTermExpression termExpression = (QTermExpression) objectExpression;

                switch (termExpression.getExpressionType()) {
                case FUNCTION:
                    namedNode = compilationUnit.getNamedNode(termExpression.getValue(), true);
                    break;
                case QUALIFIED:
                    namedNode = compilationUnit.getNamedNode(termExpression.getValue(), true);
                    break;
                case ATOMIC: {
                    QAtomicTermExpression atomicTermExpression = (QAtomicTermExpression) termExpression;
                    if (atomicTermExpression.getType() == AtomicType.NAME)
                        namedNode = compilationUnit.getNamedNode(termExpression.getValue(), true);
                    break;
                }

                case ARITHMETIC:
                case ARRAY:
                case ASSIGNMENT:
                case BLOCK:
                case BOOLEAN:
                case LOGICAL:
                case RELATIONAL:
                    break;
                }
            }

            if (namedNode == null) {
                Class<?> target = null;
                if (objectExpression instanceof QArithmeticExpression
                        || objectExpression instanceof QBlockExpression) {
                    target = RPJContextHelper.getTargetClass(compilationUnit, objectExpression, false);
                    // force boxing
                    if (String.class.isAssignableFrom(target))
                        target = QCharacter.class;
                    else if (Number.class.isAssignableFrom(target))
                        target = QNumeric.class;
                    else if (Date.class.isAssignableFrom(target))
                        target = QDatetime.class;
                } else if (objectExpression instanceof QAtomicTermExpression) {
                    QAtomicTermExpression atomicTermExpression = (QAtomicTermExpression) objectExpression;
                    switch (atomicTermExpression.getType()) {
                    case BOOLEAN:
                        target = QIndicator.class;
                        break;
                    case DATE:
                    case TIME:
                    case TIMESTAMP:
                        target = QDatetime.class;
                        break;
                    case FLOATING:
                        target = QFloating.class;
                        break;
                    case HEXADECIMAL:
                        target = QHexadecimal.class;
                        break;
                    case INDICATOR:
                        target = QIndicator.class;
                        break;
                    case INTEGER:
                        target = QDecimal.class;
                        break;
                    case STRING:
                        target = QCharacter.class;
                        break;
                    case SPECIAL:
                    case NAME:
                        target = QData.class;
                        break;
                    }
                }
                methodInvocation.setExpression(
                        JDTStatementHelper.buildExpression(ast, compilationUnit, objectExpression, target));
            }
            // display and print
            else if (namedNode.getParent() instanceof QDisplayTerm || namedNode.getParent() instanceof QPrintTerm) {

                methodInvocation.setExpression(
                        ast.newName(compilationUnit.getQualifiedName((QNamedNode) namedNode.getParent())));

                TypeLiteral typeLiteral = ast.newTypeLiteral();
                String fileName = compilationUnit.normalizeTypeName(((QNamedNode) namedNode.getParent()).getName());
                String formatName = compilationUnit.normalizeTypeName(namedNode.getName());
                typeLiteral.setType(ast.newSimpleType(ast.newName(new String[] { fileName, formatName })));

                methodInvocation.arguments().add(typeLiteral);

            } else {
                Class<?> target = RPJContextHelper.getTargetClass(compilationUnit, objectExpression, false);
                methodInvocation.setExpression(
                        JDTStatementHelper.buildExpression(ast, compilationUnit, objectExpression, target));

                if (target != null && QDataArea.class.isAssignableFrom(target)) {

                    // unwrap
                    if (!isDataAreaMethod(statement.getMethod())) {
                        MethodInvocation unwrapMethodInvocation = ast.newMethodInvocation();
                        unwrapMethodInvocation.setName(ast.newSimpleName("get"));
                        unwrapMethodInvocation.setExpression(
                                JDTStatementHelper.buildExpression(ast, compilationUnit, objectExpression, null));
                        methodInvocation.setExpression(unwrapMethodInvocation);
                    }
                }
            }

            if (statement.getParameters() != null) {
                for (String parameter : statement.getParameters()) {
                    QExpression expression = expressionParser.parseExpression(parameter);
                    Expression jdtExpression = JDTStatementHelper.buildExpression(ast, compilationUnit, expression,
                            null);
                    methodInvocation.arguments().add(jdtExpression);
                }
            }

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

        } else {
            QProcedureExec procedureExec = QIntegratedLanguageFlowFactory.eINSTANCE.createProcedureExec();
            procedureExec.setProcedure(statement.getMethod());
            procedureExec.getParameters().addAll(statement.getParameters());
            visit(procedureExec);
        }

        // test annotations
        for (QAnnotationTest annotationTest : statement.getFacets(QAnnotationTest.class))
            writeAssertion(annotationTest, statement.toString());

        return false;
    }

    private boolean isDataAreaMethod(String method) {

        for (EOperation eOperation : QIntegratedLanguageDataPackage.eINSTANCE.getDataArea().getEOperations()) {
            if (eOperation.getName().equals(method))
                return true;
        }

        return false;
    }

    @SuppressWarnings("unchecked")
    @Override
    public boolean visit(QMonitor statement) {

        Block block = blocks.peek();

        // -> try
        TryStatement tryStatement = ast.newTryStatement();
        blocks.push(tryStatement.getBody());
        if (statement.getBody() != null)
            statement.getBody().accept(this);

        String exceptionName = "e" + blocks.size();

        // catch
        CatchClause catchClause = ast.newCatchClause();
        SingleVariableDeclaration exceptionDeclaration = ast.newSingleVariableDeclaration();

        Type exception = ast
                .newSimpleType(ast.newSimpleName(OperatingSystemMessageException.class.getSimpleName()));
        exceptionDeclaration.setType(exception);
        exceptionDeclaration.setName(ast.newSimpleName(exceptionName));
        catchClause.setException(exceptionDeclaration);
        tryStatement.catchClauses().add(catchClause);

        // -> catch
        blocks.push(catchClause.getBody());

        // switch
        SwitchStatement switchStatement = ast.newSwitchStatement();

        MethodInvocation methodInvocation = ast.newMethodInvocation();
        methodInvocation.setExpression(ast.newSimpleName(exceptionName));
        methodInvocation.setName(ast.newSimpleName("getMessageName"));

        switchStatement.setExpression(methodInvocation);

        boolean defaultError = true;
        boolean caseStatement = false;
        for (QOnError error : statement.getOnErrors()) {
            if (error.getBody() == null)
                continue;

            if (error.getErrors().isEmpty() || error.getErrors().contains("CPF0000")
                    || error.getErrors().contains("*ALL")) {
                // Case
                SwitchCase switchCase = ast.newSwitchCase();
                switchCase.setExpression(null);
                switchStatement.statements().add(switchCase);
                defaultError = false;
            } else {
                for (String caseError : error.getErrors()) {
                    StringLiteral caseLiteral = ast.newStringLiteral();
                    caseLiteral.setLiteralValue(caseError);
                    // Case
                    SwitchCase switchCase = ast.newSwitchCase();
                    switchCase.setExpression(caseLiteral);
                    switchStatement.statements().add(switchCase);
                }
            }

            // Case body

            // -> Case
            Block caseBlock = ast.newBlock();
            blocks.push(caseBlock);

            error.getBody().accept(this);

            // copy case block to switch statement
            for (int i = 0; i < caseBlock.statements().size(); i++) {
                Object temp = caseBlock.statements().remove(i);
                if (temp instanceof Block) {
                    Block tempBlock = (Block) temp;
                    if (tempBlock.statements().isEmpty())
                        continue;
                }

                caseStatement = true;
                switchStatement.statements().add(temp);
            }

            switchStatement.statements().add(ast.newBreakStatement());

            // <- case
            blocks.pop();
        }

        if (defaultError) {
            SwitchCase switchCase = ast.newSwitchCase();
            switchCase.setExpression(null);
            switchStatement.statements().add(switchCase);
            ThrowStatement throwStatement = ast.newThrowStatement();
            throwStatement.setExpression(ast.newSimpleName(exceptionName));

            switchStatement.statements().add(throwStatement);

            blocks.peek().statements().add(switchStatement);
        } else if (caseStatement) {
            blocks.peek().statements().add(switchStatement);
        }

        // <-catch
        blocks.pop();

        // <-try
        blocks.pop();

        block.statements().add(tryStatement);

        return false;
    }

    @SuppressWarnings("unchecked")
    @Override
    public boolean visit(QReturn statement) {

        Block block = blocks.peek();

        ReturnStatement returnSt = ast.newReturnStatement();
        if (statement.getValue() != null) {
            QExpression returnExpression = expressionParser.parseExpression(statement.getValue());

            QProcedure procedure = (QProcedure) this.compilationUnit.getNode();

            QPrototype prototype = compilationUnit.getPrototype(procedure.getName(), true);
            if (prototype.getDefinition().getDataClass().equals(procedure.getReturnType().getDataClass())) {
                returnSt.setExpression(JDTStatementHelper.buildExpression(ast, compilationUnit, returnExpression,
                        procedure.getReturnType().getDataClass()));
            } else {
                returnSt.setExpression(JDTStatementHelper.buildExpression(ast, compilationUnit, returnExpression,
                        prototype.getDefinition().getDataClass()));
            }

            block.statements().add(returnSt);
        } else {
            // dummy condition

            IfStatement ifSt = ast.newIfStatement();
            ifSt.setExpression(ast.newName(new String[] { "RPJProgramSupport", "TRUE" }));
            ifSt.setThenStatement(returnSt);

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

        return false;
    }

    @SuppressWarnings("unchecked")
    @Override
    public boolean visit(QFor statement) {

        Block block = blocks.peek();

        ForStatement forSt = ast.newForStatement();

        // initialization
        QAssignmentExpression assignment = expressionParser.parseAssignment(statement.getInitialization());
        forSt.initializers().add(buildAssignmentMethod(assignment, false));

        // condition
        QPredicateExpression condition = buildIterationCondition(statement.getCondition());
        Expression expression = JDTStatementHelper.buildExpression(ast, compilationUnit, condition,
                RPJContextHelper.getTargetClass(compilationUnit, condition, true));
        forSt.setExpression(expression);

        // increment
        QAssignmentExpression increment = expressionParser.parseAssignment(statement.getIncrement());
        forSt.updaters().add(buildAssignmentMethod(increment, false));

        block.statements().add(forSt);

        // body
        Block bodyBlock = ast.newBlock();
        forSt.setBody(bodyBlock);

        blocks.push(bodyBlock);

        return super.visit(statement);
    }

    @SuppressWarnings("unchecked")
    @Override
    public boolean visit(QUntil statement) {

        Block block = blocks.peek();

        DoStatement doSt = ast.newDoStatement();

        QLogicalExpression logicalExpression = QIntegratedLanguageExpressionFactory.eINSTANCE
                .createLogicalExpression();
        logicalExpression.setOperator(LogicalOperator.NOT);
        QBlockExpression blockExpression = QIntegratedLanguageExpressionFactory.eINSTANCE.createBlockExpression();

        QPredicateExpression condition = buildIterationCondition(statement.getCondition());
        blockExpression.setExpression(condition);

        logicalExpression.setLeftOperand(blockExpression);

        Expression expression = JDTStatementHelper.buildExpression(ast, compilationUnit, logicalExpression,
                RPJContextHelper.getTargetClass(compilationUnit, logicalExpression, true));
        doSt.setExpression(expression);

        block.statements().add(doSt);

        // body
        Block bodyBlock = ast.newBlock();
        doSt.setBody(bodyBlock);

        blocks.push(bodyBlock);

        return super.visit(statement);
    }

    private QPredicateExpression buildIterationCondition(String condition) {

        if (condition == null || condition.isEmpty())
            condition = "%runnable";
        else {
            if (condition.equalsIgnoreCase("*ON"))
                condition = "%runnable";
            else
                condition = "%runnable and (" + condition + ")";
        }

        QPredicateExpression predicateExpression = expressionParser.parsePredicate(condition);

        return predicateExpression;
    }

    @SuppressWarnings("unchecked")
    @Override
    public boolean visit(QWhile statement) {

        Block block = blocks.peek();

        WhileStatement whileSt = ast.newWhileStatement();

        QPredicateExpression condition = buildIterationCondition(statement.getCondition());
        Expression expression = JDTStatementHelper.buildExpression(ast, compilationUnit, condition,
                RPJContextHelper.getTargetClass(compilationUnit, condition, true));
        whileSt.setExpression(expression);

        block.statements().add(whileSt);

        // body
        Block bodyBlock = ast.newBlock();
        whileSt.setBody(bodyBlock);

        blocks.push(bodyBlock);

        return super.visit(statement);
    }

    @SuppressWarnings("unchecked")
    @Override
    public boolean visit(QRoutineExec statement) {
        Block block = blocks.peek();

        MethodInvocation methodInvocation = ast.newMethodInvocation();

        QNamedNode routine = compilationUnit.getRoutine(statement.getRoutine(), true);
        if (routine == null)
            throw new IntegratedLanguageExpressionRuntimeException("Invalid routine: " + statement.getRoutine());

        methodInvocation.setName(ast.newSimpleName(compilationUnit.normalizeRoutineName(routine.getName())));

        if (!isOwner(routine)) {
            QNode parent = routine.getParent();
            if (parent instanceof QModule) {
                methodInvocation.setExpression(
                        ast.newSimpleName(compilationUnit.normalizeModuleName(((QModule) parent).getName())));
            } else if (parent instanceof QNamedNode) {
                // invoke on module
                String qualifiedParent = compilationUnit.getQualifiedName((QNamedNode) parent);
                methodInvocation.setExpression(JDTStatementHelper.buildExpression(ast, compilationUnit,
                        expressionParser.parseTerm(qualifiedParent), null));
            } else
                throw new IntegratedLanguageExpressionRuntimeException(
                        "Invalid procedure: " + statement.getRoutine());

        }

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

        // test annotations
        for (QAnnotationTest annotationTest : statement.getFacets(QAnnotationTest.class))
            writeAssertion(annotationTest, statement.toString());

        return super.visit(statement);
    }

    @SuppressWarnings("unchecked")
    private MethodInvocation buildAssignmentMethod(QAssignmentExpression assignmentExpression, boolean direction) {

        MethodInvocation methodInvocation = ast.newMethodInvocation();

        int p = 0;
        switch (assignmentExpression.getOperator()) {
        case ASSIGN:
            if (direction)
                methodInvocation.setName(ast.newSimpleName("evalr"));
            else
                methodInvocation.setName(ast.newSimpleName("eval"));
            break;
        case DIVIDE_ASSIGN:
            if (direction)
                throw new IntegratedLanguageCoreRuntimeException("Unexpected condition: vbjhgso4873y6tisbh");

            methodInvocation.setName(ast.newSimpleName("divide"));
            // methodInvocation.arguments().add(p, "/");
            // p++;
            break;
        case MINUS_ASSIGN:
            if (direction)
                throw new IntegratedLanguageCoreRuntimeException("Unexpected condition: vbjhgso4873y6tisbhA");

            methodInvocation.setName(ast.newSimpleName("minus"));
            // methodInvocation.arguments().add(p, "-");
            // p++;
            break;
        case PLUS_ASSIGN:
            if (direction)
                throw new IntegratedLanguageCoreRuntimeException("Unexpected condition: vbjhgso4873y6tisbhB");

            methodInvocation.setName(ast.newSimpleName("plus"));
            // methodInvocation.arguments().add(p, "+");
            // p++;
            break;
        case TIMES_ASSIGN:
            if (direction)
                throw new IntegratedLanguageCoreRuntimeException("Unexpected condition: vbjhgso4873y6tisbhC");

            methodInvocation.setName(ast.newSimpleName("mult"));
            // methodInvocation.arguments().add(p, "*");
            // p++;
            break;
        case POWER_ASSIGN:
            if (direction)
                throw new IntegratedLanguageCoreRuntimeException("Unexpected condition: vbjhgso4873y6tisbhD");

            methodInvocation.setName(ast.newSimpleName("power"));
            // methodInvocation.arguments().add(p, "^");
            // p++;
            break;
        }

        Expression expression = JDTStatementHelper.buildExpression(ast, compilationUnit,
                assignmentExpression.getLeftOperand(), null);
        methodInvocation.setExpression(expression);

        // TODO verify
        Class<?> targetLeft = RPJContextHelper.getTargetClass(compilationUnit,
                assignmentExpression.getLeftOperand(), false);
        if (targetLeft != null && targetLeft.isAssignableFrom(QDataArea.class)) {
            // unwrap
            MethodInvocation unwrapMethodInvocation = ast.newMethodInvocation();
            unwrapMethodInvocation.setName(ast.newSimpleName("get"));
            unwrapMethodInvocation.setExpression(JDTStatementHelper.buildExpression(ast, compilationUnit,
                    assignmentExpression.getLeftOperand(), null));
            methodInvocation.setExpression(unwrapMethodInvocation);
        }

        expression = JDTStatementHelper.buildExpression(ast, compilationUnit,
                assignmentExpression.getRightOperand(), null);
        methodInvocation.arguments().add(p, expression);

        return methodInvocation;
    }

    @SuppressWarnings("unused")
    private boolean isParentProcedure(QStatement statement) {

        QNode parent = statement.getParent();
        while (parent != null) {
            if (parent instanceof QProcedure)
                return true;
            parent = parent.getParent();
        }

        return false;
    }

    private QCallableUnit getCallableUnit(QNamedNode nameNode) {

        QCallableUnit callableUnit = null;

        QNode node = nameNode;
        while (callableUnit == null) {
            if (node instanceof QModule || node instanceof QProgram) {
                callableUnit = (QCallableUnit) node;
                break;
            } else
                node = node.getParent();

            if (node == null)
                break;
        }

        return callableUnit;
    }

    private boolean isOwner(QNamedNode namedNode) {
        return getCallableUnit((QNamedNode) compilationUnit.getNode()).equals(getCallableUnit(namedNode));
    }

    private boolean isParentFor(QStatement statement) {

        QNode parent = statement.getParent();
        while (parent != null) {
            if (parent instanceof QFor)
                return true;
            parent = parent.getParent();
        }

        return false;
    }

    private boolean isParentIf(QStatement statement) {

        QNode parent = statement.getParent();
        while (parent != null) {
            if (parent instanceof QIf)
                return true;
            parent = parent.getParent();
        }

        return false;
    }

    private boolean isParentOnError(QStatement statement) {

        QNode parent = statement.getParent();
        while (parent != null) {
            if (parent instanceof QOnError)
                return true;
            parent = parent.getParent();
        }

        return false;
    }

    public void writeAssertion(QAnnotationTest annotationTest, String message) {

        Block block = getBlocks().peek();

        if (annotationTest.getExpression() == null)
            throw new IntegratedLanguageCoreRuntimeException("Unexpected condition: rbbbb9r88888sdxgrwgxtrx");

        QPredicateExpression expression = expressionParser.parsePredicate(annotationTest.getExpression());
        QRelationalExpression relationalExpression = null;
        if (expression instanceof QRelationalExpression) {
            relationalExpression = (QRelationalExpression) expression;
        } else
            return;

        Expression leftExpression = JDTStatementHelper.buildExpression(ast, compilationUnit,
                relationalExpression.getLeftOperand(), null);

        String messageNormalized = "";
        if (annotationTest.getMessage() == null || annotationTest.getMessage().isEmpty()) {
            if (message.isEmpty()) {
                messageNormalized = "Init " + leftExpression;
            } else {
                messageNormalized = normalizeMessage(message);
            }
        } else {
            messageNormalized = annotationTest.getMessage();
        }

        writeAssertionTrue(block, messageNormalized,
                JDTStatementHelper.buildExpression(ast, compilationUnit, expression, null));
    }

    @SuppressWarnings("unchecked")
    private void writeAssertionTrue(Block target, String message, Expression expression) {
        MethodInvocation methodInvocation = ast.newMethodInvocation();
        methodInvocation.setExpression(ast.newSimpleName("testAsserter"));
        methodInvocation.setName(ast.newSimpleName("assertTrue"));

        StringLiteral literal = ast.newStringLiteral();
        literal.setLiteralValue(message);

        methodInvocation.arguments().add(literal);
        methodInvocation.arguments().add(expression);

        ExpressionStatement assertStatement = ast.newExpressionStatement(methodInvocation);
        target.statements().add(assertStatement);
    }

    @SuppressWarnings({ "unchecked", "unused" })
    private void writeAssertionEquals(Block target, String message, Expression leftExpression,
            Expression rightExpression, RelationalOperator operator) {

        MethodInvocation methodInvocation = ast.newMethodInvocation();
        methodInvocation.setExpression(ast.newSimpleName("testAsserter"));

        switch (operator) {
        case EQUAL:
            methodInvocation.setName(ast.newSimpleName("assertEquals"));
            break;
        case GREATER_THAN:
            break;
        case GREATER_THAN_EQUAL:
            break;
        case LESS_THAN:
            break;
        case LESS_THAN_EQUAL:
            break;
        case NOT_EQUAL:
            break;
        }

        StringLiteral literal = ast.newStringLiteral();
        literal.setLiteralValue(message);

        methodInvocation.arguments().add(literal);
        methodInvocation.arguments().add(leftExpression);
        methodInvocation.arguments().add(rightExpression);

        ExpressionStatement assertStatement = ast.newExpressionStatement(methodInvocation);
        target.statements().add(assertStatement);
    }

    private String normalizeMessage(String message) {
        String newMessage = "";
        int pos = message.indexOf("(");
        if (pos == -1) {
            return message;
        }
        newMessage = message.substring(pos);
        return newMessage;
    }
}