msi.gama.lang.gaml.expression.GamlExpressionCompiler.java Source code

Java tutorial

Introduction

Here is the source code for msi.gama.lang.gaml.expression.GamlExpressionCompiler.java

Source

/*********************************************************************************************
 *
 * 'GamlExpressionCompiler.java, in plugin msi.gama.lang.gaml, is part of the source code of the GAMA modeling and
 * simulation platform. (c) 2007-2016 UMI 209 UMMISCO IRD/UPMC & Partners
 *
 * Visit https://github.com/gama-platform/gama for license information and developers contact.
 * 
 *
 **********************************************************************************************/
package msi.gama.lang.gaml.expression;

import static com.google.common.collect.Iterables.toArray;
import static com.google.common.collect.Iterables.transform;
import static msi.gama.common.interfaces.IKeyword.AS;
import static msi.gama.common.interfaces.IKeyword.EACH;
import static msi.gama.common.interfaces.IKeyword.IS;
import static msi.gama.common.interfaces.IKeyword.IS_SKILL;
import static msi.gama.common.interfaces.IKeyword.MY;
import static msi.gama.common.interfaces.IKeyword.MYSELF;
import static msi.gama.common.interfaces.IKeyword.NULL;
import static msi.gama.common.interfaces.IKeyword.OF;
import static msi.gama.common.interfaces.IKeyword.POINT;
import static msi.gama.common.interfaces.IKeyword.SELF;
import static msi.gama.common.interfaces.IKeyword.SPECIES;
import static msi.gama.common.interfaces.IKeyword.SUPER;
import static msi.gama.common.interfaces.IKeyword.TRUE;
import static msi.gama.common.interfaces.IKeyword.UNKNOWN;
import static msi.gama.common.interfaces.IKeyword._DOT;
import static msi.gaml.expressions.IExpressionFactory.FALSE_EXPR;
import static msi.gaml.expressions.IExpressionFactory.TRUE_EXPR;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;

import com.google.common.collect.Iterables;

import gnu.trove.map.hash.THashMap;
import msi.gama.common.interfaces.IGamlIssue;
import msi.gama.common.interfaces.IKeyword;
import msi.gama.common.util.StringUtils;
import msi.gama.lang.gaml.EGaml;
import msi.gama.lang.gaml.gaml.Access;
import msi.gama.lang.gaml.gaml.ActionRef;
import msi.gama.lang.gaml.gaml.ArgumentPair;
import msi.gama.lang.gaml.gaml.Array;
import msi.gama.lang.gaml.gaml.BinaryOperator;
import msi.gama.lang.gaml.gaml.BooleanLiteral;
import msi.gama.lang.gaml.gaml.ColorLiteral;
import msi.gama.lang.gaml.gaml.DoubleLiteral;
import msi.gama.lang.gaml.gaml.EquationRef;
import msi.gama.lang.gaml.gaml.Expression;
import msi.gama.lang.gaml.gaml.ExpressionList;
import msi.gama.lang.gaml.gaml.Facet;
import msi.gama.lang.gaml.gaml.Function;
import msi.gama.lang.gaml.gaml.If;
import msi.gama.lang.gaml.gaml.IntLiteral;
import msi.gama.lang.gaml.gaml.Parameter;
import msi.gama.lang.gaml.gaml.Point;
import msi.gama.lang.gaml.gaml.ReservedLiteral;
import msi.gama.lang.gaml.gaml.SkillFakeDefinition;
import msi.gama.lang.gaml.gaml.SkillRef;
import msi.gama.lang.gaml.gaml.StringEvaluator;
import msi.gama.lang.gaml.gaml.StringLiteral;
import msi.gama.lang.gaml.gaml.TerminalExpression;
import msi.gama.lang.gaml.gaml.TypeDefinition;
import msi.gama.lang.gaml.gaml.TypeInfo;
import msi.gama.lang.gaml.gaml.TypeRef;
import msi.gama.lang.gaml.gaml.Unary;
import msi.gama.lang.gaml.gaml.Unit;
import msi.gama.lang.gaml.gaml.UnitName;
import msi.gama.lang.gaml.gaml.VarDefinition;
import msi.gama.lang.gaml.gaml.VariableRef;
import msi.gama.lang.gaml.gaml.util.GamlSwitch;
import msi.gama.lang.gaml.resource.GamlResource;
import msi.gama.lang.gaml.resource.GamlResourceServices;
import msi.gama.runtime.GAMA;
import msi.gama.runtime.IExecutionContext;
import msi.gama.runtime.exceptions.GamaRuntimeException;
import msi.gama.util.GAML;
import msi.gaml.compilation.ast.SyntacticFactory;
import msi.gaml.compilation.ast.SyntacticModelElement;
import msi.gaml.compilation.kernel.GamaSkillRegistry;
import msi.gaml.descriptions.ActionDescription;
import msi.gaml.descriptions.ExperimentDescription;
import msi.gaml.descriptions.IDescription;
import msi.gaml.descriptions.IExpressionDescription;
import msi.gaml.descriptions.IVarDescriptionProvider;
import msi.gaml.descriptions.ModelDescription;
import msi.gaml.descriptions.OperatorProto;
import msi.gaml.descriptions.PlatformSpeciesDescription;
import msi.gaml.descriptions.SpeciesDescription;
import msi.gaml.descriptions.StatementDescription;
import msi.gaml.descriptions.StringBasedExpressionDescription;
import msi.gaml.descriptions.TypeDescription;
import msi.gaml.descriptions.ValidationContext;
import msi.gaml.expressions.ConstantExpression;
import msi.gaml.expressions.DenotedActionExpression;
import msi.gaml.expressions.EachExpression;
import msi.gaml.expressions.IExpression;
import msi.gaml.expressions.IExpressionCompiler;
import msi.gaml.expressions.IExpressionFactory;
import msi.gaml.expressions.IVarExpression;
import msi.gaml.expressions.TimeUnitConstantExpression;
import msi.gaml.expressions.TypeFieldExpression;
import msi.gaml.expressions.UnitConstantExpression;
import msi.gaml.factories.DescriptionFactory;
import msi.gaml.operators.Dates;
import msi.gaml.operators.IUnits;
import msi.gaml.statements.Arguments;
import msi.gaml.types.GamaType;
import msi.gaml.types.IType;
import msi.gaml.types.ITypesManager;
import msi.gaml.types.ParametricType;
import msi.gaml.types.Types;

