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

Java tutorial

Introduction

Here is the source code for org.smeup.sys.dk.compiler.rpj.writer.JDTExpressionStringBuilder.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.nio.Buffer;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import javax.inject.Inject;

import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.Block;
import org.smeup.sys.dk.compiler.QCompilationUnit;
import org.smeup.sys.dk.compiler.rpj.RPJCompilerMessage;
import org.smeup.sys.dk.compiler.rpj.RPJContextHelper;
import org.smeup.sys.il.core.term.QNamedNode;
import org.smeup.sys.il.core.term.QTerm;
import org.smeup.sys.il.data.DataComparator;
import org.smeup.sys.il.data.DataSpecial;
import org.smeup.sys.il.data.DatetimeFormat;
import org.smeup.sys.il.data.IntegratedLanguageDataRuntimeException;
import org.smeup.sys.il.data.QArray;
import org.smeup.sys.il.data.QBinary;
import org.smeup.sys.il.data.QBufferedElement;
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.QHexadecimal;
import org.smeup.sys.il.data.QIndicator;
import org.smeup.sys.il.data.QList;
import org.smeup.sys.il.data.QNumeric;
import org.smeup.sys.il.data.QPointer;
import org.smeup.sys.il.data.QString;
import org.smeup.sys.il.data.def.QMultipleAtomicDataDef;
import org.smeup.sys.il.data.term.QDataTerm;
import org.smeup.sys.il.esam.QDataSetTerm;
import org.smeup.sys.il.esam.QDisplayTerm;
import org.smeup.sys.il.esam.QFileTerm;
import org.smeup.sys.il.esam.QKeyListTerm;
import org.smeup.sys.il.esam.QPrintTerm;
import org.smeup.sys.il.expr.ArithmeticOperator;
import org.smeup.sys.il.expr.AssignmentOperator;
import org.smeup.sys.il.expr.ExpressionType;
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.QArrayExpression;
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.QBooleanExpression;
import org.smeup.sys.il.expr.QExpression;
import org.smeup.sys.il.expr.QExpressionParser;
import org.smeup.sys.il.expr.QExpressionWriter;
import org.smeup.sys.il.expr.QFunctionTermExpression;
import org.smeup.sys.il.expr.QIntegratedLanguageExpressionFactory;
import org.smeup.sys.il.expr.QLogicalExpression;
import org.smeup.sys.il.expr.QQualifiedTermExpression;
import org.smeup.sys.il.expr.QRelationalExpression;
import org.smeup.sys.il.expr.impl.ExpressionVisitorImpl;
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.QPrototype;
import org.smeup.sys.mi.core.util.QStrings;
import org.smeup.sys.os.core.QExceptionManager;
import org.smeup.sys.os.core.jobs.QJob;
import org.smeup.sys.os.core.jobs.QJobLogManager;
import org.smeup.sys.os.pgm.rpj.RPJProgramSupport.Specials;
import org.smeup.sys.rt.core.QLogger;

public class JDTExpressionStringBuilder extends ExpressionVisitorImpl {
    @Inject
    private QCompilationUnit compilationUnit;
    @Inject
    private QStrings strings;
    @Inject
    private QExpressionParser expressionParser;
    @Inject
    private QExpressionWriter expressionWriter;
    @Inject
    private QExceptionManager exceptionManager;
    @Inject
    private QLogger logger;
    @Inject
    private QJob job;

    // TODO remove me   
    @Inject
    private QJobLogManager jobLogManager;

    private AST ast;
    private StringBuffer buffer = new StringBuffer();

    private Class<?> target;
    private boolean useDouble = false;

    public void setTarget(Class<?> target) {
        this.target = target;
    }

    public void useDouble(boolean useDouble) {
        this.useDouble = useDouble;
    }

    public Class<?> getTarget() {
        return this.target;
    }

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

    public AST getAST() {
        return this.ast;
    }

    public String getResult() {
        return buffer.toString();
    }

    public void clear() {
        buffer = new StringBuffer();
    }

