1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.commons.jexl.parser;
17
18 import org.apache.commons.jexl.JexlContext;
19
20 /***
21 * reference - any variable expression.
22 *
23 * @author <a href="mailto:geirm@apache.org">Geir Magnusson Jr.</a>
24 * @version $Id: ASTReference.java 398272 2006-04-30 03:14:01Z dion $
25 */
26 public class ASTReference extends SimpleNode {
27 /*** first variable in the expression. */
28 protected SimpleNode root;
29
30 /***
31 * Create the node given an id.
32 *
33 * @param id node id.
34 */
35 public ASTReference(int id) {
36 super(id);
37 }
38
39 /***
40 * Create a node with the given parser and id.
41 *
42 * @param p a parser.
43 * @param id node id.
44 */
45 public ASTReference(Parser p, int id) {
46 super(p, id);
47 }
48
49 /*** {@inheritDoc} */
50 public Object jjtAccept(ParserVisitor visitor, Object data) {
51 return visitor.visit(this, data);
52 }
53
54 /*** {@inheritDoc} */
55 public Object value(JexlContext jc) throws Exception {
56 return execute(null, jc);
57 }
58
59 /*** Store the first child as {@link ASTReference#root root}. */
60 public void jjtClose() {
61 root = (SimpleNode) jjtGetChild(0);
62 }
63
64 /***
65 * evaluate each piece of the reference.
66 *
67 * e.g. foo.bar.woogie[2].name, foo is our 'root', and we need to
68 * evaluate 'bar.woogie[2].name' relative to foo.
69 *
70 * @param jc the {@link JexlContext} to evaluate against.
71 * @param obj not used. root.value(jc) is used instead.
72 * @return the value of the array expression.
73 * @throws Exception on any error
74 */
75 public Object execute(Object obj, JexlContext jc) throws Exception {
76 Object o = root.value(jc);
77
78
79
80
81 for (int i = 1; i < jjtGetNumChildren(); i++) {
82 o = ((SimpleNode) jjtGetChild(i)).execute(o, jc);
83
84
85
86 if (o == null) {
87 String varName = getIdentifierToDepth(i);
88 o = jc.getVars().get(varName);
89 }
90 }
91
92 return o;
93 }
94
95 /***
96 * This method returns a variable from this identifier and it's children.
97 * For an expression like 'a.b.c', a is child zero, b is child 1 and c is
98 * child 2.
99 *
100 * @param i the depth of the child nodes to go to
101 * @return the a dotted variable from this identifier and it's child nodes.
102 */
103 private String getIdentifierToDepth(int i) {
104 StringBuffer varName = new StringBuffer();
105 for (int j = 0; j <= i; j++) {
106 SimpleNode node = (SimpleNode) jjtGetChild(j);
107 if (node instanceof ASTIdentifier) {
108 varName.append(((ASTIdentifier) node).getIdentifierString());
109 if (j != i) {
110 varName.append('.');
111 }
112 }
113 }
114 return varName.toString();
115 }
116
117 /***
118 * Gets the variable name of {@link ASTReference#root root}.
119 * @return the identifier.
120 * @throws Exception on any error
121 * @see ASTIdentifier#getIdentifierString()
122 * @see ASTArrayAccess#getIdentifierString()
123 */
124 public String getRootString() throws Exception {
125 if (root instanceof ASTIdentifier) {
126 return ((ASTIdentifier) root).getIdentifierString();
127 }
128
129 if (root instanceof ASTArrayAccess) {
130 return ((ASTArrayAccess) root).getIdentifierString();
131 }
132
133 throw new Exception("programmer error : ASTReference : root not known" + root);
134 }
135 }