/**
 * The Class GamlExpressionCompiler. Transforms Strings or XText Expressions into GAML IExpressions. Normally invoked by
 * an IExpressionFactory (the default being GAML.getExpressionFactory())
 */
@SuppressWarnings({ "unchecked", "rawtypes" })
public class GamlExpressionCompiler extends GamlSwitch<IExpression> implements IExpressionCompiler<Expression> {

    private final Deque<IVarExpression> iteratorContexts = new LinkedList();
    // To disable reentrant parsing (Issue 782)
    private IExpressionDescription currentExpressionDescription;
    private ITypesManager currentTypesManager;
    private final static Map<String, IExpression> constantSyntheticExpressions = new THashMap<>();
    private static final ExpressionDescriptionBuilder builder = new ExpressionDescriptionBuilder();

    /*
     * The context (IDescription) in which the parser operates. If none is given, the global context of the current
     * simulation is returned (via simulation.getModel().getDescription()) if it is available. Otherwise, only simple
     * expressions (that contain constants) can be parsed.
     */
    private IDescription currentContext;

    static {
        IExpressionCompiler.OPERATORS.put(MY, new THashMap<>());
    }

    @Override
    public IExpression compile(final IExpressionDescription s, final IDescription parsingContext) {
        // Cf. Issue 782. Returns the expression if an expression needs its
        // compiled version to be compiled.
        if (s.isConst() || s == getCurrentExpressionDescription()) {
            return s.getExpression();
        }
        setCurrentExpressionDescription(s);
        final EObject o = s.getTarget();
        if (o == null && s instanceof StringBasedExpressionDescription) {
            final IExecutionContext context = GAMA.getExperiment() == null ? null
                    : GAMA.getRuntimeScope().getExecutionContext();
            return compile(s.toString(), parsingContext, context);
        }
        final IDescription previous = setContext(parsingContext);
        try {
            final IExpression result = compile(o);
            return result;
        } finally {
            setContext(previous);
            setCurrentExpressionDescription(null);
        }

    }

    @Override
    public IExpression compile(final String expression, final IDescription parsingContext,
            final IExecutionContext tempContext) {
        final IDescription previous = setContext(parsingContext);
        try {

            IExpression result = constantSyntheticExpressions.get(expression);
            if (result != null) {
                return result;
            }
            final EObject o = getEObjectOf(expression, tempContext);
            result = compile(o);
            if (result != null && result.isContextIndependant()) {
                constantSyntheticExpressions.put(expression, result);
            }
            return result;
        } finally {
            setContext(previous);
            setCurrentExpressionDescription(null);
        }
    }

    private IExpression compile(final EObject s) {
        if (s == null) {
            // No error, since the null expressions come from previous (more
            // focused) errors and not from the parser itself.
            return null;
        }

        final IExpression expr = doSwitch(s);
        if (expr != null && getContext() != null) {
            getContext().document(s, expr);
        }
        return expr;
    }

    private IExpression skill(final String name) {
        return getFactory().createConst(name, Types.SKILL);
    }

    // KEEP
    private IExpression unary(final String op, final Expression e) {
        if (op == null) {
            return null;
        }
        final IExpression expr = compile(e);
        if (expr == null) {
            return null;
        }
        if (op.equals(MY)) {
            final IVarDescriptionProvider desc = getContext().getDescriptionDeclaringVar(MYSELF);
            if (desc instanceof IDescription) {
                // We are in a remote context, so 'my' refers to the calling
                // agent
                final IExpression myself = desc.getVarExpr(MYSELF, false);
                final IDescription species = myself.getGamlType().getSpecies();
                final IExpression var = species.getVarExpr(EGaml.getKeyOf(e), true);
                return getFactory().createOperator(_DOT, (IDescription) desc, e, myself, var);
            }
            // Otherwise, we ignore 'my' since it refers to 'self'
            return expr;
        }
        // The unary "unit" operator should let the value of its child pass
        // through
        if (op.equals("") || op.equals("#")) {
            return expr;
        }
        if (op.equals("every") && expr instanceof ConstantExpression && expr.getGamlType() == Types.INT) {
            getContext().warning(
                    "No unit provided. If this frequency concerns cycles, please use the #cycle unit. Otherwise use one of the temporal unit (#ms, #s, #mn, #h, #day, #week, #month, #year)",
                    IGamlIssue.DEPRECATED, e);
        }
        if (isSpeciesName(op)) {
            return getFactory().createAs(getContext(), expr, getSpeciesContext(op).getSpeciesExpr());
        }
        // if ( isSkillName(op) ) { return factory.createOperator(AS, context,
        // e, expr, skill(op)); }
        return getFactory().createOperator(op, getContext(), e, expr);
    }

    private IExpression casting(final String type, final IExpression toCast, final Expression typeObject) {
        if (toCast == null) {
            return null;
        }
        final IType castingType = currentTypesManager.get(type).typeIfCasting(toCast);

        final boolean isSuperType = castingType.isAssignableFrom(toCast.getGamlType());
        TypeInfo typeInfo = null;
        if (typeObject instanceof TypeRef) {
            typeInfo = ((TypeRef) typeObject).getParameter();
        } else if (typeObject instanceof Function) {
            typeInfo = ((Function) typeObject).getType();
        }
        if (isSuperType && typeInfo == null) {
            getContext().info("Unneeded casting: '" + toCast.serialize(true) + "' is already of type " + type,
                    IGamlIssue.UNUSED, typeObject);
            // Issue #2521: indicate but don't skip the casting
            // return toCast;
        }
        IType keyType = castingType.getKeyType();
        IType contentsType = castingType.getContentType();
        if (typeInfo != null) {
            IType kt = fromTypeRef((TypeRef) typeInfo.getFirst());
            IType ct = fromTypeRef((TypeRef) typeInfo.getSecond());
            if (ct == null || ct == Types.NO_TYPE) {
                ct = kt;
                kt = null;
            }
            if (ct != null && ct != Types.NO_TYPE) {
                contentsType = ct;
            }
            if (kt != null && kt != Types.NO_TYPE) {
                keyType = kt;
            }
        }
        final IType result = GamaType.from(castingType, keyType, contentsType);
        // If there is no casting to do, just return the expression unchanged.
        if (result.isAssignableFrom(toCast.getGamlType())) {
            getContext().info("Unneeded casting: '" + toCast.serialize(true) + "' is already of type " + type,
                    IGamlIssue.UNUSED, typeObject);
            // Issue #2521: indicate but don't skip the casting
            // return toCast;
        }

        return getFactory().createAs(getContext().getSpeciesContext(), toCast,
                getFactory().createTypeExpression(result));
    }