    @Override
    public boolean visit(QAtomicTermExpression expression) {

        if (mockExpression(expression))
            return false;

        Class<?> source = null;

        String value = null;

        switch (expression.getType()) {
        case BOOLEAN:
            value = expression.getValue();
            source = Boolean.class;
            break;
        case DATE:
        case TIME:
        case TIMESTAMP:
            value = expression.getValue();
            source = Date.class;
            break;
        case INTEGER:
            source = Number.class;

            if (useDouble) {
                try {
                    value = Double.toString(Double.parseDouble(expression.getValue()));
                } catch (Exception e) {
                    try {
                        value = Integer.toString(Integer.parseInt(expression.getValue())) + ".0";
                    } catch (NumberFormatException e2) {
                        value = Long.toString(Long.parseLong(expression.getValue())) + ".0";
                    }
                }
            } else {
                try {
                    value = Integer.toString(Integer.parseInt(expression.getValue()));
                } catch (NumberFormatException e) {
                    value = Long.toString(Long.parseLong(expression.getValue())) + "L";
                }
            }
            break;
        case FLOATING:
            source = Number.class;
            value = expression.getValue();
            value = value.replaceAll("\\,", "\\.");
            break;
        case HEXADECIMAL:
            value = expression.getValue();

            if (value.startsWith("X'") || value.startsWith("x'")) {
                // value = value.substring(2);
                // value = value.substring(0, value.length() - 1);

                throw new IntegratedLanguageExpressionRuntimeException(
                        "Invalid hexadecimal: " + expression.getValue());
            } else {
                source = Byte.class;
                value = "(byte) 0x" + value;
            }

            break;
        case SPECIAL:
            source = Enum.class;
            DataSpecial dataSpecial = DataSpecial.get(expression.getValue().toUpperCase());
            if (dataSpecial != null) {
                switch (dataSpecial) {
                case NULL:
                case OMIT:
                    value = "null";
                    writeValue(source, null, value);
                    return false;
                case ON:
                case OFF:
                case BLANK:
                case BLANKS:
                case HIVAL:
                case LOVAL:
                case ZERO:
                case ZEROS:
                    value = "Specials." + strings.removeFirstChar(expression.getValue()).toUpperCase();
                    break;
                }
            }

            DatetimeFormat datetimeFormat = DatetimeFormat.get(expression.getValue().toUpperCase());
            if (datetimeFormat != null) {
                switch (datetimeFormat) {
                case DAY:
                case DAYS:
                case HOURS:
                case ISO:
                case ISO0:
                case MILLISECONDS:
                case MINUTES:
                case MONTH:
                case MONTHS:
                case SECOND:
                case SECONDS:
                case YEAR:
                case YEARS:
                    value = "Specials." + strings.removeFirstChar(expression.getValue()).toUpperCase();
                    break;
                }
            }

            DataComparator dataComparator = DataComparator.get(expression.getValue().toUpperCase());
            if (dataComparator != null) {
                switch (dataComparator) {
                case EQUAL:
                case GREATER_THAN:
                case GREATER_THAN_EQUAL:
                case LESS_THAN:
                case LESS_THAN_EQUAL:
                case NOT_EQUAL:
                    value = "Specials." + strings.removeFirstChar(expression.getValue()).toUpperCase();
                    break;
                }
            }
            break;
        case STRING:

            // escaping
            value = expression.getValue().replaceAll("\\\\", "\\\\\\\\");
            value = value.replaceAll("\\\"", "\\\\\"");

            // TODO
            // value = strings.escape(expression.getValue());
            value = "\"" + value + "\"";

            source = String.class;
            break;
        case INDICATOR:
        case NAME:

            QNamedNode namedNode = null;
            namedNode = compilationUnit.getNamedNode(expression.getValue(), true);
            if (namedNode == null) {
                compilationUnit.getNamedNode(expression.getValue(), true);
                throw new IntegratedLanguageExpressionRuntimeException("Invalid term: " + expression.getValue());
            }

            value = compilationUnit.getQualifiedName(namedNode);

            QDataTerm<?> dataTerm = RPJContextHelper.getDataTerm(namedNode);

            if (dataTerm != null) {

                if (dataTerm instanceof QPrototype)
                    value = value + "()";

                if (dataTerm.getDataTermType().isMultiple()) {
                    if (this.target != null) {
                        if (QList.class.isAssignableFrom(this.target))
                            source = dataTerm.getDefinition().getDataClass();
                        else if (dataTerm.getDataTermType().isAtomic())
                            source = ((QMultipleAtomicDataDef<?>) dataTerm.getDefinition()).getArgument()
                                    .getDataClass();
                    } else
                        source = dataTerm.getDefinition().getDataClass();
                } else {
                    if (dataTerm.isConstant() && !dataTerm.getDataTermType().isMultiple())
                        source = dataTerm.getDefinition().getJavaClass();
                    else
                        source = dataTerm.getDefinition().getDataClass();
                }

            } else if (namedNode instanceof QKeyListTerm) {
                QKeyListTerm keyListTerm = (QKeyListTerm) namedNode;

                if (RPJContextHelper.containsArray(expressionParser, keyListTerm)) {
                    this.buffer.append(buildExpression(keyListTerm));
                    return false;
                }
            }

            break;
        }

        writeValue(source, target, value);

        return false;
    }

    @Override
    public boolean visit(QAssignmentExpression expression) {

        if (mockExpression(expression))
            return false;

        expression.getLeftOperand().accept(this);
        buffer.append(toJavaPrimitive(expression.getOperator()));
        expression.getRightOperand().accept(this);

        return false;
    }

    @Override
    public boolean visit(QArithmeticExpression expression) {

        if (mockExpression(expression))
            return false;

        StringBuffer value = new StringBuffer();

        JDTExpressionStringBuilder builder = compilationUnit.getContext().make(JDTExpressionStringBuilder.class);
        builder.setAST(getAST());

        // pointer
        if (RPJContextHelper.isPointer(compilationUnit, expression.getLeftOperand())) {
            // left
            builder.setTarget(null);
            builder.clear();
            expression.getLeftOperand().accept(builder);
            value.append(builder.getResult());

            // operator
            value.append(".q" + strings.firstToUpper(toJavaMethod(expression)));
            value.append("(");

            // right
            builder.clear();
            expression.getRightOperand().accept(builder);
            value.append(builder.getResult());

            value.append(")");

            builder.setTarget(QPointer.class);
        }
        // list
        else if (RPJContextHelper.isList(compilationUnit, expression.getLeftOperand())) {
            // left
            builder.setTarget(null);
            builder.clear();
            expression.getLeftOperand().accept(builder);
            value.append(builder.getResult());

            // right
            if (expression.getRightOperand() != null) {
                builder.clear();
                value.append(".q" + strings.firstToUpper(toJavaMethod(expression)));
                value.append("(");
                expression.getRightOperand().accept(builder);
                value.append(builder.getResult());
                value.append(")");
            } else {
                if (expression.getOperator() == ArithmeticOperator.SIGN_MINUS)
                    value.append(".qMult(-1)");
                else
                    throw new IntegratedLanguageExpressionRuntimeException(
                            "Unexpected condition: 9zb87we6r8vewrce6tr");
            }

            builder.setTarget(QList.class);
        }
        // plus, minus, multiple, divide ..
        else if (expression.getRightOperand() != null) {

            Class<?> target = null;

            if (expression.getOperator() == ArithmeticOperator.POWER)
                target = Integer.class;
            else
                target = RPJContextHelper.getTargetClass(compilationUnit, expression.getLeftOperand(), true);

            if (expression.getOperator() == ArithmeticOperator.DIVIDE)
                builder.useDouble(true);

            if (Boolean.class.isAssignableFrom(target))
                target = String.class;
            else if (Byte.class.isAssignableFrom(target))
                target = String.class;

            builder.setTarget(target);
            builder.clear();
            expression.getLeftOperand().accept(builder);
            value.append(builder.getResult());

            if (QPointer.class.isAssignableFrom(target))
                value.append("." + toJavaMethod(expression));
            else if (QList.class.isAssignableFrom(target))
                value.append("." + toJavaMethod(expression));
            else
                value.append(toJavaPrimitive(expression.getOperator()));

            builder.clear();
            if (expression.getOperator() == ArithmeticOperator.DIVIDE && Number.class.isAssignableFrom(target))
                builder.useDouble(true);

            expression.getRightOperand().accept(builder);

            value.append(builder.getResult());
        }
        // negate
        else {

            value.append(toJavaPrimitive(expression.getOperator()));

            if (!RPJContextHelper.isPrimitive(compilationUnit, expression.getLeftOperand()))
                builder.setTarget(Number.class);
            else
                builder.setTarget(null);

            builder.clear();
            expression.getLeftOperand().accept(builder);
            value.append(builder.getResult());

        }

        if (target != null) {
            if (Number.class.isAssignableFrom(target))
                writeValue(Number.class, target, value.toString());

            // TODO remove me
            else if (Buffer.class.isAssignableFrom(target))
                writeValue(Buffer.class, target, value.toString());
            else if (String.class.isAssignableFrom(target))
                writeValue(String.class, target, value.toString());

            else if (QNumeric.class.isAssignableFrom(target))
                writeValue(Number.class, target, value.toString());
            else if (QString.class.isAssignableFrom(target))
                writeValue(String.class, target, value.toString());
            else if (QPointer.class.isAssignableFrom(target))
                writeValue(QPointer.class, target, value.toString());
            else if (QList.class.isAssignableFrom(target))
                writeValue(QList.class, target, value.toString());
            else
                writeValue(String.class, target, value.toString());
        } else {
            buffer.append(value);
        }

        return false;
    }

