1/*
2 * Copyright (C) 2010 Google Inc.
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 com.google.clearsilver.jsilver.interpreter;
18
19import com.google.clearsilver.jsilver.syntax.analysis.DepthFirstAdapter;
20import com.google.clearsilver.jsilver.syntax.node.ADecNumberVariable;
21import com.google.clearsilver.jsilver.syntax.node.ADescendVariable;
22import com.google.clearsilver.jsilver.syntax.node.AExpandVariable;
23import com.google.clearsilver.jsilver.syntax.node.AHexNumberVariable;
24import com.google.clearsilver.jsilver.syntax.node.ANameVariable;
25import com.google.clearsilver.jsilver.syntax.node.PVariable;
26import com.google.clearsilver.jsilver.values.Value;
27
28/**
29 * Walks a PVariable node from the parse tree and returns a Data path name.
30 *
31 * @see #getVariableName(com.google.clearsilver.jsilver.syntax.node.PVariable)
32 */
33public class VariableLocator extends DepthFirstAdapter {
34
35  private StringBuilder currentName;
36
37  private final ExpressionEvaluator expressionEvaluator;
38
39  public VariableLocator(ExpressionEvaluator expressionEvaluator) {
40    this.expressionEvaluator = expressionEvaluator;
41  }
42
43  /**
44   * If the root PVariable we are evaluating is a simple one then skip creating the StringBuilder
45   * and descending the tree.
46   *
47   * @param variable the variable node to evaluate.
48   * @return a String representing the Variable name, or {@code null} if it is a compound variable
49   *         node.
50   */
51  private String quickEval(PVariable variable) {
52    if (variable instanceof ANameVariable) {
53      return ((ANameVariable) variable).getWord().getText();
54    } else if (variable instanceof ADecNumberVariable) {
55      return ((ADecNumberVariable) variable).getDecNumber().getText();
56    } else if (variable instanceof AHexNumberVariable) {
57      return ((AHexNumberVariable) variable).getHexNumber().getText();
58    } else {
59      // This is a compound variable. Evaluate the slow way.
60      return null;
61    }
62  }
63
64  /**
65   * Returns a Data variable name extracted during evaluation.
66   *
67   * @param variable the parsed variable name node to traverse
68   */
69  public String getVariableName(PVariable variable) {
70    String result = quickEval(variable);
71    if (result != null) {
72      return result;
73    }
74    StringBuilder lastName = currentName;
75    currentName = new StringBuilder(10);
76    variable.apply(this);
77    result = currentName.toString();
78    currentName = lastName;
79    return result;
80  }
81
82  @Override
83  public void caseANameVariable(ANameVariable node) {
84    descendVariable(node.getWord().getText());
85  }
86
87  @Override
88  public void caseADecNumberVariable(ADecNumberVariable node) {
89    descendVariable(node.getDecNumber().getText());
90  }
91
92  @Override
93  public void caseAHexNumberVariable(AHexNumberVariable node) {
94    descendVariable(node.getHexNumber().getText());
95  }
96
97  @Override
98  public void caseADescendVariable(ADescendVariable node) {
99    node.getParent().apply(this);
100    node.getChild().apply(this);
101  }
102
103  @Override
104  public void caseAExpandVariable(AExpandVariable node) {
105    node.getParent().apply(this);
106    Value value = expressionEvaluator.evaluate(node.getChild());
107    descendVariable(value.asString());
108  }
109
110  private void descendVariable(String name) {
111    if (currentName.length() != 0) {
112      currentName.append('.');
113    }
114    currentName.append(name);
115  }
116}
117