    IType fromTypeRef(final TypeRef object) {
        if (object == null) {
            return null;
        }
        String primary = EGaml.getKeyOf(object);

        if (primary == null) {
            primary = object.getRef().getName();
        } else if (primary.equals(SyntacticFactory.SPECIES_VAR)) {
            primary = SPECIES;
        }

        final IType t = currentTypesManager.get(primary);

        if (t == Types.NO_TYPE && !UNKNOWN.equals(primary)) {
            getContext().error(primary + " is not a valid type name", IGamlIssue.NOT_A_TYPE, object, primary);
            return t;
        }

        // case of model_alias<species>
        if (t.isAgentType() && t.getSpecies().isModel()) {
            final TypeInfo parameter = object.getParameter();
            if (parameter == null) {
                return t;
            }
            final TypeRef first = (TypeRef) parameter.getFirst();
            if (first == null) {
                return t;
            } else {
                final ITypesManager savedTypesManager = currentTypesManager;
                try {
                    currentTypesManager = t.getSpecies().getModelDescription().getTypesManager();
                    return fromTypeRef(first);
                } finally {
                    currentTypesManager = savedTypesManager;
                }
            }
        }

        if (t.isAgentType()) {
            return t;
        }

        // /

        final TypeInfo parameter = object.getParameter();
        if (parameter == null || !t.isContainer()) {
            return t;
        }
        final TypeRef first = (TypeRef) parameter.getFirst();
        if (first == null) {
            return t;
        }
        final TypeRef second = (TypeRef) parameter.getSecond();
        if (second == null) {
            return GamaType.from(t, t.getKeyType(), fromTypeRef(first));
        }
        return GamaType.from(t, fromTypeRef(first), fromTypeRef(second));
    }

    private IExpression binary(final String op, final IExpression left, final Expression originalExpression) {
        if (left == null) {
            return null;
        }
        Expression rightMember = originalExpression;
        // if the operator is "as", the right-hand expression should be a
        // casting type
        if (AS.equals(op)) {
            return binaryAs(left, rightMember);
        }
        // if the operator is "is", the right-hand expression should be a type
        if (IS.equals(op)) {
            return binaryIs(left, rightMember);
        }

        // we verify and compile apart the calls to actions as operators

        final TypeDescription sd = left.getGamlType().getSpecies();
        if (sd != null) {
            final ActionDescription action = sd.getAction(op);
            if (action != null) {
                final IExpression result = action(op, left, rightMember, action);
                if (result != null) {
                    return result;
                }
            }
        }
        // It is not an action, it must be an operator. We emit an error and
        // stop compiling if not
        if (!OPERATORS.containsKey(op)) {
            getContext().error("Unknown action or operator: " + op, IGamlIssue.UNKNOWN_ACTION,
                    rightMember.eContainer(), op);
            return null;
        }

        // if the operator is an iterator, we must initialize the context
        // sensitive "each" variable
        final boolean isIterator = ITERATORS.contains(op);
        if (isIterator) {
            final IType t = left.getGamlType().getContentType();
            final String argName = findIteratorArgName(rightMember);
            rightMember = findIteratorExpr(rightMember);
            iteratorContexts.push(new EachExpression(argName, t));
        }
        // If the right-hand expression is a list of expression, then we have a
        // n-ary operator
        if (rightMember instanceof ExpressionList) {
            final ExpressionList el = (ExpressionList) rightMember;
            final List<Expression> list = EGaml.getExprsOf(el);
            final int size = list.size();
            if (size > 1) {
                final IExpression[] compiledArgs = new IExpression[size + 1];
                compiledArgs[0] = left;
                for (int i = 0; i < size; i++) {
                    compiledArgs[i + 1] = compile(list.get(i));
                }
                final IExpression result = getFactory().createOperator(op, getContext(), rightMember, compiledArgs);
                return result;
            }
        }

        // Otherwise we can now safely compile the right-hand expression
        final IExpression right = compile(rightMember);
        // We make sure to remove any mention of the each expression after the
        // right member has been compiled
        if (isIterator) {
            iteratorContexts.pop();
        }
        // and we return the operator expression
        return getFactory().createOperator(op, getContext(), originalExpression.eContainer(), left, right);

    }

    private String findIteratorArgName(final Expression e2) {
        if (!(e2 instanceof ExpressionList)) {
            return IKeyword.EACH;
        }
        final ExpressionList params = (ExpressionList) e2;
        final List<Expression> exprs = EGaml.getExprsOf(params);
        if (exprs == null || exprs.isEmpty()) {
            return IKeyword.EACH;
        }
        final Expression arg = exprs.get(0);
        if (!(arg instanceof Parameter)) {
            return IKeyword.EACH;
        }
        final Parameter p = (Parameter) arg;
        return EGaml.getKeyOf(p);
    }

    private Expression findIteratorExpr(final Expression e2) {
        if (!(e2 instanceof ExpressionList)) {
            return e2;
        }
        final ExpressionList params = (ExpressionList) e2;
        final List<Expression> exprs = EGaml.getExprsOf(params);
        if (exprs == null || exprs.isEmpty()) {
            return e2;
        }
        final Expression arg = exprs.get(0);
        if (!(arg instanceof Parameter)) {
            return arg;
        }
        final Parameter p = (Parameter) arg;
        return p.getRight();
    }

    private IExpression binaryIs(final IExpression left, final Expression e2) {
        final String type = EGaml.getKeyOf(e2);
        if (isTypeName(type)) {
            return getFactory().createOperator(IS, getContext(), e2.eContainer(), left,
                    getFactory().createConst(type, Types.STRING));
        }
        if (isSkillName(type)) {
            return getFactory().createOperator(IS_SKILL, getContext(), e2.eContainer(), left,
                    getFactory().createConst(type, Types.SKILL));
        }
        getContext().error(
                "'is' must be followed by a type, species or skill name. " + type + " is neither of these.",
                IGamlIssue.NOT_A_TYPE, e2, type);
        return null;
    }

