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
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
12 package net.sourceforge.phpdt.core.dom;
14 import java.util.ArrayList;
15 import java.util.List;
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.ScannerHelper;
20 import net.sourceforge.phpdt.internal.compiler.parser.TerminalTokens;
23 * Character literal nodes.
26 * @noinstantiate This class is not intended to be instantiated by clients.
28 public class CharacterLiteral extends Expression {
31 * The "escapedValue" structural property of this node type.
34 public static final SimplePropertyDescriptor ESCAPED_VALUE_PROPERTY =
35 new SimplePropertyDescriptor(CharacterLiteral.class, "escapedValue", String.class, MANDATORY); //$NON-NLS-1$
38 * A list of property descriptors (element type:
39 * {@link StructuralPropertyDescriptor}),
40 * or null if uninitialized.
42 private static final List PROPERTY_DESCRIPTORS;
45 List properyList = new ArrayList(2);
46 createPropertyList(CharacterLiteral.class, properyList);
47 addProperty(ESCAPED_VALUE_PROPERTY, properyList);
48 PROPERTY_DESCRIPTORS = reapPropertyList(properyList);
52 * Returns a list of structural property descriptors for this node type.
53 * Clients must not modify the result.
55 * @param apiLevel the API level; one of the
56 * <code>AST.JLS*</code> constants
58 * @return a list of property descriptors (element type:
59 * {@link StructuralPropertyDescriptor})
62 public static List propertyDescriptors(int apiLevel) {
63 return PROPERTY_DESCRIPTORS;
67 * The literal string, including quotes and escapes; defaults to the
68 * literal for the character 'X'.
70 private String escapedValue = "\'X\'";//$NON-NLS-1$
73 * Creates a new unparented character literal node owned by the given AST.
74 * By default, the character literal denotes an unspecified character.
76 * N.B. This constructor is package-private.
79 * @param ast the AST that is to own this node
81 CharacterLiteral(AST ast) {
85 /* (omit javadoc for this method)
86 * Method declared on ASTNode.
88 final List internalStructuralPropertiesForType(int apiLevel) {
89 return propertyDescriptors(apiLevel);
92 /* (omit javadoc for this method)
93 * Method declared on ASTNode.
95 final Object internalGetSetObjectProperty(SimplePropertyDescriptor property, boolean get, Object value) {
96 if (property == ESCAPED_VALUE_PROPERTY) {
98 return getEscapedValue();
100 setEscapedValue((String) value);
104 // allow default implementation to flag the error
105 return super.internalGetSetObjectProperty(property, get, value);
108 /* (omit javadoc for this method)
109 * Method declared on ASTNode.
111 final int getNodeType0() {
112 return CHARACTER_LITERAL;
115 /* (omit javadoc for this method)
116 * Method declared on ASTNode.
118 ASTNode clone0(AST target) {
119 CharacterLiteral result = new CharacterLiteral(target);
120 result.setSourceRange(this.getStartPosition(), this.getLength());
121 result.setEscapedValue(getEscapedValue());
125 /* (omit javadoc for this method)
126 * Method declared on ASTNode.
128 final boolean subtreeMatch0(ASTMatcher matcher, Object other) {
129 // dispatch to correct overloaded match method
130 return matcher.match(this, other);
133 /* (omit javadoc for this method)
134 * Method declared on ASTNode.
136 void accept0(ASTVisitor visitor) {
138 visitor.endVisit(this);
142 * Returns the string value of this literal node. The value is the sequence
143 * of characters that would appear in the source program, including
144 * enclosing single quotes and embedded escapes.
146 * @return the escaped string value, including enclosing single quotes
147 * and embedded escapes
149 public String getEscapedValue() {
150 return this.escapedValue;
154 * Sets the string value of this literal node. The value is the sequence
155 * of characters that would appear in the source program, including
156 * enclosing single quotes and embedded escapes. For example,
158 * <li><code>'a'</code> <code>setEscapedValue("\'a\'")</code></li>
159 * <li><code>'\n'</code> <code>setEscapedValue("\'\\n\'")</code></li>
162 * @param value the string value, including enclosing single quotes
163 * and embedded escapes
164 * @exception IllegalArgumentException if the argument is incorrect
166 public void setEscapedValue(String value) {
167 // check setInternalEscapedValue(String) if this method is changed
169 throw new IllegalArgumentException();
171 Scanner scanner = this.ast.scanner;
172 char[] source = value.toCharArray();
173 scanner.setSource(source);
174 scanner.resetTo(0, source.length);
176 int tokenType = scanner.getNextToken();
178 case TerminalTokens.TokenNameCharacterLiteral:
181 throw new IllegalArgumentException();
183 } catch(InvalidInputException e) {
184 throw new IllegalArgumentException();
186 preValueChange(ESCAPED_VALUE_PROPERTY);
187 this.escapedValue = value;
188 postValueChange(ESCAPED_VALUE_PROPERTY);
192 /* (omit javadoc for this method)
193 * This method is a copy of setEscapedValue(String) that doesn't do any validation.
195 void internalSetEscapedValue(String value) {
196 preValueChange(ESCAPED_VALUE_PROPERTY);
197 this.escapedValue = value;
198 postValueChange(ESCAPED_VALUE_PROPERTY);
202 * Returns the value of this literal node.
206 * CharacterLiteral s;
207 * s.setEscapedValue("\'x\'");
208 * assert s.charValue() == 'x';
212 * @return the character value without enclosing quotes and embedded
214 * @exception IllegalArgumentException if the literal value cannot be converted
216 public char charValue() {
217 Scanner scanner = this.ast.scanner;
218 char[] source = escapedValue.toCharArray();
219 scanner.setSource(source);
220 scanner.resetTo(0, source.length);
221 int firstChar = scanner.getNextChar();
222 int secondChar = scanner.getNextChar();
224 if (firstChar == -1 || firstChar != '\'') {
225 throw new IllegalArgumentException("illegal character literal");//$NON-NLS-1$
227 char value = (char) secondChar;
228 int nextChar = scanner.getNextChar();
229 if (secondChar == '\\') {
230 if (nextChar == -1) {
231 throw new IllegalArgumentException("illegal character literal");//$NON-NLS-1$
258 default : //octal (well-formed: ended by a ' )
260 if (ScannerHelper.isDigit((char) nextChar)) {
261 int number = ScannerHelper.getNumericValue((char) nextChar);
262 nextChar = scanner.getNextChar();
263 if (nextChar == -1) {
264 throw new IllegalArgumentException("illegal character literal");//$NON-NLS-1$
266 if (nextChar != '\'') {
267 if (!ScannerHelper.isDigit((char) nextChar)) {
268 throw new IllegalArgumentException("illegal character literal");//$NON-NLS-1$
270 number = (number * 8) + ScannerHelper.getNumericValue((char) nextChar);
271 nextChar = scanner.getNextChar();
272 if (nextChar == -1) {
273 throw new IllegalArgumentException("illegal character literal");//$NON-NLS-1$
275 if (nextChar != '\'') {
276 if (!ScannerHelper.isDigit((char) nextChar)) {
277 throw new IllegalArgumentException("illegal character literal");//$NON-NLS-1$
279 number = (number * 8) + ScannerHelper.getNumericValue((char) nextChar);
282 return (char) number;
284 throw new IllegalArgumentException("illegal character literal");//$NON-NLS-1$
286 } catch (InvalidInputException e) {
287 throw new IllegalArgumentException("illegal character literal");//$NON-NLS-1$
290 nextChar = scanner.getNextChar();
291 if (nextChar == -1) {
292 throw new IllegalArgumentException("illegal character literal");//$NON-NLS-1$
295 if (nextChar == -1 || nextChar != '\'') {
296 throw new IllegalArgumentException("illegal character literal");//$NON-NLS-1$
301 * Sets the value of this character literal node to the given character.
305 * CharacterLiteral s;
306 * s.setCharValue('x');
307 * assert s.charValue() == 'x';
308 * assert s.getEscapedValue("\'x\'");
312 * @param value the character value
314 public void setCharValue(char value) {
315 StringBuffer b = new StringBuffer(3);
317 b.append('\''); // opening delimiter
320 b.append("\\b"); //$NON-NLS-1$
323 b.append("\\t"); //$NON-NLS-1$
326 b.append("\\n"); //$NON-NLS-1$
329 b.append("\\f"); //$NON-NLS-1$
332 b.append("\\r"); //$NON-NLS-1$
335 b.append("\\\""); //$NON-NLS-1$
338 b.append("\\\'"); //$NON-NLS-1$
341 b.append("\\\\"); //$NON-NLS-1$
344 b.append("\\0"); //$NON-NLS-1$
347 b.append("\\1"); //$NON-NLS-1$
350 b.append("\\2"); //$NON-NLS-1$
353 b.append("\\3"); //$NON-NLS-1$
356 b.append("\\4"); //$NON-NLS-1$
359 b.append("\\5"); //$NON-NLS-1$
362 b.append("\\6"); //$NON-NLS-1$
365 b.append("\\7"); //$NON-NLS-1$
370 b.append('\''); // closing delimiter
371 setEscapedValue(b.toString());
374 /* (omit javadoc for this method)
375 * Method declared on ASTNode.
378 int size = BASE_NODE_SIZE + 1 * 4 + stringSize(escapedValue);
382 /* (omit javadoc for this method)
383 * Method declared on ASTNode.