BracketExpr.java revision af146d6a8c0efcf5682d14047c06866a5548f78f
1f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross/*
2f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross * Copyright (C) 2015 The Android Open Source Project
3f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross *
4f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross * Licensed under the Apache License, Version 2.0 (the "License");
5f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross * you may not use this file except in compliance with the License.
6f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross * You may obtain a copy of the License at
7f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross *
8f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross *      http://www.apache.org/licenses/LICENSE-2.0
9f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross *
10f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross * Unless required by applicable law or agreed to in writing, software
11f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross * distributed under the License is distributed on an "AS IS" BASIS,
12f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross * See the License for the specific language governing permissions and
14f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross * limitations under the License.
15f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross */
16f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross
17f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Crosspackage android.databinding.tool.expr;
18f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross
19f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Crossimport android.databinding.tool.reflection.ModelAnalyzer;
20f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Crossimport android.databinding.tool.reflection.ModelClass;
21f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Crossimport android.databinding.tool.writer.KCode;
22f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross
23f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Crossimport java.util.List;
24f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross
25f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Crosspublic class BracketExpr extends Expr {
26f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross
27f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross    public enum BracketAccessor {
28f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross        ARRAY,
29f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross        LIST,
30f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross        MAP,
31f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross    }
32f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross
33f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross    private BracketAccessor mAccessor;
34e7b6cf13f94f66ea446c95ab34040b0a577e43dcJohn Michelau
35f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross    BracketExpr(Expr target, Expr arg) {
36bf7f49238d0af497d4300f7e611cf831854d6434Jeff Brown        super(target, arg);
37f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross    }
38f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross
39f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross    @Override
40f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross    protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) {
41957983787d7a753d34b582ae0165160f4ebf815cRobert Craig        ModelClass targetType = getTarget().getResolvedType();
42957983787d7a753d34b582ae0165160f4ebf815cRobert Craig        if (targetType.isArray()) {
43f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross            mAccessor = BracketAccessor.ARRAY;
44f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross        } else if (targetType.isList()) {
451dc94e315680b47fe430ef90f46c50a25c92fb6dJeff Brown            mAccessor = BracketAccessor.LIST;
461dc94e315680b47fe430ef90f46c50a25c92fb6dJeff Brown        } else if (targetType.isMap()) {
47bf7f49238d0af497d4300f7e611cf831854d6434Jeff Brown            mAccessor = BracketAccessor.MAP;
48bf7f49238d0af497d4300f7e611cf831854d6434Jeff Brown        } else {
491fc4f80fc38f782f128102795481924a97a2d3c5James Dong            throw new IllegalArgumentException("Cannot determine variable type used in [] " +
50bf7f49238d0af497d4300f7e611cf831854d6434Jeff Brown                    "expression. Cast the value to List, Map, " +
51bf7f49238d0af497d4300f7e611cf831854d6434Jeff Brown                    "or array. Type detected: " + targetType.toJavaCode());
52bf7f49238d0af497d4300f7e611cf831854d6434Jeff Brown        }
53d907b32052aca02ad679e6ae786848d328723080keunyoung        return targetType.getComponentType();
54bf7f49238d0af497d4300f7e611cf831854d6434Jeff Brown    }
55bf7f49238d0af497d4300f7e611cf831854d6434Jeff Brown
56bf7f49238d0af497d4300f7e611cf831854d6434Jeff Brown    @Override
5754bcc5ffd5a79f4f194089c58d3de571532bf39bChristopher Ferris    protected List<Dependency> constructDependencies() {
5854bcc5ffd5a79f4f194089c58d3de571532bf39bChristopher Ferris        final List<Dependency> dependencies = constructDynamicChildrenDependencies();
5954bcc5ffd5a79f4f194089c58d3de571532bf39bChristopher Ferris        for (Dependency dependency : dependencies) {
6054bcc5ffd5a79f4f194089c58d3de571532bf39bChristopher Ferris            if (dependency.getOther() == getTarget()) {
6154bcc5ffd5a79f4f194089c58d3de571532bf39bChristopher Ferris                dependency.setMandatory(true);
6254bcc5ffd5a79f4f194089c58d3de571532bf39bChristopher Ferris            }
635ecd4beef8f10f91febf916414c65d3d0e1cf734John Spurlock        }
6493d705b6d742e8f00167ff2384e35c2205a6f9daFelipe Leme        return dependencies;
655ecd4beef8f10f91febf916414c65d3d0e1cf734John Spurlock    }
665ecd4beef8f10f91febf916414c65d3d0e1cf734John Spurlock
675ecd4beef8f10f91febf916414c65d3d0e1cf734John Spurlock    protected String computeUniqueKey() {
685ecd4beef8f10f91febf916414c65d3d0e1cf734John Spurlock        final String targetKey = getTarget().computeUniqueKey();
695ecd4beef8f10f91febf916414c65d3d0e1cf734John Spurlock        return addTwoWay(join(targetKey, "$", getArg().computeUniqueKey(), "$"));
705ecd4beef8f10f91febf916414c65d3d0e1cf734John Spurlock    }
715ecd4beef8f10f91febf916414c65d3d0e1cf734John Spurlock
725ecd4beef8f10f91febf916414c65d3d0e1cf734John Spurlock    @Override
735ecd4beef8f10f91febf916414c65d3d0e1cf734John Spurlock    public String getInvertibleError() {
745ecd4beef8f10f91febf916414c65d3d0e1cf734John Spurlock        return null;
755ecd4beef8f10f91febf916414c65d3d0e1cf734John Spurlock    }
765ecd4beef8f10f91febf916414c65d3d0e1cf734John Spurlock
775ecd4beef8f10f91febf916414c65d3d0e1cf734John Spurlock    public Expr getTarget() {
785ecd4beef8f10f91febf916414c65d3d0e1cf734John Spurlock        return getChildren().get(0);
795ecd4beef8f10f91febf916414c65d3d0e1cf734John Spurlock    }
805ecd4beef8f10f91febf916414c65d3d0e1cf734John Spurlock
815ecd4beef8f10f91febf916414c65d3d0e1cf734John Spurlock    public Expr getArg() {
825ecd4beef8f10f91febf916414c65d3d0e1cf734John Spurlock        return getChildren().get(1);
835ecd4beef8f10f91febf916414c65d3d0e1cf734John Spurlock    }
845ecd4beef8f10f91febf916414c65d3d0e1cf734John Spurlock
855ecd4beef8f10f91febf916414c65d3d0e1cf734John Spurlock    public BracketAccessor getAccessor() {
865ecd4beef8f10f91febf916414c65d3d0e1cf734John Spurlock        return mAccessor;
870c22e8b31651caf12a2b4d4acef5bc65d486e570Colin Cross    }
88f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross
89f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross    public boolean argCastsInteger() {
90f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross        return mAccessor != BracketAccessor.MAP && getArg().getResolvedType().isObject();
91f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross    }
92f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross
93f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross    @Override
94f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross    protected KCode generateCode(boolean expand) {
95f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross        String cast = argCastsInteger() ? "(Integer) " : "";
96f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross        switch (getAccessor()) {
97f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross            case ARRAY: {
98f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross                return new KCode().
99f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross                        app("getFromArray(", getTarget().toCode()).
100f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross                        app(", ").
101f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross                        app(cast, getArg().toCode()).app(")");
102f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross            }
103f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross            case LIST: {
104f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross                ModelClass listType = ModelAnalyzer.getInstance().findClass(java.util.List.class).
105f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross                        erasure();
106f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross                ModelClass targetType = getTarget().getResolvedType().erasure();
107f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross                if (listType.isAssignableFrom(targetType)) {
108f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross                    return new KCode().
109cd67e9f059e270017d5defd8784c89dd8e6bcde7Nick Kralevich                            app("getFromList(", getTarget().toCode()).
110f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross                            app(", ").
111f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross                            app(cast, getArg().toCode()).
1120c22e8b31651caf12a2b4d4acef5bc65d486e570Colin Cross                            app(")");
113f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross                } else {
114f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross                    return new KCode().
1150c22e8b31651caf12a2b4d4acef5bc65d486e570Colin Cross                            app("", getTarget().toCode()).
116f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross                            app(".get(").
117f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross                            app(cast, getArg().toCode()).
118f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross                            app(")");
119f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross                }
120f45fa6b2853cc32385375a0b63ee39ad6a968869Colin Cross            }
1210c22e8b31651caf12a2b4d4acef5bc65d486e570Colin Cross            case MAP:
1228620bb4118a68721d10c29529dc6978847d08d00Felipe Leme                return new KCode().
1230c22e8b31651caf12a2b4d4acef5bc65d486e570Colin Cross                        app("", getTarget().toCode()).
1240c22e8b31651caf12a2b4d4acef5bc65d486e570Colin Cross                        app(".get(", getArg().toCode()).
1250c22e8b31651caf12a2b4d4acef5bc65d486e570Colin Cross                        app(")");
1260c22e8b31651caf12a2b4d4acef5bc65d486e570Colin Cross        }
12793d705b6d742e8f00167ff2384e35c2205a6f9daFelipe Leme        throw new IllegalStateException("Invalid BracketAccessor type");
1288620bb4118a68721d10c29529dc6978847d08d00Felipe Leme    }
1290c22e8b31651caf12a2b4d4acef5bc65d486e570Colin Cross
1300c22e8b31651caf12a2b4d4acef5bc65d486e570Colin Cross    @Override
1310c22e8b31651caf12a2b4d4acef5bc65d486e570Colin Cross    public KCode toInverseCode(KCode value) {
1320c22e8b31651caf12a2b4d4acef5bc65d486e570Colin Cross        String cast = argCastsInteger() ? "(Integer) " : "";
1330c22e8b31651caf12a2b4d4acef5bc65d486e570Colin Cross        return new KCode().
1340c22e8b31651caf12a2b4d4acef5bc65d486e570Colin Cross                app("setTo(", getTarget().toCode(true)).
1358620bb4118a68721d10c29529dc6978847d08d00Felipe Leme                app(", ").
1360c22e8b31651caf12a2b4d4acef5bc65d486e570Colin Cross                app(cast, getArg().toCode(true)).
1370c22e8b31651caf12a2b4d4acef5bc65d486e570Colin Cross                app(", ", value).app(");");
1380c22e8b31651caf12a2b4d4acef5bc65d486e570Colin Cross    }
1390c22e8b31651caf12a2b4d4acef5bc65d486e570Colin Cross}
1400c22e8b31651caf12a2b4d4acef5bc65d486e570Colin Cross