    private IExpression binaryAs(final IExpression left, final Expression e2) {
        final String type = EGaml.getKeyOf(e2);
        // if ( isSpeciesName(type) ) { return factory.createOperator(op,
        // context, e2, left, species(type)); }
        // if ( isSkillName(type) ) { return
        // factory.createOperator(AS_SKILL, context, e2, left, skill(type));
        // }
        if (isTypeName(type)) {
            return casting(type, left, e2);
        }
        getContext().error(
                "'as' must be followed by a type, species or skill name. " + type + " is neither of these.",
                IGamlIssue.NOT_A_TYPE, e2, type);
        // if (isTypeName(type)) { return casting(type, left, e2); }
        return null;
    }

    private IExpression action(final String name, final IExpression callee, final EObject args,
            final ActionDescription action) {
        final Arguments arguments = parseArguments(action, args, getContext(), true);
        return getFactory().createAction(name, getContext(), action, callee, arguments);
    }

    // KEEP
    private IExpression binary(final String op, final Expression e1, final Expression right) {

        // if the expression is " var of agents ", we must compile it apart
        if (OF.equals(op)) {
            return compileFieldExpr(right, e1);
        }
        // we can now safely compile the left-hand expression
        final IExpression left = compile(e1);
        return binary(op, left, right);
    }

    private SpeciesDescription getSpeciesContext(final String e) {
        return getContext().getSpeciesDescription(e);
    }

    private boolean isSpeciesName(final String s) {
        final ModelDescription m = getContext().getModelDescription();
        if (m == null) {
            // can occur when building the kernel
            return false;
        }
        final SpeciesDescription sd = m.getSpeciesDescription(s);
        return sd != null && !(sd instanceof ExperimentDescription);
    }

    private boolean isSkillName(final String s) {
        return GamaSkillRegistry.INSTANCE.hasSkill(s);
    }

    private boolean isTypeName(final String s) {

        if (!currentTypesManager.containsType(s)) {
            return false;
        }
        final IType t = currentTypesManager.get(s);
        final SpeciesDescription sd = t.getSpecies();
        if (sd != null && sd.isExperiment()) {
            return false;
        }
        return true;
    }

    private IExpression compileNamedExperimentFieldExpr(final Expression leftExpr, final String name) {
        final IExpression owner = compile(leftExpr);
        if (owner == null) {
            return null;
        }
        final IType type = owner.getGamlType();
        if (type.isParametricFormOf(Types.SPECIES)) {
            final SpeciesDescription sd = type.getContentType().getSpecies();
            if (sd instanceof ModelDescription) {
                final ModelDescription md = (ModelDescription) sd;
                if (md.hasExperiment(name)) {
                    return getFactory().createConst(name, GamaType.from(md.getExperiment(name)));
                }
            }
        }
        getContext().error("Only experiments can be accessed using their plain name", IGamlIssue.UNKNOWN_FIELD);
        return null;
    }

    private IExpression compileFieldExpr(final Expression leftExpr, final Expression fieldExpr) {
        final IExpression owner = compile(leftExpr);
        if (owner == null) {
            return null;
        }
        final IType type = owner.getGamlType();
        final TypeDescription species = type.getSpecies();
        // hqnghi 28-05-14 search input variable from model, not experiment
        if (type instanceof ParametricType && type.getGamlType().id() == IType.SPECIES) {
            if (type.getContentType().getSpecies() instanceof ModelDescription) {
                final ModelDescription sd = (ModelDescription) type.getContentType().getSpecies();
                final String var = EGaml.getKeyOf(fieldExpr);
                if (sd.hasExperiment(var)) {
                    return getFactory().createConst(var, GamaType.from(sd.getExperiment(var)));
                }
            }
        }
        // end-hqnghi
        if (species == null) {
            // It can only be a variable as 'actions' are not defined on simple
            // objects, except for matrices, where it
            // can also represent the dot product
            final String var = EGaml.getKeyOf(fieldExpr);
            final OperatorProto proto = type.getGetter(var);

            // Special case for matrices
            if (type.id() == IType.MATRIX && proto == null) {
                return binary(".", owner, fieldExpr);
            }

            if (proto == null) {
                getContext().error("Unknown field '" + var + "' for type " + type, IGamlIssue.UNKNOWN_FIELD,
                        leftExpr, var, type.toString());
                return null;
            }
            final TypeFieldExpression expr = (TypeFieldExpression) proto.create(getContext(), fieldExpr, owner);
            if (getContext() != null) {
                getContext().document(fieldExpr, expr);
            }
            return expr;
        }
        // We are now dealing with an agent. In that case, it can be either an
        // attribute or an
        // action call
        if (fieldExpr instanceof VariableRef) {
            final String var = EGaml.getKeyOf(fieldExpr);
            IExpression expr = species.getVarExpr(var, true);
            if (expr == null) {
                if (species instanceof ModelDescription && ((ModelDescription) species).hasExperiment(var)) {
                    final IType t = Types.get(IKeyword.SPECIES);
                    expr = getFactory()
                            .createTypeExpression(GamaType.from(t, Types.INT, species.getTypeNamed(var)));
                } else if (species.getName().equals(IKeyword.PLATFORM) && GAMA.isInHeadLessMode()) {
                    // Special case (see #2259 for headless validation of GUI preferences)
                    return ((PlatformSpeciesDescription) species).getFakePrefExpression(var);
                } else {
                    getContext().error("Unknown variable '" + var + "' for species " + species.getName(),
                            IGamlIssue.UNKNOWN_VAR, fieldExpr.eContainer(), var, species.getName());
                    return null;
                }
            }
            getContext().document(fieldExpr, expr);
            return getFactory().createOperator(_DOT, getContext(), fieldExpr, owner, expr);
        } else if (fieldExpr instanceof Function) {
            final String name = EGaml.getKeyOf(fieldExpr);
            final ActionDescription action = species.getAction(name);
            if (action != null) {
                final ExpressionList list = ((Function) fieldExpr).getRight();
                final IExpression call = action(name, owner, list, action);
                getContext().document(fieldExpr, call); // ??
                return call;
            }
        }
        return null;

    }

    // KEEP
    // private IExpression getWorldExpr() {
    // // if (world == null) {
    // final IType tt = getContext().getModelDescription()
    // ./* getWorldSpecies(). */getType();
    // final IExpression world = getFactory().createVar(WORLD_AGENT_NAME, tt,
    // true, IVarExpression.WORLD,
    // getContext().getModelDescription());
    // // }
    // return world;
    // }

