private int evalFunctions(List<Token> formula, int offset, int length) {
        for (int i = offset + length - 2; i >= offset; i--) {
            for (Function function : Tokens.function(formula.get(i))) {
                if (i == offset ||
                        (!(formula.get(i - 1) instanceof NumberToken) &&
                                !(formula.get(i - 1) instanceof ArgumentToken))) {
                    Token arguments = formula.get(i + 1);
                    BigDecimal[] values = null;
                    for (ArgumentToken argument : Tokens.argument(arguments)) {
                        values = argument.getArguments();
                    }
                    for (NumberToken numberToken : Tokens.number(arguments)) {
                        values = new BigDecimal[]{numberToken.getNumber()};
                    }
                    if (values == null) {
                        throw new ParseException("Missing arguments for " + function + ", found: " + arguments);
                    }

                    if (!function.hasArity(values.length)) {
                        throw new ParseException("Wrong number of arguments for " + function + ", found: " +
                                values.length);
                    }

                    formula.remove(i + 1);
                    formula.set(i, new NumberToken(function.calculate(values)));
                    length--;
                }
            }
        }
        return length;
    }