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