    private IDescription setContext(final IDescription context) {
        final IDescription previous = currentContext;
        currentContext = context == null ? GAML.getModelContext() : context;
        currentTypesManager = Types.builtInTypes;
        if (currentContext != null) {
            final ModelDescription md = currentContext.getModelDescription();
            if (md != null) {
                final ITypesManager tm = md.getTypesManager();
                if (tm != null) {
                    currentTypesManager = tm;
                }
            }
        }
        return previous;
    }

    private IDescription getContext() {
        return currentContext;
    }

    private ValidationContext getValidationContext() {
        if (currentContext == null) {
            return null;
        }
        return currentContext.getValidationContext();
    }

    /**
     * @see msi.gaml.expressions.IExpressionParser#parseArguments(msi.gaml.descriptions.ExpressionDescription,
     *      msi.gaml.descriptions.IDescription)
     */
    @Override
    public Arguments parseArguments(final ActionDescription action, final EObject o, final IDescription command,
            final boolean compileArgValue) {
        if (o == null) {
            return null;
        }
        boolean completeArgs = false;
        List<Expression> parameters = null;
        if (o instanceof Array) {
            parameters = EGaml.getExprsOf(((Array) o).getExprs());
        } else if (o instanceof ExpressionList) {
            parameters = EGaml.getExprsOf(o);
            completeArgs = true;
        } else {
            command.error("Arguments must be written [a1::v1, a2::v2], (a1:v1, a2:v2) or (v1, v2)");
            return null;
        }
        final Arguments argMap = new Arguments();

        int index = 0;

        for (final Expression exp : parameters) {
            String arg = null;
            IExpressionDescription ed = null;

            if (exp instanceof ArgumentPair) {
                arg = EGaml.getKeyOf(exp);
                ed = builder.create(((ArgumentPair) exp).getRight()/* , errors */);
            } else if (exp instanceof Parameter) {
                arg = EGaml.getKeyOf(exp);
                ed = builder.create(((Parameter) exp).getRight()/* , errors */);
            } else if (exp instanceof BinaryOperator && "::".equals(EGaml.getKeyOf(exp))) {
                arg = EGaml.getKeyOf(((BinaryOperator) exp).getLeft());
                ed = builder.create(((BinaryOperator) exp).getRight()/* , errors */);
            } else if (completeArgs) {
                final List<String> args = action == null ? null : action.getArgNames();
                if (args != null && action != null && index == args.size()) {
                    command.error("Wrong number of arguments. Action " + action.getName() + " expects " + args);
                    return argMap;
                }
                arg = args == null ? String.valueOf(index++) : args.get(index++);
                ed = builder.create(exp/* , errors */);

            }
            if (ed != null && compileArgValue) {
                ed.compile(command);
            }
            // if (!errors.isEmpty()) {
            // for (final Diagnostic d : errors) {
            // getContext().warning(d.getMessage(), "", exp);
            // }
            // }
            argMap.put(arg, ed);
            // errors.clear();
        }

        return argMap;
    }

    // @Override
    // public IExpression caseCast(final Cast object) {
    // return binary(AS, object.getLeft(), object.getRight());
    // }

    @Override
    public IExpression caseSkillRef(final SkillRef object) {
        // final String s = EGaml.getKeyOf(object);
        return skill(EGaml.getKeyOf(object));
    }

    @Override
    public IExpression caseActionRef(final ActionRef object) {
        final String s = EGaml.getKeyOf(object);
        final SpeciesDescription sd = getContext().getSpeciesContext();
        ActionDescription ad = sd.getAction(s);
        if (ad == null) {
            ad = sd.getModelDescription().getAction(s);
            if (ad == null) {
                getContext().error("Unknown action", IGamlIssue.UNKNOWN_ACTION, object);
                return null;
            }
        }
        if (ad.getArgNames().size() > 0) {
            getContext().error("Impossible to call an action that requires arguments", IGamlIssue.UNKNOWN_ARGUMENT,
                    object);
            return null;
        }
        return new DenotedActionExpression(ad);
    }

    @Override
    public IExpression caseExpression(final Expression object) {
        return null;
        // // If an error already exists, we discard the case
        // final ValidationContext vc = getValidationContext();
        // final Expression left = object.getLeft();
        // final Expression right = object.getRight();
        // if (vc == null || vc.hasErrorOn(object, left, right)) { return null; }
        // // in the general case, we try to return a binary expression
        // final IExpression result = binary(EGaml.getKeyOf(object), object.getLeft(), object.getRight());
        // return result;
    }

    @Override
    public IExpression caseVariableRef(final VariableRef object) {
        final String s = EGaml.getKeyOf(object);
        if (s == null) {
            return caseVarDefinition(object.getRef());
        }
        return caseVar(s, object);
    }

    @Override
    public IExpression caseTypeRef(final TypeRef object) {
        final IType t = fromTypeRef(object);

        // / SEE IF IT WORKS

        // 2 erreurs :
        // - type inconnu n'est pas mentionn (electors ??)
        // - lors d'une affectation de nil warning sur le type (candidate)

        if (t.isAgentType()) {
            return t.getSpecies().getSpeciesExpr();
        }
        return getFactory().createTypeExpression(t);
    }

    @Override
    public IExpression caseEquationRef(final EquationRef object) {
        return getFactory().createConst(EGaml.getKeyOf(object), Types.STRING);
    }

    @Override
    public IExpression caseUnitName(final UnitName object) {
        final String s = EGaml.getKeyOf(object);
        if (IUnits.UNITS_EXPR.containsKey(s)) {
            final UnitConstantExpression exp = getFactory().getUnitExpr(s);
            if (exp.isDeprecated()) {
                getContext().warning(s + " is deprecated.", IGamlIssue.NOT_A_UNIT, object, (String[]) null);
            }
            return exp;
        }
        getContext().error(s + " is not a unit name.", IGamlIssue.NOT_A_UNIT, object, (String[]) null);
        return null;
    }

    @Override
    public IExpression caseVarDefinition(final VarDefinition object) {
        return skill(object.getName());
    }

    @Override
    public IExpression caseTypeDefinition(final TypeDefinition object) {
        return caseVar(object.getName(), object);
    }

    @Override
    public IExpression caseSkillFakeDefinition(final SkillFakeDefinition object) {
        return caseVar(object.getName(), object);
    }

    @Override
    public IExpression caseReservedLiteral(final ReservedLiteral object) {
        return caseVar(EGaml.getKeyOf(object), object);
    }

