public void visitBrace()

in modules/lang-painless/src/main/java/org/elasticsearch/painless/phase/DefaultSemanticAnalysisPhase.java [3039:3190]


    public void visitBrace(EBrace userBraceNode, SemanticScope semanticScope) {
        boolean read = semanticScope.getCondition(userBraceNode, Read.class);
        boolean write = semanticScope.getCondition(userBraceNode, Write.class);

        if (read == false && write == false) {
            throw userBraceNode.createError(new IllegalArgumentException("not a statement: result of brace operator not used"));
        }

        AExpression userPrefixNode = userBraceNode.getPrefixNode();
        semanticScope.setCondition(userPrefixNode, Read.class);
        checkedVisit(userPrefixNode, semanticScope);
        Class<?> prefixValueType = semanticScope.getDecoration(userPrefixNode, ValueType.class).valueType();

        AExpression userIndexNode = userBraceNode.getIndexNode();
        Class<?> valueType;

        if (prefixValueType.isArray()) {
            semanticScope.setCondition(userIndexNode, Read.class);
            semanticScope.putDecoration(userIndexNode, new TargetType(int.class));
            checkedVisit(userIndexNode, semanticScope);
            decorateWithCast(userIndexNode, semanticScope);
            valueType = prefixValueType.getComponentType();
        } else if (prefixValueType == def.class) {
            semanticScope.setCondition(userIndexNode, Read.class);
            checkedVisit(userIndexNode, semanticScope);
            TargetType targetType = semanticScope.getDecoration(userBraceNode, TargetType.class);
            // TODO: remove ZonedDateTime exception when JodaCompatibleDateTime is removed
            valueType = targetType == null
                || targetType.targetType() == ZonedDateTime.class
                || semanticScope.getCondition(userBraceNode, Explicit.class) ? def.class : targetType.targetType();

            if (write) {
                semanticScope.setCondition(userBraceNode, DefOptimized.class);
            }
        } else if (Map.class.isAssignableFrom(prefixValueType)) {
            String canonicalClassName = PainlessLookupUtility.typeToCanonicalTypeName(prefixValueType);

            PainlessMethod getter = semanticScope.getScriptScope()
                .getPainlessLookup()
                .lookupPainlessMethod(prefixValueType, false, "get", 1);
            PainlessMethod setter = semanticScope.getScriptScope()
                .getPainlessLookup()
                .lookupPainlessMethod(prefixValueType, false, "put", 2);

            if (getter != null && (getter.returnType() == void.class || getter.typeParameters().size() != 1)) {
                throw userBraceNode.createError(
                    new IllegalArgumentException("Illegal map get shortcut for type [" + canonicalClassName + "].")
                );
            }

            if (setter != null && setter.typeParameters().size() != 2) {
                throw userBraceNode.createError(
                    new IllegalArgumentException("Illegal map set shortcut for type [" + canonicalClassName + "].")
                );
            }

            if (getter != null
                && setter != null
                && (getter.typeParameters().get(0).equals(setter.typeParameters().get(0)) == false
                    || getter.returnType().equals(setter.typeParameters().get(1)) == false)) {
                throw userBraceNode.createError(new IllegalArgumentException("Shortcut argument types must match."));
            }

            if ((read == false || getter != null) && (write == false || setter != null)) {
                semanticScope.setCondition(userIndexNode, Read.class);
                semanticScope.putDecoration(
                    userIndexNode,
                    new TargetType(setter != null ? setter.typeParameters().get(0) : getter.typeParameters().get(0))
                );
                checkedVisit(userIndexNode, semanticScope);
                decorateWithCast(userIndexNode, semanticScope);

                valueType = setter != null ? setter.typeParameters().get(1) : getter.returnType();

                if (getter != null) {
                    semanticScope.putDecoration(userBraceNode, new GetterPainlessMethod(getter));
                }

                if (setter != null) {
                    semanticScope.putDecoration(userBraceNode, new SetterPainlessMethod(setter));
                }
            } else {
                throw userBraceNode.createError(
                    new IllegalArgumentException("Illegal map shortcut for type [" + canonicalClassName + "].")
                );
            }

            semanticScope.setCondition(userBraceNode, MapShortcut.class);
        } else if (List.class.isAssignableFrom(prefixValueType)) {
            String canonicalClassName = PainlessLookupUtility.typeToCanonicalTypeName(prefixValueType);

            PainlessMethod getter = semanticScope.getScriptScope()
                .getPainlessLookup()
                .lookupPainlessMethod(prefixValueType, false, "get", 1);
            PainlessMethod setter = semanticScope.getScriptScope()
                .getPainlessLookup()
                .lookupPainlessMethod(prefixValueType, false, "set", 2);

            if (getter != null
                && (getter.returnType() == void.class
                    || getter.typeParameters().size() != 1
                    || getter.typeParameters().get(0) != int.class)) {
                throw userBraceNode.createError(
                    new IllegalArgumentException("Illegal list get shortcut for type [" + canonicalClassName + "].")
                );
            }

            if (setter != null && (setter.typeParameters().size() != 2 || setter.typeParameters().get(0) != int.class)) {
                throw userBraceNode.createError(
                    new IllegalArgumentException("Illegal list set shortcut for type [" + canonicalClassName + "].")
                );
            }

            if (getter != null
                && setter != null
                && (getter.typeParameters().get(0).equals(setter.typeParameters().get(0)) == false
                    || getter.returnType().equals(setter.typeParameters().get(1)) == false)) {
                throw userBraceNode.createError(new IllegalArgumentException("Shortcut argument types must match."));
            }

            if ((read == false || getter != null) && (write == false || setter != null)) {
                semanticScope.setCondition(userIndexNode, Read.class);
                semanticScope.putDecoration(userIndexNode, new TargetType(int.class));
                checkedVisit(userIndexNode, semanticScope);
                decorateWithCast(userIndexNode, semanticScope);

                valueType = setter != null ? setter.typeParameters().get(1) : getter.returnType();

                if (getter != null) {
                    semanticScope.putDecoration(userBraceNode, new GetterPainlessMethod(getter));
                }

                if (setter != null) {
                    semanticScope.putDecoration(userBraceNode, new SetterPainlessMethod(setter));
                }
            } else {
                throw userBraceNode.createError(
                    new IllegalArgumentException("Illegal list shortcut for type [" + canonicalClassName + "].")
                );
            }

            semanticScope.setCondition(userBraceNode, ListShortcut.class);
        } else {
            throw userBraceNode.createError(
                new IllegalArgumentException(
                    "Illegal array access on type " + "[" + PainlessLookupUtility.typeToCanonicalTypeName(prefixValueType) + "]."
                )
            );
        }

        semanticScope.putDecoration(userBraceNode, new ValueType(valueType));
    }