    @Override
    public boolean visit(QBooleanExpression expression) {

        if (mockExpression(expression))
            return false;

        if (expression.getOperand() != null) {

            if (expression.getOperand() instanceof QAtomicTermExpression) {

                QAtomicTermExpression atomicTermExpression = (QAtomicTermExpression) expression.getOperand();
                if (atomicTermExpression.getValue().equalsIgnoreCase("*ON")) {
                    buffer.append("true");
                    return false;
                } else if (atomicTermExpression.getValue().equalsIgnoreCase("*OFF")) {
                    buffer.append("false");
                    return false;
                }
            }

            JDTExpressionStringBuilder builder = compilationUnit.getContext()
                    .make(JDTExpressionStringBuilder.class);
            builder.setTarget(Boolean.class);
            builder.setAST(getAST());
            expression.getOperand().accept(builder);

            buffer.append(builder.getResult());
        }

        return false;

    }

    @Override
    public boolean visit(QLogicalExpression expression) {

        if (mockExpression(expression))
            return false;

        JDTExpressionStringBuilder builder = compilationUnit.getContext().make(JDTExpressionStringBuilder.class);
        builder.setAST(getAST());

        // and/or
        if (expression.getRightOperand() != null) {

            // left
            if (!RPJContextHelper.isPrimitive(compilationUnit, expression.getLeftOperand()))
                builder.setTarget(Boolean.class);
            // builder.setTarget(JDTContextHelper.getTargetClass(compilationUnit,
            // expression.getLeftOperand(), true));
            else
                builder.setTarget(Boolean.class);
            // builder.setTarget(JDTContextHelper.getTargetClass(compilationUnit,
            // expression.getLeftOperand(), true));
            // builder.setTarget(null);

            builder.clear();
            expression.getLeftOperand().accept(builder);
            buffer.append(builder.getResult());

            // operator
            buffer.append(toJavaPrimitive(expression.getOperator()));

            // right
            if (!RPJContextHelper.isPrimitive(compilationUnit, expression.getRightOperand()))
                builder.setTarget(Boolean.class);
            else
                builder.setTarget(Boolean.class);

            builder.clear();
            expression.getRightOperand().accept(builder);
            buffer.append(builder.getResult());

        }
        // negate
        else {

            StringBuffer value = new StringBuffer();
            // operator
            value.append(toJavaPrimitive(expression.getOperator()));

            // left
            if (!RPJContextHelper.isPrimitive(compilationUnit, expression.getLeftOperand()))
                builder.setTarget(Boolean.class);
            else
                builder.setTarget(
                        RPJContextHelper.getTargetClass(compilationUnit, expression.getLeftOperand(), true));

            builder.clear();
            expression.getLeftOperand().accept(builder);
            value.append(builder.getResult());

            if (target != null)
                writeValue(builder.getTarget(), target, value.toString());
            else
                buffer.append(value.toString());

        }

        return false;
    }

