public static Pair<String, ? extends Function> parseFuntionDeclaration(String decl) {
    final Lexer lexer = new FilterLexer(XPathLexer.create(true),
            new FilterLexer.SetFilter(TokenSet.create(XPathTokenTypes.WHITESPACE)));
    lexer.start(decl);

    String prefix = "";
    if (lexer.getTokenType() == XPathTokenTypes.EXT_PREFIX) {
      prefix = lexer.getTokenText();
      lexer.advance();
      match(lexer, XPathTokenTypes.COL);
    }

    final String name = match(lexer, XPathTokenTypes.FUNCTION_NAME);
    match(lexer, XPathTokenTypes.LPAREN);

    final List<Parameter> parameters = new ArrayList<>();
    while (lexer.getTokenType() != XPathTokenTypes.RPAREN) {
      if (lexer.getTokenType() == XPathTokenTypes.DOTDOT) {
        lexer.advance();
        match(lexer, XPathTokenTypes.DOT);

        parameters.add(new Parameter(XPathType.ANY, Parameter.Kind.VARARG));
      } else {
        match(lexer, XPathTokenTypes.DOLLAR);
        match(lexer, XPathTokenTypes.VARIABLE_NAME);

        match(lexer, XPath2TokenTypes.AS);

        final String type = parseType(lexer);

        final XPath2SequenceType.Cardinality indicator = parseCardinality(lexer);

        parameters.add(new Parameter(mapType(type, indicator), Parameter.Kind.REQUIRED));
      }

      if (lexer.getTokenType() == XPathTokenTypes.COMMA) {
        lexer.advance();
      }
    }
    lexer.advance();

    match(lexer, XPath2TokenTypes.AS);

    final String ret = parseType(lexer);
    final XPath2SequenceType.Cardinality indicator = parseCardinality(lexer);

    final XPathType returnType = mapType(ret, indicator);

    return Pair.create(prefix, new FunctionImpl(name, returnType, parameters.toArray(new Parameter[0])));
  }
public static Pair<String, ? extends Function> parseFuntionDeclaration(String decl)