001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.core.dom;
011:
012: import java.util.ArrayList;
013: import java.util.List;
014:
015: import org.eclipse.jdt.core.compiler.InvalidInputException;
016: import org.eclipse.jdt.internal.compiler.parser.Scanner;
017: import org.eclipse.jdt.internal.compiler.parser.TerminalTokens;
018:
019: /**
020: * String literal nodes.
021: *
022: * @since 2.0
023: */
024: public class StringLiteral extends Expression {
025:
026: /**
027: * The "escapedValue" structural property of this node type.
028: * @since 3.0
029: */
030: public static final SimplePropertyDescriptor ESCAPED_VALUE_PROPERTY = new SimplePropertyDescriptor(
031: StringLiteral.class,
032: "escapedValue", String.class, MANDATORY); //$NON-NLS-1$
033:
034: /**
035: * A list of property descriptors (element type:
036: * {@link StructuralPropertyDescriptor}),
037: * or null if uninitialized.
038: */
039: private static final List PROPERTY_DESCRIPTORS;
040:
041: static {
042: List propertyList = new ArrayList(2);
043: createPropertyList(StringLiteral.class, propertyList);
044: addProperty(ESCAPED_VALUE_PROPERTY, propertyList);
045: PROPERTY_DESCRIPTORS = reapPropertyList(propertyList);
046: }
047:
048: /**
049: * Returns a list of structural property descriptors for this node type.
050: * Clients must not modify the result.
051: *
052: * @param apiLevel the API level; one of the
053: * <code>AST.JLS*</code> constants
054:
055: * @return a list of property descriptors (element type:
056: * {@link StructuralPropertyDescriptor})
057: * @since 3.0
058: */
059: public static List propertyDescriptors(int apiLevel) {
060: return PROPERTY_DESCRIPTORS;
061: }
062:
063: /**
064: * The literal string, including quotes and escapes; defaults to the
065: * literal for the empty string.
066: */
067: private String escapedValue = "\"\"";//$NON-NLS-1$
068:
069: /**
070: * Creates a new unparented string literal node owned by the given AST.
071: * By default, the string literal denotes the empty string.
072: * <p>
073: * N.B. This constructor is package-private.
074: * </p>
075: *
076: * @param ast the AST that is to own this node
077: */
078: StringLiteral(AST ast) {
079: super (ast);
080: }
081:
082: /* (omit javadoc for this method)
083: * Method declared on ASTNode.
084: */
085: final List internalStructuralPropertiesForType(int apiLevel) {
086: return propertyDescriptors(apiLevel);
087: }
088:
089: /* (omit javadoc for this method)
090: * Method declared on ASTNode.
091: */
092: final Object internalGetSetObjectProperty(
093: SimplePropertyDescriptor property, boolean get, Object value) {
094: if (property == ESCAPED_VALUE_PROPERTY) {
095: if (get) {
096: return getEscapedValue();
097: } else {
098: setEscapedValue((String) value);
099: return null;
100: }
101: }
102: // allow default implementation to flag the error
103: return super .internalGetSetObjectProperty(property, get, value);
104: }
105:
106: /* (omit javadoc for this method)
107: * Method declared on ASTNode.
108: */
109: final int getNodeType0() {
110: return STRING_LITERAL;
111: }
112:
113: /* (omit javadoc for this method)
114: * Method declared on ASTNode.
115: */
116: ASTNode clone0(AST target) {
117: StringLiteral result = new StringLiteral(target);
118: result
119: .setSourceRange(this .getStartPosition(), this
120: .getLength());
121: result.setEscapedValue(getEscapedValue());
122: return result;
123: }
124:
125: /* (omit javadoc for this method)
126: * Method declared on ASTNode.
127: */
128: final boolean subtreeMatch0(ASTMatcher matcher, Object other) {
129: // dispatch to correct overloaded match method
130: return matcher.match(this , other);
131: }
132:
133: /* (omit javadoc for this method)
134: * Method declared on ASTNode.
135: */
136: void accept0(ASTVisitor visitor) {
137: visitor.visit(this );
138: visitor.endVisit(this );
139: }
140:
141: /**
142: * Returns the string value of this literal node to the given string
143: * literal token. The token is the sequence of characters that would appear
144: * in the source program, including enclosing double quotes and embedded
145: * escapes.
146: *
147: * @return the string literal token, including enclosing double
148: * quotes and embedded escapes
149: */
150: public String getEscapedValue() {
151: return this .escapedValue;
152: }
153:
154: /**
155: * Sets the string value of this literal node to the given string literal
156: * token. The token is the sequence of characters that would appear in the
157: * source program, including enclosing double quotes and embedded escapes.
158: * For example,
159: * <ul>
160: * <li><code>""</code> <code>setLiteral("\"\"")</code></li>
161: * <li><code>"hello world"</code> <code>setLiteral("\"hello world\"")</code></li>
162: * <li><code>"boo\nhoo"</code> <code>setLiteral("\"boo\\nhoo\"")</code></li>
163: * </ul>
164: *
165: * @param token the string literal token, including enclosing double
166: * quotes and embedded escapes
167: * @exception IllegalArgumentException if the argument is incorrect
168: */
169: public void setEscapedValue(String token) {
170: // update internalSetEscapedValue(String) if this is changed
171: if (token == null) {
172: throw new IllegalArgumentException("Token cannot be null"); //$NON-NLS-1$
173: }
174: Scanner scanner = this .ast.scanner;
175: char[] source = token.toCharArray();
176: scanner.setSource(source);
177: scanner.resetTo(0, source.length);
178: try {
179: int tokenType = scanner.getNextToken();
180: switch (tokenType) {
181: case TerminalTokens.TokenNameStringLiteral:
182: break;
183: default:
184: throw new IllegalArgumentException(
185: "Invalid string literal : >" + token + "<"); //$NON-NLS-1$//$NON-NLS-2$
186: }
187: } catch (InvalidInputException e) {
188: throw new IllegalArgumentException(
189: "Invalid string literal : >" + token + "<");//$NON-NLS-1$//$NON-NLS-2$
190: }
191: preValueChange(ESCAPED_VALUE_PROPERTY);
192: this .escapedValue = token;
193: postValueChange(ESCAPED_VALUE_PROPERTY);
194: }
195:
196: /* (omit javadoc for this method)
197: * This method is a copy of setEscapedValue(String) that doesn't do any validation.
198: */
199: void internalSetEscapedValue(String token) {
200: preValueChange(ESCAPED_VALUE_PROPERTY);
201: this .escapedValue = token;
202: postValueChange(ESCAPED_VALUE_PROPERTY);
203: }
204:
205: /**
206: * Returns the value of this literal node.
207: * <p>
208: * For example,
209: * <pre>
210: * StringLiteral s;
211: * s.setEscapedValue("\"hello\\nworld\"");
212: * assert s.getLiteralValue().equals("hello\nworld");
213: * </pre>
214: * </p>
215: * <p>
216: * Note that this is a convenience method that converts from the stored
217: * string literal token returned by <code>getEscapedLiteral</code>.
218: * </p>
219: *
220: * @return the string value without enclosing double quotes and embedded
221: * escapes
222: * @exception IllegalArgumentException if the literal value cannot be converted
223: */
224: public String getLiteralValue() {
225: String s = getEscapedValue();
226: int len = s.length();
227: if (len < 2 || s.charAt(0) != '\"' || s.charAt(len - 1) != '\"') {
228: throw new IllegalArgumentException();
229: }
230:
231: Scanner scanner = this .ast.scanner;
232: char[] source = s.toCharArray();
233: scanner.setSource(source);
234: scanner.resetTo(0, source.length);
235: try {
236: int tokenType = scanner.getNextToken();
237: switch (tokenType) {
238: case TerminalTokens.TokenNameStringLiteral:
239: return scanner.getCurrentStringLiteral();
240: default:
241: throw new IllegalArgumentException();
242: }
243: } catch (InvalidInputException e) {
244: throw new IllegalArgumentException();
245: }
246: }
247:
248: /**
249: * Sets the value of this literal node.
250: * <p>
251: * For example,
252: * <pre>
253: * StringLiteral s;
254: * s.setLiteralValue("hello\nworld");
255: * assert s.getEscapedValue("\"hello\\nworld\"");
256: * assert s.getLiteralValue().equals("hello\nworld");
257: * </pre>
258: * </p>
259: * <p>
260: * Note that this is a convenience method that converts to the stored
261: * string literal token acceptable to <code>setEscapedLiteral</code>.
262: * </p>
263: *
264: * @param value the string value without enclosing double quotes and
265: * embedded escapes
266: * @exception IllegalArgumentException if the argument is incorrect
267: */
268: public void setLiteralValue(String value) {
269: if (value == null) {
270: throw new IllegalArgumentException();
271: }
272: int len = value.length();
273: StringBuffer b = new StringBuffer(len + 2);
274:
275: b.append("\""); // opening delimiter //$NON-NLS-1$
276: for (int i = 0; i < len; i++) {
277: char c = value.charAt(i);
278: switch (c) {
279: case '\b':
280: b.append("\\b"); //$NON-NLS-1$
281: break;
282: case '\t':
283: b.append("\\t"); //$NON-NLS-1$
284: break;
285: case '\n':
286: b.append("\\n"); //$NON-NLS-1$
287: break;
288: case '\f':
289: b.append("\\f"); //$NON-NLS-1$
290: break;
291: case '\r':
292: b.append("\\r"); //$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 '\\':
301: b.append("\\\\"); //$NON-NLS-1$
302: break;
303: case '\0':
304: b.append("\\0"); //$NON-NLS-1$
305: break;
306: case '\1':
307: b.append("\\1"); //$NON-NLS-1$
308: break;
309: case '\2':
310: b.append("\\2"); //$NON-NLS-1$
311: break;
312: case '\3':
313: b.append("\\3"); //$NON-NLS-1$
314: break;
315: case '\4':
316: b.append("\\4"); //$NON-NLS-1$
317: break;
318: case '\5':
319: b.append("\\5"); //$NON-NLS-1$
320: break;
321: case '\6':
322: b.append("\\6"); //$NON-NLS-1$
323: break;
324: case '\7':
325: b.append("\\7"); //$NON-NLS-1$
326: break;
327: default:
328: b.append(c);
329: }
330: }
331: b.append("\""); // closing delimiter //$NON-NLS-1$
332: setEscapedValue(b.toString());
333: }
334:
335: /* (omit javadoc for this method)
336: * Method declared on ASTNode.
337: */
338: int memSize() {
339: int size = BASE_NODE_SIZE + 1 * 4 + stringSize(escapedValue);
340: return size;
341: }
342:
343: /* (omit javadoc for this method)
344: * Method declared on ASTNode.
345: */
346: int treeSize() {
347: return memSize();
348: }
349: }
|