@Override
 public final short getResultType() {
   FunctionsDefinitions def = FunctionsDefinitions.getInstance();
   Function function = def.getFunction(key);
   if (function == null) {
     return Expression.TYPE_UNDEF;
   } else {
     Method method = function.getMethod();
     if (method.getReturnType() == Integer.TYPE) {
       return Expression.TYPE_INTEGER;
     } else if (method.getReturnType() == Short.TYPE) {
       return Expression.TYPE_INTEGER;
     } else if (method.getReturnType() == Double.TYPE) {
       return Expression.TYPE_FLOAT;
     } else if (method.getReturnType() == Float.TYPE) {
       return Expression.TYPE_FLOAT;
     } else if (method.getReturnType() == String.class) {
       return Expression.TYPE_NUMERIC;
     } else {
       return Expression.TYPE_UNDEF;
     }
   }
 }
 @Override
 public final Object eval() throws ArithmeticException {
   FunctionsDefinitions def = FunctionsDefinitions.getInstance();
   Function function = def.getFunction(key);
   if (function == null) {
     throw new ArithmeticException(
         "Function " + key.getName() + "( " + key.getParamsSize() + " parameters) does not exist");
   } else {
     Method method = function.getMethod();
     if (fields == null) {
       initFieldsArray(function, method);
     }
     Object obj = function.getObject();
     if (varargs) {
       Class clazz = method.getParameterTypes()[fields.length - 1];
       Class ctype = getVarargType(clazz);
       if (ctype == Integer.TYPE) {
         fillIntField(fields);
       } else if (ctype == Float.TYPE) {
         fillFloatField(fields);
       } else {
         fillObjectField(fields);
       }
     } else {
       for (int i = 0; i < exprs.size(); i++) {
         Expression expr = exprs.get(i);
         Object _f = null;
         if (expr.getResultType() == TYPE_INTEGER) {
           _f = getField(expr.evalAsInt(), method.getParameterTypes()[i]);
         } else if (expr.getResultType() == TYPE_FLOAT) {
           _f = getField(expr.evalAsFloat(), method.getParameterTypes()[i]);
         } else if (expr.getResultType() == TYPE_BOOL) {
           _f = getField(expr.evalAsBoolean(), method.getParameterTypes()[i]);
         } else {
           _f = getField(expr.eval(), method.getParameterTypes()[i]);
         }
         fields[i] = _f;
       }
     }
     try {
       Object result = null;
       if (varargs) {
         result = method.invoke(obj, fields);
       } else {
         result = method.invoke(obj, fields);
       }
       if (method.getReturnType() == Integer.TYPE) {
         return result;
       } else if (method.getReturnType() == Short.TYPE) {
         return ((Short) result).intValue();
       } else if (method.getReturnType() == Double.TYPE) {
         return ((Double) result).floatValue();
       } else if (method.getReturnType() == Float.TYPE) {
         Float f = (Float) result;
         if (f.isInfinite()) {
           throw newArithmeticException(function);
         }
         return f;
       } else if (method.getReturnType() == Boolean.TYPE) {
         return ((Boolean) result).booleanValue();
       } else {
         return result;
       }
     } catch (IllegalAccessException ex) {
       ArithmeticException e =
           new ArithmeticException("IllegalAccessException for function " + function.getName());
       throw e;
     } catch (IllegalArgumentException ex) {
       ArithmeticException e =
           new ArithmeticException("Illegal argument for function " + function.getName());
       throw e;
     } catch (InvocationTargetException ex) {
       Throwable _ex = ex.getCause();
       String message = null;
       if (_ex != null) {
         message = "Exception in function " + function.getName() + " (" + _ex.getMessage() + ")";
       } else {
         message = "Exception in function " + function.getName();
       }
       ArithmeticException e = new ArithmeticException(message);
       e.initCause(_ex);
       e.setStackTrace(_ex.getStackTrace());
       throw e;
     }
   }
 }