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