public static RecordPathSegment buildPath()

in nifi-commons/nifi-record-path/src/main/java/org/apache/nifi/record/path/paths/RecordPathCompiler.java [125:475]


    public static RecordPathSegment buildPath(final Tree tree, final RecordPathSegment parent, final boolean absolute) {
        switch (tree.getType()) {
            case ROOT_REFERENCE: {
                return new RootPath();
            }
            case CHILD_REFERENCE: {
                if (tree.getChildCount() == 0) {
                    return new RootPath();
                }

                final Tree childTree = tree.getChild(0);
                if (childTree == null) {
                    return new RootPath();
                }

                final int childTreeType = childTree.getType();
                if (childTreeType == FIELD_NAME) {
                    final String childName = childTree.getChild(0).getText();
                    return new ChildFieldPath(childName, parent, absolute);
                } else if (childTreeType == WILDCARD) {
                    return new WildcardChildPath(parent, absolute);
                } else {
                    throw new RecordPathException("Expected field name following '/' Token but found " + childTree);
                }
            }
            case ARRAY_INDEX: {
                final Tree indexListTree = tree.getChild(0);
                if (indexListTree.getType() == NUMBER_LIST) {
                    if (indexListTree.getChildCount() == 1 && indexListTree.getChild(0).getType() == NUMBER) {
                        final Tree indexTree = indexListTree.getChild(0);
                        final int index = Integer.parseInt(indexTree.getText());
                        return new ArrayIndexPath(index, parent, absolute);
                    }

                    final List<NumericRange> indexList = new ArrayList<>();

                    for (int i = 0; i < indexListTree.getChildCount(); i++) {
                        final Tree indexTree = indexListTree.getChild(i);
                        if (indexTree.getType() == NUMBER) {
                            final int index = Integer.valueOf(indexTree.getText());
                            indexList.add(new NumericRange(index, index));
                        } else if (indexTree.getType() == NUMBER_RANGE) {
                            final int min = Integer.valueOf(indexTree.getChild(0).getText());
                            final int max = Integer.valueOf(indexTree.getChild(1).getText());
                            indexList.add(new NumericRange(min, max));
                        } else {
                            throw new RecordPathException("Expected Number or Range following '[' Token but found " + indexTree);
                        }
                    }

                    return new MultiArrayIndexPath(indexList, parent, absolute);
                } else {
                    throw new RecordPathException("Expected Number or Range following '[' Token but found " + indexListTree);
                }
            }
            case MAP_KEY: {
                final Tree keyTree = tree.getChild(0);
                if (keyTree.getType() == STRING_LIST) {
                    if (keyTree.getChildCount() == 1) {
                        return new SingularMapKeyPath(keyTree.getChild(0).getText(), parent, absolute);
                    }

                    final List<String> keys = new ArrayList<>(keyTree.getChildCount());
                    for (int i = 0; i < keyTree.getChildCount(); i++) {
                        keys.add(keyTree.getChild(i).getText());
                    }

                    return new MultiMapKeyPath(keys, parent, absolute);
                } else {
                    throw new RecordPathException("Expected Map Key following '[' Token but found " + keyTree);
                }
            }
            case WILDCARD: {
                return new WildcardIndexPath(parent, absolute);
            }
            case DESCENDANT_REFERENCE: {
                final Tree childTree = tree.getChild(0);
                final int childTreeType = childTree.getType();
                if (childTreeType == FIELD_NAME) {
                    final String descendantName = childTree.getChild(0).getText();
                    return new DescendantFieldPath(descendantName, parent, absolute);
                } else if (childTreeType == WILDCARD) {
                    return new WildcardDescendantPath(parent, absolute);
                } else {
                    throw new RecordPathException("Expected field name following '//' Token but found " + childTree);
                }
            }
            case PARENT_REFERENCE: {
                return new ParentPath(parent, absolute);
            }
            case CURRENT_FIELD: {
                return new CurrentFieldPath(parent, absolute);
            }
            case STRING_LITERAL: {
                return new LiteralValuePath(parent, tree.getText(), absolute);
            }
            case NUMBER: {
                return new LiteralValuePath(parent, Integer.parseInt(tree.getText()), absolute);
            }
            case PREDICATE: {
                final Tree operatorTree = tree.getChild(0);
                final RecordPathFilter filter = createFilter(operatorTree, parent, absolute);
                return new PredicatePath(parent, filter, absolute);
            }
            case RELATIVE_PATH: {
                return compile(tree, parent, absolute);
            }
            case PATH: {
                return compile(tree, new RootPath(), absolute);
            }
            case FUNCTION: {
                final String functionName = tree.getChild(0).getText();
                final Tree argumentListTree = tree.getChild(1);

                switch (functionName) {
                    case "substring": {
                        final RecordPathSegment[] args = getArgPaths(argumentListTree, 3, functionName, absolute);
                        return new Substring(args[0], args[1], args[2], absolute);
                    }
                    case "substringAfter": {
                        final RecordPathSegment[] args = getArgPaths(argumentListTree, 2, functionName, absolute);
                        return new SubstringAfter(args[0], args[1], absolute);
                    }
                    case "substringAfterLast": {
                        final RecordPathSegment[] args = getArgPaths(argumentListTree, 2, functionName, absolute);
                        return new SubstringAfterLast(args[0], args[1], absolute);
                    }
                    case "substringBefore": {
                        final RecordPathSegment[] args = getArgPaths(argumentListTree, 2, functionName, absolute);
                        return new SubstringBefore(args[0], args[1], absolute);
                    }
                    case "substringBeforeLast": {
                        final RecordPathSegment[] args = getArgPaths(argumentListTree, 2, functionName, absolute);
                        return new SubstringBeforeLast(args[0], args[1], absolute);
                    }
                    case "replace": {
                        final RecordPathSegment[] args = getArgPaths(argumentListTree, 3, functionName, absolute);
                        return new Replace(args[0], args[1], args[2], absolute);
                    }
                    case "replaceRegex": {
                        final RecordPathSegment[] args = getArgPaths(argumentListTree, 3, functionName, absolute);
                        return new ReplaceRegex(args[0], args[1], args[2], absolute);
                    }
                    case "replaceNull": {
                        final RecordPathSegment[] args = getArgPaths(argumentListTree, 2, functionName, absolute);
                        return new ReplaceNull(args[0], args[1], absolute);
                    }
                    case "concat": {
                        final int numArgs = argumentListTree.getChildCount();

                        final RecordPathSegment[] argPaths = new RecordPathSegment[numArgs];
                        for (int i = 0; i < numArgs; i++) {
                            argPaths[i] = buildPath(argumentListTree.getChild(i), null, absolute);
                        }

                        return new Concat(argPaths, absolute);
                    }
                    case "arrayOf": {
                        final int numArgs = argumentListTree.getChildCount();

                        final RecordPathSegment[] argPaths = new RecordPathSegment[numArgs];
                        for (int i = 0; i < numArgs; i++) {
                            argPaths[i] = buildPath(argumentListTree.getChild(i), null, absolute);
                        }

                        return new ArrayOf(argPaths, absolute);
                    }
                    case "mapOf": {
                        final int numArgs = argumentListTree.getChildCount();

                        if (numArgs % 2 != 0) {
                            throw new RecordPathException("The mapOf function requires an even number of arguments");
                        }

                        final RecordPathSegment[] argPaths = new RecordPathSegment[numArgs];
                        for (int i = 0; i < numArgs; i++) {
                            argPaths[i] = buildPath(argumentListTree.getChild(i), null, absolute);
                        }

                        return new MapOf(argPaths, absolute);
                    }
                    case "recordOf": {
                        final int numArgs = argumentListTree.getChildCount();

                        if (numArgs % 2 != 0) {
                            throw new RecordPathException("The recordOf function requires an even number of arguments");
                        }

                        final RecordPathSegment[] argPaths = new RecordPathSegment[numArgs];
                        for (int i = 0; i < numArgs; i++) {
                            argPaths[i] = buildPath(argumentListTree.getChild(i), null, absolute);
                        }

                        return new RecordOf(argPaths, absolute);
                    }
                    case "toLowerCase": {
                        final RecordPathSegment[] args = getArgPaths(argumentListTree, 1, functionName, absolute);
                        return new ToLowerCase(args[0], absolute);
                    }
                    case "toUpperCase": {
                        final RecordPathSegment[] args = getArgPaths(argumentListTree, 1, functionName, absolute);
                        return new ToUpperCase(args[0], absolute);
                    }
                    case "trim": {
                        final RecordPathSegment[] args = getArgPaths(argumentListTree, 1, functionName, absolute);
                        return new TrimString(args[0], absolute);
                    }
                    case "fieldName": {
                        final RecordPathSegment[] args = getArgPaths(argumentListTree, 1, functionName, absolute);
                        return new FieldName(args[0], absolute);
                    }
                    case "toDate": {
                        final int numArgs = argumentListTree.getChildCount();

                        if (numArgs == 2) {
                            final RecordPathSegment[] args = getArgPaths(argumentListTree, 2, functionName, absolute);
                            return new ToDate(args[0], args[1], absolute);
                        } else {
                            final RecordPathSegment[] args = getArgPaths(argumentListTree, 3, functionName, absolute);
                            return new ToDate(args[0], args[1], args[2], absolute);
                        }
                    }
                    case "toString": {
                        final RecordPathSegment[] args = getArgPaths(argumentListTree, 2, functionName, absolute);
                        return new ToString(args[0], args[1], absolute);
                    }
                    case "toBytes": {
                        final RecordPathSegment[] args = getArgPaths(argumentListTree, 2, functionName, absolute);
                        return new ToBytes(args[0], args[1], absolute);
                    }
                    case "format": {
                        final int numArgs = argumentListTree.getChildCount();

                        if (numArgs == 2) {
                            final RecordPathSegment[] args = getArgPaths(argumentListTree, 2, functionName, absolute);
                            return new Format(args[0], args[1], absolute);
                        } else {
                            final RecordPathSegment[] args = getArgPaths(argumentListTree, 3, functionName, absolute);
                            return new Format(args[0], args[1], args[2], absolute);
                        }
                    }
                    case "base64Encode": {
                        final RecordPathSegment[] args = getArgPaths(argumentListTree, 1, functionName, absolute);
                        return new Base64Encode(args[0], absolute);
                    }
                    case "base64Decode": {
                        final RecordPathSegment[] args = getArgPaths(argumentListTree, 1, functionName, absolute);
                        return new Base64Decode(args[0], absolute);
                    }
                    case "escapeJson": {
                        final RecordPathSegment[] args = getArgPaths(argumentListTree, 1, functionName, absolute);
                        return new EscapeJson(args[0], absolute);
                    }
                    case "unescapeJson": {
                        final int numArgs = argumentListTree.getChildCount();

                        final RecordPathSegment[] args = getArgPaths(argumentListTree, numArgs, functionName, absolute);
                        final RecordPathSegment convertToRecord = numArgs > 1 ? args[1] : null;
                        final RecordPathSegment recursiveConversion = numArgs > 2 ? args[2] : null;

                        return new UnescapeJson(args[0], convertToRecord, recursiveConversion, absolute);
                    }
                    case "hash": {
                        final RecordPathSegment[] args = getArgPaths(argumentListTree, 2, functionName, absolute);
                        return new Hash(args[0], args[1], absolute);
                    }
                    case "padLeft": {
                        final int numArgs = argumentListTree.getChildCount();

                        if (numArgs == 2) {
                            final RecordPathSegment[] args = getArgPaths(argumentListTree, 2, functionName, absolute);
                            return new PadLeft(args[0], args[1], absolute);
                        } else {
                            final RecordPathSegment[] args = getArgPaths(argumentListTree, 3, functionName, absolute);
                            return new PadLeft(args[0], args[1], args[2], absolute);
                        }
                    }
                    case "padRight": {
                        final int numArgs = argumentListTree.getChildCount();

                        if (numArgs == 2) {
                            final RecordPathSegment[] args = getArgPaths(argumentListTree, 2, functionName, absolute);
                            return new PadRight(args[0], args[1], absolute);
                        } else {
                            final RecordPathSegment[] args = getArgPaths(argumentListTree, 3, functionName, absolute);
                            return new PadRight(args[0], args[1], args[2], absolute);
                        }
                    }
                    case "uuid5": {
                        final int numArgs = argumentListTree.getChildCount();
                        if (numArgs == 2) {
                            final RecordPathSegment[] args = getArgPaths(argumentListTree, 2, functionName, absolute);
                            return new UUID5(args[0], args[1], absolute);
                        } else {
                            final RecordPathSegment[] args = getArgPaths(argumentListTree, 1, functionName, absolute);
                            return new UUID5(args[0], null, absolute);
                        }
                    }
                    case "coalesce": {
                        final int numArgs = argumentListTree.getChildCount();

                        final RecordPathSegment[] argPaths = new RecordPathSegment[numArgs];
                        for (int i = 0; i < numArgs; i++) {
                            argPaths[i] = buildPath(argumentListTree.getChild(i), null, absolute);
                        }

                        return new Coalesce(argPaths, absolute);
                    }
                    case "count": {
                        final RecordPathSegment[] args = getArgPaths(argumentListTree, 1, functionName, absolute);
                        return new Count(args[0], absolute);
                    }
                    case "join": {
                        final int numArgs = argumentListTree.getChildCount();
                        if (numArgs < 2) {
                            throw new RecordPathException("Invalid number of arguments: " + functionName + " function takes 2 or more arguments but got " + numArgs);
                        }

                        final RecordPathSegment[] joinPaths = new RecordPathSegment[numArgs - 1];
                        for (int i = 0; i < numArgs - 1; i++) {
                            joinPaths[i] = buildPath(argumentListTree.getChild(i + 1), null, absolute);
                        }

                        final RecordPathSegment delimiterPath = buildPath(argumentListTree.getChild(0), null, absolute);
                        return new Join(delimiterPath, joinPaths, absolute);
                    }
                    case "anchored": {
                        final RecordPathSegment[] args = getArgPaths(argumentListTree, 2, functionName, absolute);
                        return new Anchored(args[0], args[1], absolute);
                    }
                    case "not":
                    case "contains":
                    case "containsRegex":
                    case "endsWith":
                    case "startsWith":
                    case "isBlank":
                    case "isEmpty":
                    case "matchesRegex": {
                        final RecordPathFilter filter = createFilter(tree, null, absolute);
                        return new FilterFunction(functionName, filter, absolute);
                    }
                    default: {
                        throw new RecordPathException("Invalid function call: The '" + functionName + "' function does not exist or can only "
                            + "be used within a predicate, not as a standalone function");
                    }
                }
            }
        }

        throw new RecordPathException("Encountered unexpected token " + tree);
    }