1d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar/*
2d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * Copyright (C) 2015 The Android Open Source Project
3d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar *
4d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License");
5d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * you may not use this file except in compliance with the License.
6d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * You may obtain a copy of the License at
7d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar *
8d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar *      http://www.apache.org/licenses/LICENSE-2.0
9d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar *
10d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * Unless required by applicable law or agreed to in writing, software
11d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS,
12d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * See the License for the specific language governing permissions and
14d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * limitations under the License.
15d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar */
16d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
17fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountpackage android.databinding.tool.expr;
18d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
19d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport android.databinding.tool.BindingTarget;
206047998943beebd81e0ae1068df39c0cbee38628Yigit Boyarimport android.databinding.tool.CallbackWrapper;
21b522c7650bf7d9ec566845bc9eb37e761eea853dGeorge Mountimport android.databinding.tool.InverseBinding;
22fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.reflection.ModelAnalyzer;
23ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyarimport android.databinding.tool.reflection.ModelClass;
24793e979f25e190162eacf46d6a4efc3efc1d2f91George Mountimport android.databinding.tool.reflection.ModelMethod;
25c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyarimport android.databinding.tool.store.Location;
26fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.util.L;
272611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyarimport android.databinding.tool.util.Preconditions;
286047998943beebd81e0ae1068df39c0cbee38628Yigit Boyarimport android.databinding.tool.writer.ExprModelExt;
29fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.writer.FlagSet;
30d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
31d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport org.antlr.v4.runtime.ParserRuleContext;
326047998943beebd81e0ae1068df39c0cbee38628Yigit Boyarimport org.jetbrains.annotations.Nullable;
33d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
34d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarimport java.util.ArrayList;
3574f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyarimport java.util.Arrays;
36d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarimport java.util.BitSet;
37d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarimport java.util.HashMap;
38d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarimport java.util.List;
39d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarimport java.util.Map;
406047998943beebd81e0ae1068df39c0cbee38628Yigit Boyarimport java.util.concurrent.atomic.AtomicInteger;
41d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
42d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarpublic class ExprModel {
43d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
44895b618d9c6e3deb56465d0759cda57f50c46214Yigit Boyar    Map<String, Expr> mExprMap = new HashMap<String, Expr>();
45d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
46895b618d9c6e3deb56465d0759cda57f50c46214Yigit Boyar    List<Expr> mBindingExpressions = new ArrayList<Expr>();
47d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
48d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private int mInvalidateableFieldLimit = 0;
49d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
50d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private int mRequirementIdCount = 0;
51d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
52e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar    // each arg list receives a unique id even if it is the same arguments and method.
53e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar    private int mArgListIdCounter = 0;
54e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar
55d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private static final String TRUE_KEY_SUFFIX = "== true";
56d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private static final String FALSE_KEY_SUFFIX = "== false";
57d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
58d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    /**
59019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar     * Any expression can be invalidated by invalidating this flag.
60019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar     */
61019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    private BitSet mInvalidateAnyFlags;
62eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar    private int mInvalidateAnyFlagIndex;
63019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar
64019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    /**
65d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * Used by code generation. Keeps the list of expressions that are waiting to be evaluated.
66d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     */
67d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private List<Expr> mPendingExpressions;
68d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
69d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    /**
70d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * Used for converting flags into identifiers while debugging.
71d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     */
72d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private String[] mFlagMapping;
73d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
74d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private int mFlagBucketCount;// how many buckets we use to identify flags
75d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
76d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private List<Expr> mObservables;
77d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
78e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar    private boolean mSealed = false;
79e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar
80895b618d9c6e3deb56465d0759cda57f50c46214Yigit Boyar    private Map<String, String> mImports = new HashMap<String, String>();
81a7e767e576adebcddf043ad34ccb8dd167f777b3George Mount
82c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar    private ParserRuleContext mCurrentParserContext;
83c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar    private Location mCurrentLocationInFile;
846047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar
856047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    private Map<String, CallbackWrapper> mCallbackWrappers = new HashMap<String, CallbackWrapper>();
866047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar
876047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    private AtomicInteger mCallbackIdCounter = new AtomicInteger();
886047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar
896047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    private ExprModelExt mExt = new ExprModelExt();
906047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar
91d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    /**
92d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * Adds the expression to the list of expressions and returns it.
93d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * If it already exists, returns existing one.
94d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     *
95d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * @param expr The new parsed expression
96d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * @return The expression itself or another one if the same thing was parsed before
97d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     */
98d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public <T extends Expr> T register(T expr) {
992611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        Preconditions.check(!mSealed, "Cannot add expressions to a model after it is sealed");
100c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        Location location = null;
101c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        if (mCurrentParserContext != null) {
102c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar            location = new Location(mCurrentParserContext);
103c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar            location.setParentLocation(mCurrentLocationInFile);
104c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        }
1056047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        //noinspection unchecked
106d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        T existing = (T) mExprMap.get(expr.getUniqueKey());
107d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (existing != null) {
1082611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            Preconditions.check(expr.getParents().isEmpty(),
109d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    "If an expression already exists, it should've never been added to a parent,"
110d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                            + "if thats the case, somewhere we are creating an expression w/o"
111d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                            + "calling expression model");
112d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            // tell the expr that it is being swapped so that if it was added to some other expr
113d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            // as a parent, those can swap their references
114d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            expr.onSwappedWith(existing);
115c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar            if (location != null) {
116c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar                existing.addLocation(location);
117c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar            }
118d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            return existing;
119d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
120d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mExprMap.put(expr.getUniqueKey(), expr);
121d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        expr.setModel(this);
122c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        if (location != null) {
123c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar            expr.addLocation(location);
124c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        }
125d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return expr;
126d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
127d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
1286047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    protected void markSealed() {
1296047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        mSealed = true;
1306047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    }
1316047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar
1326047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    public ExprModelExt getExt() {
1336047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        return mExt;
1346047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    }
1356047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar
1366047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    public int obtainCallbackId() {
1376047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        return mCallbackIdCounter.incrementAndGet();
1386047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    }
1396047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar
140c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar    public void setCurrentParserContext(ParserRuleContext currentParserContext) {
141c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        mCurrentParserContext = currentParserContext;
142c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar    }
143c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar
1446047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    public ParserRuleContext getCurrentParserContext() {
1456047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        return mCurrentParserContext;
1466047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    }
1476047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar
1486047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    public Location getCurrentLocationInFile() {
1496047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        return mCurrentLocationInFile;
1506047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    }
1516047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar
152d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public Map<String, Expr> getExprMap() {
153d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mExprMap;
154d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
155d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
156d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public int size() {
157d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mExprMap.size();
158d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
159d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
160d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public ComparisonExpr comparison(String op, Expr left, Expr right) {
161d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return register(new ComparisonExpr(op, left, right));
162d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
163d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
164c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mount    public InstanceOfExpr instanceOfOp(Expr expr, String type) {
165c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mount        return register(new InstanceOfExpr(expr, type));
166c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mount    }
167c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mount
168d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public FieldAccessExpr field(Expr parent, String name) {
169d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return register(new FieldAccessExpr(parent, name));
170d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
171d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
1727920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount    public FieldAccessExpr observableField(Expr parent, String name) {
173bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount        return register(new ObservableFieldExpr(parent, name));
1747920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount    }
1757920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount
176c0c1dab0b6254e4d27f18c37a72a9e7952e958a0George Mount    public MethodReferenceExpr methodReference(Expr parent, String name) {
177c0c1dab0b6254e4d27f18c37a72a9e7952e958a0George Mount        return register(new MethodReferenceExpr(parent, name));
178c0c1dab0b6254e4d27f18c37a72a9e7952e958a0George Mount    }
179c0c1dab0b6254e4d27f18c37a72a9e7952e958a0George Mount
180d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public SymbolExpr symbol(String text, Class type) {
181d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return register(new SymbolExpr(text, type));
182d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
183d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
184d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public TernaryExpr ternary(Expr pred, Expr ifTrue, Expr ifFalse) {
185d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return register(new TernaryExpr(pred, ifTrue, ifFalse));
186d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
187d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
188d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public IdentifierExpr identifier(String name) {
189d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return register(new IdentifierExpr(name));
190d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
191d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
192d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public StaticIdentifierExpr staticIdentifier(String name) {
193d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return register(new StaticIdentifierExpr(name));
194d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
195d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
1967c1b078ca84336caba7f811709836562bd5550d6George Mount    public BuiltInVariableExpr builtInVariable(String name, String type, String accessCode) {
1977c1b078ca84336caba7f811709836562bd5550d6George Mount        return register(new BuiltInVariableExpr(name, type, accessCode));
1987c1b078ca84336caba7f811709836562bd5550d6George Mount    }
1997c1b078ca84336caba7f811709836562bd5550d6George Mount
200d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    public ViewFieldExpr viewFieldExpr(BindingTarget bindingTarget) {
201d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        return register(new ViewFieldExpr(bindingTarget));
202d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    }
203d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
204ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar    /**
205ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar     * Creates a static identifier for the given class or returns the existing one.
206ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar     */
207ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar    public StaticIdentifierExpr staticIdentifierFor(final ModelClass modelClass) {
208ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        final String type = modelClass.getCanonicalName();
2092611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        // check for existing
2106047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        StaticIdentifierExpr id = findStaticIdentifierExpr(type);
2116047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        if (id != null) {
2126047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar            return id;
213ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        }
214ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar
215ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        // does not exist. Find a name for it.
216ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        int cnt = 0;
217ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        int dotIndex = type.lastIndexOf(".");
218ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        String baseName;
2192611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        Preconditions.check(dotIndex < type.length() - 1, "Invalid type %s", type);
220ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        if (dotIndex == -1) {
221ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar            baseName = type;
222ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        } else {
223ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar            baseName = type.substring(dotIndex + 1);
224ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        }
225ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        while (true) {
226ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar            String candidate = cnt == 0 ? baseName : baseName + cnt;
227ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar            if (!mImports.containsKey(candidate)) {
228c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar                return addImport(candidate, type, null);
229ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar            }
230ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar            cnt ++;
2312611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            Preconditions.check(cnt < 100, "Failed to create an import for " + type);
232ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        }
233ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar    }
234ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar
2356047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    @Nullable
2366047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    private StaticIdentifierExpr findStaticIdentifierExpr(String type) {
2376047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        for (Expr expr : mExprMap.values()) {
2386047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar            if (expr instanceof StaticIdentifierExpr) {
2396047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar                StaticIdentifierExpr id = (StaticIdentifierExpr) expr;
2406047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar                if (id.getUserDefinedType().equals(type)) {
2416047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar                    return id;
2426047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar                }
2436047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar            }
2446047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        }
2456047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        return null;
2466047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    }
2476047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar
248d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public MethodCallExpr methodCall(Expr target, String name, List<Expr> args) {
249d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return register(new MethodCallExpr(target, name, args));
250d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
251d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
252d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public MathExpr math(Expr left, String op, Expr right) {
253d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return register(new MathExpr(left, op, right));
254d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
255d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
256c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mount    public TernaryExpr logical(Expr left, String op, Expr right) {
257c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mount        if ("&&".equals(op)) {
258c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mount            // left && right
2598533f27db6c31b0c295ae62d314dbf07ea640571Yigit Boyar            // left ? right : false
2608533f27db6c31b0c295ae62d314dbf07ea640571Yigit Boyar            return register(new TernaryExpr(left, right, symbol("false", boolean.class)));
261c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mount        } else {
262c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mount            // left || right
2638533f27db6c31b0c295ae62d314dbf07ea640571Yigit Boyar            // left ? true : right
2648533f27db6c31b0c295ae62d314dbf07ea640571Yigit Boyar            return register(new TernaryExpr(left, symbol("true", boolean.class), right));
265c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mount        }
266c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mount    }
267c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mount
268c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mount    public BitShiftExpr bitshift(Expr left, String op, Expr right) {
269c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mount        return register(new BitShiftExpr(left, op, right));
270c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mount    }
271c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mount
272c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mount    public UnaryExpr unary(String op, Expr expr) {
273c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mount        return register(new UnaryExpr(op, expr));
274c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mount    }
275c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mount
27678dc9ae6d67ae94bf3f637eeea0848e4f700b7a3George Mount    public Expr resourceExpr(BindingTarget target, String packageName, String resourceType,
27778dc9ae6d67ae94bf3f637eeea0848e4f700b7a3George Mount            String resourceName, List<Expr> args) {
27878dc9ae6d67ae94bf3f637eeea0848e4f700b7a3George Mount        return register(new ResourceExpr(target, packageName, resourceType, resourceName, args));
279c752a5f795baf6df435ef60881316cb748df407cGeorge Mount    }
280c752a5f795baf6df435ef60881316cb748df407cGeorge Mount
2815cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount    public Expr bracketExpr(Expr variableExpr, Expr argExpr) {
2825cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount        return register(new BracketExpr(variableExpr, argExpr));
2835cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount    }
2845cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount
285e4b93061ac703e48fc2c9994c9059ed016f05559George Mount    public Expr castExpr(String type, Expr expr) {
286e4b93061ac703e48fc2c9994c9059ed016f05559George Mount        return register(new CastExpr(type, expr));
287e4b93061ac703e48fc2c9994c9059ed016f05559George Mount    }
288e4b93061ac703e48fc2c9994c9059ed016f05559George Mount
289d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    public TwoWayListenerExpr twoWayListenerExpr(InverseBinding inverseBinding) {
290d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        return register(new TwoWayListenerExpr(inverseBinding));
291d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    }
292d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public List<Expr> getBindingExpressions() {
293d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mBindingExpressions;
294d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
295d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
296c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar    public StaticIdentifierExpr addImport(String alias, String type, Location location) {
2976047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        String existing = mImports.get(alias);
2986047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        if (existing != null) {
2996047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar            if (existing.equals(type)) {
3006047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar                final StaticIdentifierExpr id = findStaticIdentifierExpr(type);
3016047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar                Preconditions.checkNotNull(id, "Missing import expression although it is"
3026047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar                        + " registered");
3036047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar                return id;
3046047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar            } else {
3056047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar                L.e("%s has already been defined as %s but trying to re-define as %s", alias,
3066047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar                        existing, type);
3076047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar            }
3086047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        }
3096047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar
310a7e767e576adebcddf043ad34ccb8dd167f777b3George Mount        final StaticIdentifierExpr id = staticIdentifier(alias);
311a7e767e576adebcddf043ad34ccb8dd167f777b3George Mount        L.d("adding import %s as %s klass: %s", type, alias, id.getClass().getSimpleName());
312a7e767e576adebcddf043ad34ccb8dd167f777b3George Mount        id.setUserDefinedType(type);
313c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        if (location != null) {
314c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar            id.addLocation(location);
315c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        }
316a7e767e576adebcddf043ad34ccb8dd167f777b3George Mount        mImports.put(alias, type);
317ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        return id;
318a7e767e576adebcddf043ad34ccb8dd167f777b3George Mount    }
319a7e767e576adebcddf043ad34ccb8dd167f777b3George Mount
320a7e767e576adebcddf043ad34ccb8dd167f777b3George Mount    public Map<String, String> getImports() {
321a7e767e576adebcddf043ad34ccb8dd167f777b3George Mount        return mImports;
322a7e767e576adebcddf043ad34ccb8dd167f777b3George Mount    }
323a7e767e576adebcddf043ad34ccb8dd167f777b3George Mount
324d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    /**
325d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * The actual thingy that is set on the binding target.
326d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     *
327d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * Input must be already registered
328d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     */
329d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public Expr bindingExpr(Expr bindingExpr) {
3302611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        Preconditions.check(mExprMap.containsKey(bindingExpr.getUniqueKey()),
331d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                "Main expression should already be registered");
332a70fed6415aa1e8bbbe929aee776402ac3b81c86George Mount        if (!mBindingExpressions.contains(bindingExpr)) {
333a70fed6415aa1e8bbbe929aee776402ac3b81c86George Mount            mBindingExpressions.add(bindingExpr);
334a70fed6415aa1e8bbbe929aee776402ac3b81c86George Mount        }
335d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return bindingExpr;
336d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
337d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
338793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount    public void removeExpr(Expr expr) {
339d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        Preconditions.check(!mSealed, "Can't modify the expression list after sealing the model.");
340793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount        mBindingExpressions.remove(expr);
341c0c1dab0b6254e4d27f18c37a72a9e7952e958a0George Mount        mExprMap.remove(expr.getUniqueKey());
342793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount    }
343793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount
344d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public List<Expr> getObservables() {
345d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mObservables;
346d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
347d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
348d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    /**
349d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * Give id to each expression. Will be useful if we serialize.
350d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     */
351793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount    public void seal() {
3528533f27db6c31b0c295ae62d314dbf07ea640571Yigit Boyar        L.d("sealing model");
353895b618d9c6e3deb56465d0759cda57f50c46214Yigit Boyar        List<Expr> notifiableExpressions = new ArrayList<Expr>();
354d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        //ensure class analyzer. We need to know observables at this point
35579fc7f3727815ab35bb1bb2e060bfb7db3176eedGeorge Mount        final ModelAnalyzer modelAnalyzer = ModelAnalyzer.getInstance();
356ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        updateExpressions(modelAnalyzer);
357d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
358d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        int counter = 0;
35979fc7f3727815ab35bb1bb2e060bfb7db3176eedGeorge Mount        final Iterable<Expr> observables = filterObservables(modelAnalyzer);
3609784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        List<String> flagMapping = new ArrayList<String>();
3619784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        mObservables = new ArrayList<Expr>();
362d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Expr expr : observables) {
363d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            // observables gets initial ids
364d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            flagMapping.add(expr.getUniqueKey());
365d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            expr.setId(counter++);
366d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            mObservables.add(expr);
367dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar            notifiableExpressions.add(expr);
368d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            L.d("observable %s", expr.getUniqueKey());
369d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
370d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
371d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        // non-observable identifiers gets next ids
37279fc7f3727815ab35bb1bb2e060bfb7db3176eedGeorge Mount        final Iterable<Expr> nonObservableIds = filterNonObservableIds(modelAnalyzer);
373d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Expr expr : nonObservableIds) {
374d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            flagMapping.add(expr.getUniqueKey());
375d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            expr.setId(counter++);
376dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar            notifiableExpressions.add(expr);
377d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            L.d("non-observable %s", expr.getUniqueKey());
378d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
379d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
380ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        // descendants of observables gets following ids
381d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Expr expr : observables) {
382d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            for (Expr parent : expr.getParents()) {
383d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                if (parent.hasId()) {
384d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    continue;// already has some id, means observable
385d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
386d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                // only fields earn an id
3879e20571da789c7d50650513c38d5a333b11b9fd3Yigit Boyar                if (parent instanceof FieldAccessExpr) {
3889e20571da789c7d50650513c38d5a333b11b9fd3Yigit Boyar                    FieldAccessExpr fae = (FieldAccessExpr) parent;
3899e20571da789c7d50650513c38d5a333b11b9fd3Yigit Boyar                    L.d("checking field access expr %s. getter: %s", fae,fae.getGetter());
3906047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar                    // FAE#getter might be null if it is used only in a callback.
3916047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar                    if (fae.getGetter() != null && fae.isDynamic()
3926047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar                            && fae.getGetter().canBeInvalidated()) {
3939e20571da789c7d50650513c38d5a333b11b9fd3Yigit Boyar                        flagMapping.add(parent.getUniqueKey());
3949e20571da789c7d50650513c38d5a333b11b9fd3Yigit Boyar                        parent.setId(counter++);
3959e20571da789c7d50650513c38d5a333b11b9fd3Yigit Boyar                        notifiableExpressions.add(parent);
3969e20571da789c7d50650513c38d5a333b11b9fd3Yigit Boyar                        L.d("notifiable field %s : %s for %s : %s", parent.getUniqueKey(),
3979e20571da789c7d50650513c38d5a333b11b9fd3Yigit Boyar                                Integer.toHexString(System.identityHashCode(parent)),
3989e20571da789c7d50650513c38d5a333b11b9fd3Yigit Boyar                                expr.getUniqueKey(),
3999e20571da789c7d50650513c38d5a333b11b9fd3Yigit Boyar                                Integer.toHexString(System.identityHashCode(expr)));
4009e20571da789c7d50650513c38d5a333b11b9fd3Yigit Boyar                    }
401d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
402d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
403d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
404dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar
405d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        // now all 2-way bound view fields
406d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        for (Expr expr : mExprMap.values()) {
407d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount            if (expr instanceof FieldAccessExpr) {
408d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                FieldAccessExpr fieldAccessExpr = (FieldAccessExpr) expr;
409bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount                if (fieldAccessExpr.getTarget() instanceof ViewFieldExpr) {
410d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                    flagMapping.add(fieldAccessExpr.getUniqueKey());
411d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                    fieldAccessExpr.setId(counter++);
412d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                }
413d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount            }
414d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        }
415d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
416dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar        // non-dynamic binding expressions receive some ids so that they can be invalidated
4178533f27db6c31b0c295ae62d314dbf07ea640571Yigit Boyar        L.d("list of binding expressions");
418a70fed6415aa1e8bbbe929aee776402ac3b81c86George Mount        for (int i = 0; i < mBindingExpressions.size(); i++) {
419c96847768305d83c6bc4919432af9bd9bfe4c08eGeorge Mount            L.d("[%d] %s", i, mBindingExpressions.get(i));
420a70fed6415aa1e8bbbe929aee776402ac3b81c86George Mount        }
4218533f27db6c31b0c295ae62d314dbf07ea640571Yigit Boyar        // we don't assign ids to constant binding expressions because now invalidateAll has its own
4228533f27db6c31b0c295ae62d314dbf07ea640571Yigit Boyar        // flag.
423dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar
424dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar        for (Expr expr : notifiableExpressions) {
425d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            expr.enableDirectInvalidation();
426d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
427d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
428d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        // make sure all dependencies are resolved to avoid future race conditions
429d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Expr expr : mExprMap.values()) {
430d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            expr.getDependencies();
431d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
432eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        mInvalidateAnyFlagIndex = counter ++;
433d1369ca2b7114fa456293695f3850e5be5e6d21eYigit Boyar        flagMapping.add("INVALIDATE ANY");
434658c71b9ba3211ac5c10f261a8c6f38b1916d3bfYigit Boyar        mInvalidateableFieldLimit = counter;
4356047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        BitSet invalidateableFlags = new BitSet();
436d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (int i = 0; i < mInvalidateableFieldLimit; i++) {
4376047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar            invalidateableFlags.set(i, true);
438d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
439d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
440d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        // make sure all dependencies are resolved to avoid future race conditions
441d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Expr expr : mExprMap.values()) {
442d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            if (expr.isConditional()) {
4438533f27db6c31b0c295ae62d314dbf07ea640571Yigit Boyar                L.d("requirement id for %s is %d", expr, counter);
444d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                expr.setRequirementId(counter);
445d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                flagMapping.add(expr.getUniqueKey() + FALSE_KEY_SUFFIX);
446d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                flagMapping.add(expr.getUniqueKey() + TRUE_KEY_SUFFIX);
447d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                counter += 2;
448d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
449d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
4506047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        BitSet conditionalFlags = new BitSet();
451d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (int i = mInvalidateableFieldLimit; i < counter; i++) {
4526047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar            conditionalFlags.set(i, true);
453d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
454d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mRequirementIdCount = (counter - mInvalidateableFieldLimit) / 2;
455d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
456d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        // everybody gets an id
457d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Map.Entry<String, Expr> entry : mExprMap.entrySet()) {
458d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            final Expr value = entry.getValue();
459d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            if (!value.hasId()) {
460d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                value.setId(counter++);
461d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
462d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
463d1369ca2b7114fa456293695f3850e5be5e6d21eYigit Boyar
464d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mFlagMapping = new String[flagMapping.size()];
465d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        flagMapping.toArray(mFlagMapping);
466d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
467019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        mFlagBucketCount = 1 + (getTotalFlagCount() / FlagSet.sBucketSize);
468019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        mInvalidateAnyFlags = new BitSet();
469eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        mInvalidateAnyFlags.set(mInvalidateAnyFlagIndex, true);
470019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar
471d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Expr expr : mExprMap.values()) {
472d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            expr.getShouldReadFlagsWithConditionals();
473d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
474d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
475d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Expr expr : mExprMap.values()) {
476d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            // ensure all types are calculated
477d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            expr.getResolvedType();
478d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
479d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
480e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar        mSealed = true;
481d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
482d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
483ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar    /**
484ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar     * Run updateExpr on each binding expression until no new expressions are added.
485ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar     * <p>
486ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar     * Some expressions (e.g. field access) may replace themselves and add/remove new dependencies
487ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar     * so we need to make sure each expression's update is called at least once.
488ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar     */
489ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar    private void updateExpressions(ModelAnalyzer modelAnalyzer) {
490ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        int startSize = -1;
491ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        while (startSize != mExprMap.size()) {
492ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar            startSize = mExprMap.size();
493ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar            ArrayList<Expr> exprs = new ArrayList<Expr>(mBindingExpressions);
494ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar            for (Expr expr : exprs) {
495ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar                expr.updateExpr(modelAnalyzer);
496ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar            }
497ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        }
498ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar    }
499ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar
500d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public int getFlagBucketCount() {
501d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mFlagBucketCount;
502d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
503d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
504d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public int getTotalFlagCount() {
505d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mRequirementIdCount * 2 + mInvalidateableFieldLimit;
506d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
507d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
508d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public int getInvalidateableFieldLimit() {
509d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mInvalidateableFieldLimit;
510d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
511d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
512d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public String[] getFlagMapping() {
513d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mFlagMapping;
514d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
515d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
516d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public String getFlag(int id) {
517d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mFlagMapping[id];
518d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
519d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
5202611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar    private List<Expr> filterNonObservableIds(final ModelAnalyzer modelAnalyzer) {
5219784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        List<Expr> result = new ArrayList<Expr>();
5222611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        for (Expr input : mExprMap.values()) {
5232611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            if (input instanceof IdentifierExpr
5242611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                    && !input.hasId()
5252611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                    && !input.isObservable()
5262611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                    && input.isDynamic()) {
5272611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                result.add(input);
528d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
5292611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        }
5302611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        return result;
531d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
532d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
53379fc7f3727815ab35bb1bb2e060bfb7db3176eedGeorge Mount    private Iterable<Expr> filterObservables(final ModelAnalyzer modelAnalyzer) {
5349784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        List<Expr> result = new ArrayList<Expr>();
5352611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        for (Expr input : mExprMap.values()) {
5362611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            if (input.isObservable()) {
5372611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                result.add(input);
538d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
5392611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        }
5402611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        return result;
541d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
542d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
543d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public List<Expr> getPendingExpressions() {
544d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (mPendingExpressions == null) {
5459784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            mPendingExpressions = new ArrayList<Expr>();
546d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            for (Expr expr : mExprMap.values()) {
54709aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar                // if an expression is NOT dynanic but has conditional dependants, still return it
54809aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar                // so that conditional flags can be set
54909aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar                if (!expr.isRead() && (expr.isDynamic() || expr.hasConditionalDependant())) {
550d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    mPendingExpressions.add(expr);
551d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
552d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
553d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
554d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mPendingExpressions;
555d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
556d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
557d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public boolean markBitsRead() {
558d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        // each has should read flags, we set them back on them
5599784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        List<Expr> markedSomeFlagsRead = new ArrayList<Expr>();
560d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Expr expr : filterShouldRead(getPendingExpressions())) {
561d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            expr.markFlagsAsRead(expr.getShouldReadFlags());
5627b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar            markedSomeFlagsRead.add(expr);
563d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
5647b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        return pruneDone(markedSomeFlagsRead);
565d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
566d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
5677b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar    private boolean pruneDone(List<Expr> markedSomeFlagsAsRead) {
568d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        boolean marked = true;
5699784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        List<Expr> markedAsReadList = new ArrayList<Expr>();
570d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        while (marked) {
571d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            marked = false;
572d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            for (Expr expr : mExprMap.values()) {
573d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                if (expr.isRead()) {
574d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    continue;
575d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
576d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                if (expr.markAsReadIfDone()) {
577d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    L.d("marked %s as read ", expr.getUniqueKey());
578d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    marked = true;
579d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    markedAsReadList.add(expr);
5807b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar                    markedSomeFlagsAsRead.remove(expr);
581d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
582d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
583d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
584d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        boolean elevated = false;
585d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Expr markedAsRead : markedAsReadList) {
586d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            for (Dependency dependency : markedAsRead.getDependants()) {
587d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                if (dependency.getDependant().considerElevatingConditionals(markedAsRead)) {
588d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    elevated = true;
589d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
590d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
591d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
592f58c3bd412f9bdc5ec589fdcfed470889abb6ea6Yigit Boyar        if (!elevated) {
593f58c3bd412f9bdc5ec589fdcfed470889abb6ea6Yigit Boyar            for (Expr partialRead : markedSomeFlagsAsRead) {
594f58c3bd412f9bdc5ec589fdcfed470889abb6ea6Yigit Boyar                // even if all paths are not satisfied, we can elevate certain conditional
595f58c3bd412f9bdc5ec589fdcfed470889abb6ea6Yigit Boyar                // dependencies if all of their paths are satisfied.
596f58c3bd412f9bdc5ec589fdcfed470889abb6ea6Yigit Boyar                for (Dependency dependency : partialRead.getDependants()) {
597f58c3bd412f9bdc5ec589fdcfed470889abb6ea6Yigit Boyar                    Expr dependant = dependency.getDependant();
598f58c3bd412f9bdc5ec589fdcfed470889abb6ea6Yigit Boyar                    if (dependant.isConditional() && dependant.getAllCalculationPaths()
599f58c3bd412f9bdc5ec589fdcfed470889abb6ea6Yigit Boyar                            .areAllPathsSatisfied(partialRead.mReadSoFar)) {
600f58c3bd412f9bdc5ec589fdcfed470889abb6ea6Yigit Boyar                        if (dependant.considerElevatingConditionals(partialRead)) {
601f58c3bd412f9bdc5ec589fdcfed470889abb6ea6Yigit Boyar                            elevated = true;
602f58c3bd412f9bdc5ec589fdcfed470889abb6ea6Yigit Boyar                        }
603eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                    }
6047b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar                }
6057b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar            }
6067b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        }
607d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (elevated) {
608d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            // some conditionals are elevated. We should re-calculate flags
609d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            for (Expr expr : getPendingExpressions()) {
610d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                if (!expr.isRead()) {
611d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    expr.invalidateReadFlags();
612d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
613d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
614d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            mPendingExpressions = null;
615d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
616d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return elevated;
617d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
618d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
6192611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar    private static boolean hasConditionalOrNestedCannotReadDependency(Expr expr) {
6202611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        for (Dependency dependency : expr.getDependencies()) {
6212611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            if (dependency.isConditional() || dependency.getOther().hasNestedCannotRead()) {
6222611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                return true;
6232611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            }
6242611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        }
6252611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        return false;
626d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
627d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
6286047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    public static ArrayList<Expr> filterShouldRead(Iterable<Expr> exprs) {
6296047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        ArrayList<Expr> result = new ArrayList<Expr>();
6302611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        for (Expr expr : exprs) {
6312611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            if (!expr.getShouldReadFlags().isEmpty() &&
6322611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                    !hasConditionalOrNestedCannotReadDependency(expr)) {
6332611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                result.add(expr);
6342611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            }
635d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
6362611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        return result;
6372611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar    }
638d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
639d1369ca2b7114fa456293695f3850e5be5e6d21eYigit Boyar    /**
640d1369ca2b7114fa456293695f3850e5be5e6d21eYigit Boyar     * May return null if flag is equal to invalidate any flag.
641d1369ca2b7114fa456293695f3850e5be5e6d21eYigit Boyar     */
642d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public Expr findFlagExpression(int flag) {
643d1369ca2b7114fa456293695f3850e5be5e6d21eYigit Boyar        if (mInvalidateAnyFlags.get(flag)) {
644d1369ca2b7114fa456293695f3850e5be5e6d21eYigit Boyar            return null;
645d1369ca2b7114fa456293695f3850e5be5e6d21eYigit Boyar        }
646d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        final String key = mFlagMapping[flag];
647d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (mExprMap.containsKey(key)) {
648d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            return mExprMap.get(key);
649d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
650d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        int falseIndex = key.indexOf(FALSE_KEY_SUFFIX);
651d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (falseIndex > -1) {
652d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            final String trimmed = key.substring(0, falseIndex);
653d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            return mExprMap.get(trimmed);
654d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
655d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        int trueIndex = key.indexOf(TRUE_KEY_SUFFIX);
656d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (trueIndex > -1) {
657d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            final String trimmed = key.substring(0, trueIndex);
658d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            return mExprMap.get(trimmed);
659d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
660d1369ca2b7114fa456293695f3850e5be5e6d21eYigit Boyar        // log everything we call
661d1369ca2b7114fa456293695f3850e5be5e6d21eYigit Boyar        StringBuilder error = new StringBuilder();
662d1369ca2b7114fa456293695f3850e5be5e6d21eYigit Boyar        error.append("cannot find flag:").append(flag).append("\n");
663d1369ca2b7114fa456293695f3850e5be5e6d21eYigit Boyar        error.append("invalidate any flag:").append(mInvalidateAnyFlags).append("\n");
664d1369ca2b7114fa456293695f3850e5be5e6d21eYigit Boyar        error.append("key:").append(key).append("\n");
665d1369ca2b7114fa456293695f3850e5be5e6d21eYigit Boyar        error.append("flag mapping:").append(Arrays.toString(mFlagMapping));
6662611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        L.e(error.toString());
667d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return null;
668d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
669019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar
670019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    public BitSet getInvalidateAnyBitSet() {
671019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        return mInvalidateAnyFlags;
672019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    }
673e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar
674eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar    public int getInvalidateAnyFlagIndex() {
675eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        return mInvalidateAnyFlagIndex;
676eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar    }
677eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar
678e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar    public Expr argListExpr(Iterable<Expr> expressions) {
679e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar        return register(new ArgListExpr(mArgListIdCounter ++, expressions));
680e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar    }
681716ba89e7f459f49ea85070d4710c1d79d715298George Mount
682c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar    public void setCurrentLocationInFile(Location location) {
683c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        mCurrentLocationInFile = location;
684c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar    }
685c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar
686793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount    public Expr listenerExpr(Expr expression, String name, ModelClass listenerType,
687793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount            ModelMethod listenerMethod) {
688793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount        return register(new ListenerExpr(expression, name, listenerType, listenerMethod));
689716ba89e7f459f49ea85070d4710c1d79d715298George Mount    }
6906047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar
691bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount    public FieldAssignmentExpr assignment(Expr target, String name, Expr value) {
692bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount        return register(new FieldAssignmentExpr(target, name, value));
693bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount    }
694bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount
6956047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    public Map<String, CallbackWrapper> getCallbackWrappers() {
6966047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        return mCallbackWrappers;
6976047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    }
6986047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar
6996047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    public CallbackWrapper callbackWrapper(ModelClass klass, ModelMethod method) {
7006047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        final String key = CallbackWrapper.uniqueKey(klass, method);
7016047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        CallbackWrapper wrapper = mCallbackWrappers.get(key);
7026047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        if (wrapper == null) {
7036047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar            wrapper = new CallbackWrapper(klass, method);
7046047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar            mCallbackWrappers.put(key, wrapper);
7056047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        }
7066047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        return wrapper;
7076047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    }
7086047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar
709bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount    public LambdaExpr lambdaExpr(Expr expr, CallbackExprModel callbackExprModel) {
7106047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        return register(new LambdaExpr(expr, callbackExprModel));
7116047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    }
7126047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar
7136047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    public IdentifierExpr findIdentifier(String name) {
7146047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        for (Expr expr : mExprMap.values()) {
7156047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar            if (expr instanceof IdentifierExpr && name.equals(((IdentifierExpr) expr).getName())) {
7166047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar                return (IdentifierExpr) expr;
7176047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar            }
7186047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        }
7196047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        return null;
7206047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    }
721d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
722