/*******************************************************************************
* Copyright (c) 2004, 2011 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:
* John Camelon (IBM) - Initial API and implementation
* Markus Schorn (Wind River Systems)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression;
import org.eclipse.cdt.core.dom.ast.IBasicType;
import org.eclipse.cdt.core.dom.ast.IBasicType.Kind;
import org.eclipse.cdt.core.dom.ast.IScope;
import org.eclipse.cdt.core.dom.ast.ISemanticProblem;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.IValue;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLiteralExpression;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
import org.eclipse.cdt.internal.core.dom.parser.ProblemType;
import org.eclipse.cdt.internal.core.dom.parser.Value;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
/**
* Represents a C++ literal.
*/
public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralExpression {
public static final CPPASTLiteralExpression INT_ZERO =
new CPPASTLiteralExpression(lk_integer_constant, new char[] {'0'});
private int kind;
private char[] value = CharArrayUtils.EMPTY;
public CPPASTLiteralExpression() {
}
public CPPASTLiteralExpression(int kind, char[] value) {
this.kind = kind;
this.value = value;
}
public CPPASTLiteralExpression copy() {
return copy(CopyStyle.withoutLocations);
}
public CPPASTLiteralExpression copy(CopyStyle style) {
CPPASTLiteralExpression copy = new CPPASTLiteralExpression(kind, value == null ? null
: value.clone());
copy.setOffsetAndLength(this);
if (style == CopyStyle.withLocations) {
copy.setCopyLocation(this);
}
return copy;
}
public int getKind() {
return kind;
}
public void setKind(int value) {
assertNotFrozen();
kind = value;
}
public char[] getValue() {
return value;
}
public void setValue(char[] value) {
assertNotFrozen();
this.value= value;
}
@Override
public String toString() {
return new String(value);
}
@Override
public boolean accept(ASTVisitor action) {
if (action.shouldVisitExpressions) {
switch (action.visit(this)) {
case ASTVisitor.PROCESS_ABORT: return false;
case ASTVisitor.PROCESS_SKIP: return true;
default: break;
}
}
if (action.shouldVisitExpressions) {
switch (action.leave(this)) {
case ASTVisitor.PROCESS_ABORT: return false;
case ASTVisitor.PROCESS_SKIP: return true;
default: break;
}
}
return true;
}
public IType getExpressionType() {
switch (getKind()) {
case lk_this: {
IScope scope = CPPVisitor.getContainingScope(this);
IType type= CPPVisitor.getImpliedObjectType(scope);
if (type == null) {
return new ProblemType(ISemanticProblem.TYPE_UNRESOLVED_NAME);
}
return new CPPPointerType(type);
}
case lk_true:
case lk_false:
return CPPBasicType.BOOLEAN;
case lk_char_constant:
return new CPPBasicType(getCharType(), 0, this);
case lk_float_constant:
return classifyTypeOfFloatLiteral();
case lk_integer_constant:
return classifyTypeOfIntLiteral();
case lk_string_literal:
IType type = new CPPBasicType(getCharType(), 0, this);
type = new CPPQualifierType(type, true, false);
return new CPPArrayType(type, getStringLiteralSize());
}
return new ProblemType(ISemanticProblem.TYPE_UNKNOWN_FOR_EXPRESSION);
}
public boolean isLValue() {
return getKind() == IASTLiteralExpression.lk_string_literal;
}
public ValueCategory getValueCategory() {
return isLValue() ? ValueCategory.LVALUE : ValueCategory.PRVALUE;
}
private IValue getStringLiteralSize() {
char[] value= getValue();
int length= value.length-1;
boolean isRaw= false;
for (int i = 0; i < length; i++) {
final char c = value[i];
if (c == '"') {
if (isRaw) {
for (int j = i + 1; j < length; j++) {
final char d= value[j];
if (d == '(') {
length -= 2*(j-i);
break;
}
}
}
length -= i;
if (length < 0)
length = 0;
break;
} else if (c == 'R') {
isRaw = true;
}
}
return Value.create(length);
}
private Kind getCharType() {
switch (getValue()[0]) {
case 'L':
return Kind.eWChar;
case 'u':
return Kind.eChar16;
case 'U':
return Kind.eChar32;
default:
return Kind.eChar;
}
}
private IType classifyTypeOfFloatLiteral() {
final char[] lit= getValue();
final int len= lit.length;
Kind kind= Kind.eDouble;
int flags= 0;
if (len > 0) {
switch (lit[len - 1]) {
case 'f': case 'F':
kind= Kind.eFloat;
break;
case 'l': case 'L':
flags |= IBasicType.IS_LONG;
break;
}
}
return new CPPBasicType(kind, flags, this);
}
private IType classifyTypeOfIntLiteral() {
int makelong= 0;
boolean unsigned= false;
final char[] lit= getValue();
for (int i= lit.length - 1; i >= 0; i--) {
final char c= lit[i];
if (!(c > 'f' && c <= 'z') && !(c > 'F' && c <= 'Z')) {
break;
}
switch (c) {
case 'u':
case 'U':
unsigned = true;
break;
case 'l':
case 'L':
makelong++;
break;
}
}
int flags= 0;
if (unsigned) {
flags |= IBasicType.IS_UNSIGNED;
}
if (makelong > 1) {
flags |= IBasicType.IS_LONG_LONG;
} else if (makelong == 1) {
flags |= IBasicType.IS_LONG;
}
return new CPPBasicType(Kind.eInt, flags, this);
}
/**
* @deprecated, use {@link #setValue(char[])}, instead.
*/
@Deprecated
public void setValue(String value) {
assertNotFrozen();
this.value = value.toCharArray();
}
/**
* @deprecated use {@link #CPPASTLiteralExpression(int, char[])}, instead.
*/
@Deprecated
public CPPASTLiteralExpression(int kind, String value) {
this(kind, value.toCharArray());
}
}