class SubscriptObjectFunction extends Scalar<Object, Map<String, Object>> {

    public static final String NAME = "subscript_obj";

    public static final Signature SIGNATURE = Signature
        .scalar(
            NAME,
            DataTypes.UNTYPED_OBJECT.getTypeSignature(),
            DataTypes.STRING.getTypeSignature(),
            DataTypes.UNDEFINED.getTypeSignature())
        .withVariableArity();

    public static void register(Functions.Builder module) {
        module.add(
            SIGNATURE,
            SubscriptObjectFunction::new
        );
    }

    private SubscriptObjectFunction(Signature signature, BoundSignature boundSignature) {
        super(signature, boundSignature);
    }

    @Override
    public Symbol normalizeSymbol(Function func, TransactionContext txnCtx, NodeContext nodeCtx) {
        Symbol result = evaluateIfLiterals(this, txnCtx, nodeCtx, func);
        if (result instanceof Literal) {
            return result;
        }
        return tryToInferReturnTypeFromObjectTypeAndArguments(func);
    }

    static Symbol tryToInferReturnTypeFromObjectTypeAndArguments(Function func) {
        if (!func.valueType().equals(DataTypes.UNDEFINED)) {
            return func;
        }
        var arguments = func.arguments();
        ObjectType objectType = (ObjectType) arguments.get(0).valueType();
        List<String> path = maybeCreatePath(arguments);
        if (path == null) {
            return func;
        } else {
            DataType<?> returnType = objectType.resolveInnerType(path);
            return returnType.equals(DataTypes.UNDEFINED)
                ? func
                : new Function(
                    func.signature(),
                    func.arguments(),
                    returnType
            );
        }
    }

    @Nullable
    private static List<String> maybeCreatePath(List<Symbol> arguments) {
        List<String> path = null;
        for (int i = 1; i < arguments.size(); i++) {
            Symbol arg = arguments.get(i);
            if (arg instanceof Literal) {
                if (path == null) {
                    path = new ArrayList<>();
                }
                path.add(DataTypes.STRING.sanitizeValue(((Literal<?>) arg).value()));
            } else {
                return null;
            }
        }
        return path;
    }

    @Override
    @SafeVarargs
    public final Object evaluate(TransactionContext txnCtx, NodeContext ndeCtx, Input<Map<String, Object>>... args) {<FILL_FUNCTION_BODY>}
}

        assert args.length >= 2 : NAME + " takes 2 or more arguments, got " + args.length;
        Object mapValue = args[0].value();
        for (var i = 1; i < args.length; i++) {
            if (mapValue == null) {
                return null;
            }
            mapValue = SubscriptFunction.lookupByName(
                boundSignature.argTypes(),
                mapValue,
                args[i].value(),
                txnCtx.sessionSettings().errorOnUnknownObjectKey()
            );
        }
        return mapValue;
    
<methods>public BoundSignature boundSignature() ,public Scalar<java.lang.Object,Map<java.lang.String,java.lang.Object>> compile(List<io.crate.expression.symbol.Symbol>, java.lang.String, io.crate.role.Roles) ,public transient abstract java.lang.Object evaluate(io.crate.metadata.TransactionContext, io.crate.metadata.NodeContext, Input<Map<java.lang.String,java.lang.Object>>[]) ,public io.crate.expression.symbol.Symbol normalizeSymbol(io.crate.expression.symbol.Function, io.crate.metadata.TransactionContext, io.crate.metadata.NodeContext) ,public io.crate.metadata.functions.Signature signature() <variables>public static final Set<io.crate.metadata.Scalar.Feature> DETERMINISTIC_AND_COMPARISON_REPLACEMENT,public static final Set<io.crate.metadata.Scalar.Feature> DETERMINISTIC_ONLY,public static final Set<io.crate.metadata.Scalar.Feature> NO_FEATURES,protected final non-sealed BoundSignature boundSignature,protected final non-sealed io.crate.metadata.functions.Signature signature