1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.databinding.tool.expr; 18 19 import android.databinding.tool.reflection.ModelAnalyzer; 20 import android.databinding.tool.reflection.ModelClass; 21 import android.databinding.tool.writer.KCode; 22 23 import java.util.ArrayList; 24 import java.util.BitSet; 25 import java.util.List; 26 27 public class TernaryExpr extends Expr { TernaryExpr(Expr pred, Expr ifTrue, Expr ifFalse)28 TernaryExpr(Expr pred, Expr ifTrue, Expr ifFalse) { 29 super(pred, ifTrue, ifFalse); 30 } 31 getPred()32 public Expr getPred() { 33 return getChildren().get(0); 34 } 35 getIfTrue()36 public Expr getIfTrue() { 37 return getChildren().get(1); 38 } 39 getIfFalse()40 public Expr getIfFalse() { 41 return getChildren().get(2); 42 } 43 44 @Override computeUniqueKey()45 protected String computeUniqueKey() { 46 return "?:" + super.computeUniqueKey(); 47 } 48 49 @Override getInvertibleError()50 public String getInvertibleError() { 51 if (getPred().isDynamic()) { 52 return "The condition of a ternary operator must be constant: " + 53 getPred().toFullCode(); 54 } 55 final String trueInvertible = getIfTrue().getInvertibleError(); 56 if (trueInvertible != null) { 57 return trueInvertible; 58 } else { 59 return getIfFalse().getInvertibleError(); 60 } 61 } 62 63 @Override resolveType(ModelAnalyzer modelAnalyzer)64 protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) { 65 final Expr ifTrue = getIfTrue(); 66 final Expr ifFalse = getIfFalse(); 67 if (isNullLiteral(ifTrue)) { 68 return ifFalse.getResolvedType(); 69 } else if (isNullLiteral(ifFalse)) { 70 return ifTrue.getResolvedType(); 71 } 72 return modelAnalyzer.findCommonParentOf(getIfTrue().getResolvedType(), 73 getIfFalse().getResolvedType()); 74 } 75 isNullLiteral(Expr expr)76 private static boolean isNullLiteral(Expr expr) { 77 final ModelClass type = expr.getResolvedType(); 78 return (type.isObject() && (expr instanceof SymbolExpr) && 79 "null".equals(((SymbolExpr)expr).getText())); 80 } 81 82 @Override constructDependencies()83 protected List<Dependency> constructDependencies() { 84 List<Dependency> deps = new ArrayList<Dependency>(); 85 Expr predExpr = getPred(); 86 final Dependency pred = new Dependency(this, predExpr); 87 pred.setMandatory(true); 88 deps.add(pred); 89 90 Expr ifTrueExpr = getIfTrue(); 91 if (ifTrueExpr.isDynamic()) { 92 deps.add(new Dependency(this, ifTrueExpr, predExpr, true)); 93 } 94 Expr ifFalseExpr = getIfFalse(); 95 if (ifFalseExpr.isDynamic()) { 96 deps.add(new Dependency(this, ifFalseExpr, predExpr, false)); 97 } 98 return deps; 99 } 100 101 @Override getPredicateInvalidFlags()102 protected BitSet getPredicateInvalidFlags() { 103 return getPred().getInvalidFlags(); 104 } 105 106 @Override generateCode(boolean expand)107 protected KCode generateCode(boolean expand) { 108 return new KCode() 109 .app("", getPred().toCode(expand)) 110 .app(" ? ", getIfTrue().toCode(expand)) 111 .app(" : ", getIfFalse().toCode(expand)); 112 113 } 114 115 @Override toInverseCode(KCode variable)116 public KCode toInverseCode(KCode variable) { 117 return new KCode() 118 .app("if (", getPred().toCode(true)) 119 .app(") {") 120 .tab(getIfTrue().toInverseCode(variable)) 121 .nl(new KCode("} else {")) 122 .tab(getIfFalse().toInverseCode(variable)) 123 .nl(new KCode("}")); 124 } 125 126 @Override isConditional()127 public boolean isConditional() { 128 return true; 129 } 130 } 131