--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package net.sourceforge.phpdt.core.dom;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import net.sourceforge.phpdt.core.compiler.InvalidInputException;
+import net.sourceforge.phpdt.internal.compiler.parser.Scanner;
+import net.sourceforge.phpdt.internal.compiler.parser.ScannerHelper;
+import net.sourceforge.phpdt.internal.compiler.parser.TerminalTokens;
+
+/**
+ * Character literal nodes.
+ *
+ * @since 2.0
+ * @noinstantiate This class is not intended to be instantiated by clients.
+ */
+public class CharacterLiteral extends Expression {
+
+ /**
+ * The "escapedValue" structural property of this node type.
+ * @since 3.0
+ */
+ public static final SimplePropertyDescriptor ESCAPED_VALUE_PROPERTY =
+ new SimplePropertyDescriptor(CharacterLiteral.class, "escapedValue", String.class, MANDATORY); //$NON-NLS-1$
+
+ /**
+ * A list of property descriptors (element type:
+ * {@link StructuralPropertyDescriptor}),
+ * or null if uninitialized.
+ */
+ private static final List PROPERTY_DESCRIPTORS;
+
+ static {
+ List properyList = new ArrayList(2);
+ createPropertyList(CharacterLiteral.class, properyList);
+ addProperty(ESCAPED_VALUE_PROPERTY, properyList);
+ PROPERTY_DESCRIPTORS = reapPropertyList(properyList);
+ }
+
+ /**
+ * Returns a list of structural property descriptors for this node type.
+ * Clients must not modify the result.
+ *
+ * @param apiLevel the API level; one of the
+ * <code>AST.JLS*</code> constants
+
+ * @return a list of property descriptors (element type:
+ * {@link StructuralPropertyDescriptor})
+ * @since 3.0
+ */
+ public static List propertyDescriptors(int apiLevel) {
+ return PROPERTY_DESCRIPTORS;
+ }
+
+ /**
+ * The literal string, including quotes and escapes; defaults to the
+ * literal for the character 'X'.
+ */
+ private String escapedValue = "\'X\'";//$NON-NLS-1$
+
+ /**
+ * Creates a new unparented character literal node owned by the given AST.
+ * By default, the character literal denotes an unspecified character.
+ * <p>
+ * N.B. This constructor is package-private.
+ * </p>
+ *
+ * @param ast the AST that is to own this node
+ */
+ CharacterLiteral(AST ast) {
+ super(ast);
+ }
+
+ /* (omit javadoc for this method)
+ * Method declared on ASTNode.
+ */
+ final List internalStructuralPropertiesForType(int apiLevel) {
+ return propertyDescriptors(apiLevel);
+ }
+
+ /* (omit javadoc for this method)
+ * Method declared on ASTNode.
+ */
+ final Object internalGetSetObjectProperty(SimplePropertyDescriptor property, boolean get, Object value) {
+ if (property == ESCAPED_VALUE_PROPERTY) {
+ if (get) {
+ return getEscapedValue();
+ } else {
+ setEscapedValue((String) value);
+ return null;
+ }
+ }
+ // allow default implementation to flag the error
+ return super.internalGetSetObjectProperty(property, get, value);
+ }
+
+ /* (omit javadoc for this method)
+ * Method declared on ASTNode.
+ */
+ final int getNodeType0() {
+ return CHARACTER_LITERAL;
+ }
+
+ /* (omit javadoc for this method)
+ * Method declared on ASTNode.
+ */
+ ASTNode clone0(AST target) {
+ CharacterLiteral result = new CharacterLiteral(target);
+ result.setSourceRange(this.getStartPosition(), this.getLength());
+ result.setEscapedValue(getEscapedValue());
+ return result;
+ }
+
+ /* (omit javadoc for this method)
+ * Method declared on ASTNode.
+ */
+ final boolean subtreeMatch0(ASTMatcher matcher, Object other) {
+ // dispatch to correct overloaded match method
+ return matcher.match(this, other);
+ }
+
+ /* (omit javadoc for this method)
+ * Method declared on ASTNode.
+ */
+ void accept0(ASTVisitor visitor) {
+ visitor.visit(this);
+ visitor.endVisit(this);
+ }
+
+ /**
+ * Returns the string value of this literal node. The value is the sequence
+ * of characters that would appear in the source program, including
+ * enclosing single quotes and embedded escapes.
+ *
+ * @return the escaped string value, including enclosing single quotes
+ * and embedded escapes
+ */
+ public String getEscapedValue() {
+ return this.escapedValue;
+ }
+
+ /**
+ * Sets the string value of this literal node. The value is the sequence
+ * of characters that would appear in the source program, including
+ * enclosing single quotes and embedded escapes. For example,
+ * <ul>
+ * <li><code>'a'</code> <code>setEscapedValue("\'a\'")</code></li>
+ * <li><code>'\n'</code> <code>setEscapedValue("\'\\n\'")</code></li>
+ * </ul>
+ *
+ * @param value the string value, including enclosing single quotes
+ * and embedded escapes
+ * @exception IllegalArgumentException if the argument is incorrect
+ */
+ public void setEscapedValue(String value) {
+ // check setInternalEscapedValue(String) if this method is changed
+ if (value == null) {
+ throw new IllegalArgumentException();
+ }
+ Scanner scanner = this.ast.scanner;
+ char[] source = value.toCharArray();
+ scanner.setSource(source);
+ scanner.resetTo(0, source.length);
+ try {
+ int tokenType = scanner.getNextToken();
+ switch(tokenType) {
+ case TerminalTokens.TokenNameCharacterLiteral:
+ break;
+ default:
+ throw new IllegalArgumentException();
+ }
+ } catch(InvalidInputException e) {
+ throw new IllegalArgumentException();
+ }
+ preValueChange(ESCAPED_VALUE_PROPERTY);
+ this.escapedValue = value;
+ postValueChange(ESCAPED_VALUE_PROPERTY);
+ }
+
+
+ /* (omit javadoc for this method)
+ * This method is a copy of setEscapedValue(String) that doesn't do any validation.
+ */
+ void internalSetEscapedValue(String value) {
+ preValueChange(ESCAPED_VALUE_PROPERTY);
+ this.escapedValue = value;
+ postValueChange(ESCAPED_VALUE_PROPERTY);
+ }
+
+ /**
+ * Returns the value of this literal node.
+ * <p>
+ * For example,
+ * <pre>
+ * CharacterLiteral s;
+ * s.setEscapedValue("\'x\'");
+ * assert s.charValue() == 'x';
+ * </pre>
+ * </p>
+ *
+ * @return the character value without enclosing quotes and embedded
+ * escapes
+ * @exception IllegalArgumentException if the literal value cannot be converted
+ */
+ public char charValue() {
+ Scanner scanner = this.ast.scanner;
+ char[] source = escapedValue.toCharArray();
+ scanner.setSource(source);
+ scanner.resetTo(0, source.length);
+ int firstChar = scanner.getNextChar();
+ int secondChar = scanner.getNextChar();
+
+ if (firstChar == -1 || firstChar != '\'') {
+ throw new IllegalArgumentException("illegal character literal");//$NON-NLS-1$
+ }
+ char value = (char) secondChar;
+ int nextChar = scanner.getNextChar();
+ if (secondChar == '\\') {
+ if (nextChar == -1) {
+ throw new IllegalArgumentException("illegal character literal");//$NON-NLS-1$
+ }
+ switch(nextChar) {
+ case 'b' :
+ value = '\b';
+ break;
+ case 't' :
+ value = '\t';
+ break;
+ case 'n' :
+ value = '\n';
+ break;
+ case 'f' :
+ value = '\f';
+ break;
+ case 'r' :
+ value = '\r';
+ break;
+ case '\"':
+ value = '\"';
+ break;
+ case '\'':
+ value = '\'';
+ break;
+ case '\\':
+ value = '\\';
+ break;
+ default : //octal (well-formed: ended by a ' )
+ try {
+ if (ScannerHelper.isDigit((char) nextChar)) {
+ int number = ScannerHelper.getNumericValue((char) nextChar);
+ nextChar = scanner.getNextChar();
+ if (nextChar == -1) {
+ throw new IllegalArgumentException("illegal character literal");//$NON-NLS-1$
+ }
+ if (nextChar != '\'') {
+ if (!ScannerHelper.isDigit((char) nextChar)) {
+ throw new IllegalArgumentException("illegal character literal");//$NON-NLS-1$
+ }
+ number = (number * 8) + ScannerHelper.getNumericValue((char) nextChar);
+ nextChar = scanner.getNextChar();
+ if (nextChar == -1) {
+ throw new IllegalArgumentException("illegal character literal");//$NON-NLS-1$
+ }
+ if (nextChar != '\'') {
+ if (!ScannerHelper.isDigit((char) nextChar)) {
+ throw new IllegalArgumentException("illegal character literal");//$NON-NLS-1$
+ }
+ number = (number * 8) + ScannerHelper.getNumericValue((char) nextChar);
+ }
+ }
+ return (char) number;
+ } else {
+ throw new IllegalArgumentException("illegal character literal");//$NON-NLS-1$
+ }
+ } catch (InvalidInputException e) {
+ throw new IllegalArgumentException("illegal character literal");//$NON-NLS-1$
+ }
+ }
+ nextChar = scanner.getNextChar();
+ if (nextChar == -1) {
+ throw new IllegalArgumentException("illegal character literal");//$NON-NLS-1$
+ }
+ }
+ if (nextChar == -1 || nextChar != '\'') {
+ throw new IllegalArgumentException("illegal character literal");//$NON-NLS-1$
+ }
+ return value;
+ }
+ /**
+ * Sets the value of this character literal node to the given character.
+ * <p>
+ * For example,
+ * <pre>
+ * CharacterLiteral s;
+ * s.setCharValue('x');
+ * assert s.charValue() == 'x';
+ * assert s.getEscapedValue("\'x\'");
+ * </pre>
+ * </p>
+ *
+ * @param value the character value
+ */
+ public void setCharValue(char value) {
+ StringBuffer b = new StringBuffer(3);
+
+ b.append('\''); // opening delimiter
+ switch(value) {
+ case '\b' :
+ b.append("\\b"); //$NON-NLS-1$
+ break;
+ case '\t' :
+ b.append("\\t"); //$NON-NLS-1$
+ break;
+ case '\n' :
+ b.append("\\n"); //$NON-NLS-1$
+ break;
+ case '\f' :
+ b.append("\\f"); //$NON-NLS-1$
+ break;
+ case '\r' :
+ b.append("\\r"); //$NON-NLS-1$
+ break;
+ case '\"':
+ b.append("\\\""); //$NON-NLS-1$
+ break;
+ case '\'':
+ b.append("\\\'"); //$NON-NLS-1$
+ break;
+ case '\\':
+ b.append("\\\\"); //$NON-NLS-1$
+ break;
+ case '\0' :
+ b.append("\\0"); //$NON-NLS-1$
+ break;
+ case '\1' :
+ b.append("\\1"); //$NON-NLS-1$
+ break;
+ case '\2' :
+ b.append("\\2"); //$NON-NLS-1$
+ break;
+ case '\3' :
+ b.append("\\3"); //$NON-NLS-1$
+ break;
+ case '\4' :
+ b.append("\\4"); //$NON-NLS-1$
+ break;
+ case '\5' :
+ b.append("\\5"); //$NON-NLS-1$
+ break;
+ case '\6' :
+ b.append("\\6"); //$NON-NLS-1$
+ break;
+ case '\7' :
+ b.append("\\7"); //$NON-NLS-1$
+ break;
+ default:
+ b.append(value);
+ }
+ b.append('\''); // closing delimiter
+ setEscapedValue(b.toString());
+ }
+
+ /* (omit javadoc for this method)
+ * Method declared on ASTNode.
+ */
+ int memSize() {
+ int size = BASE_NODE_SIZE + 1 * 4 + stringSize(escapedValue);
+ return size;
+ }
+
+ /* (omit javadoc for this method)
+ * Method declared on ASTNode.
+ */
+ int treeSize() {
+ return memSize();
+ }
+}
+