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