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