    @Override
    public boolean visit(QRelationalExpression expression) {

        if (mockExpression(expression))
            return false;

        // normalize arithmetic left
        if (expression.getLeftOperand() instanceof QArithmeticExpression) {
            QBlockExpression blockExpression = QIntegratedLanguageExpressionFactory.eINSTANCE
                    .createBlockExpression();
            blockExpression.setExpression(expression.getLeftOperand());
            expression.setLeftOperand(blockExpression);
        }

        // normalize arithmetic right
        if (expression.getRightOperand() instanceof QArithmeticExpression) {
            QBlockExpression blockExpression = QIntegratedLanguageExpressionFactory.eINSTANCE
                    .createBlockExpression();
            blockExpression.setExpression(expression.getRightOperand());
            expression.setRightOperand(blockExpression);
        }

        JDTExpressionStringBuilder leftBuilder = compilationUnit.getContext()
                .make(JDTExpressionStringBuilder.class);
        leftBuilder.setAST(getAST());

        JDTExpressionStringBuilder rightBuilder = compilationUnit.getContext()
                .make(JDTExpressionStringBuilder.class);
        rightBuilder.setAST(getAST());

        if (RPJContextHelper.isPrimitive(compilationUnit, expression.getLeftOperand())) {

            leftBuilder.clear();
            if (RPJContextHelper.isSpecial(compilationUnit, expression.getRightOperand()))
                leftBuilder.setTarget(QData.class);
            else
                leftBuilder.setTarget(QData.class);

            expression.getLeftOperand().accept(leftBuilder);
            buffer.append(leftBuilder.getResult());

            // operator
            if (leftBuilder.getTarget() != null)
                buffer.append("." + toJavaMethod(expression));
            else
                buffer.append(".compareTo");
            buffer.append("(");

            // right
            rightBuilder.clear();
            if (RPJContextHelper.isPrimitive(compilationUnit, expression.getRightOperand()))
                rightBuilder.setTarget(null);
            else
                rightBuilder.setTarget(
                        RPJContextHelper.getTargetClass(compilationUnit, expression.getRightOperand(), true));

            expression.getRightOperand().accept(rightBuilder);
            buffer.append(rightBuilder.getResult());

            buffer.append(")");

            if (leftBuilder.getTarget() == null) {
                switch (expression.getOperator()) {
                case EQUAL:
                    buffer.append(" == 0");
                    break;
                case GREATER_THAN:
                    buffer.append(" > 0");
                    break;
                case GREATER_THAN_EQUAL:
                    buffer.append(" >= 0");
                    break;
                case LESS_THAN:
                    buffer.append(" < 0");
                    break;
                case LESS_THAN_EQUAL:
                    buffer.append(" <= 0");
                    break;
                case NOT_EQUAL:
                    buffer.append(" != 0");
                    break;
                }
            }

        } else {

            // left
            leftBuilder.clear();
            leftBuilder.setTarget(null);

            expression.getLeftOperand().accept(leftBuilder);
            buffer.append(leftBuilder.getResult());

            // TODO verify
            Class<?> targetLeft = RPJContextHelper.getTargetClass(compilationUnit, expression.getLeftOperand(),
                    false);
            if (targetLeft != null && targetLeft.isAssignableFrom(QDataArea.class)) {
                // unwrap
                buffer.append(".get()");
            }

            // operator
            buffer.append("." + toJavaMethod(expression));
            buffer.append("(");

            // right
            rightBuilder.clear();
            expression.getRightOperand().accept(rightBuilder);
            buffer.append(rightBuilder.getResult());

            buffer.append(")");
        }

        return false;
    }

    @Override
    public boolean visit(QBlockExpression expression) {

        if (mockExpression(expression))
            return false;

        // TODO statement return in procedure
        if (expression.getParent() == null
                && expression.getExpression().getExpressionType().equals(ExpressionType.RELATIONAL)) {
            expression.getExpression().accept(this);
            String value = getResult();
            buffer.delete(0, buffer.length());
            writeValue(expression.getExpression().getClass(), target, value);
            // TODO Remove me
            jobLogManager.info(job,
                    "Program " + compilationUnit.getNode().getName() + " write new return statement");
        } else {
            buffer.append("(");
            expression.getExpression().accept(this);
            buffer.append(")");
        }
        return false;
    }

    private String toJavaPrimitive(AssignmentOperator assignOperator) {

        String result = null;

        switch (assignOperator) {
        case ASSIGN:
            result = "=";
            break;
        case DIVIDE_ASSIGN:
            result = "/";
            break;
        case MINUS_ASSIGN:
            result = "-";
            break;
        case PLUS_ASSIGN:
            result = "+";
            break;
        case POWER_ASSIGN:
            result = "^";
            break;
        case TIMES_ASSIGN:
            result = "*";
            break;
        }

        return result;
    }

    private String toJavaPrimitive(ArithmeticOperator operator) {

        String result = null;

        switch (operator) {
        case DIVIDE:
            result = "/";
            break;
        case MINUS:
            result = "-";
            break;
        case MULT:
            result = "*";
            break;
        case SIGN_MINUS:
            result = "-";
            break;
        case SIGN_PLUS:
            result = "+";
            break;
        case PLUS:
            result = "+";
            break;
        case POWER:
            result = "^";
            break;
        case MODULAR:
            result = "%";
            break;
        }

        return result;
    }

    private String toJavaPrimitive(LogicalOperator operator) {

        String result = null;

        switch (operator) {
        case AND:
            result = " && ";
            break;
        case NOT:
            result = " !";
            break;
        case OR:
            result = " || ";
            break;
        }

        return result;
    }

    private String toJavaMethod(QExpression expression) {

        String result = null;

        switch (expression.getExpressionType()) {
        case ARITHMETIC:
            result = ((QArithmeticExpression) expression).getOperator().getLiteral().toLowerCase();
            break;
        case ASSIGNMENT:
            result = ((QAssignmentExpression) expression).getOperator().getLiteral().toLowerCase();
            break;
        case QUALIFIED:
        case FUNCTION:
            break;
        case LOGICAL:
            result = ((QLogicalExpression) expression).getOperator().getLiteral().toLowerCase();
            break;
        case RELATIONAL:
            result = ((QRelationalExpression) expression).getOperator().getLiteral().toLowerCase();
            break;
        case ATOMIC:
            break;
        case BLOCK:
            break;
        case BOOLEAN:
            break;
        case ARRAY:
            break;
        }

        return result;
    }

