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