b393337b2a2f6f84bb02e8abaa9a021650b2fcbe
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / core / dom / StringLiteral.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2008 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11
12 package net.sourceforge.phpdt.core.dom;
13
14 import java.util.ArrayList;
15 import java.util.List;
16
17 import net.sourceforge.phpdt.core.compiler.InvalidInputException;
18 import net.sourceforge.phpdt.internal.compiler.parser.Scanner;
19 import net.sourceforge.phpdt.internal.compiler.parser.TerminalTokens;
20
21 /**
22  * String literal nodes.
23  * 
24  * @since 2.0
25  * @noinstantiate This class is not intended to be instantiated by clients.
26  */
27 public class StringLiteral extends Expression {
28
29         /**
30          * The "escapedValue" structural property of this node type.
31          * @since 3.0
32          */
33         public static final SimplePropertyDescriptor ESCAPED_VALUE_PROPERTY = 
34                 new SimplePropertyDescriptor(StringLiteral.class, "escapedValue", String.class, MANDATORY); //$NON-NLS-1$
35         
36         /**
37          * A list of property descriptors (element type: 
38          * {@link StructuralPropertyDescriptor}),
39          * or null if uninitialized.
40          */
41         private static final List PROPERTY_DESCRIPTORS;
42         
43         static {
44                 List propertyList = new ArrayList(2);
45                 createPropertyList(StringLiteral.class, propertyList);
46                 addProperty(ESCAPED_VALUE_PROPERTY, propertyList);
47                 PROPERTY_DESCRIPTORS = reapPropertyList(propertyList);
48         }
49
50         /**
51          * Returns a list of structural property descriptors for this node type.
52          * Clients must not modify the result.
53          * 
54          * @param apiLevel the API level; one of the
55          * <code>AST.JLS*</code> constants
56
57          * @return a list of property descriptors (element type: 
58          * {@link StructuralPropertyDescriptor})
59          * @since 3.0
60          */
61         public static List propertyDescriptors(int apiLevel) {
62                 return PROPERTY_DESCRIPTORS;
63         }
64                         
65         /**
66          * The literal string, including quotes and escapes; defaults to the 
67          * literal for the empty string.
68          */
69         private String escapedValue = "\"\"";//$NON-NLS-1$
70
71         /**
72          * Creates a new unparented string literal node owned by the given AST.
73          * By default, the string literal denotes the empty string.
74          * <p>
75          * N.B. This constructor is package-private.
76          * </p>
77          * 
78          * @param ast the AST that is to own this node
79          */
80         StringLiteral(AST ast) {
81                 super(ast);
82         }
83
84         /* (omit javadoc for this method)
85          * Method declared on ASTNode.
86          */
87         final List internalStructuralPropertiesForType(int apiLevel) {
88                 return propertyDescriptors(apiLevel);
89         }
90         
91         /* (omit javadoc for this method)
92          * Method declared on ASTNode.
93          */
94         final Object internalGetSetObjectProperty(SimplePropertyDescriptor property, boolean get, Object value) {
95                 if (property == ESCAPED_VALUE_PROPERTY) {
96                         if (get) {
97                                 return getEscapedValue();
98                         } else {
99                                 setEscapedValue((String) value);
100                                 return null;
101                         }
102                 }
103                 // allow default implementation to flag the error
104                 return super.internalGetSetObjectProperty(property, get, value);
105         }
106         
107         /* (omit javadoc for this method)
108          * Method declared on ASTNode.
109          */
110         final int getNodeType0() {
111                 return STRING_LITERAL;
112         }
113
114         /* (omit javadoc for this method)
115          * Method declared on ASTNode.
116          */
117         ASTNode clone0(AST target) {
118                 StringLiteral result = new StringLiteral(target);
119                 result.setSourceRange(this.getStartPosition(), this.getLength());
120                 result.setEscapedValue(getEscapedValue());
121                 return result;
122         }
123
124         /* (omit javadoc for this method)
125          * Method declared on ASTNode.
126          */
127         final boolean subtreeMatch0(ASTMatcher matcher, Object other) {
128                 // dispatch to correct overloaded match method
129                 return matcher.match(this, other);
130         }
131
132         /* (omit javadoc for this method)
133          * Method declared on ASTNode.
134          */
135         void accept0(ASTVisitor visitor) {
136                 visitor.visit(this);
137                 visitor.endVisit(this);
138         }
139         
140         /**
141          * Returns the string value of this literal node to the given string
142          * literal token. The token is the sequence of characters that would appear
143          * in the source program, including enclosing double quotes and embedded
144          * escapes.
145          * 
146          * @return the string literal token, including enclosing double
147          *    quotes and embedded escapes
148          */ 
149         public String getEscapedValue() {
150                 return this.escapedValue;
151         }
152                 
153         /**
154          * Sets the string value of this literal node to the given string literal
155          * token. The token is the sequence of characters that would appear in the
156          * source program, including enclosing double quotes and embedded escapes.
157          * For example,
158          * <ul>
159          * <li><code>""</code> <code>setLiteral("\"\"")</code></li>
160          * <li><code>"hello world"</code> <code>setLiteral("\"hello world\"")</code></li>
161          * <li><code>"boo\nhoo"</code> <code>setLiteral("\"boo\\nhoo\"")</code></li>
162          * </ul>
163          * 
164          * @param token the string literal token, including enclosing double
165          *    quotes and embedded escapes
166          * @exception IllegalArgumentException if the argument is incorrect
167          */ 
168         public void setEscapedValue(String token) {
169                 // update internalSetEscapedValue(String) if this is changed
170                 if (token == null) {
171                         throw new IllegalArgumentException("Token cannot be null"); //$NON-NLS-1$
172                 }
173                 Scanner scanner = this.ast.scanner;
174                 char[] source = token.toCharArray();
175                 scanner.setSource(source);
176                 scanner.resetTo(0, source.length);
177                 try {
178                         int tokenType = scanner.getNextToken();
179                         switch(tokenType) {
180                                 case TerminalTokens.TokenNameStringLiteral:
181                                         break;
182                                 default:
183                                         throw new IllegalArgumentException("Invalid string literal : >" + token + "<"); //$NON-NLS-1$//$NON-NLS-2$
184                         }
185                 } catch(InvalidInputException e) {
186                         throw new IllegalArgumentException("Invalid string literal : >" + token + "<");//$NON-NLS-1$//$NON-NLS-2$
187                 }
188                 preValueChange(ESCAPED_VALUE_PROPERTY);
189                 this.escapedValue = token;
190                 postValueChange(ESCAPED_VALUE_PROPERTY);
191         }
192
193         /* (omit javadoc for this method)
194          * This method is a copy of setEscapedValue(String) that doesn't do any validation.
195          */
196         void internalSetEscapedValue(String token) {
197                 preValueChange(ESCAPED_VALUE_PROPERTY);
198                 this.escapedValue = token;
199                 postValueChange(ESCAPED_VALUE_PROPERTY);
200         }
201
202         /**
203          * Returns the value of this literal node. 
204          * <p>
205          * For example,
206          * <pre>
207          * StringLiteral s;
208          * s.setEscapedValue("\"hello\\nworld\"");
209          * assert s.getLiteralValue().equals("hello\nworld");
210          * </pre>
211          * </p>
212          * <p>
213          * Note that this is a convenience method that converts from the stored 
214          * string literal token returned by <code>getEscapedLiteral</code>.
215          * </p>
216          * 
217          * @return the string value without enclosing double quotes and embedded
218          *    escapes
219          * @exception IllegalArgumentException if the literal value cannot be converted
220          */ 
221         public String getLiteralValue() {
222                 String s = getEscapedValue();
223                 int len = s.length();
224                 if (len < 2 || s.charAt(0) != '\"' || s.charAt(len-1) != '\"' ) {
225                         throw new IllegalArgumentException();
226                 }
227                 
228                 Scanner scanner = this.ast.scanner;
229                 char[] source = s.toCharArray();
230                 scanner.setSource(source);
231                 scanner.resetTo(0, source.length);
232                 try {
233                         int tokenType = scanner.getNextToken();
234                         switch(tokenType) {
235                                 case TerminalTokens.TokenNameStringLiteral:
236                                         return scanner.getCurrentStringLiteral();
237                                 default:
238                                         throw new IllegalArgumentException();
239                         }
240                 } catch(InvalidInputException e) {
241                         throw new IllegalArgumentException();
242                 }
243         }
244
245         /**
246          * Sets the value of this literal node. 
247          * <p>
248          * For example,
249          * <pre>
250          * StringLiteral s;
251          * s.setLiteralValue("hello\nworld");
252          * assert s.getEscapedValue("\"hello\\nworld\"");
253          * assert s.getLiteralValue().equals("hello\nworld");
254          * </pre>
255          * </p>
256          * <p>
257          * Note that this is a convenience method that converts to the stored 
258          * string literal token acceptable to <code>setEscapedLiteral</code>.
259          * </p>
260          * 
261          * @param value the string value without enclosing double quotes and 
262          *    embedded escapes
263          * @exception IllegalArgumentException if the argument is incorrect
264          */
265         public void setLiteralValue(String value) {
266                 if (value == null) {
267                         throw new IllegalArgumentException();
268                 }
269                 int len = value.length();
270                 StringBuffer b = new StringBuffer(len + 2);
271                 
272                 b.append("\""); // opening delimiter //$NON-NLS-1$
273                 for (int i = 0; i < len; i++) {
274                         char c = value.charAt(i);
275                         switch(c) {
276                                 case '\b' :
277                                         b.append("\\b"); //$NON-NLS-1$
278                                         break;
279                                 case '\t' :
280                                         b.append("\\t"); //$NON-NLS-1$
281                                         break;
282                                 case '\n' :
283                                         b.append("\\n"); //$NON-NLS-1$
284                                         break;
285                                 case '\f' :
286                                         b.append("\\f"); //$NON-NLS-1$
287                                         break;
288                                 case '\r' :
289                                         b.append("\\r"); //$NON-NLS-1$
290                                         break;
291                                 case '\"':
292                                         b.append("\\\""); //$NON-NLS-1$
293                                         break;
294                                 case '\'':
295                                         b.append("\\\'"); //$NON-NLS-1$
296                                         break;
297                                 case '\\':
298                                         b.append("\\\\"); //$NON-NLS-1$
299                                         break;
300                                 case '\0' :
301                                         b.append("\\0"); //$NON-NLS-1$
302                                         break;
303                                 case '\1' :
304                                         b.append("\\1"); //$NON-NLS-1$
305                                         break;
306                                 case '\2' :
307                                         b.append("\\2"); //$NON-NLS-1$
308                                         break;
309                                 case '\3' :
310                                         b.append("\\3"); //$NON-NLS-1$
311                                         break;
312                                 case '\4' :
313                                         b.append("\\4"); //$NON-NLS-1$
314                                         break;
315                                 case '\5' :
316                                         b.append("\\5"); //$NON-NLS-1$
317                                         break;
318                                 case '\6' :
319                                         b.append("\\6"); //$NON-NLS-1$
320                                         break;
321                                 case '\7' :
322                                         b.append("\\7"); //$NON-NLS-1$
323                                         break;                  
324                                 default:
325                                         b.append(c);
326                         }
327                 }
328                 b.append("\""); // closing delimiter //$NON-NLS-1$
329                 setEscapedValue(b.toString());
330         }
331         /* (omit javadoc for this method)
332          * Method declared on ASTNode.
333          */
334         int memSize() {
335                 int size = BASE_NODE_SIZE + 1 * 4 + stringSize(escapedValue);
336                 return size;
337         }
338         
339         /* (omit javadoc for this method)
340          * Method declared on ASTNode.
341          */
342         int treeSize() {
343                 return memSize();
344         }
345 }