    private void writeValue(Class<?> source, Class<?> target, String value) {

        if (value == null)
            return;

        if (source == null || target == null) {
            buffer.append(value);
            return;
        }

        // if (target.equals(Byte.class) &&
        // Number.class.isAssignableFrom(source)) {
        // buffer.append(value);
        // return;
        // }

        if (target.isAssignableFrom(source)) {
            buffer.append(value);
            return;
        }

        if (Number.class.isAssignableFrom(source) && source.isAssignableFrom(target)) {
            buffer.append(value);
            return;
        }

        if (Buffer.class.isAssignableFrom(target)) {
            buffer.append(value);
            return;
        }

        // TODO remove?
        // Hexadecimal
        if (QHexadecimal.class.isAssignableFrom(source))
            buffer.append(value);
        // TODO
        else if (Enum.class.isAssignableFrom(source)) {

            if (QCharacter.class.isAssignableFrom(this.target)) {
                if (value.equalsIgnoreCase("Specials.ON"))
                    buffer.append("qRPJ.qBox(true)");
                else if (value.equalsIgnoreCase("Specials.OFF"))
                    buffer.append("qRPJ.qBox(false)");
                else
                    buffer.append("qRPJ.qBox(" + value + ")");
            } else if (String.class.isAssignableFrom(this.target)) {
                if (value.equalsIgnoreCase("Specials.ON"))
                    buffer.append("\"1\"");
                else if (value.equalsIgnoreCase("Specials.OFF"))
                    buffer.append("\"0\"");
                else if (value.equalsIgnoreCase("Specials.BLANK"))
                    buffer.append("\"\"");
                else if (value.equalsIgnoreCase("Specials.BLANKS"))
                    buffer.append("\"\"");
                else if (value.equalsIgnoreCase("Specials.ZERO"))
                    buffer.append("0");
                else if (value.equalsIgnoreCase("Specials.ZEROS"))
                    buffer.append("0");
                else
                    buffer.append(value);
            } else if (Boolean.class.isAssignableFrom(this.target)) {
                if (value.equalsIgnoreCase("Specials.ON"))
                    buffer.append("true");
                else if (value.equalsIgnoreCase("Specials.OFF"))
                    buffer.append("false");
                else if (value.equalsIgnoreCase("Specials.BLANK"))
                    buffer.append("false");
                else if (value.equalsIgnoreCase("Specials.BLANKS"))
                    buffer.append("false");
                else if (value.equalsIgnoreCase("Specials.ZERO"))
                    buffer.append("false");
                else if (value.equalsIgnoreCase("Specials.ZEROS"))
                    buffer.append("false");
                else
                    buffer.append(value);
            } else
                buffer.append(value);

        }
        // cast
        else if (QIndicator.class.isAssignableFrom(target) && QCharacter.class.isAssignableFrom(source))
            buffer.append("qRPJ.qCast(" + value + ")");

        // boxing
        else if (QData.class.isAssignableFrom(target)) {

            // pointer
            if (QPointer.class.isAssignableFrom(target))
                buffer.append("qRPJ.qPointer(" + value + ")");

            // string
            else if (QString.class.isAssignableFrom(target))
                buffer.append("qRPJ.qBox(" + value + ")");
            else if (target.equals(QData.class) && source.equals(String.class))
                buffer.append("qRPJ.qBox(" + value + ")");

            // buffered
            else if (target.equals(QBufferedElement.class)) {
                if (source.equals(String.class))
                    buffer.append("qRPJ.qBox(" + value + ")");
                else if (Number.class.isAssignableFrom(source))
                    buffer.append("qRPJ.qBox(" + value + ")");
                else
                    throw new IntegratedLanguageExpressionRuntimeException(
                            "Invalid boxing type: " + source.getSimpleName());
            } else if (target.equals(QData.class) && Number.class.isAssignableFrom(source))
                buffer.append("qRPJ.qBox(" + value + ")");

            // binary
            else if (QBinary.class.isAssignableFrom(target) && Number.class.isAssignableFrom(source))
                buffer.append("qRPJ.qBoxBinary(" + value + ")");

            // numeric
            else if (QNumeric.class.isAssignableFrom(target) && Number.class.isAssignableFrom(source))
                buffer.append("qRPJ.qBox(" + value + ")");

            // indicator
            else if (QIndicator.class.isAssignableFrom(target))
                buffer.append("qRPJ.qBox(" + value + ")");

            // hexadecimal
            else if (target.equals(QHexadecimal.class) && source.equals(Byte.class))
                buffer.append("qRPJ.qBox(" + value + ")");
            else if (target.equals(QHexadecimal.class) && source.equals(String.class))
                buffer.append("qRPJ.qBox(" + value + ")");
            // array
            else if (QArray.class.isAssignableFrom(target))
                buffer.append("qRPJ.qBoxArray(" + value + ")");

            // datetime
            else if (QDatetime.class.isAssignableFrom(target)) {
                buffer.append("qRPJ.qBox(" + value + ")");
                buffer.append(value);
                buffer.append(".asDatetime()");
            }

        }
        // unboxing
        else {

            if (source != null && !QData.class.isAssignableFrom(source)) {
                // JVM casting
                if (Number.class.isAssignableFrom(source) && Number.class.isAssignableFrom(target)) {
                    buffer.append(value);
                    return;
                } else {
                    buffer.append("qRPJ.qBox" + getTarget().getSimpleName() + "(");
                    buffer.append(value);
                    buffer.append(")");
                }
            } else
                buffer.append(value);

            if (target != null && source != null && source.isAssignableFrom(QDataArea.class))
                buffer.append(".get()");

            // string
            if (String.class.isAssignableFrom(target)) {
                buffer.append(".s()");
                // number
            } else if (Number.class.isAssignableFrom(target)) {
                if (target.equals(Byte.class)) {
                    buffer.append(".i()");
                } else if (target.equals(Short.class)) {
                    buffer.append(".i()");
                } else if (target.equals(Integer.class)) {
                    buffer.append(".i()");
                } else if (target.equals(Long.class)) {
                    buffer.append(".l()");
                } else if (target.equals(Double.class)) {
                    buffer.append(".d()");
                } else {
                    buffer.append(".i()");
                }
            }
            // boolean
            else if (Boolean.class.isAssignableFrom(target)) {
                buffer.append(".b()");
            }
            // date
            else if (Date.class.isAssignableFrom(target)) {
                buffer.append(".t()");
            }
            // list
            else if (List.class.isAssignableFrom(target)) {
                // buffer.append(".asList()");
            }
            // dataSet
            else if (QFileTerm.class.isAssignableFrom(target)) {
                // buffer.append(".asList()");
            } else
                throw new IntegratedLanguageExpressionRuntimeException(
                        "Invalid unboxing type: " + target.getSimpleName());
        }
    }

