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
19c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyarimport org.antlr.v4.runtime.misc.Nullable;
20c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar
21731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyarimport android.databinding.tool.processing.ErrorMessages;
22731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyarimport android.databinding.tool.processing.Scope;
23731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyarimport android.databinding.tool.processing.scopes.LocationScopeProvider;
24fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.reflection.ModelAnalyzer;
25fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.reflection.ModelClass;
26c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyarimport android.databinding.tool.store.Location;
27731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyarimport android.databinding.tool.util.L;
282611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyarimport android.databinding.tool.util.Preconditions;
29e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mountimport android.databinding.tool.writer.KCode;
3059229481aec5a284d322a2ca80dff836485feb0cYigit Boyarimport android.databinding.tool.writer.LayoutBinderWriterKt;
31d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
3218243f6f1b7527272ef4feccdf4327d80d9f2241George Mountimport java.util.ArrayList;
3318243f6f1b7527272ef4feccdf4327d80d9f2241George Mountimport java.util.BitSet;
3418243f6f1b7527272ef4feccdf4327d80d9f2241George Mountimport java.util.Collections;
3518243f6f1b7527272ef4feccdf4327d80d9f2241George Mountimport java.util.List;
36793e979f25e190162eacf46d6a4efc3efc1d2f91George Mountimport java.util.Map;
3718243f6f1b7527272ef4feccdf4327d80d9f2241George Mount
38731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyarabstract public class Expr implements VersionProvider, LocationScopeProvider {
390fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar
40d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public static final int NO_ID = -1;
41895b618d9c6e3deb56465d0759cda57f50c46214Yigit Boyar    protected List<Expr> mChildren = new ArrayList<Expr>();
42d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
43d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    // any expression that refers to this. Useful if this expr is duplicate and being replaced
44895b618d9c6e3deb56465d0759cda57f50c46214Yigit Boyar    private List<Expr> mParents = new ArrayList<Expr>();
45d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
46d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private Boolean mIsDynamic;
47d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
4879fc7f3727815ab35bb1bb2e060bfb7db3176eedGeorge Mount    private ModelClass mResolvedType;
49d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
50d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private String mUniqueKey;
51d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
52d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private List<Dependency> mDependencies;
53d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
54c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar    private List<Dependency> mDependants = new ArrayList<Dependency>();
55d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
56d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private int mId = NO_ID;
57d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
58d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private int mRequirementId = NO_ID;
59d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
607b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar    private int mVersion = 0;
617b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar
62d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    // means this expression can directly be invalidated by the user
63d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private boolean mCanBeInvalidated = false;
64d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
65c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar    @Nullable
669784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar    private List<Location> mLocations = new ArrayList<Location>();
67c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar
68d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    /**
69d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * This set denotes the times when this expression is invalid.
70d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * If it is an Identifier expression, it is its index
71d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * If it is a composite expression, it is the union of invalid flags of its descendants
72d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     */
73d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private BitSet mInvalidFlags;
74d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
75d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    /**
76d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * Set when this expression is registered to a model
77d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     */
78d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private ExprModel mModel;
79d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
80d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    /**
81d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * This set denotes the times when this expression must be read.
82d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     *
83d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * It is the union of invalidation flags of all of its non-conditional dependants.
84d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     */
85d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    BitSet mShouldReadFlags;
86d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
87d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    BitSet mReadSoFar = new BitSet();// i've read this variable for these flags
88d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
89d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    /**
90d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * calculated on initialization, assuming all conditionals are true
91d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     */
92d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    BitSet mShouldReadWithConditionals;
93d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
94d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private boolean mIsBindingExpression;
95d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
96d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    /**
97d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * Used by generators when this expression is resolved.
98d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     */
99d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private boolean mRead;
1005bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar    private boolean mIsUsed = false;
101d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    private boolean mIsTwoWay = false;
102d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
103d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    Expr(Iterable<Expr> children) {
104d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Expr expr : children) {
105d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            mChildren.add(expr);
106d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
107d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        addParents();
108d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
109d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
110d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    Expr(Expr... children) {
111d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        Collections.addAll(mChildren, children);
112d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        addParents();
113d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
114d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
115d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public int getId() {
1162611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        Preconditions.check(mId != NO_ID, "if getId is called on an expression, it should have"
1172611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                + " an id: %s", this);
118d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mId;
119d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
120d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
121d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public void setId(int id) {
1222611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        Preconditions.check(mId == NO_ID, "ID is already set on %s", this);
123d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mId = id;
124d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
125d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
126c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar    public void addLocation(Location location) {
127c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        mLocations.add(location);
128c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar    }
129c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar
130c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar    public List<Location> getLocations() {
131c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        return mLocations;
132c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar    }
133c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar
134d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public ExprModel getModel() {
135d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mModel;
136d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
137d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
138d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public BitSet getInvalidFlags() {
139d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (mInvalidFlags == null) {
140d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            mInvalidFlags = resolveInvalidFlags();
141d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
142d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mInvalidFlags;
143d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
144d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
145d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private BitSet resolveInvalidFlags() {
146019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        BitSet bitSet = (BitSet) mModel.getInvalidateAnyBitSet().clone();
147dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar        if (mCanBeInvalidated) {
148d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            bitSet.set(getId(), true);
149d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
150d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Dependency dependency : getDependencies()) {
151d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            // TODO optional optimization: do not invalidate for conditional flags
152d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            bitSet.or(dependency.getOther().getInvalidFlags());
153d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
154d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return bitSet;
155d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
156d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
157d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public void setBindingExpression(boolean isBindingExpression) {
158d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mIsBindingExpression = isBindingExpression;
159d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
160d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
161dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar    public boolean isBindingExpression() {
162dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar        return mIsBindingExpression;
163dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar    }
164dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar
165e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar    public boolean canBeEvaluatedToAVariable() {
166e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar        return true; // anything except arg expr can be evaluated to a variable
167e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar    }
168e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar
1697920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount    public boolean isObservable() {
170fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount        return getResolvedType().isObservable();
1717920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount    }
1727920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount
173793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount    public Expr resolveListeners(ModelClass valueType, Expr parent) {
174793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount        for (int i = mChildren.size() - 1; i >= 0; i--) {
175793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount            Expr child = mChildren.get(i);
176793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount            child.resolveListeners(valueType, this);
177716ba89e7f459f49ea85070d4710c1d79d715298George Mount        }
178793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount        resetResolvedType();
179793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount        return this;
180716ba89e7f459f49ea85070d4710c1d79d715298George Mount    }
181716ba89e7f459f49ea85070d4710c1d79d715298George Mount
182d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    public Expr resolveTwoWayExpressions(Expr parent) {
183d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        for (int i = mChildren.size() - 1; i >= 0; i--) {
184d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount            final Expr child = mChildren.get(i);
185d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount            child.resolveTwoWayExpressions(this);
186d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        }
187d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        return this;
188d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    }
189d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
190716ba89e7f459f49ea85070d4710c1d79d715298George Mount    protected void resetResolvedType() {
191716ba89e7f459f49ea85070d4710c1d79d715298George Mount        mResolvedType = null;
192716ba89e7f459f49ea85070d4710c1d79d715298George Mount    }
193716ba89e7f459f49ea85070d4710c1d79d715298George Mount
194d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public BitSet getShouldReadFlags() {
195d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (mShouldReadFlags == null) {
196d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            getShouldReadFlagsWithConditionals();
197d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            mShouldReadFlags = resolveShouldReadFlags();
198d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
199d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mShouldReadFlags;
200d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
201d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
202d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public BitSet getShouldReadFlagsWithConditionals() {
203d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (mShouldReadWithConditionals == null) {
204d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            mShouldReadWithConditionals = resolveShouldReadWithConditionals();
205d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
206d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mShouldReadWithConditionals;
207d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
208d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
209d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public void setModel(ExprModel model) {
210d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mModel = model;
211d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
212d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
213d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    public void setTwoWay(boolean isTwoWay) {
214d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        mIsTwoWay = isTwoWay;
215d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    }
216d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
217d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    public boolean isTwoWay() {
218d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        return mIsTwoWay;
219d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    }
220d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
221d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    protected String addTwoWay(String uniqueKey) {
222d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        if (mIsTwoWay) {
223d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount            return "twoWay(" + uniqueKey + ")";
224d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        } else {
225d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount            return "oneWay(" + uniqueKey + ")";
226d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        }
227d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    }
228d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
229d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private BitSet resolveShouldReadWithConditionals() {
230d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        // ensure we have invalid flags
231d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        BitSet bitSet = new BitSet();
232d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        // if i'm invalid, that DOES NOT mean i should be read :/.
233d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (mIsBindingExpression) {
234d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            bitSet.or(getInvalidFlags());
235d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
236d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
237d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Dependency dependency : getDependants()) {
238d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            if (dependency.getCondition() == null) {
239d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                bitSet.or(dependency.getDependant().getShouldReadFlagsWithConditionals());
240d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            } else {
241d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                bitSet.set(dependency.getDependant()
242d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                        .getRequirementFlagIndex(dependency.getExpectedOutput()));
243d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
244d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
245d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return bitSet;
246d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
247d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
248d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private BitSet resolveShouldReadFlags() {
249d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        // ensure we have invalid flags
250d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        BitSet bitSet = new BitSet();
251d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (isRead()) {
252d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            return bitSet;
253d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
254d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (mIsBindingExpression) {
255d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            bitSet.or(getInvalidFlags());
256d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
257d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Dependency dependency : getDependants()) {
2582611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            final boolean isUnreadElevated = isUnreadElevated(dependency);
259d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            if (dependency.isConditional()) {
260e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar                continue; // will be resolved later when conditional is elevated
261d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
2627b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar            if (isUnreadElevated) {
2637b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar                bitSet.set(dependency.getDependant()
2647b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar                        .getRequirementFlagIndex(dependency.getExpectedOutput()));
265d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            } else {
266d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                bitSet.or(dependency.getDependant().getShouldReadFlags());
267d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
268d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
269d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        bitSet.and(mShouldReadWithConditionals);
2707b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        bitSet.andNot(mReadSoFar);
271d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return bitSet;
272d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
273d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
2742611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar    private static boolean isUnreadElevated(Dependency input) {
2752611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        return input.isElevated() && !input.getDependant().isRead();
2762611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar    }
277d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private void addParents() {
278d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Expr expr : mChildren) {
279d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            expr.mParents.add(this);
280d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
281d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
282d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
283d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public void onSwappedWith(Expr existing) {
284d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Expr child : mChildren) {
285d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            child.onParentSwapped(this, existing);
286d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
287d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
288d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
289d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private void onParentSwapped(Expr oldParent, Expr newParent) {
2902611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        Preconditions.check(mParents.remove(oldParent), "trying to remove non-existent parent %s"
2912611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                + " from %s", oldParent, mParents);
292d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mParents.add(newParent);
293d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
294d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
295d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public List<Expr> getChildren() {
296d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mChildren;
297d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
298d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
299d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public List<Expr> getParents() {
300d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mParents;
301d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
302d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
303d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    /**
304d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * Whether the result of this expression can change or not.
305d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     *
306d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * For example, 3 + 5 can not change vs 3 + x may change.
307d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     *
308d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * Default implementations checks children and returns true if any of them returns true
309d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     *
310d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * @return True if the result of this expression may change due to variables
311d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     */
312d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public boolean isDynamic() {
313d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (mIsDynamic == null) {
314d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            mIsDynamic = isAnyChildDynamic();
315d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
316d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mIsDynamic;
317d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
318d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
319d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private boolean isAnyChildDynamic() {
3202611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        for (Expr expr : mChildren) {
3212611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            if (expr.isDynamic()) {
3222611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                return true;
323d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
3242611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        }
3252611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        return false;
326d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
327d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
32879fc7f3727815ab35bb1bb2e060bfb7db3176eedGeorge Mount    public ModelClass getResolvedType() {
329d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (mResolvedType == null) {
330d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            // TODO not get instance
331731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar            try {
332731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar                Scope.enter(this);
333731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar                mResolvedType = resolveType(ModelAnalyzer.getInstance());
334731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar                if (mResolvedType == null) {
335731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar                    L.e(ErrorMessages.CANNOT_RESOLVE_TYPE, this);
336731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar                }
337731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar            } finally {
338731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar                Scope.exit();
339731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar            }
340d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
341d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mResolvedType;
342d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
343d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
34479fc7f3727815ab35bb1bb2e060bfb7db3176eedGeorge Mount    abstract protected ModelClass resolveType(ModelAnalyzer modelAnalyzer);
345d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
346d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    abstract protected List<Dependency> constructDependencies();
347d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
348d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    /**
349d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * Creates a dependency for each dynamic child. Should work for any expression besides
350d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * conditionals.
351d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     */
352d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    protected List<Dependency> constructDynamicChildrenDependencies() {
353895b618d9c6e3deb56465d0759cda57f50c46214Yigit Boyar        List<Dependency> dependencies = new ArrayList<Dependency>();
354d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Expr node : mChildren) {
355d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            if (!node.isDynamic()) {
356d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                continue;
357d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
358d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            dependencies.add(new Dependency(this, node));
359d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
360d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return dependencies;
361d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
362d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
363d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public final List<Dependency> getDependencies() {
364d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (mDependencies == null) {
365d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            mDependencies = constructDependencies();
366d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
367d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mDependencies;
368d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
369d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
370d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    void addDependant(Dependency dependency) {
371d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mDependants.add(dependency);
372d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
373d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
374d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public List<Dependency> getDependants() {
375d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mDependants;
376d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
377d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
378d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    protected static final String KEY_JOIN = "~";
379d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
380d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    /**
381d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * Returns a unique string key that can identify this expression.
382d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     *
383d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * It must take into account any dependencies
384d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     *
385d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * @return A unique identifier for this expression
386d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     */
387d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public final String getUniqueKey() {
388d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (mUniqueKey == null) {
389d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            mUniqueKey = computeUniqueKey();
390d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            Preconditions.checkNotNull(mUniqueKey,
391d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    "if there are no children, you must override computeUniqueKey");
3922611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            Preconditions.check(!mUniqueKey.trim().equals(""),
393d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    "if there are no children, you must override computeUniqueKey");
394d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
395d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mUniqueKey;
396d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
397d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
398d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    protected String computeUniqueKey() {
399d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return computeChildrenKey();
400d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
401d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
402d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    protected final String computeChildrenKey() {
4032611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        return join(mChildren);
404d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
405d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
406d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public void enableDirectInvalidation() {
407d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mCanBeInvalidated = true;
408d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
409d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
410d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public boolean canBeInvalidated() {
411d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mCanBeInvalidated;
412d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
413d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
414d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public void trimShouldReadFlags(BitSet bitSet) {
415d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mShouldReadFlags.andNot(bitSet);
416d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
417d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
418d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public boolean isConditional() {
419d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return false;
420d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
421d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
422d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public int getRequirementId() {
423d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mRequirementId;
424d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
425d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
426d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public void setRequirementId(int requirementId) {
427d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mRequirementId = requirementId;
428d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
429d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
430d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    /**
431d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * This is called w/ a dependency of mine.
432d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * Base method should thr
433d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     */
434d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public int getRequirementFlagIndex(boolean expectedOutput) {
4352611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        Preconditions.check(mRequirementId != NO_ID, "If this is an expression w/ conditional"
43609aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar                + " dependencies, it must be assigned a requirement ID. %s", this);
437d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return expectedOutput ? mRequirementId + 1 : mRequirementId;
438d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
439d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
440d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public boolean hasId() {
441d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mId != NO_ID;
442d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
443d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
444d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public void markFlagsAsRead(BitSet flags) {
445d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mReadSoFar.or(flags);
446d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
447d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
448d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public boolean isRead() {
449d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mRead;
450d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
451d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
45274f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar    public boolean considerElevatingConditionals(Expr justRead) {
453d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        boolean elevated = false;
454d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Dependency dependency : mDependencies) {
45574f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar            if (dependency.isConditional() && dependency.getCondition() == justRead) {
456d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                dependency.elevate();
45774f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar                elevated = true;
458d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
459d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
460d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return elevated;
461d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
462d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
463d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public void invalidateReadFlags() {
464d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mShouldReadFlags = null;
4657b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        mVersion ++;
4667b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar    }
4677b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar
4687b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar    @Override
4697b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar    public int getVersion() {
4707b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        return mVersion;
471d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
472d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
473d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public boolean hasNestedCannotRead() {
474d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (isRead()) {
475d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            return false;
476d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
477d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (getShouldReadFlags().isEmpty()) {
478d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            return true;
479d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
4802611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        for (Dependency dependency : getDependencies()) {
4812611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            if (hasNestedCannotRead(dependency)) {
4822611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                return true;
4832611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            }
4842611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        }
4852611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        return false;
486d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
487d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
4882611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar    private static boolean hasNestedCannotRead(Dependency input) {
4892611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        return input.isConditional() || input.getOther().hasNestedCannotRead();
4902611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar    }
491d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
492d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public boolean markAsReadIfDone() {
493d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (mRead) {
494d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            return false;
495d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
496d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        // TODO avoid clone, we can calculate this iteratively
497d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        BitSet clone = (BitSet) mShouldReadWithConditionals.clone();
498d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
499d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        clone.andNot(mReadSoFar);
500d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mRead = clone.isEmpty();
501eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar
502d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (!mRead && !mReadSoFar.isEmpty()) {
503d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            // check if remaining dependencies can be satisfied w/ existing values
504d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            // for predicate flags, this expr may already be calculated to get the predicate
505d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            // to detect them, traverse them later on, see which flags should be calculated to calculate
506d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            // them. If any of them is completely covered w/ our non-conditional flags, no reason
507d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            // to add them to the list since we'll already be calculated due to our non-conditional
508d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            // flags
509eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar            boolean allCovered = true;
510d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            for (int i = clone.nextSetBit(0); i != -1; i = clone.nextSetBit(i + 1)) {
511d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                final Expr expr = mModel.findFlagExpression(i);
512eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                if (expr == null) {
513d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    continue;
514d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
515eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                if (!expr.isConditional()) {
516eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                    allCovered = false;
517eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                    break;
518eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                }
519eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                final BitSet readForConditional = (BitSet) expr.findConditionalFlags().clone();
520eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar
521eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                // FIXME: this does not do full traversal so misses some cases
522d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                // to calculate that conditional, i should've read /readForConditional/ flags
523eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                // if my read-so-far bits cover that; that means i would've already
524d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                // read myself
525eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                readForConditional.andNot(mReadSoFar);
526eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                if (!readForConditional.isEmpty()) {
527eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                    allCovered = false;
5288533f27db6c31b0c295ae62d314dbf07ea640571Yigit Boyar                    break;
5298533f27db6c31b0c295ae62d314dbf07ea640571Yigit Boyar                }
530d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
531eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar            mRead = allCovered;
532d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
53374f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar        if (mRead) {
53474f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar            mShouldReadFlags = null; // if we've been marked as read, clear should read flags
53574f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar        }
536d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mRead;
537d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
538d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
539d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    BitSet mConditionalFlags;
5400fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar
541d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private BitSet findConditionalFlags() {
5422611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        Preconditions.check(isConditional(), "should not call this on a non-conditional expr");
543d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (mConditionalFlags == null) {
544d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            mConditionalFlags = new BitSet();
545d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            resolveConditionalFlags(mConditionalFlags);
546d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
547d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mConditionalFlags;
548d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
549d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
550d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private void resolveConditionalFlags(BitSet flags) {
551d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        flags.or(getPredicateInvalidFlags());
552d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        // if i have only 1 dependency which is conditional, traverse it as well
553d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (getDependants().size() == 1) {
554d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            final Dependency dependency = getDependants().get(0);
555d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            if (dependency.getCondition() != null) {
556d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                flags.or(dependency.getDependant().findConditionalFlags());
5570fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar                flags.set(dependency.getDependant()
5580fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar                        .getRequirementFlagIndex(dependency.getExpectedOutput()));
559d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
560d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
561d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
562d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
563d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
564d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    @Override
565d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public String toString() {
566d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return getUniqueKey();
567d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
568d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
569d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public BitSet getReadSoFar() {
570d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mReadSoFar;
571d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
572d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
573d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private Node mCalculationPaths = null;
5740fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar
575eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar    /**
576eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar     * All flag paths that will result in calculation of this expression.
577eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar     */
578d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    protected Node getAllCalculationPaths() {
579d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (mCalculationPaths == null) {
580d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            Node node = new Node();
581d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            if (isConditional()) {
582d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                node.mBitSet.or(getPredicateInvalidFlags());
583d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            } else {
584d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                node.mBitSet.or(getInvalidFlags());
585d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
586d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            for (Dependency dependency : getDependants()) {
587d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                final Expr dependant = dependency.getDependant();
588d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                if (dependency.getCondition() != null) {
589d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    Node cond = new Node();
590d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    cond.setConditionFlag(
591d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                            dependant.getRequirementFlagIndex(dependency.getExpectedOutput()));
592d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    cond.mParents.add(dependant.getAllCalculationPaths());
593eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                    node.mParents.add(cond);
594d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                } else {
595d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    node.mParents.add(dependant.getAllCalculationPaths());
596d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
597d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
598d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            mCalculationPaths = node;
599d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
600d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mCalculationPaths;
601d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
602d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
603d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public String getDefaultValue() {
60479fc7f3727815ab35bb1bb2e060bfb7db3176eedGeorge Mount        return ModelAnalyzer.getInstance().getDefaultValue(getResolvedType().toJavaCode());
605d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
606d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
607d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    protected BitSet getPredicateInvalidFlags() {
6080fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        throw new IllegalStateException(
6090fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar                "must override getPredicateInvalidFlags in " + getClass().getSimpleName());
6100fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar    }
6110fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar
6120fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar    /**
6130fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar     * Used by code generation
6140fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar     */
6152611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar    public boolean shouldReadNow(final List<Expr> justRead) {
6162611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        if (getShouldReadFlags().isEmpty()) {
6172611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            return false;
6182611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        }
6192611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        for (Dependency input : getDependencies()) {
6202611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            boolean dependencyReady = input.getOther().isRead() || (justRead != null &&
6212611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                    justRead.contains(input.getOther()));
6222611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            if(!dependencyReady) {
6232611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                return false;
6242611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            }
6252611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        }
6262611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        return true;
627d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
628d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
629d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public boolean isEqualityCheck() {
630d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return false;
631d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
632d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
6335bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar    public void setIsUsed(boolean isUsed) {
6345bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar        mIsUsed = isUsed;
635716ba89e7f459f49ea85070d4710c1d79d715298George Mount        for (Expr child : getChildren()) {
636716ba89e7f459f49ea85070d4710c1d79d715298George Mount            child.setIsUsed(isUsed);
637716ba89e7f459f49ea85070d4710c1d79d715298George Mount        }
6385bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar    }
6395bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar
6405bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar    public boolean isUsed() {
6415bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar        return mIsUsed;
6425bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar    }
6435bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar
64479fc7f3727815ab35bb1bb2e060bfb7db3176eedGeorge Mount    public void updateExpr(ModelAnalyzer modelAnalyzer) {
645793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount        final Map<String, Expr> exprMap = mModel.getExprMap();
646793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount        for (int i = mParents.size() - 1; i >= 0; i--) {
647793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount            final Expr parent = mParents.get(i);
648793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount            if (exprMap.get(parent.getUniqueKey()) != parent) {
649793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount                mParents.remove(i);
650793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount            }
651793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount        }
65218243f6f1b7527272ef4feccdf4327d80d9f2241George Mount        for (Expr child : mChildren) {
65318243f6f1b7527272ef4feccdf4327d80d9f2241George Mount            child.updateExpr(modelAnalyzer);
65418243f6f1b7527272ef4feccdf4327d80d9f2241George Mount        }
65518243f6f1b7527272ef4feccdf4327d80d9f2241George Mount    }
65618243f6f1b7527272ef4feccdf4327d80d9f2241George Mount
6572611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar    protected static String join(String... items) {
6582611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        StringBuilder result = new StringBuilder();
6592611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        for (int i = 0; i < items.length; i ++) {
6602611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            if (i > 0) {
6612611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                result.append(KEY_JOIN);
6622611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            }
6632611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            result.append(items[i]);
6642611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        }
6652611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        return result.toString();
6662611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar    }
6672611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar
6682611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar    protected static String join(List<Expr> items) {
6692611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        StringBuilder result = new StringBuilder();
6702611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        for (int i = 0; i < items.size(); i ++) {
6712611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            if (i > 0) {
6722611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                result.append(KEY_JOIN);
6732611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            }
6742611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            result.append(items.get(i).getUniqueKey());
6752611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        }
6762611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        return result.toString();
6772611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar    }
6782611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar
67918243f6f1b7527272ef4feccdf4327d80d9f2241George Mount    protected String asPackage() {
68018243f6f1b7527272ef4feccdf4327d80d9f2241George Mount        return null;
6817920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount    }
6827920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount
683731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar    @Override
684731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar    public List<Location> provideScopeLocation() {
685731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar        return mLocations;
686731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar    }
687731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar
688e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount    public KCode toCode() {
689d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        return toCode(false);
690d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    }
691d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
692d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    protected KCode toCode(boolean expand) {
693d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        if (!expand && isDynamic()) {
69459229481aec5a284d322a2ca80dff836485feb0cYigit Boyar            return new KCode(LayoutBinderWriterKt.getExecutePendingLocalName(this));
695e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount        }
696d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        return generateCode(expand);
697e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount    }
698e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount
699e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount    public KCode toFullCode() {
700d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        return generateCode(false);
701d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    }
702d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
703d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    protected abstract KCode generateCode(boolean expand);
704d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
705d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    public KCode toInverseCode(KCode value) {
706d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        throw new IllegalStateException("expression does not support two-way binding");
707e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount    }
708e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount
709d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    public void assertIsInvertible() {
710d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        final String errorMessage = getInvertibleError();
711d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        if (errorMessage != null) {
712d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount            L.e(ErrorMessages.EXPRESSION_NOT_INVERTIBLE, toFullCode().generate(),
713d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                    errorMessage);
714d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        }
715d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    }
716d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
717d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    /**
718d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount     * @return The reason the expression wasn't invertible or null if it was invertible.
719d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount     */
720d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    protected abstract String getInvertibleError();
721e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount
72209aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar    /**
72309aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar     * This expression is the predicate for 1 or more ternary expressions.
72409aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar     */
72509aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar    public boolean hasConditionalDependant() {
72609aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar        for (Dependency dependency : getDependants()) {
72709aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar            Expr dependant = dependency.getDependant();
72809aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar            if (dependant.isConditional() && dependant instanceof TernaryExpr) {
72909aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar                TernaryExpr ternary = (TernaryExpr) dependant;
73009aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar                return ternary.getPred() == this;
73109aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar            }
73209aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar        }
73309aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar        return false;
73409aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar    }
73509aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar
736d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    static class Node {
7370fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar
738d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        BitSet mBitSet = new BitSet();
739895b618d9c6e3deb56465d0759cda57f50c46214Yigit Boyar        List<Node> mParents = new ArrayList<Node>();
740d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        int mConditionFlag = -1;
741d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
742d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        public boolean areAllPathsSatisfied(BitSet readSoFar) {
743d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            if (mConditionFlag != -1) {
744eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                return readSoFar.get(mConditionFlag)
745eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                        || mParents.get(0).areAllPathsSatisfied(readSoFar);
746d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            } else {
747eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                final BitSet myBitsClone = (BitSet) mBitSet.clone();
748eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                myBitsClone.andNot(readSoFar);
749eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                if (!myBitsClone.isEmpty()) {
750eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                    // read so far does not cover all of my invalidation. The only way I could be
751eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                    // covered is that I only have 1 conditional dependent which is covered by this.
752eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                    if (mParents.size() == 1 && mParents.get(0).mConditionFlag != -1) {
753eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                        return mParents.get(0).areAllPathsSatisfied(readSoFar);
754eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                    }
755eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                    return false;
756d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
757d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                if (mParents.isEmpty()) {
758eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                    return true;
759d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
760d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                for (Node parent : mParents) {
761eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                    if (!parent.areAllPathsSatisfied(readSoFar)) {
762d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                        return false;
763d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    }
764d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
765d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                return true;
766d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
767d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
768d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
769d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        public void setConditionFlag(int requirementFlagIndex) {
770d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            mConditionFlag = requirementFlagIndex;
771d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
772d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
773d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
774