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