    @Override
    public IExpression caseIf(final If object) {
        final IExpression ifFalse = compile(object.getIfFalse());
        final IExpression alt = getFactory().createOperator(":", getContext(), object, compile(object.getRight()),
                ifFalse);
        return getFactory().createOperator("?", getContext(), object, compile(object.getLeft()), alt);
    }

    @Override
    public IExpression caseArgumentPair(final ArgumentPair object) {
        final IExpression result = binary("::", caseVar(EGaml.getKeyOf(object), object), object.getRight());
        return result;
    }

    @Override
    public IExpression caseUnit(final Unit object) {
        // We simply return a multiplication, since the right member (the
        // "unit") will be
        // translated into its float value

        // Case of dates: #month and #year
        final String name = EGaml.toString(object.getRight());
        if (TimeUnitConstantExpression.UNCOMPUTABLE_DURATIONS.contains(name)) {
            return binary(Dates.APPROXIMATE_TEMPORAL_QUERY, object.getLeft(), object.getRight());
        }
        // AD: Hack to address Issue 387. If the unit is a pixel, we add +1 to
        // the whole expression.
        // final IExpression right = compile(object.getRight());
        final IExpression result = binary("*", object.getLeft(), object.getRight());
        // AD: removal of the hack to address #1325 -- needs to be tested in
        // OpenGL
        // if ( result != null && ((BinaryOperator) result).arg(1) instanceof
        // PixelUnitExpression ) {
        // result = factory.createOperator("+", getContext(), object,
        // factory.createConst(1, Types.INT), result);
        // }
        return result;
    }

    @Override
    public IExpression caseUnary(final Unary object) {
        return unary(EGaml.getKeyOf(object), object.getRight());
    }

    public IExpression caseDot(final Access object) {
        final Expression right = object.getRight();
        if (right instanceof StringLiteral) {
            return compileNamedExperimentFieldExpr(object.getLeft(), EGaml.getKeyOf(right));
        } else if (right != null) {
            return compileFieldExpr(object.getLeft(), object.getRight());
        }
        return null;
    }

    @Override
    public IExpression caseAccess(final Access object) {
        if (object.getOp().equals(".")) {
            return caseDot(object);
        }
        final IExpression container = compile(object.getLeft());
        // If no container is defined, return a null expression
        if (container == null) {
            return null;
        }
        final IType contType = container.getGamlType();
        final boolean isMatrix = contType.id() == IType.MATRIX;
        final IType keyType = contType.getKeyType();
        final List<? extends Expression> list = EGaml.getExprsOf(object.getRight());
        final List<IExpression> result = new ArrayList<>();
        final int size = list.size();
        for (int i = 0; i < size; i++) {
            final Expression eExpr = list.get(i);
            final IExpression e = compile(eExpr);
            if (e != null) {
                final IType elementType = e.getGamlType();
                if (keyType != Types.NO_TYPE && !keyType.isAssignableFrom(e.getGamlType())) {
                    if (!(isMatrix && elementType.id() == IType.INT && size > 1)) {
                        getContext().warning("a " + contType.toString() + " cannot be accessed using a "
                                + elementType.toString() + " index", IGamlIssue.WRONG_TYPE, eExpr);
                    }
                }
                result.add(e);
            }
        }
        if (size > 2) {
            final String end = !isMatrix ? " only 1 index" : " 1 or 2 indices";
            getContext().warning("a " + contType.toString() + " should be accessed using" + end,
                    IGamlIssue.DIFFERENT_ARGUMENTS, object);
        }

        final IExpression indices = getFactory().createList(result);

        IVarExpression varDiff = null;
        if (container instanceof IVarExpression.Agent && ((IVarExpression.Agent) container).getOwner() != null) {
            varDiff = ((IVarExpression.Agent) container).getVar();

            final SpeciesDescription species = ((IVarExpression.Agent) varDiff).getDefinitionDescription()
                    .getSpeciesContext();
            if (species != null) {
                final Iterable<IDescription> equations = species.getChildrenWithKeyword(IKeyword.EQUATION);
                for (final IDescription equation : equations) {
                    if (equation.manipulatesVar(varDiff.getName())) {
                        return getFactory().createOperator("internal_integrated_value", getContext(), object,
                                ((IVarExpression.Agent) container).getOwner(), varDiff);
                    }

                }
            }
        }

        return getFactory().createOperator("internal_at", getContext(), object, container, indices);
    }

    @Override
    public IExpression caseArray(final Array object) {
        final List<? extends Expression> list = EGaml.getExprsOf(object.getExprs());
        final boolean allPairs = !list.isEmpty() && Iterables.all(list, each -> "::".equals(EGaml.getKeyOf(each)));
        final Iterable<IExpression> result = Iterables.transform(list, input -> compile(input));
        return allPairs ? getFactory().createMap(result) : getFactory().createList(result);
    }

    @Override
    public IExpression casePoint(final Point object) {
        final Expression z = object.getZ();
        if (z == null) {
            return binary(POINT, object.getLeft(), object.getRight());
        }
        final IExpression[] exprs = new IExpression[3];
        exprs[0] = compile(object.getLeft());
        exprs[1] = compile(object.getRight());
        exprs[2] = compile(z);
        return getFactory().createOperator(POINT, getContext(), object, exprs);
    }
    //
    // @Override
    // public IExpression caseParameters(final Parameters object) {
    // final Iterable it = Iterables.transform(EGaml.getExprsOf(object.getParams()), input -> binary("::",
    // getFactory().createConst(EGaml.getKeyOf(input.getLeft()), Types.STRING), input.getRight()));
    // return getFactory().createMap(it);
    // }

    @Override
    public IExpression caseExpressionList(final ExpressionList object) {
        final List<Expression> list = EGaml.getExprsOf(object);
        if (list.isEmpty()) {
            return null;
        }
        if (list.size() > 1) {
            getContext().warning(
                    "A sequence of expressions is not expected here. Only the first expression will be evaluated",
                    IGamlIssue.UNKNOWN_ARGUMENT, object);
        }
        final IExpression expr = compile(list.get(0));
        return expr;
    }

    @Override
    public IExpression caseFunction(final Function object) {
        final String op = EGaml.getKeyOf(object);
        IExpression result = tryCastingFunction(op, object);
        if (result != null) {
            return result;
        }
        result = tryActionCall(op, object);
        if (result != null) {
            return result;
        }
        final List<Expression> args = EGaml.getExprsOf(object.getRight());
        switch (args.size()) {
        case 0:
            getContext().error("Unknown operator or action: " + op, IGamlIssue.UNKNOWN_ACTION, object);
            return null;
        case 1:
            return unary(op, args.get(0));
        case 2:
            return binary(op, args.get(0), args.get(1));
        default:
            return getFactory().createOperator(op, getContext(), object,
                    toArray(transform(args, a -> compile(a)), IExpression.class));
        }
    }

