ExpressionVisitor.java revision c6bcb7bf9cab139b3141c4644e5b3267deed5213
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 17package android.databinding.tool; 18 19import com.google.common.base.Preconditions; 20 21import org.antlr.v4.runtime.misc.NotNull; 22import org.antlr.v4.runtime.tree.ParseTree; 23import org.antlr.v4.runtime.tree.TerminalNode; 24import org.apache.commons.lang3.ObjectUtils; 25 26import android.databinding.parser.BindingExpressionBaseVisitor; 27import android.databinding.parser.BindingExpressionParser; 28import android.databinding.parser.BindingExpressionParser.AndOrOpContext; 29import android.databinding.parser.BindingExpressionParser.BinaryOpContext; 30import android.databinding.parser.BindingExpressionParser.BitShiftOpContext; 31import android.databinding.parser.BindingExpressionParser.InstanceOfOpContext; 32import android.databinding.parser.BindingExpressionParser.UnaryOpContext; 33import android.databinding.tool.expr.Expr; 34import android.databinding.tool.expr.ExprModel; 35import android.databinding.tool.expr.StaticIdentifierExpr; 36import android.databinding.tool.reflection.ModelAnalyzer; 37import android.databinding.tool.reflection.ModelClass; 38 39import java.util.ArrayList; 40import java.util.List; 41 42public class ExpressionVisitor extends BindingExpressionBaseVisitor<Expr> { 43 private final ExprModel mModel; 44 public ExpressionVisitor(ExprModel model) { 45 mModel = model; 46 } 47 48 @Override 49 public Expr visitStringLiteral(@NotNull BindingExpressionParser.StringLiteralContext ctx) { 50 final String javaString; 51 if (ctx.SingleQuoteString() != null) { 52 String str = ctx.SingleQuoteString().getText(); 53 String contents = str.substring(1, str.length() - 1); 54 contents = contents.replace("\"", "\\\"").replace("\\`", "`"); 55 javaString = '"' + contents + '"'; 56 } else { 57 javaString = ctx.DoubleQuoteString().getText(); 58 } 59 60 return mModel.symbol(javaString, String.class); 61 } 62 63 @Override 64 public Expr visitGrouping(@NotNull BindingExpressionParser.GroupingContext ctx) { 65 Preconditions.checkArgument(ctx.children.size() == 3, "Grouping expression should have" 66 + " 3 children. # of children: %d", ctx.children.size()); 67 return mModel.group(ctx.children.get(1).accept(this)); 68 } 69 70 @Override 71 public Expr visitBindingSyntax(@NotNull BindingExpressionParser.BindingSyntaxContext ctx) { 72 try { 73 // TODO handle defaults 74 return mModel.bindingExpr(ctx.expression().accept(this)); 75 } catch (Exception e) { 76 System.out.println("Error while parsing! " + ctx.getText()); 77 e.printStackTrace(); 78 throw new RuntimeException(e); 79 } 80 } 81 82 @Override 83 public Expr visitDotOp(@NotNull BindingExpressionParser.DotOpContext ctx) { 84 ModelAnalyzer analyzer = ModelAnalyzer.getInstance(); 85 ModelClass modelClass = analyzer.findClass(ctx.getText(), mModel.getImports()); 86 if (modelClass == null) { 87 return mModel.field(ctx.expression().accept(this), 88 ctx.Identifier().getSymbol().getText()); 89 } else { 90 String name = modelClass.toJavaCode(); 91 StaticIdentifierExpr expr = mModel.staticIdentifier(name); 92 expr.setUserDefinedType(name); 93 return expr; 94 } 95 } 96 97 @Override 98 public Expr visitQuestionQuestionOp(@NotNull BindingExpressionParser.QuestionQuestionOpContext ctx) { 99 final Expr left = ctx.left.accept(this); 100 return mModel.ternary(mModel.comparison("==", left, mModel.symbol("null", Object.class)), 101 ctx.right.accept(this), left); 102 } 103 104 @Override 105 public Expr visitTerminal(@NotNull TerminalNode node) { 106 final int type = node.getSymbol().getType(); 107 Class classType; 108 switch (type) { 109 case BindingExpressionParser.IntegerLiteral: 110 classType = int.class; 111 break; 112 case BindingExpressionParser.FloatingPointLiteral: 113 classType = float.class; 114 break; 115 case BindingExpressionParser.BooleanLiteral: 116 classType = boolean.class; 117 break; 118 case BindingExpressionParser.CharacterLiteral: 119 classType = char.class; 120 break; 121 case BindingExpressionParser.SingleQuoteString: 122 case BindingExpressionParser.DoubleQuoteString: 123 classType = String.class; 124 break; 125 case BindingExpressionParser.NullLiteral: 126 classType = Object.class; 127 break; 128 default: 129 throw new RuntimeException("cannot create expression from terminal node " + node.toString()); 130 } 131 return mModel.symbol(node.getText(), classType); 132 } 133 134 @Override 135 public Expr visitComparisonOp(@NotNull BindingExpressionParser.ComparisonOpContext ctx) { 136 return mModel.comparison(ctx.op.getText(), ctx.left.accept(this), ctx.right.accept(this)); 137 } 138 139 @Override 140 public Expr visitIdentifier(@NotNull BindingExpressionParser.IdentifierContext ctx) { 141 return mModel.identifier(ctx.getText()); 142 } 143 144 @Override 145 public Expr visitTernaryOp(@NotNull BindingExpressionParser.TernaryOpContext ctx) { 146 return mModel.ternary(ctx.left.accept(this), ctx.iftrue.accept(this), 147 ctx.iffalse.accept(this)); 148 } 149 150 @Override 151 public Expr visitMethodInvocation( 152 @NotNull BindingExpressionParser.MethodInvocationContext ctx) { 153 List<Expr> args = new ArrayList<Expr>(); 154 if (ctx.args != null) { 155 for (ParseTree item : ctx.args.children) { 156 if (ObjectUtils.equals(item.getText(), ",")) { 157 continue; 158 } 159 args.add(item.accept(this)); 160 } 161 } 162 return mModel.methodCall(ctx.target.accept(this), 163 ctx.Identifier().getText(), args); 164 } 165 166 @Override 167 public Expr visitMathOp(@NotNull BindingExpressionParser.MathOpContext ctx) { 168 return mModel.math(ctx.left.accept(this), ctx.op.getText(), ctx.right.accept(this)); 169 } 170 171 @Override 172 public Expr visitAndOrOp(@NotNull AndOrOpContext ctx) { 173 return mModel.logical(ctx.left.accept(this), ctx.op.getText(), ctx.right.accept(this)); 174 } 175 176 @Override 177 public Expr visitBinaryOp(@NotNull BinaryOpContext ctx) { 178 return mModel.math(ctx.left.accept(this), ctx.op.getText(), ctx.right.accept(this)); 179 } 180 181 @Override 182 public Expr visitBitShiftOp(@NotNull BitShiftOpContext ctx) { 183 return mModel.bitshift(ctx.left.accept(this), ctx.op.getText(), ctx.right.accept(this)); 184 } 185 186 @Override 187 public Expr visitInstanceOfOp(@NotNull InstanceOfOpContext ctx) { 188 return mModel.instanceOfOp(ctx.expression().accept(this), ctx.type().getText()); 189 } 190 191 @Override 192 public Expr visitUnaryOp(@NotNull UnaryOpContext ctx) { 193 return mModel.unary(ctx.op.getText(), ctx.expression().accept(this)); 194 } 195 196 @Override 197 public Expr visitResources(@NotNull BindingExpressionParser.ResourcesContext ctx) { 198 final List<Expr> args = new ArrayList<Expr>(); 199 if (ctx.resourceParameters() != null) { 200 for (ParseTree item : ctx.resourceParameters().expressionList().children) { 201 if (ObjectUtils.equals(item.getText(), ",")) { 202 continue; 203 } 204 args.add(item.accept(this)); 205 } 206 } 207 final String resourceReference = ctx.ResourceReference().getText(); 208 final int colonIndex = resourceReference.indexOf(':'); 209 final int slashIndex = resourceReference.indexOf('/'); 210 final String packageName = colonIndex < 0 ? null : 211 resourceReference.substring(1, colonIndex).trim(); 212 final int startIndex = Math.max(1, colonIndex + 1); 213 final String resourceType = resourceReference.substring(startIndex, slashIndex).trim(); 214 final String resourceName = resourceReference.substring(slashIndex + 1).trim(); 215 return mModel.resourceExpr(packageName, resourceType, resourceName, args); 216 } 217 218 @Override 219 public Expr visitBracketOp(@NotNull BindingExpressionParser.BracketOpContext ctx) { 220 return mModel.bracketExpr(visit(ctx.expression(0)), visit(ctx.expression(1))); 221 } 222 223 @Override 224 public Expr visitCastOp(@NotNull BindingExpressionParser.CastOpContext ctx) { 225 return mModel.castExpr(ctx.type().getText(), visit(ctx.expression())); 226 } 227 228 // @Override 229// public Expr visitIdentifier(@NotNull BindingExpressionParser.IdentifierContext ctx) { 230// final String identifier = ctx.Identifier().getText(); 231// final VariableRef variableRef = mModel.getOrCreateVariable(identifier, null); 232// mAccessedVariables.add(variableRef); 233// 234// return new FieldExpr(variableRef, new ArrayList<VariableRef>(0)); 235// } 236// 237// @Override 238// public Expr visit(@NotNull ParseTree tree) { 239// if (tree == null) { 240// return null; 241// } 242// return super.visit(tree); 243// } 244// 245// @Override 246// public Expr visitTernaryOp(@NotNull BindingExpressionParser.TernaryOpContext ctx) { 247// return new TernaryExpr(ctx.left.accept(this), ctx.iftrue.accept(this), ctx.iffalse.accept(this)); 248// } 249// 250// @Override 251// public Expr visitTerminal(@NotNull TerminalNode node) { 252// 253// final int type = node.getSymbol().getType(); 254// switch (type) { 255// case IntegerLiteral: 256// return new SymbolExpr(node.getText(), Integer.class); 257// case FloatingPointLiteral: 258// return new SymbolExpr(node.getText(), Float.class); 259// case BooleanLiteral: 260// return new SymbolExpr(node.getText(), Boolean.class); 261// case CharacterLiteral: 262// return new SymbolExpr(node.getText(), Character.class); 263// case SingleQuoteString: 264// return new SymbolExpr(node.getText(), String.class); 265// case DoubleQuoteString: 266// return new SymbolExpr(node.getText(), String.class); 267// case NullLiteral: 268// return new SymbolExpr(node.getText(), Object.class); 269// default: 270// throw new RuntimeException("cannot create expression from terminal node " + node.toString()); 271// } 272// } 273// 274// @Override 275// public Expr visitMathOp(@NotNull BindingExpressionParser.MathOpContext ctx) { 276// // TODO must support upper cast 277// return new OpExpr(ctx.left.accept(this), ctx.op.getText(), ctx.right.accept(this)); 278// } 279// 280// @Override 281// public Expr visitBitShiftOp(@NotNull BindingExpressionParser.BitShiftOpContext ctx) { 282// return new BinaryOpExpr(ctx.left.accept(this), ctx.op.getText(), ctx.right.accept(this)); 283// } 284// 285// @Override 286// public Expr visitComparisonOp(@NotNull BindingExpressionParser.ComparisonOpContext ctx) { 287// return new ComparisonOpExpr(ctx.left.accept(this), ctx.op.getText(), ctx.right.accept(this)); 288// } 289// 290// @Override 291// public Expr visitBinaryOp(@NotNull BindingExpressionParser.BinaryOpContext ctx) { 292// return new BinaryOpExpr(ctx.left.accept(this), ctx.op.getText(), ctx.right.accept(this)); 293// } 294// 295// @Override 296// public Expr visitAndOrOp(@NotNull BindingExpressionParser.AndOrOpContext ctx) { 297// return new AndOrOpExpr(ctx.left.accept(this), ctx.op.getText(), ctx.right.accept(this)); 298// } 299// 300// @Override 301// protected Expr aggregateResult(final Expr aggregate, final Expr nextResult) { 302// if (aggregate == null) { 303// return nextResult; 304// } else { 305// return new Expr() { 306// @org.jetbrains.annotations.NotNull 307// @Override 308// public Class<? extends Object> resolveValueType( 309// @org.jetbrains.annotations.NotNull ModelAnalyzer modelAnalyzer) { 310// return modelAnalyzer.commonParentOf(aggregate.getResolvedClass(), nextResult.getResolvedClass()); 311// } 312// 313// @org.jetbrains.annotations.NotNull 314// @Override 315// public String toReadableString() { 316// return aggregate.toReadableString() + ' ' + nextResult.toReadableString(); 317// } 318// 319// @org.jetbrains.annotations.NotNull 320// @Override 321// public String toJava() { 322// return aggregate.toJava() + ' ' + nextResult.toJava(); 323// } 324// }; 325// } 326// } 327// 328// @Override 329// public Expr visitDefaults(@NotNull BindingExpressionParser.DefaultsContext ctx) { 330// return visit(ctx.constantValue()); 331// } 332// 333// @Override 334// public Expr visitMethodInvocation( 335// @NotNull BindingExpressionParser.MethodInvocationContext ctx) { 336// final Expr expression = visit(ctx.expression()); 337// final String methodName = ctx.Identifier().getText(); 338// final ArrayList<Expr> parameters = new ArrayList<>(); 339// if (ctx.expressionList() != null) { 340// for (BindingExpressionParser.ExpressionContext parameter : ctx.expressionList() 341// .expression()) { 342// parameters.add(visit(parameter)); 343// } 344// } 345// return new MethodCallExpr(expression, methodName, parameters); 346// } 347} 348