    public String buildExpression(QKeyListTerm keyList) {

        StringBuffer stringBuffer = new StringBuffer();

        stringBuffer.append("new QBufferedData[] {");

        JDTExpressionStringBuilder fieldBuilder = this.compilationUnit.getContext()
                .make(JDTExpressionStringBuilder.class);
        fieldBuilder.setAST(getAST());

        int i = 0;
        for (String keyField : keyList.getKeyFields()) {
            // procedure with constant
            QNamedNode namedNode = null;
            namedNode = compilationUnit.getNamedNode(keyField, true);
            QDataTerm<?> dataTerm = null;
            if (namedNode != null) {
                dataTerm = RPJContextHelper.getDataTerm(namedNode);
            }

            if (dataTerm.isConstant()) {
                String value = compilationUnit.getQualifiedName(namedNode);
                writeValue(dataTerm.getDefinition().getJavaClass(), dataTerm.getDefinition().getDataClass(), value);
                if (i > 0)
                    stringBuffer.append(", ");
                stringBuffer.append(getResult());
                buffer.delete(0, buffer.length());
            } else {
                QExpression fieldExpression = expressionParser.parseExpression(keyField);
                fieldBuilder.clear();
                fieldBuilder.setTarget(null);
                fieldExpression.accept(fieldBuilder);
                if (i > 0)
                    stringBuffer.append(", ");
                stringBuffer.append(fieldBuilder.getResult());
            }

            i++;
        }

        stringBuffer.append("}");

        return stringBuffer.toString();
    }

    @Override
    public boolean visit(QQualifiedTermExpression expression) {

        if (mockExpression(expression))
            return false;

        QDataTerm<?> dataTerm = compilationUnit.getDataTerm(expression.getValue(), true);
        if (dataTerm == null)
            throw new IntegratedLanguageExpressionRuntimeException("Invalid term: " + expression.getValue());

        // atomic
        if (dataTerm.getDataTermType().isAtomic()) {

            StringBuffer value = new StringBuffer();
            value.append(compilationUnit.getQualifiedName(dataTerm));

            if (expression.getElements().get(1) instanceof QFunctionTermExpression) {

                QFunctionTermExpression functionTermExpression = (QFunctionTermExpression) expression.getElements()
                        .get(1);
                if (functionTermExpression.getElements().size() > 1)
                    throw new IntegratedLanguageExpressionRuntimeException("Unexpected condition ptc98av38etaeyt");

                value.append(".get");
                value.append("(");

                JDTExpressionStringBuilder indexBuilder = compilationUnit.getContext()
                        .make(JDTExpressionStringBuilder.class);
                indexBuilder.setAST(getAST());
                functionTermExpression.getElements().get(0).accept(indexBuilder);
                value.append(indexBuilder.getResult());

                value.append(")");

                Class<?> source = null;
                if (dataTerm.getDataTermType().isMultiple()) {
                    if (this.target != null) {
                        if (QList.class.isAssignableFrom(this.target))
                            source = dataTerm.getDefinition().getDataClass();
                        else if (dataTerm.getDataTermType().isAtomic())
                            source = ((QMultipleAtomicDataDef<?>) dataTerm.getDefinition()).getArgument()
                                    .getDataClass();
                    } else
                        source = dataTerm.getDefinition().getDataClass();
                } else {
                    if (dataTerm.isConstant() && !dataTerm.getDataTermType().isMultiple())
                        source = dataTerm.getDefinition().getJavaClass();
                    else
                        source = dataTerm.getDefinition().getDataClass();
                }
                writeValue(source, this.target, value.toString());
            } else
                writeValue(dataTerm.getDefinition().getDataClass(), this.target, value.toString());
        }
        // compound
        else {
            this.buffer.append(compilationUnit.getQualifiedName(dataTerm));
        }

        return false;
    }

    @SuppressWarnings("unchecked")
    @Override
    public boolean visit(QFunctionTermExpression expression) {

        if (mockExpression(expression))
            return false;

        QPrototype prototype = null;

        // search object method
        if (!expression.getElements().isEmpty()) {
            QExpression expressionChild = expression.getElements().get(0);

            Class<?> objectTarget = null;
            if (!RPJContextHelper.isPrimitive(compilationUnit, expressionChild))
                objectTarget = (Class<? extends QData>) RPJContextHelper.getTargetClass(compilationUnit,
                        expressionChild, false);
            else
                objectTarget = RPJContextHelper.getModelClass(
                        (Class<?>) RPJContextHelper.getTargetClass(compilationUnit, expressionChild, true));

            if (objectTarget.isAssignableFrom(QDataArea.class)) {
                prototype = compilationUnit.getMethod(QCharacter.class, expression.getValue());
                if (prototype == null)
                    prototype = compilationUnit.getMethod(QDecimal.class, expression.getValue());
                if (prototype == null)
                    prototype = compilationUnit.getMethod(QIndicator.class, expression.getValue());
            } else
                prototype = compilationUnit.getMethod(objectTarget, expression.getValue());

            if (prototype != null)
                return writeMethod(prototype, expression.getElements());
        }

        // prototype
        prototype = compilationUnit.getPrototype(expression.getValue(), true);
        if (prototype != null) {
            writePrototype(prototype, expression.getElements());
            return false;
        }

        // search dataTerm
        QDataTerm<?> dataTerm = compilationUnit.getDataTerm(expression.getValue(), true);
        if (dataTerm != null) {
            writeDataTerm(dataTerm, expression.getElements());
            return false;
        }

        QNamedNode namedNode = compilationUnit.getNamedNode(expression.getValue(), true);
        if (namedNode != null) {
            writeNamedNode(namedNode);
            return false;
        }

        throw new IntegratedLanguageDataRuntimeException("Invalid expression " + expression);
    }

