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