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