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 19fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.reflection.ModelAnalyzer; 20fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.reflection.ModelClass; 21e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mountimport android.databinding.tool.writer.KCode; 22d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar 232611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyarimport java.util.ArrayList; 24d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarimport java.util.BitSet; 25d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarimport java.util.List; 26d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar 27d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarpublic class TernaryExpr extends Expr { 28d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar TernaryExpr(Expr pred, Expr ifTrue, Expr ifFalse) { 29d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar super(pred, ifTrue, ifFalse); 30d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar } 31d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar 32d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar public Expr getPred() { 337920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount return getChildren().get(0); 34d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar } 35d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar 36d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar public Expr getIfTrue() { 377920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount return getChildren().get(1); 38d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar } 39d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar 40d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar public Expr getIfFalse() { 417920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount return getChildren().get(2); 42d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar } 43d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar 44d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar @Override 45d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar protected String computeUniqueKey() { 46d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar return "?:" + super.computeUniqueKey(); 47d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar } 48d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar 49d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar @Override 50d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount public String getInvertibleError() { 51d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount if (getPred().isDynamic()) { 52d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount return "The condition of a ternary operator must be constant: " + 53d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount getPred().toFullCode(); 54d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } 55d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount final String trueInvertible = getIfTrue().getInvertibleError(); 56d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount if (trueInvertible != null) { 57d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount return trueInvertible; 58d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } else { 59d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount return getIfFalse().getInvertibleError(); 60d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } 61d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } 62d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount 63d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount @Override 6479fc7f3727815ab35bb1bb2e060bfb7db3176eedGeorge Mount protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) { 6591beb3a1a89a58b1c0b6b874d889394a3be90b6cGeorge Mount final Expr ifTrue = getIfTrue(); 6691beb3a1a89a58b1c0b6b874d889394a3be90b6cGeorge Mount final Expr ifFalse = getIfFalse(); 6791beb3a1a89a58b1c0b6b874d889394a3be90b6cGeorge Mount if (isNullLiteral(ifTrue)) { 6891beb3a1a89a58b1c0b6b874d889394a3be90b6cGeorge Mount return ifFalse.getResolvedType(); 6991beb3a1a89a58b1c0b6b874d889394a3be90b6cGeorge Mount } else if (isNullLiteral(ifFalse)) { 7091beb3a1a89a58b1c0b6b874d889394a3be90b6cGeorge Mount return ifTrue.getResolvedType(); 7191beb3a1a89a58b1c0b6b874d889394a3be90b6cGeorge Mount } 7279fc7f3727815ab35bb1bb2e060bfb7db3176eedGeorge Mount return modelAnalyzer.findCommonParentOf(getIfTrue().getResolvedType(), 737920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount getIfFalse().getResolvedType()); 74d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar } 75d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar 7691beb3a1a89a58b1c0b6b874d889394a3be90b6cGeorge Mount private static boolean isNullLiteral(Expr expr) { 7791beb3a1a89a58b1c0b6b874d889394a3be90b6cGeorge Mount final ModelClass type = expr.getResolvedType(); 7891beb3a1a89a58b1c0b6b874d889394a3be90b6cGeorge Mount return (type.isObject() && (expr instanceof SymbolExpr) && 7991beb3a1a89a58b1c0b6b874d889394a3be90b6cGeorge Mount "null".equals(((SymbolExpr)expr).getText())); 8091beb3a1a89a58b1c0b6b874d889394a3be90b6cGeorge Mount } 8191beb3a1a89a58b1c0b6b874d889394a3be90b6cGeorge Mount 82d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar @Override 83d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar protected List<Dependency> constructDependencies() { 849784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar List<Dependency> deps = new ArrayList<Dependency>(); 857920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount Expr predExpr = getPred(); 8609aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar final Dependency pred = new Dependency(this, predExpr); 8709aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar pred.setMandatory(true); 8809aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar deps.add(pred); 8909aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar 907920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount Expr ifTrueExpr = getIfTrue(); 917920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount if (ifTrueExpr.isDynamic()) { 927920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount deps.add(new Dependency(this, ifTrueExpr, predExpr, true)); 93d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar } 947920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount Expr ifFalseExpr = getIfFalse(); 957920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount if (ifFalseExpr.isDynamic()) { 967920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount deps.add(new Dependency(this, ifFalseExpr, predExpr, false)); 97d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar } 98d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar return deps; 99d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar } 100d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar 101d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar @Override 102d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar protected BitSet getPredicateInvalidFlags() { 1037920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount return getPred().getInvalidFlags(); 104d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar } 105d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar 106d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar @Override 107d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount protected KCode generateCode(boolean expand) { 108e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount return new KCode() 109d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount .app("", getPred().toCode(expand)) 110d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount .app(" ? ", getIfTrue().toCode(expand)) 111d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount .app(" : ", getIfFalse().toCode(expand)); 112e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount 113e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount } 114e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount 115e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount @Override 116d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount public KCode toInverseCode(KCode variable) { 117d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount return new KCode() 118d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount .app("if (", getPred().toCode(true)) 119d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount .app(") {") 120d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount .tab(getIfTrue().toInverseCode(variable)) 121d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount .nl(new KCode("} else {")) 122d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount .tab(getIfFalse().toInverseCode(variable)) 123d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount .nl(new KCode("}")); 124d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } 125d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount 126d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount @Override 127d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar public boolean isConditional() { 128d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar return true; 129d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar } 130d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar} 131