    private void writeDataTerm(QDataTerm<?> dataTerm, List<QExpression> elements) {
        // atomic
        if (dataTerm.getDataTermType().isAtomic()) {
            StringBuffer value = new StringBuffer();
            value.append(compilationUnit.getQualifiedName(dataTerm));
            if (dataTerm.getDataTermType().isMultiple()) {

                value.append(".get");
                value.append("(");

                JDTExpressionStringBuilder indexBuilder = compilationUnit.getContext()
                        .make(JDTExpressionStringBuilder.class);
                indexBuilder.setAST(getAST());
                for (QExpression element : elements)
                    element.accept(indexBuilder);
                value.append(indexBuilder.getResult());
                value.append(")");
            }

            Class<?> source = null;
            if (dataTerm.getDataTermType().isMultiple()) {
                if (this.target != null) {
                    if (QList.class.isAssignableFrom(this.target))
                        source = dataTerm.getDefinition().getDataClass();
                    else if (dataTerm.getDataTermType().isAtomic())
                        source = ((QMultipleAtomicDataDef<?>) dataTerm.getDefinition()).getArgument()
                                .getDataClass();
                } else
                    source = dataTerm.getDefinition().getDataClass();
            } else {
                if (dataTerm.isConstant() && !dataTerm.getDataTermType().isMultiple())
                    source = dataTerm.getDefinition().getJavaClass();
                else
                    source = dataTerm.getDefinition().getDataClass();
            }
            writeValue(source, this.target, value.toString());
        }
        // compound
        else {
            this.buffer.append(compilationUnit.getQualifiedName(dataTerm));
        }
    }

    private boolean writeMethod(QPrototype prototype, List<QExpression> elements) {

        QExpression expressionObject = elements.get(0);
        switch (expressionObject.getExpressionType()) {
        case ARRAY:
        case ATOMIC:
        case FUNCTION:
        case QUALIFIED:
        case ARITHMETIC:
        case BLOCK:
        case BOOLEAN:

            QMethodExec methodExec = QIntegratedLanguageFlowFactory.eINSTANCE.createMethodExec();
            methodExec.setObject(expressionWriter.writeExpression(expressionObject));
            methodExec.setMethod(prototype.getName());
            for (QExpression elementExpression : elements) {
                if (elementExpression == expressionObject)
                    continue;
                methodExec.getParameters().add(expressionWriter.writeExpression(elementExpression));
            }

            JDTStatementWriter statementWriter = compilationUnit.getContext().make(JDTStatementWriter.class);
            statementWriter.setAST(getAST());
            Block block = getAST().newBlock();
            statementWriter.getBlocks().push(block);

            methodExec.accept(statementWriter);
            if (!block.statements().isEmpty()) {
                String content = block.statements().get(0).toString().trim();
                writeValue(prototype.getDefinition().getDataClass(), this.target, strings.removeLastChar(content));
            }

            statementWriter.getBlocks().pop();
            return false;
        case ASSIGNMENT:
        case LOGICAL:
        case RELATIONAL:
            break;
        }

        return true;
    }

    private void writePrototype(QPrototype prototype, List<QExpression> parameters) {
        StringBuffer value = new StringBuffer();

        value.append(compilationUnit.getQualifiedName(prototype));

        value.append("(");
        if (prototype.getEntry() != null) {
            Iterator<QEntryParameter<?>> entryParameters = prototype.getEntry().getParameters().iterator();

            // parameters
            JDTExpressionStringBuilder parameterBuilder = compilationUnit.getContext()
                    .make(JDTExpressionStringBuilder.class);
            parameterBuilder.setAST(getAST());
            boolean first = true;
            for (QExpression element : parameters) {

                if (!entryParameters.hasNext())
                    throw new IntegratedLanguageExpressionRuntimeException(
                            "Invalid procedure invocation: " + prototype.getName());

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

                parameterBuilder.clear();
                if (parameterDelegate instanceof QDataTerm) {
                    QDataTerm<?> dataTerm = (QDataTerm<?>) parameterDelegate;
                    if (dataTerm.isConstant() && !dataTerm.getDataTermType().isMultiple()) {
                        parameterBuilder.setTarget(dataTerm.getDefinition().getJavaClass());
                    } else {
                        parameterBuilder.setTarget(dataTerm.getDefinition().getDataClass());
                    }
                } else if (parameterDelegate instanceof QFileTerm) {
                    parameterBuilder.setTarget(QFileTerm.class);
                }

                element.accept(parameterBuilder);

                if (!first)
                    value.append(", ");

                value.append(parameterBuilder.getResult());

                first = false;
            }

            while (entryParameters.hasNext()) {
                entryParameters.next();
                if (!first)
                    value.append(", null");

                first = false;
            }
        } else {
            if (!parameters.isEmpty())
                throw new IntegratedLanguageExpressionRuntimeException(
                        "Invalid parameters number binding  procedure: " + prototype.getName());
        }

        value.append(")");

        // TODO filler
        if (prototype.getName().equalsIgnoreCase("%ALL")) {
            writeValue(null, this.target, value.toString());
        } else {
            if (prototype.isConstant())
                writeValue(prototype.getDefinition().getJavaClass(), this.target, value.toString());
            else
                writeValue(prototype.getDefinition().getDataClass(), this.target, value.toString());
        }
    }

