private String parseValueTokens(final List<AbstractToken> tokens) {
            if (tokens.isEmpty()) {
                return "";
            }

            boolean dateExpression = false;
            boolean numericExpression = false;
            final StringBuilder sb = new StringBuilder();
            for (final AbstractToken token : tokens) {
                if (TokenType.FUNCTION_GROUP.equals(token.getTokenType())) {
                    final FunctionGroup functionGroup = (FunctionGroup) token;
                    DatePoint foundFunction = null;
                    if (functionGroup.getName().equalsIgnoreCase("param")) {
                        return resolveParam(functionGroup);

                    } else {
                        final String function = token.getUnescapedText();
                        for (final DatePoint datePoint : DatePoint.values()) {
                            if (datePoint.getFunction().equals(function)) {
                                foundFunction = datePoint;
                                break;
                            }
                        }
                        if (foundFunction == null) {
                            throw new TokenException(token, "Unexpected function in value");
                        } else {
                            dateExpression = true;
                        }
                    }
                } else if (TokenType.DURATION.equals(token.getTokenType())) {
                    dateExpression = true;
                } else if (TokenType.NUMBER.equals(token.getTokenType())) {
                    numericExpression = true;
                }

                sb.append(token.getUnescapedText());
            }

            final String expression = sb.toString();
            if (dateExpression) {
                DateExpressionParser.parse(tokens, expressionContext.getDateTimeSettings());

            } else if (numericExpression) {
                boolean seenSign = false;
                boolean seenNumber = false;
                for (final AbstractToken token : tokens) {
                    if (TokenType.PLUS.equals(token.getTokenType()) ||
                        TokenType.MINUS.equals(token.getTokenType())) {
                        if (seenSign || seenNumber) {
                            throw new TokenException(token, "Unexpected token");
                        }
                        seenSign = true;
                    } else if (TokenType.NUMBER.equals(token.getTokenType())) {
                        if (seenNumber) {
                            throw new TokenException(token, "Unexpected token");
                        }
                        seenNumber = true;
                    } else {
                        throw new TokenException(token, "Unexpected token");
                    }
                }
            } else if (tokens.size() > 1) {
                throw new TokenException(tokens.get(1), "Unexpected token");
            }

            return expression;
        }
@param isLenient Ignores any additional child tokens found. This is to support getting just
                 the data source from a partially written query, which is likely to not be
                 a valid query. For example, you may type
                 <pre>{@code from View sel}</pre> and at this point do code completion on 'sel'
                 so if this method is called it will treat 'sel as an extra child.
stroom-query/stroom-query-common/src/main/java/stroom/query/language/SearchRequestFactory.java