• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package android.databinding.tool;
18 
19 import com.google.common.base.Objects;
20 
21 import org.antlr.v4.runtime.ParserRuleContext;
22 import org.antlr.v4.runtime.misc.NotNull;
23 import org.antlr.v4.runtime.tree.ParseTree;
24 import org.antlr.v4.runtime.tree.ParseTreeListener;
25 import org.antlr.v4.runtime.tree.TerminalNode;
26 
27 import android.databinding.parser.BindingExpressionBaseVisitor;
28 import android.databinding.parser.BindingExpressionParser;
29 import android.databinding.parser.BindingExpressionParser.AndOrOpContext;
30 import android.databinding.parser.BindingExpressionParser.BinaryOpContext;
31 import android.databinding.parser.BindingExpressionParser.BitShiftOpContext;
32 import android.databinding.parser.BindingExpressionParser.InstanceOfOpContext;
33 import android.databinding.parser.BindingExpressionParser.UnaryOpContext;
34 import android.databinding.tool.expr.Expr;
35 import android.databinding.tool.expr.ExprModel;
36 import android.databinding.tool.expr.StaticIdentifierExpr;
37 import android.databinding.tool.reflection.ModelAnalyzer;
38 import android.databinding.tool.reflection.ModelClass;
39 import android.databinding.tool.util.Preconditions;
40 
41 import java.util.ArrayList;
42 import java.util.List;
43 
44 public class ExpressionVisitor extends BindingExpressionBaseVisitor<Expr> {
45     private final ExprModel mModel;
46     private ParseTreeListener mParseTreeListener;
47 
ExpressionVisitor(ExprModel model)48     public ExpressionVisitor(ExprModel model) {
49         mModel = model;
50     }
51 
setParseTreeListener(ParseTreeListener parseTreeListener)52     public void setParseTreeListener(ParseTreeListener parseTreeListener) {
53         mParseTreeListener = parseTreeListener;
54     }
55 
onEnter(ParserRuleContext context)56     private void onEnter(ParserRuleContext context) {
57         if (mParseTreeListener != null) {
58             mParseTreeListener.enterEveryRule(context);
59         }
60     }
61 
onExit(ParserRuleContext context)62     private void onExit(ParserRuleContext context) {
63         if (mParseTreeListener != null) {
64             mParseTreeListener.exitEveryRule(context);
65         }
66     }
67 
68     @Override
visitStringLiteral(@otNull BindingExpressionParser.StringLiteralContext ctx)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
visitGrouping(@otNull BindingExpressionParser.GroupingContext ctx)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
visitBindingSyntax(@otNull BindingExpressionParser.BindingSyntaxContext ctx)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
visitDotOp(@otNull BindingExpressionParser.DotOpContext ctx)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
visitQuestionQuestionOp(@otNull BindingExpressionParser.QuestionQuestionOpContext ctx)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
visitTerminal(@otNull TerminalNode node)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
visitComparisonOp(@otNull BindingExpressionParser.ComparisonOpContext ctx)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
visitIdentifier(@otNull BindingExpressionParser.IdentifierContext ctx)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
visitTernaryOp(@otNull BindingExpressionParser.TernaryOpContext ctx)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
visitMethodInvocation( @otNull BindingExpressionParser.MethodInvocationContext ctx)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
visitMathOp(@otNull BindingExpressionParser.MathOpContext ctx)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
visitAndOrOp(@otNull AndOrOpContext ctx)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
visitBinaryOp(@otNull BinaryOpContext ctx)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
visitBitShiftOp(@otNull BitShiftOpContext ctx)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
visitInstanceOfOp(@otNull InstanceOfOpContext ctx)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
visitUnaryOp(@otNull UnaryOpContext ctx)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
visitResources(@otNull BindingExpressionParser.ResourcesContext ctx)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