    private IExpression tryCastingFunction(final String op, final Function object) {
        if (!isCastingFunction(op, object)) {
            return null;
        }
        final List<Expression> args = EGaml.getExprsOf(object.getRight());
        final int size = args.size();
        IExpression toCast;
        if (size == 1) {
            toCast = compile(args.get(0));
        } else {
            toCast = getFactory().createList(transform(args, a -> compile(a)));
        }
        return binaryAs(toCast, object);
    }

    private IExpression tryActionCall(final String op, final Function object) {
        final SpeciesDescription sd = getContext().getSpeciesContext();
        if (sd == null) {
            return null;
        }
        final boolean isSuper = getContext() instanceof StatementDescription
                && ((StatementDescription) getContext()).isSuperInvocation();
        final ActionDescription action = isSuper ? sd.getParent().getAction(op) : sd.getAction(op);
        if (action == null) {
            return null;
        }
        final EObject params = object.getRight();
        return action(op, caseVar(isSuper ? SUPER : SELF, object), params, action);
    }

    private boolean isCastingFunction(final String op, final Function object) {
        // If the operator is not a type name, no match
        if (!isTypeName(op)) {
            // We nevertheless emit a warning if the operator name contains parametric type information
            if (object.getType() != null) {
                getContext().warning(op
                        + " is not a type name: key and contents types are not expected and will not be evaluated",
                        IGamlIssue.UNKNOWN_ARGUMENT, object.getType());
            }
            return false;
        }
        // We look at the arguments of the operator
        final List<Expression> args = EGaml.getExprsOf(object.getRight());
        final int size = args.size();
        // If there is none, it can't be a casting
        if (size == 0) {
            return false;
        }
        // If there is one, we match
        if (size == 1) {
            return true;
        }
        // If more than one, we need to check if there are operators that match. If yes, we return false
        return !getFactory().hasOperator(op, getContext(), object,
                toArray(transform(args, a -> compile(a)), IExpression.class));
    }

    @Override
    public IExpression caseIntLiteral(final IntLiteral object) {
        try {
            final Integer val = Integer.parseInt(EGaml.getKeyOf(object), 10);
            return getFactory().createConst(val, Types.INT);
        } catch (final NumberFormatException e) {
            getContext().error("Malformed integer: " + EGaml.getKeyOf(object), IGamlIssue.UNKNOWN_NUMBER, object);
            return null;
        }
    }

    @Override
    public IExpression caseDoubleLiteral(final DoubleLiteral object) {

        String s = EGaml.getKeyOf(object);

        if (s == null) {
            return null;
        }
        try {
            return getFactory().createConst(Double.parseDouble(s), Types.FLOAT);
        } catch (final NumberFormatException e) {
            try {
                final NumberFormat nf = NumberFormat.getInstance(Locale.US);
                // More robust, but slower parsing used in case
                // Double.parseDouble() cannot handle it
                // See Issue 1025. Exponent notation is capitalized, and '+' is
                // removed beforehand
                s = s.replace('e', 'E').replace("+", "");
                return getFactory().createConst(nf.parse(s).doubleValue(), Types.FLOAT);
            } catch (final ParseException ex) {
                getContext().error("Malformed float: " + s, IGamlIssue.UNKNOWN_NUMBER, object);
                return null;
            }
        }

    }

    @Override
    public IExpression caseColorLiteral(final ColorLiteral object) {
        try {
            final Integer val = Integer.parseInt(EGaml.getKeyOf(object).substring(1), 16);
            return getFactory().createConst(val, Types.INT);
        } catch (final NumberFormatException e) {
            getContext().error("Malformed integer: " + EGaml.getKeyOf(object), IGamlIssue.UNKNOWN_NUMBER, object);
            return null;
        }
    }

    @Override
    public IExpression caseStringLiteral(final StringLiteral object) {
        return getFactory().createConst(StringUtils.unescapeJava(EGaml.getKeyOf(object)), Types.STRING);
    }

    @Override
    public IExpression caseBooleanLiteral(final BooleanLiteral object) {
        final String s = EGaml.getKeyOf(object);
        if (s == null) {
            return null;
        }
        return s.equalsIgnoreCase(TRUE) ? TRUE_EXPR : FALSE_EXPR;
    }

    @Override
    public IExpression defaultCase(final EObject object) {
        final ValidationContext vc = getValidationContext();
        if (vc != null && !vc.hasErrors()) {
            // In order to avoid too many "useless errors"
            getContext().error("Cannot compile: " + object, IGamlIssue.GENERAL, object);
        }
        return null;
    }

