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
19731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyarimport android.databinding.tool.processing.ErrorMessages;
20731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyarimport android.databinding.tool.processing.Scope;
21731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyarimport android.databinding.tool.processing.scopes.LocationScopeProvider;
22fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.reflection.ModelAnalyzer;
23fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.reflection.ModelClass;
246047998943beebd81e0ae1068df39c0cbee38628Yigit Boyarimport android.databinding.tool.solver.ExecutionPath;
25c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyarimport android.databinding.tool.store.Location;
26731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyarimport android.databinding.tool.util.L;
272611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyarimport android.databinding.tool.util.Preconditions;
28e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mountimport android.databinding.tool.writer.KCode;
2959229481aec5a284d322a2ca80dff836485feb0cYigit Boyarimport android.databinding.tool.writer.LayoutBinderWriterKt;
30d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
316047998943beebd81e0ae1068df39c0cbee38628Yigit Boyarimport org.jetbrains.annotations.NotNull;
326047998943beebd81e0ae1068df39c0cbee38628Yigit Boyarimport org.jetbrains.annotations.Nullable;
336047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar
3418243f6f1b7527272ef4feccdf4327d80d9f2241George Mountimport java.util.ArrayList;
3518243f6f1b7527272ef4feccdf4327d80d9f2241George Mountimport java.util.BitSet;
3618243f6f1b7527272ef4feccdf4327d80d9f2241George Mountimport java.util.Collections;
3718243f6f1b7527272ef4feccdf4327d80d9f2241George Mountimport java.util.List;
38793e979f25e190162eacf46d6a4efc3efc1d2f91George Mountimport java.util.Map;
3918243f6f1b7527272ef4feccdf4327d80d9f2241George Mount
40731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyarabstract public class Expr implements VersionProvider, LocationScopeProvider {
41d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public static final int NO_ID = -1;
42895b618d9c6e3deb56465d0759cda57f50c46214Yigit Boyar    protected List<Expr> mChildren = new ArrayList<Expr>();
43d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
44d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    // any expression that refers to this. Useful if this expr is duplicate and being replaced
45895b618d9c6e3deb56465d0759cda57f50c46214Yigit Boyar    private List<Expr> mParents = new ArrayList<Expr>();
46d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
47d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private Boolean mIsDynamic;
48d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
4979fc7f3727815ab35bb1bb2e060bfb7db3176eedGeorge Mount    private ModelClass mResolvedType;
50d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
51d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private String mUniqueKey;
52d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
53d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private List<Dependency> mDependencies;
54d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
55c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar    private List<Dependency> mDependants = new ArrayList<Dependency>();
56d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
57d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private int mId = NO_ID;
58d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
59d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private int mRequirementId = NO_ID;
60d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
617b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar    private int mVersion = 0;
627b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar
63d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    // means this expression can directly be invalidated by the user
64d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private boolean mCanBeInvalidated = false;
65d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
66c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar    @Nullable
679784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar    private List<Location> mLocations = new ArrayList<Location>();
68c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar
69d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    /**
70d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * This set denotes the times when this expression is invalid.
71d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * If it is an Identifier expression, it is its index
72d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * If it is a composite expression, it is the union of invalid flags of its descendants
73d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     */
74d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private BitSet mInvalidFlags;
75d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
76d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    /**
77d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * Set when this expression is registered to a model
78d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     */
79d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private ExprModel mModel;
80d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
81d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    /**
82d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * This set denotes the times when this expression must be read.
83d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     *
84d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * It is the union of invalidation flags of all of its non-conditional dependants.
85d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     */
86d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    BitSet mShouldReadFlags;
87d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
88d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    BitSet mReadSoFar = new BitSet();// i've read this variable for these flags
89d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
90d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    /**
91d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * calculated on initialization, assuming all conditionals are true
92d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     */
93d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    BitSet mShouldReadWithConditionals;
94d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
95d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private boolean mIsBindingExpression;
96d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
97d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    /**
98d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * Used by generators when this expression is resolved.
99d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     */
100d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private boolean mRead;
1015bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar    private boolean mIsUsed = false;
1026047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    private boolean mIsUsedInCallback = false;
103d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
104d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    Expr(Iterable<Expr> children) {
105d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Expr expr : children) {
106d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            mChildren.add(expr);
107d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
108d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        addParents();
109d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
110d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
111d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    Expr(Expr... children) {
112d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        Collections.addAll(mChildren, children);
113d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        addParents();
114d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
115d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
116d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public int getId() {
1172611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        Preconditions.check(mId != NO_ID, "if getId is called on an expression, it should have"
1182611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                + " an id: %s", this);
119d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mId;
120d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
121d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
122d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public void setId(int id) {
1232611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        Preconditions.check(mId == NO_ID, "ID is already set on %s", this);
124d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mId = id;
125d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
126d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
127c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar    public void addLocation(Location location) {
128c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        mLocations.add(location);
129c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar    }
130c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar
131c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar    public List<Location> getLocations() {
132c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        return mLocations;
133c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar    }
134c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar
135d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public ExprModel getModel() {
136d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mModel;
137d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
138d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
139d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public BitSet getInvalidFlags() {
140d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (mInvalidFlags == null) {
141d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            mInvalidFlags = resolveInvalidFlags();
142d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
143d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mInvalidFlags;
144d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
145d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
146d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private BitSet resolveInvalidFlags() {
147019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        BitSet bitSet = (BitSet) mModel.getInvalidateAnyBitSet().clone();
148dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar        if (mCanBeInvalidated) {
149d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            bitSet.set(getId(), true);
150d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
151d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Dependency dependency : getDependencies()) {
152d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            // TODO optional optimization: do not invalidate for conditional flags
153d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            bitSet.or(dependency.getOther().getInvalidFlags());
154d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
155d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return bitSet;
156d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
157d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
158d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public void setBindingExpression(boolean isBindingExpression) {
159d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mIsBindingExpression = isBindingExpression;
160d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
161d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
162dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar    public boolean isBindingExpression() {
163dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar        return mIsBindingExpression;
164dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar    }
165dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar
166e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar    public boolean canBeEvaluatedToAVariable() {
1676047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        return true; // anything except arg/return expr can be evaluated to a variable
168e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar    }
169e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar
1707920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount    public boolean isObservable() {
171fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        return getResolvedType().isObservable();
1727920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount    }
1737920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount
174793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount    public Expr resolveListeners(ModelClass valueType, Expr parent) {
175793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount        for (int i = mChildren.size() - 1; i >= 0; i--) {
176793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount            Expr child = mChildren.get(i);
177793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount            child.resolveListeners(valueType, this);
178716ba89e7f459f49ea85070d4710c1d79d715298George Mount        }
179793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount        resetResolvedType();
180793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount        return this;
181716ba89e7f459f49ea85070d4710c1d79d715298George Mount    }
182716ba89e7f459f49ea85070d4710c1d79d715298George Mount
183d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    public Expr resolveTwoWayExpressions(Expr parent) {
184d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        for (int i = mChildren.size() - 1; i >= 0; i--) {
185d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount            final Expr child = mChildren.get(i);
186d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount            child.resolveTwoWayExpressions(this);
187d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        }
188d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        return this;
189d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    }
190d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
191716ba89e7f459f49ea85070d4710c1d79d715298George Mount    protected void resetResolvedType() {
192716ba89e7f459f49ea85070d4710c1d79d715298George Mount        mResolvedType = null;
193716ba89e7f459f49ea85070d4710c1d79d715298George Mount    }
194716ba89e7f459f49ea85070d4710c1d79d715298George Mount
195d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public BitSet getShouldReadFlags() {
196d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (mShouldReadFlags == null) {
197d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            getShouldReadFlagsWithConditionals();
198d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            mShouldReadFlags = resolveShouldReadFlags();
199d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
200d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mShouldReadFlags;
201d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
202d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
203d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public BitSet getShouldReadFlagsWithConditionals() {
204d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (mShouldReadWithConditionals == null) {
205d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            mShouldReadWithConditionals = resolveShouldReadWithConditionals();
206d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
207d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mShouldReadWithConditionals;
208d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
209d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
210d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public void setModel(ExprModel model) {
211d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mModel = model;
212d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
213d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
214d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private BitSet resolveShouldReadWithConditionals() {
215d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        // ensure we have invalid flags
216d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        BitSet bitSet = new BitSet();
217d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        // if i'm invalid, that DOES NOT mean i should be read :/.
218d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (mIsBindingExpression) {
219d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            bitSet.or(getInvalidFlags());
220d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
221d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
222d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Dependency dependency : getDependants()) {
223d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            if (dependency.getCondition() == null) {
224d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                bitSet.or(dependency.getDependant().getShouldReadFlagsWithConditionals());
225d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            } else {
226d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                bitSet.set(dependency.getDependant()
227d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                        .getRequirementFlagIndex(dependency.getExpectedOutput()));
228d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
229d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
230d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return bitSet;
231d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
232d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
233d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private BitSet resolveShouldReadFlags() {
234d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        // ensure we have invalid flags
235d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        BitSet bitSet = new BitSet();
236d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (isRead()) {
237d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            return bitSet;
238d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
239d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (mIsBindingExpression) {
240d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            bitSet.or(getInvalidFlags());
241d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
242d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Dependency dependency : getDependants()) {
2432611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            final boolean isUnreadElevated = isUnreadElevated(dependency);
244d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            if (dependency.isConditional()) {
245e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar                continue; // will be resolved later when conditional is elevated
246d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
2477b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar            if (isUnreadElevated) {
2487b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar                bitSet.set(dependency.getDependant()
2497b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar                        .getRequirementFlagIndex(dependency.getExpectedOutput()));
250d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            } else {
251d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                bitSet.or(dependency.getDependant().getShouldReadFlags());
252d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
253d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
254d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        bitSet.and(mShouldReadWithConditionals);
2557b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        bitSet.andNot(mReadSoFar);
256d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return bitSet;
257d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
258d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
2592611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar    private static boolean isUnreadElevated(Dependency input) {
2602611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        return input.isElevated() && !input.getDependant().isRead();
2612611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar    }
262d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private void addParents() {
263d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Expr expr : mChildren) {
264d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            expr.mParents.add(this);
265d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
266d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
267d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
268d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public void onSwappedWith(Expr existing) {
269d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Expr child : mChildren) {
270d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            child.onParentSwapped(this, existing);
271d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
272d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
273d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
274d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private void onParentSwapped(Expr oldParent, Expr newParent) {
2752611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        Preconditions.check(mParents.remove(oldParent), "trying to remove non-existent parent %s"
2762611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                + " from %s", oldParent, mParents);
277d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mParents.add(newParent);
278d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
279d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
280d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public List<Expr> getChildren() {
281d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mChildren;
282d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
283d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
284d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public List<Expr> getParents() {
285d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mParents;
286d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
287d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
288d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    /**
289d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * Whether the result of this expression can change or not.
290d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     *
291d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * For example, 3 + 5 can not change vs 3 + x may change.
292d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     *
293d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * Default implementations checks children and returns true if any of them returns true
294d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     *
295d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * @return True if the result of this expression may change due to variables
296d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     */
297d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public boolean isDynamic() {
298d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (mIsDynamic == null) {
299d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            mIsDynamic = isAnyChildDynamic();
300d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
301d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mIsDynamic;
302d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
303d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
304d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private boolean isAnyChildDynamic() {
3052611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        for (Expr expr : mChildren) {
3062611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            if (expr.isDynamic()) {
3072611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                return true;
308d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
3092611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        }
3102611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        return false;
311d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
312d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
31379fc7f3727815ab35bb1bb2e060bfb7db3176eedGeorge Mount    public ModelClass getResolvedType() {
314d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (mResolvedType == null) {
315d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            // TODO not get instance
316731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar            try {
317731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar                Scope.enter(this);
318731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar                mResolvedType = resolveType(ModelAnalyzer.getInstance());
319731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar                if (mResolvedType == null) {
320731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar                    L.e(ErrorMessages.CANNOT_RESOLVE_TYPE, this);
321731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar                }
322731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar            } finally {
323731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar                Scope.exit();
324731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar            }
325d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
326d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mResolvedType;
327d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
328d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
3296047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    public final List<ExecutionPath> toExecutionPath(ExecutionPath path) {
3306047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        List<ExecutionPath> paths = new ArrayList<ExecutionPath>();
3316047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        paths.add(path);
3326047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        return toExecutionPath(paths);
3336047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    }
3346047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar
3356047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    public List<ExecutionPath> toExecutionPath(List<ExecutionPath> paths) {
3366047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        if (getChildren().isEmpty()) {
3376047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar            return addJustMeToExecutionPath(paths);
3386047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        } else {
3396047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar            return toExecutionPathInOrder(paths, getChildren());
3406047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        }
3416047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar
3426047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    }
3436047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar
3446047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    @NotNull
3456047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    protected final List<ExecutionPath> addJustMeToExecutionPath(List<ExecutionPath> paths) {
3466047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        List<ExecutionPath> result = new ArrayList<ExecutionPath>();
3476047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        for (ExecutionPath path : paths) {
3486047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar            result.add(path.addPath(this));
3496047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        }
3506047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        return result;
3516047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    }
3526047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar
3536047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    @SuppressWarnings("Duplicates")
3546047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    protected final List<ExecutionPath> toExecutionPathInOrder(List<ExecutionPath> paths,
3556047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar            Expr... order) {
3566047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        List<ExecutionPath> executionPaths = paths;
3576047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        for (Expr anOrder : order) {
3586047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar            executionPaths = anOrder.toExecutionPath(executionPaths);
3596047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        }
3606047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        List<ExecutionPath> result = new ArrayList<ExecutionPath>(paths.size());
3616047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        for (ExecutionPath path : executionPaths) {
3626047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar            result.add(path.addPath(this));
3636047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        }
3646047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        return result;
3656047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    }
3666047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar
3676047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    @SuppressWarnings("Duplicates")
3686047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    protected final List<ExecutionPath> toExecutionPathInOrder(List<ExecutionPath> paths,
3696047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar            List<Expr> order) {
3706047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        List<ExecutionPath> executionPaths = paths;
3716047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        for (Expr expr : order) {
3726047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar            executionPaths = expr.toExecutionPath(executionPaths);
3736047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        }
3746047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        List<ExecutionPath> result = new ArrayList<ExecutionPath>(paths.size());
3756047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        for (ExecutionPath path : executionPaths) {
3766047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar            result.add(path.addPath(this));
3776047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        }
3786047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        return result;
3796047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    }
3806047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar
38179fc7f3727815ab35bb1bb2e060bfb7db3176eedGeorge Mount    abstract protected ModelClass resolveType(ModelAnalyzer modelAnalyzer);
382d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
383d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    abstract protected List<Dependency> constructDependencies();
384d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
385d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    /**
386d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * Creates a dependency for each dynamic child. Should work for any expression besides
387d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * conditionals.
388d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     */
389d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    protected List<Dependency> constructDynamicChildrenDependencies() {
390895b618d9c6e3deb56465d0759cda57f50c46214Yigit Boyar        List<Dependency> dependencies = new ArrayList<Dependency>();
391d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Expr node : mChildren) {
392d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            if (!node.isDynamic()) {
393d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                continue;
394d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
395d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            dependencies.add(new Dependency(this, node));
396d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
397d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return dependencies;
398d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
399d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
400d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public final List<Dependency> getDependencies() {
401d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (mDependencies == null) {
402d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            mDependencies = constructDependencies();
403d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
404d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mDependencies;
405d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
406d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
407d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    void addDependant(Dependency dependency) {
408d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mDependants.add(dependency);
409d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
410d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
411d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public List<Dependency> getDependants() {
412d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mDependants;
413d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
414d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
415d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    protected static final String KEY_JOIN = "~";
416d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
417d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    /**
418d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * Returns a unique string key that can identify this expression.
419d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     *
420d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * It must take into account any dependencies
421d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     *
422d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * @return A unique identifier for this expression
423d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     */
424d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public final String getUniqueKey() {
425d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (mUniqueKey == null) {
426d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            mUniqueKey = computeUniqueKey();
427d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            Preconditions.checkNotNull(mUniqueKey,
428d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    "if there are no children, you must override computeUniqueKey");
4292611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            Preconditions.check(!mUniqueKey.trim().equals(""),
430d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    "if there are no children, you must override computeUniqueKey");
431d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
432d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mUniqueKey;
433d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
434d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
435d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    protected String computeUniqueKey() {
436d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return computeChildrenKey();
437d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
438d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
439d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    protected final String computeChildrenKey() {
4402611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        return join(mChildren);
441d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
442d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
443d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public void enableDirectInvalidation() {
444d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mCanBeInvalidated = true;
445d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
446d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
447d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public boolean canBeInvalidated() {
448d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mCanBeInvalidated;
449d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
450d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
451d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public void trimShouldReadFlags(BitSet bitSet) {
452d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mShouldReadFlags.andNot(bitSet);
453d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
454d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
455d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public boolean isConditional() {
456d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return false;
457d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
458d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
459d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public int getRequirementId() {
460d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mRequirementId;
461d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
462d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
463d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public void setRequirementId(int requirementId) {
464d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mRequirementId = requirementId;
465d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
466d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
467d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    /**
468d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * This is called w/ a dependency of mine.
469d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * Base method should thr
470d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     */
471d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public int getRequirementFlagIndex(boolean expectedOutput) {
4722611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        Preconditions.check(mRequirementId != NO_ID, "If this is an expression w/ conditional"
47309aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar                + " dependencies, it must be assigned a requirement ID. %s", this);
474d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return expectedOutput ? mRequirementId + 1 : mRequirementId;
475d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
476d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
477d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public boolean hasId() {
478d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mId != NO_ID;
479d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
480d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
481d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public void markFlagsAsRead(BitSet flags) {
482d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mReadSoFar.or(flags);
483d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
484d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
485d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public boolean isRead() {
486d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mRead;
487d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
488d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
48974f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar    public boolean considerElevatingConditionals(Expr justRead) {
490d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        boolean elevated = false;
491d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Dependency dependency : mDependencies) {
49274f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar            if (dependency.isConditional() && dependency.getCondition() == justRead) {
493d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                dependency.elevate();
49474f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar                elevated = true;
495d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
496d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
497d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return elevated;
498d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
499d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
500d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public void invalidateReadFlags() {
501d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mShouldReadFlags = null;
5027b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        mVersion ++;
5037b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar    }
5047b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar
5057b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar    @Override
5067b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar    public int getVersion() {
5077b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        return mVersion;
508d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
509d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
510d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public boolean hasNestedCannotRead() {
511d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (isRead()) {
512d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            return false;
513d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
514d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (getShouldReadFlags().isEmpty()) {
515d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            return true;
516d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
5172611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        for (Dependency dependency : getDependencies()) {
5182611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            if (hasNestedCannotRead(dependency)) {
5192611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                return true;
5202611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            }
5212611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        }
5222611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        return false;
523d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
524d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
5252611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar    private static boolean hasNestedCannotRead(Dependency input) {
5262611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        return input.isConditional() || input.getOther().hasNestedCannotRead();
5272611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar    }
528d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
529d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public boolean markAsReadIfDone() {
530d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (mRead) {
531d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            return false;
532d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
533d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        // TODO avoid clone, we can calculate this iteratively
534d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        BitSet clone = (BitSet) mShouldReadWithConditionals.clone();
535d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
536d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        clone.andNot(mReadSoFar);
537d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mRead = clone.isEmpty();
538eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar
539d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (!mRead && !mReadSoFar.isEmpty()) {
540d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            // check if remaining dependencies can be satisfied w/ existing values
541d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            // for predicate flags, this expr may already be calculated to get the predicate
542d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            // to detect them, traverse them later on, see which flags should be calculated to calculate
543d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            // them. If any of them is completely covered w/ our non-conditional flags, no reason
544d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            // to add them to the list since we'll already be calculated due to our non-conditional
545d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            // flags
546eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar            boolean allCovered = true;
547d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            for (int i = clone.nextSetBit(0); i != -1; i = clone.nextSetBit(i + 1)) {
548d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                final Expr expr = mModel.findFlagExpression(i);
549eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                if (expr == null) {
550d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    continue;
551d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
552eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                if (!expr.isConditional()) {
553eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                    allCovered = false;
554eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                    break;
555eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                }
556f58c3bd412f9bdc5ec589fdcfed470889abb6ea6Yigit Boyar                final BitSet readForConditional = (BitSet) expr
557f58c3bd412f9bdc5ec589fdcfed470889abb6ea6Yigit Boyar                        .getShouldReadFlagsWithConditionals().clone();
558eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar
559eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                // FIXME: this does not do full traversal so misses some cases
560d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                // to calculate that conditional, i should've read /readForConditional/ flags
561eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                // if my read-so-far bits cover that; that means i would've already
562d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                // read myself
563eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                readForConditional.andNot(mReadSoFar);
564eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                if (!readForConditional.isEmpty()) {
565eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                    allCovered = false;
5668533f27db6c31b0c295ae62d314dbf07ea640571Yigit Boyar                    break;
5678533f27db6c31b0c295ae62d314dbf07ea640571Yigit Boyar                }
568d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
569eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar            mRead = allCovered;
570d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
57174f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar        if (mRead) {
57274f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar            mShouldReadFlags = null; // if we've been marked as read, clear should read flags
57374f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar        }
574d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mRead;
575d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
576d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
577d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    BitSet mConditionalFlags;
5780fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar
579d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private BitSet findConditionalFlags() {
5802611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        Preconditions.check(isConditional(), "should not call this on a non-conditional expr");
581d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (mConditionalFlags == null) {
582d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            mConditionalFlags = new BitSet();
583d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            resolveConditionalFlags(mConditionalFlags);
584d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
585d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mConditionalFlags;
586d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
587d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
588d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private void resolveConditionalFlags(BitSet flags) {
589d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        flags.or(getPredicateInvalidFlags());
590d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        // if i have only 1 dependency which is conditional, traverse it as well
591d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (getDependants().size() == 1) {
592d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            final Dependency dependency = getDependants().get(0);
593d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            if (dependency.getCondition() != null) {
594d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                flags.or(dependency.getDependant().findConditionalFlags());
5950fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar                flags.set(dependency.getDependant()
5960fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar                        .getRequirementFlagIndex(dependency.getExpectedOutput()));
597d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
598d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
599d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
600d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
601d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
602d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    @Override
603d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public String toString() {
604d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return getUniqueKey();
605d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
606d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
607d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public BitSet getReadSoFar() {
608d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mReadSoFar;
609d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
610d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
611d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private Node mCalculationPaths = null;
6120fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar
613eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar    /**
614eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar     * All flag paths that will result in calculation of this expression.
615eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar     */
616d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    protected Node getAllCalculationPaths() {
617d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (mCalculationPaths == null) {
618d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            Node node = new Node();
619d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            if (isConditional()) {
620d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                node.mBitSet.or(getPredicateInvalidFlags());
621d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            } else {
622d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                node.mBitSet.or(getInvalidFlags());
623d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
624d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            for (Dependency dependency : getDependants()) {
625d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                final Expr dependant = dependency.getDependant();
626d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                if (dependency.getCondition() != null) {
627d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    Node cond = new Node();
628d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    cond.setConditionFlag(
629d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                            dependant.getRequirementFlagIndex(dependency.getExpectedOutput()));
630d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    cond.mParents.add(dependant.getAllCalculationPaths());
631eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                    node.mParents.add(cond);
632d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                } else {
633d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    node.mParents.add(dependant.getAllCalculationPaths());
634d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
635d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
636d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            mCalculationPaths = node;
637d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
638d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mCalculationPaths;
639d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
640d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
641d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public String getDefaultValue() {
64279fc7f3727815ab35bb1bb2e060bfb7db3176eedGeorge Mount        return ModelAnalyzer.getInstance().getDefaultValue(getResolvedType().toJavaCode());
643d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
644d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
645d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    protected BitSet getPredicateInvalidFlags() {
6460fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        throw new IllegalStateException(
6470fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar                "must override getPredicateInvalidFlags in " + getClass().getSimpleName());
6480fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar    }
6490fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar
6500fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar    /**
6510fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar     * Used by code generation
6520fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar     */
6532611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar    public boolean shouldReadNow(final List<Expr> justRead) {
6542611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        if (getShouldReadFlags().isEmpty()) {
6552611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            return false;
6562611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        }
6572611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        for (Dependency input : getDependencies()) {
6582611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            boolean dependencyReady = input.getOther().isRead() || (justRead != null &&
6592611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                    justRead.contains(input.getOther()));
6602611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            if(!dependencyReady) {
6612611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                return false;
6622611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            }
6632611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        }
6642611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        return true;
665d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
666d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
667d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public boolean isEqualityCheck() {
668d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return false;
669d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
670d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
6716047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    public void markAsUsed() {
6726047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        mIsUsed = true;
673716ba89e7f459f49ea85070d4710c1d79d715298George Mount        for (Expr child : getChildren()) {
6746047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar            child.markAsUsed();
675716ba89e7f459f49ea85070d4710c1d79d715298George Mount        }
6765bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar    }
6775bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar
6786047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    public void markAsUsedInCallback() {
6796047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        mIsUsedInCallback = true;
6806047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        for (Expr child : getChildren()) {
6816047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar            child.markAsUsedInCallback();
6826047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        }
6836047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    }
6846047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar
6856047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    public boolean isIsUsedInCallback() {
6866047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        return mIsUsedInCallback;
6876047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    }
6886047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar
6895bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar    public boolean isUsed() {
6905bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar        return mIsUsed;
6915bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar    }
6925bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar
69379fc7f3727815ab35bb1bb2e060bfb7db3176eedGeorge Mount    public void updateExpr(ModelAnalyzer modelAnalyzer) {
694793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount        final Map<String, Expr> exprMap = mModel.getExprMap();
695793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount        for (int i = mParents.size() - 1; i >= 0; i--) {
696793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount            final Expr parent = mParents.get(i);
697793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount            if (exprMap.get(parent.getUniqueKey()) != parent) {
698793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount                mParents.remove(i);
699793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount            }
700793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount        }
70118243f6f1b7527272ef4feccdf4327d80d9f2241George Mount        for (Expr child : mChildren) {
70218243f6f1b7527272ef4feccdf4327d80d9f2241George Mount            child.updateExpr(modelAnalyzer);
70318243f6f1b7527272ef4feccdf4327d80d9f2241George Mount        }
70418243f6f1b7527272ef4feccdf4327d80d9f2241George Mount    }
70518243f6f1b7527272ef4feccdf4327d80d9f2241George Mount
7062611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar    protected static String join(String... items) {
7072611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        StringBuilder result = new StringBuilder();
7082611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        for (int i = 0; i < items.length; i ++) {
7092611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            if (i > 0) {
7102611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                result.append(KEY_JOIN);
7112611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            }
7122611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            result.append(items[i]);
7132611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        }
7142611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        return result.toString();
7152611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar    }
7162611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar
7172611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar    protected static String join(List<Expr> items) {
7182611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        StringBuilder result = new StringBuilder();
7192611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        for (int i = 0; i < items.size(); i ++) {
7202611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            if (i > 0) {
7212611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                result.append(KEY_JOIN);
7222611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            }
7232611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            result.append(items.get(i).getUniqueKey());
7242611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        }
7252611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        return result.toString();
7262611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar    }
7272611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar
72818243f6f1b7527272ef4feccdf4327d80d9f2241George Mount    protected String asPackage() {
72918243f6f1b7527272ef4feccdf4327d80d9f2241George Mount        return null;
7307920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount    }
7317920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount
732731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar    @Override
733731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar    public List<Location> provideScopeLocation() {
734731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar        return mLocations;
735731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar    }
736731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar
737e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount    public KCode toCode() {
738bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount        if (isDynamic()) {
7396047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar            return new KCode(LayoutBinderWriterKt.scopedName(this));
740e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount        }
741bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount        return generateCode();
742e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount    }
743e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount
744e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount    public KCode toFullCode() {
745bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount        return generateCode();
746d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    }
747d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
748bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount    protected abstract KCode generateCode();
749d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
750bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount    public Expr generateInverse(ExprModel model, Expr value, String bindingClassName) {
751d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        throw new IllegalStateException("expression does not support two-way binding");
752e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount    }
753e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount
754bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount    public abstract Expr cloneToModel(ExprModel model);
755bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount
756bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount    protected static List<Expr> cloneToModel(ExprModel model, List<Expr> exprs) {
757bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount        ArrayList<Expr> clones = new ArrayList<Expr>();
758bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount        for (Expr expr : exprs) {
759bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount            clones.add(expr.cloneToModel(model));
760bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount        }
761bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount        return clones;
762bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount    }
763bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount
764d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    public void assertIsInvertible() {
765d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        final String errorMessage = getInvertibleError();
766d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        if (errorMessage != null) {
767d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount            L.e(ErrorMessages.EXPRESSION_NOT_INVERTIBLE, toFullCode().generate(),
768d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                    errorMessage);
769d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        }
770d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    }
771d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
772d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    /**
773d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount     * @return The reason the expression wasn't invertible or null if it was invertible.
774d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount     */
775d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    protected abstract String getInvertibleError();
776e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount
77709aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar    /**
77809aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar     * This expression is the predicate for 1 or more ternary expressions.
77909aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar     */
78009aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar    public boolean hasConditionalDependant() {
78109aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar        for (Dependency dependency : getDependants()) {
78209aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar            Expr dependant = dependency.getDependant();
78309aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar            if (dependant.isConditional() && dependant instanceof TernaryExpr) {
78409aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar                TernaryExpr ternary = (TernaryExpr) dependant;
78509aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar                return ternary.getPred() == this;
78609aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar            }
78709aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar        }
78809aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar        return false;
78909aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar    }
79009aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar
791d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    static class Node {
7920fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar
793d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        BitSet mBitSet = new BitSet();
794895b618d9c6e3deb56465d0759cda57f50c46214Yigit Boyar        List<Node> mParents = new ArrayList<Node>();
795d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        int mConditionFlag = -1;
796d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
797d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        public boolean areAllPathsSatisfied(BitSet readSoFar) {
798d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            if (mConditionFlag != -1) {
799eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                return readSoFar.get(mConditionFlag)
800eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                        || mParents.get(0).areAllPathsSatisfied(readSoFar);
801d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            } else {
802eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                final BitSet myBitsClone = (BitSet) mBitSet.clone();
803eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                myBitsClone.andNot(readSoFar);
804eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                if (!myBitsClone.isEmpty()) {
805eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                    // read so far does not cover all of my invalidation. The only way I could be
806eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                    // covered is that I only have 1 conditional dependent which is covered by this.
807eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                    if (mParents.size() == 1 && mParents.get(0).mConditionFlag != -1) {
808eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                        return mParents.get(0).areAllPathsSatisfied(readSoFar);
809eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                    }
810eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                    return false;
811d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
812d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                if (mParents.isEmpty()) {
813eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                    return true;
814d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
815d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                for (Node parent : mParents) {
816eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                    if (!parent.areAllPathsSatisfied(readSoFar)) {
817d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                        return false;
818d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    }
819d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
820d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                return true;
821d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
822d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
823d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
824d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        public void setConditionFlag(int requirementFlagIndex) {
825d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            mConditionFlag = requirementFlagIndex;
826d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
827d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
828d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
829