1d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar/*
2d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * Copyright (C) 2015 The Android Open Source Project
3d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar *
4d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License");
5d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * you may not use this file except in compliance with the License.
6d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * You may obtain a copy of the License at
7d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar *
8d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar *      http://www.apache.org/licenses/LICENSE-2.0
9d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar *
10d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * Unless required by applicable law or agreed to in writing, software
11d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS,
12d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * See the License for the specific language governing permissions and
14d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * limitations under the License.
15d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar */
16d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
17fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountpackage android.databinding.tool.expr;
18d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
19d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport android.databinding.tool.BindingTarget;
20d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport android.databinding.tool.InverseBinding;
21fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.reflection.ModelAnalyzer;
22ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyarimport android.databinding.tool.reflection.ModelClass;
23793e979f25e190162eacf46d6a4efc3efc1d2f91George Mountimport android.databinding.tool.reflection.ModelMethod;
24c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyarimport android.databinding.tool.store.Location;
25fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.util.L;
262611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyarimport android.databinding.tool.util.Preconditions;
27fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.writer.FlagSet;
28d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
29d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport org.antlr.v4.runtime.ParserRuleContext;
30d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
31d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarimport java.util.ArrayList;
3274f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyarimport java.util.Arrays;
33d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarimport java.util.BitSet;
34d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarimport java.util.HashMap;
35d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarimport java.util.List;
36d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarimport java.util.Map;
37d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
38d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarpublic class ExprModel {
39d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
40895b618d9c6e3deb56465d0759cda57f50c46214Yigit Boyar    Map<String, Expr> mExprMap = new HashMap<String, Expr>();
41d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
42895b618d9c6e3deb56465d0759cda57f50c46214Yigit Boyar    List<Expr> mBindingExpressions = new ArrayList<Expr>();
43d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
44d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private int mInvalidateableFieldLimit = 0;
45d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
46d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private int mRequirementIdCount = 0;
47d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
48e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar    // each arg list receives a unique id even if it is the same arguments and method.
49e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar    private int mArgListIdCounter = 0;
50e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar
51d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private static final String TRUE_KEY_SUFFIX = "== true";
52d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private static final String FALSE_KEY_SUFFIX = "== false";
53d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
54d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    /**
55019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar     * Any expression can be invalidated by invalidating this flag.
56019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar     */
57019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    private BitSet mInvalidateAnyFlags;
58eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar    private int mInvalidateAnyFlagIndex;
59019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar
60019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    /**
61d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * Used by code generation. Keeps the list of expressions that are waiting to be evaluated.
62d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     */
63d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private List<Expr> mPendingExpressions;
64d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
65d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    /**
66d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * Used for converting flags into identifiers while debugging.
67d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     */
68d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private String[] mFlagMapping;
69d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
70d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private BitSet mInvalidateableFlags;
71d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private BitSet mConditionalFlags;
72d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
73d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private int mFlagBucketCount;// how many buckets we use to identify flags
74d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
75d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private List<Expr> mObservables;
76d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
77e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar    private boolean mSealed = false;
78e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar
79895b618d9c6e3deb56465d0759cda57f50c46214Yigit Boyar    private Map<String, String> mImports = new HashMap<String, String>();
80a7e767e576adebcddf043ad34ccb8dd167f777b3George Mount
81c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar    private ParserRuleContext mCurrentParserContext;
82c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar    private Location mCurrentLocationInFile;
83d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    /**
84d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * Adds the expression to the list of expressions and returns it.
85d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * If it already exists, returns existing one.
86d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     *
87d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * @param expr The new parsed expression
88d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * @return The expression itself or another one if the same thing was parsed before
89d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     */
90d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public <T extends Expr> T register(T expr) {
912611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        Preconditions.check(!mSealed, "Cannot add expressions to a model after it is sealed");
92c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        Location location = null;
93c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        if (mCurrentParserContext != null) {
94c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar            location = new Location(mCurrentParserContext);
95c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar            location.setParentLocation(mCurrentLocationInFile);
96c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        }
97d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        T existing = (T) mExprMap.get(expr.getUniqueKey());
98d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (existing != null) {
992611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            Preconditions.check(expr.getParents().isEmpty(),
100d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    "If an expression already exists, it should've never been added to a parent,"
101d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                            + "if thats the case, somewhere we are creating an expression w/o"
102d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                            + "calling expression model");
103d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            // tell the expr that it is being swapped so that if it was added to some other expr
104d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            // as a parent, those can swap their references
105d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            expr.onSwappedWith(existing);
106c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar            if (location != null) {
107c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar                existing.addLocation(location);
108c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar            }
109d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            return existing;
110d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
111d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mExprMap.put(expr.getUniqueKey(), expr);
112d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        expr.setModel(this);
113c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        if (location != null) {
114c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar            expr.addLocation(location);
115c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        }
116d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return expr;
117d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
118d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
119c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar    public void setCurrentParserContext(ParserRuleContext currentParserContext) {
120c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        mCurrentParserContext = currentParserContext;
121c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar    }
122c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar
123d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public Map<String, Expr> getExprMap() {
124d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mExprMap;
125d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
126d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
127d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public int size() {
128d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mExprMap.size();
129d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
130d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
131d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public ComparisonExpr comparison(String op, Expr left, Expr right) {
132d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return register(new ComparisonExpr(op, left, right));
133d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
134d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
135c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mount    public InstanceOfExpr instanceOfOp(Expr expr, String type) {
136c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mount        return register(new InstanceOfExpr(expr, type));
137c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mount    }
138c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mount
139d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public FieldAccessExpr field(Expr parent, String name) {
140d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return register(new FieldAccessExpr(parent, name));
141d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
142d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
1437920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount    public FieldAccessExpr observableField(Expr parent, String name) {
1447920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount        return register(new FieldAccessExpr(parent, name, true));
1457920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount    }
1467920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount
147d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public SymbolExpr symbol(String text, Class type) {
148d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return register(new SymbolExpr(text, type));
149d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
150d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
151d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public TernaryExpr ternary(Expr pred, Expr ifTrue, Expr ifFalse) {
152d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return register(new TernaryExpr(pred, ifTrue, ifFalse));
153d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
154d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
155d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public IdentifierExpr identifier(String name) {
156d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return register(new IdentifierExpr(name));
157d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
158d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
159d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public StaticIdentifierExpr staticIdentifier(String name) {
160d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return register(new StaticIdentifierExpr(name));
161d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
162d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
1637c1b078ca84336caba7f811709836562bd5550d6George Mount    public BuiltInVariableExpr builtInVariable(String name, String type, String accessCode) {
1647c1b078ca84336caba7f811709836562bd5550d6George Mount        return register(new BuiltInVariableExpr(name, type, accessCode));
1657c1b078ca84336caba7f811709836562bd5550d6George Mount    }
1667c1b078ca84336caba7f811709836562bd5550d6George Mount
167d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    public ViewFieldExpr viewFieldExpr(BindingTarget bindingTarget) {
168d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        return register(new ViewFieldExpr(bindingTarget));
169d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    }
170d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
171ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar    /**
172ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar     * Creates a static identifier for the given class or returns the existing one.
173ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar     */
174ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar    public StaticIdentifierExpr staticIdentifierFor(final ModelClass modelClass) {
175ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        final String type = modelClass.getCanonicalName();
1762611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        // check for existing
1772611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        for (Expr expr : mExprMap.values()) {
1782611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            if (expr instanceof StaticIdentifierExpr) {
1792611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                StaticIdentifierExpr id = (StaticIdentifierExpr) expr;
1802611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                if (id.getUserDefinedType().equals(type)) {
1812611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                    return id;
182ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar                }
183ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar            }
184ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        }
185ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar
186ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        // does not exist. Find a name for it.
187ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        int cnt = 0;
188ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        int dotIndex = type.lastIndexOf(".");
189ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        String baseName;
1902611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        Preconditions.check(dotIndex < type.length() - 1, "Invalid type %s", type);
191ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        if (dotIndex == -1) {
192ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar            baseName = type;
193ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        } else {
194ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar            baseName = type.substring(dotIndex + 1);
195ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        }
196ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        while (true) {
197ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar            String candidate = cnt == 0 ? baseName : baseName + cnt;
198ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar            if (!mImports.containsKey(candidate)) {
199c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar                return addImport(candidate, type, null);
200ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar            }
201ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar            cnt ++;
2022611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            Preconditions.check(cnt < 100, "Failed to create an import for " + type);
203ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        }
204ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar    }
205ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar
206d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public MethodCallExpr methodCall(Expr target, String name, List<Expr> args) {
207d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return register(new MethodCallExpr(target, name, args));
208d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
209d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
210d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public MathExpr math(Expr left, String op, Expr right) {
211d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return register(new MathExpr(left, op, right));
212d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
213d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
214c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mount    public TernaryExpr logical(Expr left, String op, Expr right) {
215c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mount        if ("&&".equals(op)) {
216c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mount            // left && right
2178533f27db6c31b0c295ae62d314dbf07ea640571Yigit Boyar            // left ? right : false
2188533f27db6c31b0c295ae62d314dbf07ea640571Yigit Boyar            return register(new TernaryExpr(left, right, symbol("false", boolean.class)));
219c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mount        } else {
220c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mount            // left || right
2218533f27db6c31b0c295ae62d314dbf07ea640571Yigit Boyar            // left ? true : right
2228533f27db6c31b0c295ae62d314dbf07ea640571Yigit Boyar            return register(new TernaryExpr(left, symbol("true", boolean.class), right));
223c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mount        }
224c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mount    }
225c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mount
226c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mount    public BitShiftExpr bitshift(Expr left, String op, Expr right) {
227c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mount        return register(new BitShiftExpr(left, op, right));
228c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mount    }
229c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mount
230c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mount    public UnaryExpr unary(String op, Expr expr) {
231c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mount        return register(new UnaryExpr(op, expr));
232c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mount    }
233c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mount
234d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public Expr group(Expr grouped) {
235d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return register(new GroupExpr(grouped));
236d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
237d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
238ae7cb82316e351c488ee3b9c7226602321f34301George Mount    public Expr resourceExpr(String packageName, String resourceType, String resourceName,
239ae7cb82316e351c488ee3b9c7226602321f34301George Mount            List<Expr> args) {
240ae7cb82316e351c488ee3b9c7226602321f34301George Mount        return register(new ResourceExpr(packageName, resourceType, resourceName, args));
241c752a5f795baf6df435ef60881316cb748df407cGeorge Mount    }
242c752a5f795baf6df435ef60881316cb748df407cGeorge Mount
2435cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount    public Expr bracketExpr(Expr variableExpr, Expr argExpr) {
2445cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount        return register(new BracketExpr(variableExpr, argExpr));
2455cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount    }
2465cd681c345db8f606d7d5a8662e20e059f21a86cGeorge Mount
247e4b93061ac703e48fc2c9994c9059ed016f05559George Mount    public Expr castExpr(String type, Expr expr) {
248e4b93061ac703e48fc2c9994c9059ed016f05559George Mount        return register(new CastExpr(type, expr));
249e4b93061ac703e48fc2c9994c9059ed016f05559George Mount    }
250e4b93061ac703e48fc2c9994c9059ed016f05559George Mount
251d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    public TwoWayListenerExpr twoWayListenerExpr(InverseBinding inverseBinding) {
252d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        return register(new TwoWayListenerExpr(inverseBinding));
253d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    }
254d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public List<Expr> getBindingExpressions() {
255d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mBindingExpressions;
256d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
257d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
258c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar    public StaticIdentifierExpr addImport(String alias, String type, Location location) {
2592611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        Preconditions.check(!mImports.containsKey(alias),
260a7e767e576adebcddf043ad34ccb8dd167f777b3George Mount                "%s has already been defined as %s", alias, type);
261a7e767e576adebcddf043ad34ccb8dd167f777b3George Mount        final StaticIdentifierExpr id = staticIdentifier(alias);
262a7e767e576adebcddf043ad34ccb8dd167f777b3George Mount        L.d("adding import %s as %s klass: %s", type, alias, id.getClass().getSimpleName());
263a7e767e576adebcddf043ad34ccb8dd167f777b3George Mount        id.setUserDefinedType(type);
264c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        if (location != null) {
265c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar            id.addLocation(location);
266c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        }
267a7e767e576adebcddf043ad34ccb8dd167f777b3George Mount        mImports.put(alias, type);
268ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        return id;
269a7e767e576adebcddf043ad34ccb8dd167f777b3George Mount    }
270a7e767e576adebcddf043ad34ccb8dd167f777b3George Mount
271a7e767e576adebcddf043ad34ccb8dd167f777b3George Mount    public Map<String, String> getImports() {
272a7e767e576adebcddf043ad34ccb8dd167f777b3George Mount        return mImports;
273a7e767e576adebcddf043ad34ccb8dd167f777b3George Mount    }
274a7e767e576adebcddf043ad34ccb8dd167f777b3George Mount
275d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    /**
276d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * The actual thingy that is set on the binding target.
277d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     *
278d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * Input must be already registered
279d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     */
280d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public Expr bindingExpr(Expr bindingExpr) {
2812611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        Preconditions.check(mExprMap.containsKey(bindingExpr.getUniqueKey()),
282d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                "Main expression should already be registered");
283a70fed6415aa1e8bbbe929aee776402ac3b81c86George Mount        if (!mBindingExpressions.contains(bindingExpr)) {
284a70fed6415aa1e8bbbe929aee776402ac3b81c86George Mount            mBindingExpressions.add(bindingExpr);
285a70fed6415aa1e8bbbe929aee776402ac3b81c86George Mount        }
286d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return bindingExpr;
287d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
288d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
289793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount    public void removeExpr(Expr expr) {
290d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        Preconditions.check(!mSealed, "Can't modify the expression list after sealing the model.");
291793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount        mBindingExpressions.remove(expr);
292793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount        mExprMap.remove(expr.computeUniqueKey());
293793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount    }
294793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount
295d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public List<Expr> getObservables() {
296d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mObservables;
297d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
298d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
299d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    /**
300d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     * Give id to each expression. Will be useful if we serialize.
301d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar     */
302793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount    public void seal() {
3038533f27db6c31b0c295ae62d314dbf07ea640571Yigit Boyar        L.d("sealing model");
304895b618d9c6e3deb56465d0759cda57f50c46214Yigit Boyar        List<Expr> notifiableExpressions = new ArrayList<Expr>();
305d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        //ensure class analyzer. We need to know observables at this point
30679fc7f3727815ab35bb1bb2e060bfb7db3176eedGeorge Mount        final ModelAnalyzer modelAnalyzer = ModelAnalyzer.getInstance();
307ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        updateExpressions(modelAnalyzer);
308d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
309d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        int counter = 0;
31079fc7f3727815ab35bb1bb2e060bfb7db3176eedGeorge Mount        final Iterable<Expr> observables = filterObservables(modelAnalyzer);
3119784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        List<String> flagMapping = new ArrayList<String>();
3129784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        mObservables = new ArrayList<Expr>();
313d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Expr expr : observables) {
314d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            // observables gets initial ids
315d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            flagMapping.add(expr.getUniqueKey());
316d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            expr.setId(counter++);
317d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            mObservables.add(expr);
318dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar            notifiableExpressions.add(expr);
319d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            L.d("observable %s", expr.getUniqueKey());
320d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
321d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
322d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        // non-observable identifiers gets next ids
32379fc7f3727815ab35bb1bb2e060bfb7db3176eedGeorge Mount        final Iterable<Expr> nonObservableIds = filterNonObservableIds(modelAnalyzer);
324d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Expr expr : nonObservableIds) {
325d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            flagMapping.add(expr.getUniqueKey());
326d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            expr.setId(counter++);
327dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar            notifiableExpressions.add(expr);
328d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            L.d("non-observable %s", expr.getUniqueKey());
329d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
330d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
331ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        // descendants of observables gets following ids
332d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Expr expr : observables) {
333d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            for (Expr parent : expr.getParents()) {
334d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                if (parent.hasId()) {
335d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    continue;// already has some id, means observable
336d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
337d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                // only fields earn an id
3389e20571da789c7d50650513c38d5a333b11b9fd3Yigit Boyar                if (parent instanceof FieldAccessExpr) {
3399e20571da789c7d50650513c38d5a333b11b9fd3Yigit Boyar                    FieldAccessExpr fae = (FieldAccessExpr) parent;
3409e20571da789c7d50650513c38d5a333b11b9fd3Yigit Boyar                    L.d("checking field access expr %s. getter: %s", fae,fae.getGetter());
341019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar                    if (fae.isDynamic() && fae.getGetter().canBeInvalidated()) {
3429e20571da789c7d50650513c38d5a333b11b9fd3Yigit Boyar                        flagMapping.add(parent.getUniqueKey());
3439e20571da789c7d50650513c38d5a333b11b9fd3Yigit Boyar                        parent.setId(counter++);
3449e20571da789c7d50650513c38d5a333b11b9fd3Yigit Boyar                        notifiableExpressions.add(parent);
3459e20571da789c7d50650513c38d5a333b11b9fd3Yigit Boyar                        L.d("notifiable field %s : %s for %s : %s", parent.getUniqueKey(),
3469e20571da789c7d50650513c38d5a333b11b9fd3Yigit Boyar                                Integer.toHexString(System.identityHashCode(parent)),
3479e20571da789c7d50650513c38d5a333b11b9fd3Yigit Boyar                                expr.getUniqueKey(),
3489e20571da789c7d50650513c38d5a333b11b9fd3Yigit Boyar                                Integer.toHexString(System.identityHashCode(expr)));
3499e20571da789c7d50650513c38d5a333b11b9fd3Yigit Boyar                    }
350d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
351d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
352d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
353dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar
354d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        // now all 2-way bound view fields
355d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        for (Expr expr : mExprMap.values()) {
356d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount            if (expr instanceof FieldAccessExpr) {
357d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                FieldAccessExpr fieldAccessExpr = (FieldAccessExpr) expr;
358d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                if (fieldAccessExpr.getChild() instanceof ViewFieldExpr) {
359d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                    flagMapping.add(fieldAccessExpr.getUniqueKey());
360d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                    fieldAccessExpr.setId(counter++);
361d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                }
362d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount            }
363d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        }
364d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
365dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar        // non-dynamic binding expressions receive some ids so that they can be invalidated
3668533f27db6c31b0c295ae62d314dbf07ea640571Yigit Boyar        L.d("list of binding expressions");
367a70fed6415aa1e8bbbe929aee776402ac3b81c86George Mount        for (int i = 0; i < mBindingExpressions.size(); i++) {
368c96847768305d83c6bc4919432af9bd9bfe4c08eGeorge Mount            L.d("[%d] %s", i, mBindingExpressions.get(i));
369a70fed6415aa1e8bbbe929aee776402ac3b81c86George Mount        }
3708533f27db6c31b0c295ae62d314dbf07ea640571Yigit Boyar        // we don't assign ids to constant binding expressions because now invalidateAll has its own
3718533f27db6c31b0c295ae62d314dbf07ea640571Yigit Boyar        // flag.
372dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar
373dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar        for (Expr expr : notifiableExpressions) {
374d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            expr.enableDirectInvalidation();
375d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
376d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
377d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        // make sure all dependencies are resolved to avoid future race conditions
378d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Expr expr : mExprMap.values()) {
379d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            expr.getDependencies();
380d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
381eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        mInvalidateAnyFlagIndex = counter ++;
382d1369ca2b7114fa456293695f3850e5be5e6d21eYigit Boyar        flagMapping.add("INVALIDATE ANY");
383658c71b9ba3211ac5c10f261a8c6f38b1916d3bfYigit Boyar        mInvalidateableFieldLimit = counter;
384d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mInvalidateableFlags = new BitSet();
385d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (int i = 0; i < mInvalidateableFieldLimit; i++) {
386d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            mInvalidateableFlags.set(i, true);
387d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
388d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
389d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        // make sure all dependencies are resolved to avoid future race conditions
390d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Expr expr : mExprMap.values()) {
391d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            if (expr.isConditional()) {
3928533f27db6c31b0c295ae62d314dbf07ea640571Yigit Boyar                L.d("requirement id for %s is %d", expr, counter);
393d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                expr.setRequirementId(counter);
394d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                flagMapping.add(expr.getUniqueKey() + FALSE_KEY_SUFFIX);
395d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                flagMapping.add(expr.getUniqueKey() + TRUE_KEY_SUFFIX);
396d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                counter += 2;
397d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
398d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
399d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mConditionalFlags = new BitSet();
400d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (int i = mInvalidateableFieldLimit; i < counter; i++) {
401d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            mConditionalFlags.set(i, true);
402d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
403d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mRequirementIdCount = (counter - mInvalidateableFieldLimit) / 2;
404d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
405d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        // everybody gets an id
406d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Map.Entry<String, Expr> entry : mExprMap.entrySet()) {
407d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            final Expr value = entry.getValue();
408d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            if (!value.hasId()) {
409d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                value.setId(counter++);
410d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
411d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
412d1369ca2b7114fa456293695f3850e5be5e6d21eYigit Boyar
413d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mFlagMapping = new String[flagMapping.size()];
414d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        flagMapping.toArray(mFlagMapping);
415d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
416019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        mFlagBucketCount = 1 + (getTotalFlagCount() / FlagSet.sBucketSize);
417019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        mInvalidateAnyFlags = new BitSet();
418eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        mInvalidateAnyFlags.set(mInvalidateAnyFlagIndex, true);
419019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar
420d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Expr expr : mExprMap.values()) {
421d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            expr.getShouldReadFlagsWithConditionals();
422d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
423d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
424d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Expr expr : mExprMap.values()) {
425d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            // ensure all types are calculated
426d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            expr.getResolvedType();
427d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
428d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
429e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar        mSealed = true;
430d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
431d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
432ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar    /**
433ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar     * Run updateExpr on each binding expression until no new expressions are added.
434ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar     * <p>
435ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar     * Some expressions (e.g. field access) may replace themselves and add/remove new dependencies
436ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar     * so we need to make sure each expression's update is called at least once.
437ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar     */
438ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar    private void updateExpressions(ModelAnalyzer modelAnalyzer) {
439ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        int startSize = -1;
440ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        while (startSize != mExprMap.size()) {
441ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar            startSize = mExprMap.size();
442ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar            ArrayList<Expr> exprs = new ArrayList<Expr>(mBindingExpressions);
443ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar            for (Expr expr : exprs) {
444ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar                expr.updateExpr(modelAnalyzer);
445ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar            }
446ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        }
447ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar    }
448ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar
449d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public int getFlagBucketCount() {
450d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mFlagBucketCount;
451d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
452d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
453d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public int getTotalFlagCount() {
454d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mRequirementIdCount * 2 + mInvalidateableFieldLimit;
455d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
456d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
457d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public int getInvalidateableFieldLimit() {
458d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mInvalidateableFieldLimit;
459d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
460d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
461d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public String[] getFlagMapping() {
462d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mFlagMapping;
463d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
464d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
465d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public String getFlag(int id) {
466d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mFlagMapping[id];
467d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
468d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
4692611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar    private List<Expr> filterNonObservableIds(final ModelAnalyzer modelAnalyzer) {
4709784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        List<Expr> result = new ArrayList<Expr>();
4712611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        for (Expr input : mExprMap.values()) {
4722611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            if (input instanceof IdentifierExpr
4732611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                    && !input.hasId()
4742611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                    && !input.isObservable()
4752611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                    && input.isDynamic()) {
4762611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                result.add(input);
477d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
4782611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        }
4792611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        return result;
480d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
481d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
48279fc7f3727815ab35bb1bb2e060bfb7db3176eedGeorge Mount    private Iterable<Expr> filterObservables(final ModelAnalyzer modelAnalyzer) {
4839784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        List<Expr> result = new ArrayList<Expr>();
4842611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        for (Expr input : mExprMap.values()) {
4852611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            if (input.isObservable()) {
4862611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                result.add(input);
487d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
4882611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        }
4892611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        return result;
490d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
491d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
492d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public List<Expr> getPendingExpressions() {
493d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (mPendingExpressions == null) {
4949784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            mPendingExpressions = new ArrayList<Expr>();
495d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            for (Expr expr : mExprMap.values()) {
49609aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar                // if an expression is NOT dynanic but has conditional dependants, still return it
49709aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar                // so that conditional flags can be set
49809aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar                if (!expr.isRead() && (expr.isDynamic() || expr.hasConditionalDependant())) {
499d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    mPendingExpressions.add(expr);
500d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
501d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
502d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
503d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return mPendingExpressions;
504d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
505d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
506d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public boolean markBitsRead() {
507d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        // each has should read flags, we set them back on them
5089784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        List<Expr> markedSomeFlagsRead = new ArrayList<Expr>();
509d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Expr expr : filterShouldRead(getPendingExpressions())) {
510d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            expr.markFlagsAsRead(expr.getShouldReadFlags());
5117b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar            markedSomeFlagsRead.add(expr);
512d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
5137b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        return pruneDone(markedSomeFlagsRead);
514d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
515d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
5167b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar    private boolean pruneDone(List<Expr> markedSomeFlagsAsRead) {
517d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        boolean marked = true;
5189784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        List<Expr> markedAsReadList = new ArrayList<Expr>();
519d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        while (marked) {
520d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            marked = false;
521d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            for (Expr expr : mExprMap.values()) {
522d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                if (expr.isRead()) {
523d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    continue;
524d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
525d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                if (expr.markAsReadIfDone()) {
526d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    L.d("marked %s as read ", expr.getUniqueKey());
527d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    marked = true;
528d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    markedAsReadList.add(expr);
5297b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar                    markedSomeFlagsAsRead.remove(expr);
530d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
531d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
532d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
533d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        boolean elevated = false;
534d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Expr markedAsRead : markedAsReadList) {
535d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            for (Dependency dependency : markedAsRead.getDependants()) {
536d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                if (dependency.getDependant().considerElevatingConditionals(markedAsRead)) {
537d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    elevated = true;
538d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
539d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
540d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
5417b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        for (Expr partialRead : markedSomeFlagsAsRead) {
542eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar            // even if all paths are not satisfied, we can elevate certain conditional dependencies
543eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar            // if all of their paths are satisfied.
5447b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar            for (Dependency dependency : partialRead.getDependants()) {
545eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                Expr dependant = dependency.getDependant();
546eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                if (dependant.isConditional() && dependant.getAllCalculationPaths()
547eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                        .areAllPathsSatisfied(partialRead.mReadSoFar)) {
548eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                    if (dependant.considerElevatingConditionals(partialRead)) {
549eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                        elevated = true;
550eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                    }
5517b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar                }
5527b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar            }
5537b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        }
554d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (elevated) {
555d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            // some conditionals are elevated. We should re-calculate flags
556d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            for (Expr expr : getPendingExpressions()) {
557d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                if (!expr.isRead()) {
558d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    expr.invalidateReadFlags();
559d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
560d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
561d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            mPendingExpressions = null;
562d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
563d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return elevated;
564d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
565d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
5662611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar    private static boolean hasConditionalOrNestedCannotReadDependency(Expr expr) {
5672611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        for (Dependency dependency : expr.getDependencies()) {
5682611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            if (dependency.isConditional() || dependency.getOther().hasNestedCannotRead()) {
5692611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                return true;
5702611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            }
5712611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        }
5722611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        return false;
573d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
574d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
5752611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar    public static List<Expr> filterShouldRead(Iterable<Expr> exprs) {
5769784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        List<Expr> result = new ArrayList<Expr>();
5772611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        for (Expr expr : exprs) {
5782611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            if (!expr.getShouldReadFlags().isEmpty() &&
5792611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                    !hasConditionalOrNestedCannotReadDependency(expr)) {
5802611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                result.add(expr);
5812611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            }
582d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
5832611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        return result;
5842611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar    }
585d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
586d1369ca2b7114fa456293695f3850e5be5e6d21eYigit Boyar    /**
587d1369ca2b7114fa456293695f3850e5be5e6d21eYigit Boyar     * May return null if flag is equal to invalidate any flag.
588d1369ca2b7114fa456293695f3850e5be5e6d21eYigit Boyar     */
589d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public Expr findFlagExpression(int flag) {
590d1369ca2b7114fa456293695f3850e5be5e6d21eYigit Boyar        if (mInvalidateAnyFlags.get(flag)) {
591d1369ca2b7114fa456293695f3850e5be5e6d21eYigit Boyar            return null;
592d1369ca2b7114fa456293695f3850e5be5e6d21eYigit Boyar        }
593d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        final String key = mFlagMapping[flag];
594d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (mExprMap.containsKey(key)) {
595d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            return mExprMap.get(key);
596d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
597d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        int falseIndex = key.indexOf(FALSE_KEY_SUFFIX);
598d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (falseIndex > -1) {
599d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            final String trimmed = key.substring(0, falseIndex);
600d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            return mExprMap.get(trimmed);
601d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
602d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        int trueIndex = key.indexOf(TRUE_KEY_SUFFIX);
603d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (trueIndex > -1) {
604d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            final String trimmed = key.substring(0, trueIndex);
605d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            return mExprMap.get(trimmed);
606d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
607d1369ca2b7114fa456293695f3850e5be5e6d21eYigit Boyar        // log everything we call
608d1369ca2b7114fa456293695f3850e5be5e6d21eYigit Boyar        StringBuilder error = new StringBuilder();
609d1369ca2b7114fa456293695f3850e5be5e6d21eYigit Boyar        error.append("cannot find flag:").append(flag).append("\n");
610d1369ca2b7114fa456293695f3850e5be5e6d21eYigit Boyar        error.append("invalidate any flag:").append(mInvalidateAnyFlags).append("\n");
611d1369ca2b7114fa456293695f3850e5be5e6d21eYigit Boyar        error.append("key:").append(key).append("\n");
612d1369ca2b7114fa456293695f3850e5be5e6d21eYigit Boyar        error.append("flag mapping:").append(Arrays.toString(mFlagMapping));
6132611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        L.e(error.toString());
614d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return null;
615d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
616019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar
617019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    public BitSet getInvalidateAnyBitSet() {
618019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        return mInvalidateAnyFlags;
619019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    }
620e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar
621eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar    public int getInvalidateAnyFlagIndex() {
622eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        return mInvalidateAnyFlagIndex;
623eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar    }
624eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar
625e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar    public Expr argListExpr(Iterable<Expr> expressions) {
626e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar        return register(new ArgListExpr(mArgListIdCounter ++, expressions));
627e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar    }
628716ba89e7f459f49ea85070d4710c1d79d715298George Mount
629c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar    public void setCurrentLocationInFile(Location location) {
630c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        mCurrentLocationInFile = location;
631c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar    }
632c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar
633793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount    public Expr listenerExpr(Expr expression, String name, ModelClass listenerType,
634793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount            ModelMethod listenerMethod) {
635793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount        return register(new ListenerExpr(expression, name, listenerType, listenerMethod));
636716ba89e7f459f49ea85070d4710c1d79d715298George Mount    }
637d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
638