    private IExpression caseVar(final String varName, final EObject object) {
        if (varName == null) {
            getContext().error("Unknown variable", IGamlIssue.UNKNOWN_VAR, object);
            return null;
        }
        switch (varName) {
        case IKeyword.GAMA:
            return GAMA.getPlatformAgent();
        case EACH:
            return getEachExpr(object);
        case NULL:
            return IExpressionFactory.NIL_EXPR;
        case SELF:
            final IDescription temp_sd = getContext().getSpeciesContext();
            if (temp_sd == null) {
                getContext().error("Unable to determine the species of self", IGamlIssue.GENERAL, object);
                return null;
            }
            final IType tt = temp_sd.getGamlType();
            return getFactory().createVar(SELF, tt, true, IVarExpression.SELF, null);
        case SUPER:
            SpeciesDescription sd = getContext().getSpeciesContext();
            if (sd != null) {
                sd = sd.getParent();
            }
            if (sd == null) {
                getContext().error("Unable to determine the species of super", IGamlIssue.GENERAL, object);
                return null;
            }
            final IType t = sd.getGamlType();
            return getFactory().createVar(SUPER, t, true, IVarExpression.SUPER, null);

        // case WORLD_AGENT_NAME:
        // return getWorldExpr();
        }

        // check if the var has been declared in an iterator context
        for (final IVarExpression it : iteratorContexts) {
            if (it.getName().equals(varName)) {
                return it;
            }
        }

        if (isSpeciesName(varName)) {
            final SpeciesDescription sd = getSpeciesContext(varName);
            return sd == null ? null : sd.getSpeciesExpr();
        }
        final IVarDescriptionProvider temp_sd = getContext() == null ? null
                : getContext().getDescriptionDeclaringVar(varName);

        if (temp_sd != null) {
            if (temp_sd instanceof SpeciesDescription) {
                final SpeciesDescription remote_sd = getContext().getSpeciesContext();
                if (remote_sd != null) {
                    final SpeciesDescription found_sd = (SpeciesDescription) temp_sd;

                    if (remote_sd != temp_sd && !remote_sd.isBuiltIn() && !remote_sd.hasMacroSpecies(found_sd)) {
                        getContext().error(
                                "The variable " + varName + " is not accessible in this context ("
                                        + remote_sd.getName() + "), but in the context of " + found_sd.getName()
                                        + ". It should be preceded by 'myself.'",
                                IGamlIssue.UNKNOWN_VAR, object, varName);
                    }
                }
            }

            return temp_sd.getVarExpr(varName, false);
        }

        if (isTypeName(varName)) {
            return getFactory().createTypeExpression(currentTypesManager.get(varName));
        }

        if (isSkillName(varName)) {
            return skill(varName);
        }

        if (getContext() != null) {

            // Finally, a last possibility (enabled in rare occasions, like in
            // the "elevation" facet of grid layers), is that the variable
            // belongs to the species denoted by the
            // current statement
            if (getContext() instanceof StatementDescription) {
                final SpeciesDescription denotedSpecies = getContext().getGamlType().getDenotedSpecies();
                if (denotedSpecies != null) {
                    if (denotedSpecies.hasAttribute(varName)) {
                        return denotedSpecies.getVarExpr(varName, false);
                    }
                }
            }

            // An experimental possibility is that the variable refers to a
            // an action (used like a variable, see Issue 853) or also any
            // behavior or aspect
            final SpeciesDescription sd = getContext().getSpeciesContext();
            if (sd.hasAction(varName, false)) {
                return new DenotedActionExpression(sd.getAction(varName));
            }
            if (sd.hasBehavior(varName)) {
                return new DenotedActionExpression(sd.getBehavior(varName));
            }
            if (sd.hasAspect(varName)) {
                return new DenotedActionExpression(sd.getAspect(varName));
            }

            getContext().error(
                    "The variable " + varName
                            + " is not defined or accessible in this context. Check its name or declare it",
                    IGamlIssue.UNKNOWN_VAR, object, varName);
        }
        return null;

    }

    private EObject getEObjectOf(final String string, final IExecutionContext tempContext)
            throws GamaRuntimeException {
        EObject result = null;
        final String s = "dummy <- " + string;
        final GamlResource resource = GamlResourceServices.getTemporaryResource(getContext());
        try {
            final InputStream is = new ByteArrayInputStream(s.getBytes());
            try {
                resource.loadSynthetic(is, tempContext);
            } catch (final Exception e1) {
                e1.printStackTrace();
                return null;
            }

            if (!resource.hasErrors()) {
                final EObject e = resource.getContents().get(0);
                if (e instanceof StringEvaluator) {
                    result = ((StringEvaluator) e).getExpr();
                }
            } else {
                final Resource.Diagnostic d = resource.getErrors().get(0);
                throw GamaRuntimeException.error(d.getMessage(), tempContext.getScope());
            }

            return result;
        } finally {
            GamlResourceServices.discardTemporaryResource(resource);
        }
    }

    @Override
    public List<IDescription> compileBlock(final String string, final IDescription actionContext,
            final IExecutionContext tempContext) throws GamaRuntimeException {
        final List<IDescription> result = new ArrayList<>();
        final String s = "__synthetic__ {" + string + "}";
        final GamlResource resource = GamlResourceServices.getTemporaryResource(getContext());
        try {
            final InputStream is = new ByteArrayInputStream(s.getBytes());
            try {
                resource.loadSynthetic(is, tempContext);
            } catch (final Exception e1) {
                e1.printStackTrace();
                return null;
            } finally {
            }
            if (!resource.hasErrors()) {
                final SyntacticModelElement elt = (SyntacticModelElement) resource.getSyntacticContents();
                // We have a problem -- can be simply an empty block or an expression
                if (!elt.hasChildren()) {
                    if (elt.hasFacet(IKeyword.FUNCTION)) {
                        // Compile the expression is the best way to know if this expression is correct
                        elt.getExpressionAt(IKeyword.FUNCTION).compile(actionContext);
                    }
                }
                elt.visitChildren(e -> {
                    final IDescription desc = DescriptionFactory.create(e, actionContext, null);
                    result.add(desc);
                });

            } else {
                final Resource.Diagnostic d = resource.getErrors().get(0);
                throw GamaRuntimeException.error(d.getMessage(), tempContext.getScope());
            }
            return result;
        } finally {
            GamlResourceServices.discardTemporaryResource(resource);
        }
    }

    /**
     * Method getFacetExpression()
     * 
     * @see msi.gaml.expressions.IExpressionCompiler#getFacetExpression(msi.gaml.descriptions.IDescription,
     *      java.lang.Object)
     */
    @Override
    public EObject getFacetExpression(final IDescription context, final EObject target) {
        if (target.eContainer() instanceof Facet) {
            return target.eContainer();
        }
        return target;
    }

    //
    // end-hqnghi
    //

    public IVarExpression getEachExpr(final EObject object) {
        final IVarExpression p = iteratorContexts.peek();
        if (p == null) {
            getContext().error("'each' is not accessible in this context", IGamlIssue.UNKNOWN_VAR, object);
            return null;
        }
        return p;
    }

    private IExpressionDescription getCurrentExpressionDescription() {
        return currentExpressionDescription;
    }

    private void setCurrentExpressionDescription(final IExpressionDescription currentExpressionDescription) {
        this.currentExpressionDescription = currentExpressionDescription;
    }

    private IExpressionFactory getFactory() {
        return GAML.getExpressionFactory();
    }

    @Override
    public void dispose() {
        this.currentContext = null;
        this.currentTypesManager = null;
        this.currentExpressionDescription = null;
        this.iteratorContexts.clear();

    }

    @Override
    public IExpression caseTerminalExpression(final TerminalExpression object) {
        return null;
    }

    @Override
    public IExpression caseBinaryOperator(final BinaryOperator object) {
        return binary(object.getOp(), object.getLeft(), object.getRight());
    }

}