1 package org.apache.velocity.runtime.parser.node;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 import org.apache.commons.lang.text.StrBuilder;
23 import org.apache.velocity.context.Context;
24 import org.apache.velocity.exception.MethodInvocationException;
25 import org.apache.velocity.runtime.parser.ParserConstants;
26 import org.apache.velocity.runtime.parser.Token;
27
28 /**
29 * Utilities for dealing with the AST node structure.
30 *
31 * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
32 * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
33 * @version $Id: NodeUtils.java 687386 2008-08-20 16:57:07Z nbubna $
34 */
35 public class NodeUtils
36 {
37 /**
38 * @deprecated use getSpecialText(Token t)
39 */
40 public static String specialText(Token t)
41 {
42 if (t.specialToken == null || t.specialToken.image.startsWith("##") )
43 {
44 return "";
45 }
46 return getSpecialText(t).toString();
47 }
48
49 /**
50 * Collect all the <SPECIAL_TOKEN>s that
51 * are carried along with a token. Special
52 * tokens do not participate in parsing but
53 * can still trigger certain lexical actions.
54 * In some cases you may want to retrieve these
55 * special tokens, this is simply a way to
56 * extract them.
57 * @param t the Token
58 * @return StrBuilder with the special tokens.
59 */
60 public static StrBuilder getSpecialText(Token t)
61 {
62 StrBuilder sb = new StrBuilder();
63
64 Token tmp_t = t.specialToken;
65
66 while (tmp_t.specialToken != null)
67 {
68 tmp_t = tmp_t.specialToken;
69 }
70
71 while (tmp_t != null)
72 {
73 String st = tmp_t.image;
74
75 for(int i = 0, is = st.length(); i < is; i++)
76 {
77 char c = st.charAt(i);
78
79 if ( c == '#' || c == '$' )
80 {
81 sb.append( c );
82 }
83
84 /*
85 * more dreaded MORE hack :)
86 *
87 * looking for ("\\")*"$" sequences
88 */
89
90 if ( c == '\\')
91 {
92 boolean ok = true;
93 boolean term = false;
94
95 int j = i;
96 for( ok = true; ok && j < is; j++)
97 {
98 char cc = st.charAt( j );
99
100 if (cc == '\\')
101 {
102 /*
103 * if we see a \, keep going
104 */
105 continue;
106 }
107 else if( cc == '$' )
108 {
109 /*
110 * a $ ends it correctly
111 */
112 term = true;
113 ok = false;
114 }
115 else
116 {
117 /*
118 * nah...
119 */
120 ok = false;
121 }
122 }
123
124 if (term)
125 {
126 String foo = st.substring( i, j );
127 sb.append( foo );
128 i = j;
129 }
130 }
131 }
132
133 tmp_t = tmp_t.next;
134 }
135 return sb;
136 }
137
138 /**
139 * complete node literal
140 * @param t
141 * @return A node literal.
142 */
143 public static String tokenLiteral( Token t )
144 {
145 // Look at kind of token and return "" when it's a multiline comment
146 if (t.kind == ParserConstants.MULTI_LINE_COMMENT)
147 {
148 return "";
149 }
150 else if (t.specialToken == null || t.specialToken.image.startsWith("##"))
151 {
152 return t.image;
153 }
154 else
155 {
156 StrBuilder special = getSpecialText(t);
157 if (special.length() > 0)
158 {
159 return special.append(t.image).toString();
160 }
161 return t.image;
162 }
163 }
164
165 /**
166 * Utility method to interpolate context variables
167 * into string literals. So that the following will
168 * work:
169 *
170 * #set $name = "candy"
171 * $image.getURI("${name}.jpg")
172 *
173 * And the string literal argument will
174 * be transformed into "candy.jpg" before
175 * the method is executed.
176 *
177 * @deprecated this method isn't called by any class
178 *
179 * @param argStr
180 * @param vars
181 * @return Interpoliation result.
182 * @throws MethodInvocationException
183 */
184 public static String interpolate(String argStr, Context vars) throws MethodInvocationException
185 {
186 // if there's nothing to replace, skip this (saves buffer allocation)
187 if( argStr.indexOf('$') == -1 )
188 return argStr;
189
190 StrBuilder argBuf = new StrBuilder();
191
192 for (int cIdx = 0, is = argStr.length(); cIdx < is;)
193 {
194 char ch = argStr.charAt(cIdx);
195
196 if( ch == '$' )
197 {
198 StrBuilder nameBuf = new StrBuilder();
199 for (++cIdx ; cIdx < is; ++cIdx)
200 {
201 ch = argStr.charAt(cIdx);
202 if (ch == '_' || ch == '-'
203 || Character.isLetterOrDigit(ch))
204 nameBuf.append(ch);
205 else if (ch == '{' || ch == '}')
206 continue;
207 else
208 break;
209 }
210
211 if (nameBuf.length() > 0)
212 {
213 Object value = vars.get(nameBuf.toString());
214
215 if (value == null)
216 argBuf.append("$").append(nameBuf.toString());
217 else
218 argBuf.append(value.toString());
219 }
220
221 }
222 else
223 {
224 argBuf.append(ch);
225 ++cIdx;
226 }
227 }
228
229 return argBuf.toString();
230 }
231 }