    @Override
    public boolean visit(QArrayExpression expression) {

        if (mockExpression(expression))
            return false;

        if (expression.getExpression().isEmpty()) {
            buffer.append("new QBufferedData[] {}");
        } else if (expression.getExpression().size() == 1) {
            expression.getExpression().get(0).accept(this);
        } else {
            buffer.append("new QBufferedData[] { ");

            boolean first = true;
            for (QExpression expressionChild : expression.getExpression()) {
                if (!first)
                    buffer.append(", ");
                expressionChild.accept(this);
                first = false;
            }
            buffer.append(" }");
        }

        return false;
    }

    private void writeNamedNode(QNamedNode namedNode) {

        // dataSet
        if (namedNode instanceof QDataSetTerm) {
            this.buffer.append(compilationUnit.getQualifiedName(namedNode));
            this.buffer.append(".get");
            this.buffer.append("(");
            this.buffer.append(")");
        }
        // display
        else if (namedNode instanceof QDisplayTerm) {
            this.buffer.append(compilationUnit.getQualifiedName(namedNode));
            this.buffer.append(".get");
            this.buffer.append("(");
            this.buffer.append(")");
        }
        // print
        else if (namedNode instanceof QPrintTerm) {
            this.buffer.append(compilationUnit.getQualifiedName(namedNode));
            this.buffer.append(".get");
            this.buffer.append("(");
            this.buffer.append(")");
        }
        // dataTerm
        else if (namedNode instanceof QDataTerm<?>) {
            QDataTerm<?> dataTerm = (QDataTerm<?>) namedNode;
            // atomic
            if (dataTerm.getDataTermType().isAtomic())
                writeValue(dataTerm.getDefinition().getDataClass(), this.target,
                        compilationUnit.getQualifiedName(namedNode));
            // compound
            else {
                this.buffer.append(compilationUnit.getQualifiedName(namedNode));
            }
        } else
            logger.warning(exceptionManager.prepareException(job, RPJCompilerMessage.AS00106, namedNode));
    }

    private boolean mockExpression(QExpression expression) {

        String expressionString = expression.toString();
        String expressionRewrited = null;

        //      System.out.println(expressionString);

        // BG00G
        if (expressionString.equals("W$DIV+'       '+WDIV")) {
            expressionRewrited = "w$div.qPlus(\"       \").qPlus(wdiv)";
        } else if (expressionString.equals("X$AZ+'        '+XAZ")) {
            expressionRewrited = "x$az.qPlus(\"        \").qPlus(xaz)";
        }
        // BIR10
        else if (expressionString.contains("%SUBARR(POG: 1: $CONTD)+' '+%SUBARR(PDE: 1: $CONTD)")) {
            expressionRewrited = "pog.qSubarr(1, $contd).qPlus(\" \").qPlus(pde.qSubarr(1, $contd))";
        }
        // BSER_26
        else if (expressionString.equals("P_RxATT(UIBPA: 'Scp(': *HIVAL)")) {
            expressionRewrited = "Jax.p_rxatt(Uib.uibds.uibpa.s(), \"Scp(\", \"999999999999999\", null, null)";
        }
        // C5CI00A / C5MB00A
        else if (expressionString.contains("VALORI+A9+DESCRIZIONI")) {
            expressionRewrited = "valori.qPlus(a9).qPlus(descrizioni)";
        }
        // C5SER_50
        else if (expressionString.equals("P_RXATT(STRPAR: 'FF': *HIVAL)")) {
            expressionRewrited = "Jax.p_rxatt(strpar.s(), \"FF\", \"999999999999999\", null, null)";
        }

        // D0CC01
        else if (expressionString.contains("SK_FACS/SK_FACS($$IGQ)*SK_FAQC($F)")) {
            expressionRewrited = "oc_facs.current().sk_facs.qDiv(oc_facs.current().sk_facs.get($$igq)).qMult(sk_faqc.get($f))";
        }
        // D0CC01A
        else if (expressionString.contains("SK_FPCS/SK_FPCS($$IGQ)*D0QTCA")) {
            expressionRewrited = "sk_fpcs.qDiv(sk_fpcs.get($$igq)).qMult(d0coso.d0qtca)";
        } else if (expressionString.contains("SK_COST*D0PAPR/100")) {
            expressionRewrited = "sk_cost.qMult(d0coso.d0papr).qDiv(100.0)";
        }
        // D0CC01B
        else if (expressionString.contains("SK_COST*P$PERC/100")) {
            expressionRewrited = "sk_cost.qMult(p$perc).qDiv(100.0)";
        } else if (expressionString.contains("SK_FACS+(SK_COST/QTXX*SK_FACS($$IGQ))")) {
            expressionRewrited = "oc_facs.current().sk_facs.qPlus(sk_cost.qDiv(qtxx).qMult(oc_facs.current().sk_facs.get($$igq)))";
        }
        // MTISAR
        else if (expressionString.equals("%runnable() and (%EQUAL())")) {
            expressionRewrited = "qRPJ.qRunnable() && (qRPJ.qEqual(brdist0).b())";
        }
        // MUTE02_01
        else if (expressionString.contains("AR10+10+AR11")) {
            expressionRewrited = "ar10.qPlus(10).qPlus(ar11)";
        } else if (expressionString.contains("AR10+2,666+AR11")) {
            expressionRewrited = "ar10.qPlus(2.666).qPlus(ar11)";
        } else if (expressionString.contains("AR13+' '+AR14")) {
            expressionRewrited = "ar13.qPlus(\" \").qPlus(ar14)";
        } else if (expressionString.contains("AR13+' + '+AR14")) {
            expressionRewrited = "ar13.qPlus(\" + \").qPlus(ar14)";
        }

        if (expressionRewrited != null) {
            buffer.append(expressionRewrited);
            return true;
        } else
            return false;

    }
}